From a294aa028dc28d0d8ed9b6913a073c9a6dec0afe Mon Sep 17 00:00:00 2001 From: Antti Kauppila Date: Mon, 12 Mar 2018 13:30:00 +0200 Subject: [PATCH 01/25] LoRa: LoRaWANInterface refactored. - Only internal changes, no functionality changes - Some minor improvements to LoRaWanStack --- features/lorawan/LoRaWANInterface.cpp | 96 +------ features/lorawan/LoRaWANInterface.h | 3 - features/lorawan/LoRaWANStack.cpp | 267 +++++++++--------- features/lorawan/LoRaWANStack.h | 211 ++++++++------ features/lorawan/lorastack/mac/LoRaMac.cpp | 12 + .../lorawan/lorastack/phy/loraphy_target.h | 58 ++++ .../lorawan/system/lorawan_data_structures.h | 24 -- 7 files changed, 334 insertions(+), 337 deletions(-) create mode 100644 features/lorawan/lorastack/phy/loraphy_target.h diff --git a/features/lorawan/LoRaWANInterface.cpp b/features/lorawan/LoRaWANInterface.cpp index 8d45b0dee30..a8f1654e941 100644 --- a/features/lorawan/LoRaWANInterface.cpp +++ b/features/lorawan/LoRaWANInterface.cpp @@ -28,14 +28,9 @@ inline LoRaWANStack& stk_obj() return LoRaWANStack::get_lorawan_stack(); } -LoRaWANInterface::LoRaWANInterface(LoRaRadio& radio) : _link_check_requested(false) +LoRaWANInterface::LoRaWANInterface(LoRaRadio& radio) { - // Pass mac_handlers to radio to the radio driver after - // binding radio driver to PHY layer - radio_events_t *events = stk_obj().bind_radio_driver(radio); - radio.lock(); - radio.init_radio(events); - radio.unlock(); + stk_obj().bind_radio_driver(radio); } LoRaWANInterface::~LoRaWANInterface() @@ -44,71 +39,17 @@ LoRaWANInterface::~LoRaWANInterface() lorawan_status_t LoRaWANInterface::initialize(EventQueue *queue) { - if(!queue) { - return LORAWAN_STATUS_PARAMETER_INVALID; - } - return stk_obj().initialize_mac_layer(queue); } lorawan_status_t LoRaWANInterface::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. - - lorawan_connect_t connection_params; - - if (MBED_CONF_LORA_OVER_THE_AIR_ACTIVATION) { - static uint8_t dev_eui[] = MBED_CONF_LORA_DEVICE_EUI; - static uint8_t app_eui[] = MBED_CONF_LORA_APPLICATION_EUI; - static uint8_t app_key[] = MBED_CONF_LORA_APPLICATION_KEY; - /** - * - * OTAA join - */ - connection_params.connect_type = LORAWAN_CONNECTION_OTAA; - connection_params.connection_u.otaa.app_eui = app_eui; - connection_params.connection_u.otaa.dev_eui = dev_eui; - connection_params.connection_u.otaa.app_key = app_key; - connection_params.connection_u.otaa.nb_trials = MBED_CONF_LORA_NB_TRIALS; - - return connect(connection_params); - } else { - static uint8_t nwk_skey[] = MBED_CONF_LORA_NWKSKEY; - static uint8_t app_skey[] = MBED_CONF_LORA_APPSKEY; - static uint32_t dev_addr = MBED_CONF_LORA_DEVICE_ADDRESS; - static uint32_t nwk_id = (MBED_CONF_LORA_DEVICE_ADDRESS & LORAWAN_NETWORK_ID_MASK); - - /** - * - * ABP connection - */ - connection_params.connect_type = LORAWAN_CONNECTION_ABP; - connection_params.connection_u.abp.nwk_id = nwk_id; - connection_params.connection_u.abp.dev_addr = dev_addr; - connection_params.connection_u.abp.nwk_skey = nwk_skey; - connection_params.connection_u.abp.app_skey = app_skey; - - return connect(connection_params); - } + return stk_obj().connect(); } lorawan_status_t LoRaWANInterface::connect(const lorawan_connect_t &connect) { - lorawan_status_t mac_status; - - if (connect.connect_type == LORAWAN_CONNECTION_OTAA) { - mac_status = stk_obj().join_request_by_otaa(connect); - } else if (connect.connect_type == LORAWAN_CONNECTION_ABP) { - mac_status = stk_obj().activation_by_personalization(connect); - } else { - return LORAWAN_STATUS_PARAMETER_INVALID; - } - - return mac_status; + return stk_obj().connect(connect); } lorawan_status_t LoRaWANInterface::disconnect() @@ -118,13 +59,12 @@ lorawan_status_t LoRaWANInterface::disconnect() lorawan_status_t LoRaWANInterface::add_link_check_request() { - _link_check_requested = true; return stk_obj().set_link_check_request(); } void LoRaWANInterface::remove_link_check_request() { - _link_check_requested = false; + stk_obj().remove_link_check_request(); } lorawan_status_t LoRaWANInterface::set_datarate(uint8_t data_rate) @@ -170,37 +110,17 @@ lorawan_status_t LoRaWANInterface::remove_channel_plan() int16_t LoRaWANInterface::send(uint8_t port, const uint8_t* data, uint16_t length, int flags) { - if (_link_check_requested) { - // add a link check request with normal data, until the application - // explicitly removes it. - add_link_check_request(); - } + return stk_obj().handle_tx(port, data, length, flags); - if (data) { - return stk_obj().handle_tx(port, data, length, flags); - } else { - return LORAWAN_STATUS_PARAMETER_INVALID; - } } int16_t LoRaWANInterface::receive(uint8_t port, uint8_t* data, uint16_t length, int flags) { - if (data && length > 0) { - return stk_obj().handle_rx(port, data, length, flags); - } else { - return LORAWAN_STATUS_PARAMETER_INVALID; - } + return stk_obj().handle_rx(port, data, length, flags); } lorawan_status_t LoRaWANInterface::add_app_callbacks(lorawan_app_callbacks_t *callbacks) { - - if (!callbacks || !callbacks->events) { - // Event Callback is mandatory - return LORAWAN_STATUS_PARAMETER_INVALID; - } - - stk_obj().set_lora_callbacks(callbacks); - return LORAWAN_STATUS_OK; + return stk_obj().set_lora_callbacks(callbacks); } diff --git a/features/lorawan/LoRaWANInterface.h b/features/lorawan/LoRaWANInterface.h index b181ca10465..ffec1d93442 100644 --- a/features/lorawan/LoRaWANInterface.h +++ b/features/lorawan/LoRaWANInterface.h @@ -428,9 +428,6 @@ class LoRaWANInterface: public LoRaWANBase { * callbacks. */ virtual lorawan_status_t add_app_callbacks(lorawan_app_callbacks_t *callbacks); - -private: - bool _link_check_requested; }; #endif /* LORAWANINTERFACE_H_ */ diff --git a/features/lorawan/LoRaWANStack.cpp b/features/lorawan/LoRaWANStack.cpp index e055d3b7c0a..9a5faae3a41 100644 --- a/features/lorawan/LoRaWANStack.cpp +++ b/features/lorawan/LoRaWANStack.cpp @@ -85,10 +85,9 @@ lorawan_status_t LoRaWANStack::set_application_port(uint8_t port) * Constructor and destructor * ****************************************************************************/ LoRaWANStack::LoRaWANStack() -: _loramac(_lora_time), _lora_phy(_lora_time), - _device_current_state(DEVICE_STATE_NOT_INITIALIZED), _mac_handlers(NULL), - _num_retry(1), _app_port(INVALID_PORT), _duty_cycle_on(MBED_CONF_LORA_DUTY_CYCLE_ON), - _queue(NULL) +: _loramac(), + _device_current_state(DEVICE_STATE_NOT_INITIALIZED), _num_retry(1), + _app_port(INVALID_PORT), _link_check_requested(false), _queue(NULL) { #ifdef MBED_CONF_LORA_APP_PORT if (is_port_valid(MBED_CONF_LORA_APP_PORT)) { @@ -121,17 +120,82 @@ LoRaWANStack& LoRaWANStack::get_lorawan_stack() return _lw_stack; } -radio_events_t *LoRaWANStack::bind_radio_driver(LoRaRadio& radio) +void LoRaWANStack::bind_radio_driver(LoRaRadio& radio) { - // Store pointer to callback routines inside MAC layer (non-IRQ safe) - _mac_handlers = _loramac.get_phy_event_handlers(); - // passes the reference to radio driver down to PHY layer + //Move these to LoRaMAC class + radio_events_t *events = _loramac.get_phy_event_handlers(); _lora_phy.set_radio_instance(radio); - return _mac_handlers; + radio.lock(); + radio.init_radio(events); + radio.unlock(); +} + +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. + + lorawan_connect_t connection_params; + + if (MBED_CONF_LORA_OVER_THE_AIR_ACTIVATION) { + static uint8_t dev_eui[] = MBED_CONF_LORA_DEVICE_EUI; + static uint8_t app_eui[] = MBED_CONF_LORA_APPLICATION_EUI; + static uint8_t app_key[] = MBED_CONF_LORA_APPLICATION_KEY; + /** + * + * OTAA join + */ + connection_params.connect_type = LORAWAN_CONNECTION_OTAA; + connection_params.connection_u.otaa.app_eui = app_eui; + connection_params.connection_u.otaa.dev_eui = dev_eui; + connection_params.connection_u.otaa.app_key = app_key; + connection_params.connection_u.otaa.nb_trials = MBED_CONF_LORA_NB_TRIALS; + + return join_request_by_otaa(connection_params); + } else { + static uint8_t nwk_skey[] = MBED_CONF_LORA_NWKSKEY; + static uint8_t app_skey[] = MBED_CONF_LORA_APPSKEY; + static uint32_t dev_addr = MBED_CONF_LORA_DEVICE_ADDRESS; + static uint32_t nwk_id = (MBED_CONF_LORA_DEVICE_ADDRESS & LORAWAN_NETWORK_ID_MASK); + + /** + * + * ABP connection + */ + connection_params.connect_type = LORAWAN_CONNECTION_ABP; + connection_params.connection_u.abp.nwk_id = nwk_id; + connection_params.connection_u.abp.dev_addr = dev_addr; + connection_params.connection_u.abp.nwk_skey = nwk_skey; + connection_params.connection_u.abp.app_skey = app_skey; + + return activation_by_personalization(connection_params); + } +} + +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; + } + + return mac_status; } lorawan_status_t LoRaWANStack::initialize_mac_layer(EventQueue *queue) { + if(!queue) { + return LORAWAN_STATUS_PARAMETER_INVALID; + } + if (DEVICE_STATE_NOT_INITIALIZED != _device_current_state) { tr_debug("Initialized already"); @@ -139,34 +203,19 @@ lorawan_status_t LoRaWANStack::initialize_mac_layer(EventQueue *queue) } tr_debug("Initializing MAC layer"); - - //store a pointer to Event Queue _queue = queue; #if defined(LORAWAN_COMPLIANCE_TEST) _compliance_test.app_data_buffer = compliance_test_buffer; #endif - _lora_time.activate_timer_subsystem(queue); _loramac.initialize(&LoRaMacPrimitives, &_lora_phy, queue); - loramac_mib_req_confirm_t mib_req; - - mib_req.type = MIB_ADR; - mib_req.param.is_adr_enable = MBED_CONF_LORA_ADR_ON; - mib_set_request(&mib_req); - - mib_req.type = MIB_PUBLIC_NETWORK; - mib_req.param.enable_public_nwk = MBED_CONF_LORA_PUBLIC_NETWORK; - mib_set_request(&mib_req); - // Reset counters to zero. Will change in future with 1.1 support. _lw_session.downlink_counter = 0; _lw_session.uplink_counter = 0; - // Start loRaWAN state machine. - set_device_state(DEVICE_STATE_INIT); - return lora_state_machine(); + return lora_state_machine(DEVICE_STATE_INIT); } uint16_t LoRaWANStack::check_possible_tx_size(uint16_t size) @@ -255,11 +304,6 @@ lorawan_status_t LoRaWANStack::set_confirmed_msg_retry(uint8_t count) return LORAWAN_STATUS_OK; } -void LoRaWANStack::set_device_state(device_states_t new_state) -{ - _device_current_state = new_state; -} - /*! * \brief MLME-Indication event function * @@ -281,26 +325,27 @@ void LoRaWANStack::mlme_indication_handler(loramac_mlme_indication_t *mlmeIndica } } -void LoRaWANStack::set_lora_callbacks(lorawan_app_callbacks_t *cbs) +lorawan_status_t LoRaWANStack::set_lora_callbacks(lorawan_app_callbacks_t *cbs) { - if (cbs) { - if (cbs->events) { - _callbacks.events = cbs->events; - } + if (!cbs || !cbs->events) { + return LORAWAN_STATUS_PARAMETER_INVALID; + } - if (cbs->link_check_resp) { - _callbacks.link_check_resp = cbs->link_check_resp; - } + _callbacks.events = cbs->events; - if (cbs->battery_level) { - _callbacks.battery_level = cbs->battery_level; - } + if (cbs->link_check_resp) { + _callbacks.link_check_resp = cbs->link_check_resp; + } + + if (cbs->battery_level) { + _callbacks.battery_level = cbs->battery_level; } + + return LORAWAN_STATUS_OK; } lorawan_status_t LoRaWANStack::add_channels(const lorawan_channelplan_t &channel_plan) { - // If device is not initialized, stop right away if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) { tr_error("Stack not initialized!"); return LORAWAN_STATUS_NOT_INITIALIZED; @@ -380,39 +425,12 @@ lorawan_status_t LoRaWANStack::set_channel_data_rate(uint8_t data_rate) return mib_set_request(&mib_params); } -void LoRaWANStack::commission_device(const lorawan_dev_commission_t &commission_data) -{ - _lw_session.connection.connect_type = commission_data.connection.connect_type; - _lw_session.downlink_counter = commission_data.downlink_counter; - _lw_session.uplink_counter = commission_data.uplink_counter; - - if (commission_data.connection.connect_type == LORAWAN_CONNECTION_OTAA) { - _lw_session.connection.connection_u.otaa.app_eui = - commission_data.connection.connection_u.otaa.app_eui; - _lw_session.connection.connection_u.otaa.app_key = - commission_data.connection.connection_u.otaa.app_key; - _lw_session.connection.connection_u.otaa.dev_eui = - commission_data.connection.connection_u.otaa.dev_eui; - _lw_session.connection.connection_u.otaa.nb_trials = - commission_data.connection.connection_u.otaa.nb_trials; - } else { - _lw_session.connection.connection_u.abp.dev_addr = - commission_data.connection.connection_u.abp.dev_addr; - _lw_session.connection.connection_u.abp.nwk_skey = - commission_data.connection.connection_u.abp.nwk_skey; - _lw_session.connection.connection_u.abp.app_skey = - commission_data.connection.connection_u.abp.app_skey; - } -} - /** * * Join OTAA */ lorawan_status_t LoRaWANStack::join_request_by_otaa(const lorawan_connect_t ¶ms) { - lorawan_dev_commission_t commission; - if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { tr_error("Stack not initialized!"); @@ -421,21 +439,19 @@ lorawan_status_t LoRaWANStack::join_request_by_otaa(const lorawan_connect_t &par tr_debug("Initiating OTAA"); - commission.connection.connect_type = LORAWAN_CONNECTION_OTAA; - commission.connection.connection_u.otaa.dev_eui = params.connection_u.otaa.dev_eui; - commission.connection.connection_u.otaa.app_eui = params.connection_u.otaa.app_eui; - commission.connection.connection_u.otaa.app_key = params.connection_u.otaa.app_key; - commission.connection.connection_u.otaa.nb_trials = params.connection_u.otaa.nb_trials; - // 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. - commission.downlink_counter = 0; - commission.uplink_counter = 0; + _lw_session.downlink_counter = 0; + _lw_session.uplink_counter = 0; + _lw_session.connection.connect_type = LORAWAN_CONNECTION_OTAA; - commission_device(commission); - set_device_state(DEVICE_STATE_JOINING); - return lora_state_machine(); + _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); } /** @@ -444,9 +460,6 @@ lorawan_status_t LoRaWANStack::join_request_by_otaa(const lorawan_connect_t &par */ lorawan_status_t LoRaWANStack::activation_by_personalization(const lorawan_connect_t ¶ms) { - lorawan_status_t status; - lorawan_dev_commission_t commission; - if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { tr_error("Stack not initialized!"); return LORAWAN_STATUS_NOT_INITIALIZED; @@ -454,36 +467,36 @@ lorawan_status_t LoRaWANStack::activation_by_personalization(const lorawan_conne tr_debug("Initiating ABP"); - commission.connection.connect_type = LORAWAN_CONNECTION_ABP; - commission.connection.connection_u.abp.dev_addr = params.connection_u.abp.dev_addr; - commission.connection.connection_u.abp.nwk_skey = params.connection_u.abp.nwk_skey; - commission.connection.connection_u.abp.app_skey = params.connection_u.abp.app_skey; + _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, so we try a last ditch effort here to restore correct - // frame counters. If that doesn't work, user must manually reset frame - // counters on their network server. - commission.downlink_counter = _lw_session.downlink_counter; - commission.uplink_counter = _lw_session.uplink_counter; + // memory storage. + //_lw_session.downlink_counter; //Get from NVM + //_lw_session.uplink_counter; //Get from NVM tr_debug("Frame Counters. UpCnt=%lu, DownCnt=%lu", - commission.uplink_counter, commission.downlink_counter); - - commission_device(commission); - - set_device_state(DEVICE_STATE_ABP_CONNECTING); - status = lora_state_machine(); + _lw_session.uplink_counter, _lw_session.downlink_counter); - return status; + 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) { + if (_link_check_requested) { + // add a link check request with normal data, until the application + // explicitly removes it. + set_link_check_request(); + } + if (!_lw_session.active) { return LORAWAN_STATUS_NO_ACTIVE_SESSIONS; } @@ -577,8 +590,7 @@ int16_t LoRaWANStack::handle_tx(uint8_t port, const uint8_t* data, } tr_info("RTS = %u bytes, PEND = %u", _tx_msg.f_buffer_size, _tx_msg.pending_size); - set_device_state(DEVICE_STATE_SEND); - status = lora_state_machine(); + status = lora_state_machine(DEVICE_STATE_SEND); // send user the length of data which is scheduled now. // user should take care of the pending data. @@ -603,7 +615,7 @@ int16_t LoRaWANStack::handle_rx(const uint8_t port, uint8_t* data, } #endif - if (data == NULL) { + if (data == NULL || length == 0) { return LORAWAN_STATUS_PARAMETER_INVALID; } @@ -667,15 +679,6 @@ int16_t LoRaWANStack::handle_rx(const uint8_t port, uint8_t* data, return base_size; } -lorawan_status_t LoRaWANStack::mlme_request_handler(loramac_mlme_req_t *mlme_request) -{ - if (mlme_request == NULL) { - return LORAWAN_STATUS_PARAMETER_INVALID; - } - - return _loramac.mlme_request(mlme_request); -} - /** MLME-Confirm event function * * \param mlme_confirm Pointer to the confirm structure, @@ -693,14 +696,12 @@ void LoRaWANStack::mlme_confirm_handler(loramac_mlme_confirm_t *mlme_confirm) case MLME_JOIN: if (mlme_confirm->status == LORAMAC_EVENT_INFO_STATUS_OK) { // Status is OK, node has joined the network - set_device_state(DEVICE_STATE_JOINED); - if (lora_state_machine() != LORAWAN_STATUS_OK) { + 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. - set_device_state(DEVICE_STATE_IDLE); - if (lora_state_machine() != LORAWAN_STATUS_IDLE) { + if (lora_state_machine(DEVICE_STATE_IDLE) != LORAWAN_STATUS_IDLE) { tr_error("Lora state machine did not return DEVICE_STATE_IDLE !"); } @@ -950,7 +951,10 @@ void LoRaWANStack::compliance_test_handler(loramac_mcps_indication_t *mcps_indic #endif //5000ms _loramac.LoRaMacSetTxTimer(5000); - set_device_state(DEVICE_STATE_COMPLIANCE_TEST); + + //TODO: Should we call lora_state_machine here instead of just setting the state? + _device_current_state = DEVICE_STATE_COMPLIANCE_TEST; +// lora_state_machine(DEVICE_STATE_COMPLIANCE_TEST); tr_debug("Compliance test activated."); } } else { @@ -976,8 +980,7 @@ void LoRaWANStack::compliance_test_handler(loramac_mcps_indication_t *mcps_indic // Clear any compliance test message stuff before going back to normal operation. memset(&_tx_msg, 0, sizeof(_tx_msg)); - set_device_state(DEVICE_STATE_IDLE); - lora_state_machine(); + lora_state_machine(DEVICE_STATE_IDLE); break; case 1: // (iii, iv) _compliance_test.app_data_size = 2; @@ -1003,7 +1006,7 @@ void LoRaWANStack::compliance_test_handler(loramac_mcps_indication_t *mcps_indic case 5: // (viii) loramac_mlme_req_t mlme_req; mlme_req.type = MLME_LINK_CHECK; - mlme_request_handler(&mlme_req); + _loramac.mlme_request(&mlme_req); break; case 6: // (ix) loramac_mlme_req_t mlme_request; @@ -1027,14 +1030,14 @@ void LoRaWANStack::compliance_test_handler(loramac_mcps_indication_t *mcps_indic mlme_request.req.join.app_eui = _lw_session.connection.connection_u.otaa.app_eui; mlme_request.req.join.app_key = _lw_session.connection.connection_u.otaa.app_key; mlme_request.req.join.nb_trials = _lw_session.connection.connection_u.otaa.nb_trials; - mlme_request_handler(&mlme_request); + _loramac.mlme_request(&mlme_request); break; case 7: // (x) if (mcps_indication->buffer_size == 3) { loramac_mlme_req_t mlme_req; mlme_req.type = MLME_TXCW; mlme_req.req.cw_tx_mode.timeout = (uint16_t)((mcps_indication->buffer[1] << 8) | mcps_indication->buffer[2]); - mlme_request_handler(&mlme_req); + _loramac.mlme_request(&mlme_req); } else if (mcps_indication->buffer_size == 7) { loramac_mlme_req_t mlme_req; mlme_req.type = MLME_TXCW_1; @@ -1042,7 +1045,7 @@ void LoRaWANStack::compliance_test_handler(loramac_mcps_indication_t *mcps_indic mlme_req.req.cw_tx_mode.frequency = (uint32_t)((mcps_indication->buffer[3] << 16) | (mcps_indication->buffer[4] << 8) | mcps_indication->buffer[5]) * 100; mlme_req.req.cw_tx_mode.power = mcps_indication->buffer[6]; - mlme_request_handler(&mlme_req); + _loramac.mlme_request(&mlme_req); } _compliance_test.state = 1; break; @@ -1069,28 +1072,34 @@ lorawan_status_t LoRaWANStack::mib_get_request(loramac_mib_req_confirm_t *mib_ge lorawan_status_t LoRaWANStack::set_link_check_request() { + _link_check_requested = true; if (!_callbacks.link_check_resp) { tr_error("Must assign a callback function for link check request. "); return LORAWAN_STATUS_PARAMETER_INVALID; } loramac_mlme_req_t mlme_req; - mlme_req.type = MLME_LINK_CHECK; - return mlme_request_handler(&mlme_req); + return _loramac.mlme_request(&mlme_req); +} + +void LoRaWANStack::remove_link_check_request() +{ + _link_check_requested = false; } lorawan_status_t LoRaWANStack::shutdown() { - set_device_state(DEVICE_STATE_SHUTDOWN); - return lora_state_machine(); + return lora_state_machine(DEVICE_STATE_SHUTDOWN); } -lorawan_status_t LoRaWANStack::lora_state_machine() +lorawan_status_t LoRaWANStack::lora_state_machine(device_states_t new_state) { loramac_mib_req_confirm_t mib_req; lorawan_status_t status = LORAWAN_STATUS_DEVICE_OFF; + _device_current_state = new_state; + switch (_device_current_state) { case DEVICE_STATE_SHUTDOWN: /* @@ -1153,7 +1162,7 @@ lorawan_status_t LoRaWANStack::lora_state_machine() mlme_req.req.join.nb_trials = _lw_session.connection.connection_u.otaa.nb_trials; // Send join request to server. - status = mlme_request_handler(&mlme_req); + status = _loramac.mlme_request(&mlme_req); if (status != LORAWAN_STATUS_OK) { return status; } @@ -1243,7 +1252,7 @@ lorawan_status_t LoRaWANStack::lora_state_machine() } } // otherwise all done, put device in idle state - set_device_state(DEVICE_STATE_IDLE); + _device_current_state = DEVICE_STATE_IDLE; break; case DEVICE_STATE_IDLE: //Do nothing diff --git a/features/lorawan/LoRaWANStack.h b/features/lorawan/LoRaWANStack.h index 6be13cc8381..0d2f3f013dd 100644 --- a/features/lorawan/LoRaWANStack.h +++ b/features/lorawan/LoRaWANStack.h @@ -34,42 +34,7 @@ SPDX-License-Identifier: BSD-3-Clause #include "lorastack/mac/LoRaMac.h" #include "lorawan/system/lorawan_data_structures.h" #include "LoRaRadio.h" - -#ifdef MBED_CONF_LORA_PHY - #if MBED_CONF_LORA_PHY == 0 - #include "lorawan/lorastack/phy/LoRaPHYEU868.h" - #define LoRaPHY_region LoRaPHYEU868 - #elif MBED_CONF_LORA_PHY == 1 - #include "lorawan/lorastack/phy/LoRaPHYAS923.h" - #define LoRaPHY_region LoRaPHYAS923 - #elif MBED_CONF_LORA_PHY == 2 - #include "lorawan/lorastack/phy/LoRaPHYAU915.h" - #define LoRaPHY_region LoRaPHYAU915; - #elif MBED_CONF_LORA_PHY == 3 - #include "lorawan/lorastack/phy/LoRaPHYCN470.h" - #define LoRaPHY_region LoRaPHYCN470 - #elif MBED_CONF_LORA_PHY == 4 - #include "lorawan/lorastack/phy/LoRaPHYCN779.h" - #define LoRaPHY_region LoRaPHYCN779 - #elif MBED_CONF_LORA_PHY == 5 - #include "lorawan/lorastack/phy/LoRaPHYEU433.h" - #define LoRaPHY_region LoRaPHYEU433 - #elif MBED_CONF_LORA_PHY == 6 - #include "lorawan/lorastack/phy/LoRaPHYIN865.h" - #define LoRaPHY_region LoRaPHYIN865 - #elif MBED_CONF_LORA_PHY == 7 - #include "lorawan/lorastack/phy/LoRaPHYKR920.h" - #define LoRaPHY_region LoRaPHYKR920 - #elif MBED_CONF_LORA_PHY == 8 - #include "lorawan/lorastack/phy/LoRaPHYUS915.h" - #define LoRaPHY_region LoRaPHYUS915 - #elif MBED_CONF_LORA_PHY == 9 - #include "lorawan/lorastack/phy/LoRaPHYUS915Hybrid.h" - #define LoRaPHY_region LoRaPHYUS915Hybrid - #endif //MBED_CONF_LORA_PHY == VALUE -#else - #error "Must set LoRa PHY layer parameters." -#endif //MBED_CONF_LORA_PHY +#include "loraphy_target.h" /** * A mask for the network ID. @@ -103,15 +68,90 @@ class LoRaWANStack: private mbed::NonCopyable { * MAC layer is totally detached from the PHY layer so the stack layer * needs to play the role of an arbitrator. This API gets a radio driver * object from the application (via LoRaWANInterface), binds it to the PHY - * layer and returns MAC layer callback handles which the radio driver will + * layer and initialises radio callback handles which the radio driver will * use in order to report events. * * @param radio LoRaRadio object, i.e., the radio driver * - * @return A list of callbacks from MAC layer that needs to - * be passed to radio driver */ - radio_events_t *bind_radio_driver(LoRaRadio& radio); + void bind_radio_driver(LoRaRadio& radio); + + /** Connect OTAA or ABP using Mbed-OS config system + * + * Connect by Over The Air Activation or Activation By Personalization. + * You need to configure the connection properly via the Mbed OS configuration + * system. + * + * When connecting via OTAA, the return code for success (LORAWAN_STATUS_CONNECT_IN_PROGRESS) is negative. + * However, this is not a real error. It tells you that the connection is in progress and you will + * be notified of the completion via an event. By default, after the Join Accept message + * is received, base stations may provide the node with a CF-List that replaces + * all user-configured channels except the Join/Default channels. A CF-List can + * configure a maximum of five channels other than the default channels. + * + * In case of ABP, the CONNECTED event is posted before the call to `connect()` returns. + * To configure more channels, we recommend that you use the `set_channel_plan()` API after the connection. + * By default, the PHY layers configure only the mandatory Join channels. The retransmission back-off restrictions + * on these channels are severe and you may experience long delays or even failures in the confirmed traffic. + * If you add more channels, the aggregated duty cycle becomes much more relaxed as compared to the Join (default) channels only. + * + * **NOTES ON RECONNECTION:** + * Currently, the Mbed OS LoRaWAN implementation does not support non-volatile + * memory storage. Therefore, the state and frame counters cannot be restored after + * a power cycle. However, if you use the `disconnect()` API to shut down the LoRaWAN + * protocol, the state and frame counters are saved. Connecting again would try to + * restore the previous session. According to the LoRaWAN 1.0.2 specification, the frame counters are always reset + * to zero for OTAA and a new Join request lets the network server know + * that the counters need a reset. The same is said about the ABP but there + * is no way to convey this information to the network server. For a network + * server, an ABP device is always connected. That's why storing the frame counters + * is important, at least for ABP. That's why we try to restore frame counters from + * session information after a disconnection. + * + * @return LORAWAN_STATUS_OK or LORAWAN_STATUS_CONNECT_IN_PROGRESS + * on success, or a negative error code on failure. + */ + lorawan_status_t connect(); + + /** Connect OTAA or ABP with parameters + * + * All connection parameters are chosen by the user and provided in the + * data structure passed down. + * + * When connecting via OTAA, the return code for success (LORAWAN_STATUS_CONNECT_IN_PROGRESS) is negative. + * However, this is not a real error. It tells you that connection is in progress and you will + * be notified of completion via an event. By default, after Join Accept message + * is received, base stations may provide the node with a CF-List which replaces + * all user-configured channels except the Join/Default channels. A CF-List can + * configure a maximum of five channels other than the default channels. + * + * In case of ABP, the CONNECTED event is posted before the call to `connect()` returns. + * To configure more channels, we recommend that you use the `set_channel_plan()` API after the connection. + * By default, the PHY layers configure only the mandatory Join + * channels. The retransmission back-off restrictions on these channels + * are severe and you may experience long delays or even + * failures in the confirmed traffic. If you add more channels, the aggregated duty + * cycle becomes much more relaxed as compared to the Join (default) channels only. + * + * **NOTES ON RECONNECTION:** + * Currently, the Mbed OS LoRaWAN implementation does not support non-volatile + * memory storage. Therefore, the state and frame counters cannot be restored after + * a power cycle. However, if you use the `disconnect()` API to shut down the LoRaWAN + * protocol, the state and frame counters are saved. Connecting again would try to + * restore the previous session. According to the LoRaWAN 1.0.2 specification, the frame counters are always reset + * to zero for OTAA and a new Join request lets the network server know + * that the counters need a reset. The same is said about the ABP but there + * is no way to convey this information to the network server. For a network + * server, an ABP device is always connected. That's why storing the frame counters + * is important, at least for ABP. That's why we try to restore frame counters from + * session information after a disconnection. + * + * @param connect Options for an end device connection to the gateway. + * + * @return LORAWAN_STATUS_OK or LORAWAN_STATUS_CONNECT_IN_PROGRESS, + * a negative error code on failure. + */ + lorawan_status_t connect(const lorawan_connect_t &connect); /** End device initialization. * @param queue A pointer to an EventQueue passed from the application. @@ -122,8 +162,9 @@ class LoRaWANStack: private mbed::NonCopyable { /** Sets all callbacks for the application. * * @param callbacks A pointer to the structure carrying callbacks. + * @return LORAWAN_STATUS_OK on success, a negative error code on failure. */ - void set_lora_callbacks(lorawan_app_callbacks_t *callbacks); + lorawan_status_t set_lora_callbacks(lorawan_app_callbacks_t *callbacks); /** Adds channels to use. * @@ -209,39 +250,6 @@ class LoRaWANStack: private mbed::NonCopyable { */ lorawan_status_t enable_adaptive_datarate(bool adr_enabled); - /** Commissions a LoRa device. - * - * @param commission_data A structure representing all the commission - * information. - */ - void commission_device(const lorawan_dev_commission_t &commission_data); - - /** 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. - */ - 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); - /** Send message to gateway * * @param port The application port number. Port numbers 0 and 224 @@ -337,6 +345,13 @@ class LoRaWANStack: private mbed::NonCopyable { */ lorawan_status_t set_link_check_request(); + /** Removes link check request sticky MAC command. + * + * Any already queued request may still get entertained. However, no new + * requests will be made. + */ + void remove_link_check_request(); + /** Shuts down the LoRaWAN protocol. * * In response to the user call for disconnection, the stack shuts down itself. @@ -356,17 +371,8 @@ class LoRaWANStack: private mbed::NonCopyable { /** * State machine for stack controller layer. - * Needs to be wriggled for every state change */ - lorawan_status_t lora_state_machine(); - - /** - * Sets the current state of the device. - * Every call to set_device_state() should precede with - * a call to lora_state_machine() in order to take the state change - * in effect. - */ - void set_device_state(device_states_t new_state); + lorawan_status_t lora_state_machine(device_states_t new_state); /** * Hands over the packet to Mac layer by posting an MCPS request. @@ -380,13 +386,6 @@ class LoRaWANStack: private mbed::NonCopyable { */ void mlme_indication_handler(loramac_mlme_indication_t *mlmeIndication); - /** - * Handles an MLME request coming from the upper layers and delegates - * it to the Mac layer, for example, a Join request goes as an MLME request - * to the Mac layer. - */ - lorawan_status_t mlme_request_handler(loramac_mlme_req_t *mlme_request); - /** * Handles an MLME confirmation coming from the Mac layer and uses it to * update the state for example, a Join Accept triggers an MLME confirmation, @@ -442,6 +441,32 @@ class LoRaWANStack: private mbed::NonCopyable { */ uint16_t check_possible_tx_size(uint16_t size); + /** 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. + */ + 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); + private: LoRaWANTimeHandler _lora_time; @@ -451,13 +476,13 @@ class LoRaWANStack: private mbed::NonCopyable { device_states_t _device_current_state; lorawan_app_callbacks_t _callbacks; - radio_events_t *_mac_handlers; lorawan_session_t _lw_session; loramac_tx_message_t _tx_msg; loramac_rx_message_t _rx_msg; uint8_t _num_retry; uint8_t _app_port; - bool _duty_cycle_on; + bool _link_check_requested; + events::EventQueue *_queue; #if defined(LORAWAN_COMPLIANCE_TEST) diff --git a/features/lorawan/lorastack/mac/LoRaMac.cpp b/features/lorawan/lorastack/mac/LoRaMac.cpp index bb82dcd7d76..90b10bd23c8 100644 --- a/features/lorawan/lorastack/mac/LoRaMac.cpp +++ b/features/lorawan/lorastack/mac/LoRaMac.cpp @@ -1582,6 +1582,8 @@ lorawan_status_t LoRaMac::send_frame_on_channel(uint8_t channel) lorawan_status_t LoRaMac::initialize(loramac_primitives_t *primitives, LoRaPHY *phy, EventQueue *queue) { + _lora_time.activate_timer_subsystem(queue); + //store event queue pointer ev_queue = queue; @@ -1649,6 +1651,16 @@ lorawan_status_t LoRaMac::initialize(loramac_primitives_t *primitives, // Store the current initialization time _params.timers.mac_init_time = _lora_time.get_current_time(); + loramac_mib_req_confirm_t mib_req; + + mib_req.type = MIB_ADR; + mib_req.param.is_adr_enable = MBED_CONF_LORA_ADR_ON; + mib_set_request_confirm(&mib_req); + + mib_req.type = MIB_PUBLIC_NETWORK; + mib_req.param.enable_public_nwk = MBED_CONF_LORA_PUBLIC_NETWORK; + mib_set_request_confirm(&mib_req); + return LORAWAN_STATUS_OK; } diff --git a/features/lorawan/lorastack/phy/loraphy_target.h b/features/lorawan/lorastack/phy/loraphy_target.h new file mode 100644 index 00000000000..ef83458b567 --- /dev/null +++ b/features/lorawan/lorastack/phy/loraphy_target.h @@ -0,0 +1,58 @@ +/** + * Copyright (c) 2017, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LORAPHY_TARGET +#define LORAPHY_TARGET + +#ifdef MBED_CONF_LORA_PHY + #if MBED_CONF_LORA_PHY == 0 + #include "lorawan/lorastack/phy/LoRaPHYEU868.h" + #define LoRaPHY_region LoRaPHYEU868 + #elif MBED_CONF_LORA_PHY == 1 + #include "lorawan/lorastack/phy/LoRaPHYAS923.h" + #define LoRaPHY_region LoRaPHYAS923 + #elif MBED_CONF_LORA_PHY == 2 + #include "lorawan/lorastack/phy/LoRaPHYAU915.h" + #define LoRaPHY_region LoRaPHYAU915; + #elif MBED_CONF_LORA_PHY == 3 + #include "lorawan/lorastack/phy/LoRaPHYCN470.h" + #define LoRaPHY_region LoRaPHYCN470 + #elif MBED_CONF_LORA_PHY == 4 + #include "lorawan/lorastack/phy/LoRaPHYCN779.h" + #define LoRaPHY_region LoRaPHYCN779 + #elif MBED_CONF_LORA_PHY == 5 + #include "lorawan/lorastack/phy/LoRaPHYEU433.h" + #define LoRaPHY_region LoRaPHYEU433 + #elif MBED_CONF_LORA_PHY == 6 + #include "lorawan/lorastack/phy/LoRaPHYIN865.h" + #define LoRaPHY_region LoRaPHYIN865 + #elif MBED_CONF_LORA_PHY == 7 + #include "lorawan/lorastack/phy/LoRaPHYKR920.h" + #define LoRaPHY_region LoRaPHYKR920 + #elif MBED_CONF_LORA_PHY == 8 + #include "lorawan/lorastack/phy/LoRaPHYUS915.h" + #define LoRaPHY_region LoRaPHYUS915 + #elif MBED_CONF_LORA_PHY == 9 + #include "lorawan/lorastack/phy/LoRaPHYUS915Hybrid.h" + #define LoRaPHY_region LoRaPHYUS915Hybrid + #endif //MBED_CONF_LORA_PHY == VALUE +#else + #error "Must set LoRa PHY layer parameters." +#endif //MBED_CONF_LORA_PHY + +#endif // LORAPHY_TARGET + diff --git a/features/lorawan/system/lorawan_data_structures.h b/features/lorawan/system/lorawan_data_structures.h index 2c8d357f3f0..183e1f9968b 100644 --- a/features/lorawan/system/lorawan_data_structures.h +++ b/features/lorawan/system/lorawan_data_structures.h @@ -1839,30 +1839,6 @@ typedef struct lorawan_session { uint32_t downlink_counter; } lorawan_session_t; -/** Commissioning data - * - * A structure for data in commission. - */ -typedef struct { - /** Connection information - * - * Saves information for etc. keys - */ - lorawan_connect_t connection; - /** - * LoRaWAN Up-link counter - * - * Related MIB type: LORA_MIB_UPLINK_COUNTER - */ - uint32_t uplink_counter; - /** - * LoRaWAN Down-link counter - * - * Related MIB type: LORA_MIB_DOWNLINK_COUNTER - */ - uint32_t downlink_counter; -} lorawan_dev_commission_t; - /** Structure containing the uplink status * */ From 339306ed1b8cfd295f1bd4eff91a474728883b9b Mon Sep 17 00:00:00 2001 From: Kimmo Vaisanen Date: Thu, 15 Feb 2018 15:12:18 +0200 Subject: [PATCH 02/25] Ensure DR_6 cannot be selected for IN865 region --- features/lorawan/lorastack/phy/LoRaPHY.cpp | 91 +++++++++++-------- features/lorawan/lorastack/phy/LoRaPHY.h | 4 +- .../lorawan/lorastack/phy/LoRaPHYIN865.cpp | 2 +- 3 files changed, 58 insertions(+), 39 deletions(-) diff --git a/features/lorawan/lorastack/phy/LoRaPHY.cpp b/features/lorawan/lorastack/phy/LoRaPHY.cpp index 0461c6517e1..c362f4d31c1 100644 --- a/features/lorawan/lorastack/phy/LoRaPHY.cpp +++ b/features/lorawan/lorastack/phy/LoRaPHY.cpp @@ -427,13 +427,13 @@ int8_t LoRaPHY::compute_tx_power(int8_t tx_power_idx, float max_eirp, int8_t LoRaPHY::get_next_lower_dr(int8_t dr, int8_t min_dr) { - uint8_t next_lower_dr = 0; + uint8_t next_lower_dr = dr; - if (dr == min_dr) { - next_lower_dr = min_dr; - } else { - next_lower_dr = dr - 1; - } + do { + if (next_lower_dr != min_dr) { + next_lower_dr -= 1; + } + } while((next_lower_dr != min_dr) && !is_datarate_supported(next_lower_dr)); return next_lower_dr; } @@ -487,6 +487,15 @@ uint8_t LoRaPHY::enabled_channel_count(bool joined, uint8_t datarate, return count; } +bool LoRaPHY::is_datarate_supported(const int8_t datarate) const +{ + if (datarate < phy_params.datarates.size) { + return (((uint8_t *)phy_params.datarates.table)[datarate] != 0) ? true : false; + } else { + return false; + } +} + void LoRaPHY::reset_to_default_values(loramac_protocol_params *params, bool init) { if (init) { @@ -629,30 +638,36 @@ void LoRaPHY::restore_default_channels() bool LoRaPHY::verify_rx_datarate(uint8_t datarate) { - if (phy_params.dl_dwell_time_setting == 0) { - //TODO: Check this! datarate must be same as minimum! Can be compared directly if OK - return val_in_range(datarate, - phy_params.min_rx_datarate, - phy_params.min_rx_datarate); - } else { - return val_in_range(datarate, - phy_params.dwell_limit_datarate, - phy_params.min_rx_datarate ); + if (is_datarate_supported(datarate)) { + if (phy_params.dl_dwell_time_setting == 0) { + //TODO: Check this! datarate must be same as minimum! Can be compared directly if OK + return val_in_range(datarate, + phy_params.min_rx_datarate, + phy_params.max_rx_datarate); + } else { + return val_in_range(datarate, + phy_params.dwell_limit_datarate, + phy_params.max_rx_datarate ); + } } + return false; } bool LoRaPHY::verify_tx_datarate(uint8_t datarate, bool use_default) { - if (use_default) { - return val_in_range(datarate, phy_params.default_datarate, - phy_params.default_max_datarate); - } else if (phy_params.ul_dwell_time_setting == 0) { - return val_in_range(datarate, phy_params.min_tx_datarate, - phy_params.max_tx_datarate); - } else { - return val_in_range(datarate, phy_params.dwell_limit_datarate, - phy_params.max_tx_datarate); + if (is_datarate_supported(datarate)) { + if (use_default) { + return val_in_range(datarate, phy_params.default_datarate, + phy_params.default_max_datarate); + } else if (phy_params.ul_dwell_time_setting == 0) { + return val_in_range(datarate, phy_params.min_tx_datarate, + phy_params.max_tx_datarate); + } else { + return val_in_range(datarate, phy_params.dwell_limit_datarate, + phy_params.max_tx_datarate); + } } + return false; } bool LoRaPHY::verify_tx_power(uint8_t tx_power) @@ -976,23 +991,27 @@ uint8_t LoRaPHY::link_ADR_request(adr_req_params_t* link_adr_req, } } - verify_params.status = status; + if (is_datarate_supported(adr_settings.datarate)) { + verify_params.status = status; - verify_params.adr_enabled = link_adr_req->adr_enabled; - verify_params.current_datarate = link_adr_req->current_datarate; - verify_params.current_tx_power = link_adr_req->current_tx_power; - verify_params.current_nb_rep = link_adr_req->current_nb_rep; + verify_params.adr_enabled = link_adr_req->adr_enabled; + verify_params.current_datarate = link_adr_req->current_datarate; + verify_params.current_tx_power = link_adr_req->current_tx_power; + verify_params.current_nb_rep = link_adr_req->current_nb_rep; - verify_params.datarate = adr_settings.datarate; - verify_params.tx_power = adr_settings.tx_power; - verify_params.nb_rep = adr_settings.nb_rep; + verify_params.datarate = adr_settings.datarate; + verify_params.tx_power = adr_settings.tx_power; + verify_params.nb_rep = adr_settings.nb_rep; - verify_params.channel_mask = temp_channel_mask; + verify_params.channel_mask = temp_channel_mask; - // Verify the parameters and update, if necessary - status = verify_link_ADR_req(&verify_params, &adr_settings.datarate, - &adr_settings.tx_power, &adr_settings.nb_rep); + // Verify the parameters and update, if necessary + status = verify_link_ADR_req(&verify_params, &adr_settings.datarate, + &adr_settings.tx_power, &adr_settings.nb_rep); + } else { + status &= 0xFD; // Datarate KO + } // Update channelsMask if everything is correct if (status == 0x07) { diff --git a/features/lorawan/lorastack/phy/LoRaPHY.h b/features/lorawan/lorastack/phy/LoRaPHY.h index fe0ec358d33..4023b4396bb 100644 --- a/features/lorawan/lorastack/phy/LoRaPHY.h +++ b/features/lorawan/lorastack/phy/LoRaPHY.h @@ -614,8 +614,8 @@ class LoRaPHY : private mbed::NonCopyable { uint8_t enabled_channel_count(bool joined, uint8_t datarate, const uint16_t *mask, uint8_t* enabledChannels, uint8_t* delayTx); -}; - + bool is_datarate_supported(const int8_t datarate) const; +}; #endif /* MBED_OS_LORAPHY_BASE_ */ diff --git a/features/lorawan/lorastack/phy/LoRaPHYIN865.cpp b/features/lorawan/lorastack/phy/LoRaPHYIN865.cpp index 80aa112c0c8..5594647ebc5 100644 --- a/features/lorawan/lorastack/phy/LoRaPHYIN865.cpp +++ b/features/lorawan/lorastack/phy/LoRaPHYIN865.cpp @@ -210,7 +210,7 @@ static const channel_params_t IN865_LC3 = { 865985000, 0, { ( ( DR_5 << 4 ) | DR /*! * Data rates table definition */ -static const uint8_t datarates_IN865[] = { 12, 11, 10, 9, 8, 7, 7, 50 }; +static const uint8_t datarates_IN865[] = { 12, 11, 10, 9, 8, 7, 0, 50 }; /*! * Bandwidths table definition in Hz From e206c1ee542053530f982cff52751f13eb4b2635 Mon Sep 17 00:00:00 2001 From: Kimmo Vaisanen Date: Fri, 16 Feb 2018 10:15:23 +0200 Subject: [PATCH 03/25] Changed RegionNextChannel function in order to return LoRaMacStatus_t instead of a boolean Removed the while loop checking the return value from set_next_channel (GitHub Issue https://github.com/Lora-net/LoRaMac-node/issues/357) The new return values are: LORAWAN_STATUS_OK : A channel has been found. LORAWAN_STATUS_NO_FREE_CHANNEL_FOUND : No free channel has been found (AS923 and KR920 regions) LORAWAN_STATUS_DUTYCYCLE_RESTRICTED : No channel found due to the duty-cycle or JoinReq back-off restrictions. Trial must be delayed. LORAWAN_STATUS_NO_CHANNEL_FOUND : No channel has been found. Re-enabled the default channels. --- features/lorawan/lorastack/mac/LoRaMac.cpp | 39 ++++++++++--------- features/lorawan/lorastack/phy/LoRaPHY.cpp | 12 +++--- features/lorawan/lorastack/phy/LoRaPHY.h | 6 +-- .../lorawan/lorastack/phy/LoRaPHYAS923.cpp | 14 +++---- features/lorawan/lorastack/phy/LoRaPHYAS923.h | 6 +-- .../lorawan/lorastack/phy/LoRaPHYAU915.cpp | 12 +++--- features/lorawan/lorastack/phy/LoRaPHYAU915.h | 6 +-- .../lorawan/lorastack/phy/LoRaPHYKR920.cpp | 14 +++---- features/lorawan/lorastack/phy/LoRaPHYKR920.h | 6 +-- .../lorawan/lorastack/phy/LoRaPHYUS915.cpp | 12 +++--- features/lorawan/lorastack/phy/LoRaPHYUS915.h | 4 +- .../lorastack/phy/LoRaPHYUS915Hybrid.cpp | 12 +++--- .../lorastack/phy/LoRaPHYUS915Hybrid.h | 6 +-- .../lorawan/system/lorawan_data_structures.h | 3 ++ 14 files changed, 78 insertions(+), 74 deletions(-) diff --git a/features/lorawan/lorastack/mac/LoRaMac.cpp b/features/lorawan/lorastack/mac/LoRaMac.cpp index 90b10bd23c8..42535277183 100644 --- a/features/lorawan/lorastack/mac/LoRaMac.cpp +++ b/features/lorawan/lorastack/mac/LoRaMac.cpp @@ -1152,6 +1152,7 @@ lorawan_status_t LoRaMac::schedule_tx(void) { lorawan_time_t dutyCycleTimeOff = 0; channel_selection_params_t nextChan; + lorawan_status_t status = LORAWAN_STATUS_PARAMETER_INVALID; // Check if the device is off if (_params.sys_params.max_duty_cycle == 255) { @@ -1173,12 +1174,23 @@ lorawan_status_t LoRaMac::schedule_tx(void) nextChan.last_aggregate_tx_time = _params.timers.aggregated_last_tx_time; // Select channel - while (lora_phy->set_next_channel(&nextChan, &_params.channel, - &dutyCycleTimeOff, - &_params.timers.aggregated_timeoff) == false) { - _params.sys_params.channel_data_rate = lora_phy->get_default_tx_datarate(); - // Update datarate in the function parameters - nextChan.current_datarate = _params.sys_params.channel_data_rate; + status = lora_phy->set_next_channel(&nextChan, &_params.channel, + &dutyCycleTimeOff, + &_params.timers.aggregated_timeoff); + switch (status) { + case LORAWAN_STATUS_NO_CHANNEL_FOUND: + case LORAWAN_STATUS_NO_FREE_CHANNEL_FOUND: + return status; + case LORAWAN_STATUS_DUTYCYCLE_RESTRICTED: + if (dutyCycleTimeOff != 0) { + // Send later - prepare timer + tr_debug("Next Transmission in %lu ms", dutyCycleTimeOff); + _params.mac_state |= LORAMAC_TX_DELAYED; + _lora_time.start(_params.timers.tx_delayed_timer, dutyCycleTimeOff); + } + return LORAWAN_STATUS_OK; + default: + break; } tr_debug("Next Channel Idx=%d, DR=%d", _params.channel, nextChan.current_datarate); @@ -1214,19 +1226,8 @@ lorawan_status_t LoRaMac::schedule_tx(void) + _params.rx_window2_config.window_offset; } - // Schedule transmission of frame - if (dutyCycleTimeOff == 0) { - // Try to send now - return send_frame_on_channel(_params.channel); - } else { - // Send later - prepare timer - _params.mac_state |= LORAMAC_TX_DELAYED; - tr_debug("Next Transmission in %lu ms", dutyCycleTimeOff); - - _lora_time.start(_params.timers.tx_delayed_timer, dutyCycleTimeOff); - - return LORAWAN_STATUS_OK; - } + // Try to send now + return send_frame_on_channel(_params.channel); } void LoRaMac::calculate_backOff(uint8_t channel) diff --git a/features/lorawan/lorastack/phy/LoRaPHY.cpp b/features/lorawan/lorastack/phy/LoRaPHY.cpp index c362f4d31c1..3af695778e2 100644 --- a/features/lorawan/lorastack/phy/LoRaPHY.cpp +++ b/features/lorawan/lorastack/phy/LoRaPHY.cpp @@ -1195,9 +1195,9 @@ void LoRaPHY::calculate_backoff(backoff_params_t* calc_backoff) } } -bool LoRaPHY::set_next_channel(channel_selection_params_t* params, - uint8_t* channel, lorawan_time_t* time, - lorawan_time_t* aggregate_timeoff) +lorawan_status_t LoRaPHY::set_next_channel(channel_selection_params_t* params, + uint8_t* channel, lorawan_time_t* time, + lorawan_time_t* aggregate_timeoff) { uint8_t channel_count = 0; uint8_t delay_tx = 0; @@ -1247,13 +1247,13 @@ bool LoRaPHY::set_next_channel(channel_selection_params_t* params, // We found a valid channel *channel = enabled_channels[get_random(0, channel_count - 1)]; *time = 0; - return true; + return LORAWAN_STATUS_OK; } if (delay_tx > 0) { // Delay transmission due to AggregatedTimeOff or to a band time off *time = next_tx_delay; - return true; + return LORAWAN_STATUS_DUTYCYCLE_RESTRICTED; } // Datarate not supported by any channel, restore defaults @@ -1261,7 +1261,7 @@ bool LoRaPHY::set_next_channel(channel_selection_params_t* params, phy_params.channels.default_mask, phy_params.channels.mask_size); *time = 0; - return false; + return LORAWAN_STATUS_NO_CHANNEL_FOUND; } lorawan_status_t LoRaPHY::add_channel(channel_params_t* new_channel, uint8_t id) diff --git a/features/lorawan/lorastack/phy/LoRaPHY.h b/features/lorawan/lorastack/phy/LoRaPHY.h index 4023b4396bb..ca895bde7d6 100644 --- a/features/lorawan/lorastack/phy/LoRaPHY.h +++ b/features/lorawan/lorastack/phy/LoRaPHY.h @@ -332,9 +332,9 @@ class LoRaPHY : private mbed::NonCopyable { * * @return Function status [1: OK, 0: Unable to find a channel on the current datarate]. */ - virtual bool set_next_channel(channel_selection_params_t* nextChanParams, - uint8_t* channel, lorawan_time_t* time, - lorawan_time_t* aggregatedTimeOff); + virtual lorawan_status_t set_next_channel(channel_selection_params_t* nextChanParams, + uint8_t* channel, lorawan_time_t* time, + lorawan_time_t* aggregatedTimeOff); /** Adds a channel to the channel list. * diff --git a/features/lorawan/lorastack/phy/LoRaPHYAS923.cpp b/features/lorawan/lorastack/phy/LoRaPHYAS923.cpp index bd9ededc37c..4ce26dd84c9 100644 --- a/features/lorawan/lorastack/phy/LoRaPHYAS923.cpp +++ b/features/lorawan/lorastack/phy/LoRaPHYAS923.cpp @@ -334,9 +334,9 @@ int8_t LoRaPHYAS923::get_alternate_DR(uint8_t nb_trials) return AS923_DWELL_LIMIT_DATARATE; } -bool LoRaPHYAS923::set_next_channel(channel_selection_params_t* next_channel_prams, - uint8_t* channel, lorawan_time_t* time, - lorawan_time_t* aggregate_timeoff) +lorawan_status_t LoRaPHYAS923::set_next_channel(channel_selection_params_t* next_channel_prams, + uint8_t* channel, lorawan_time_t* time, + lorawan_time_t* aggregate_timeoff) { uint8_t next_channel_idx = 0; uint8_t nb_enabled_channels = 0; @@ -387,23 +387,23 @@ bool LoRaPHYAS923::set_next_channel(channel_selection_params_t* next_channel_pra _radio->unlock(); *channel = next_channel_idx; *time = 0; - return true; + return LORAWAN_STATUS_OK; } } _radio->unlock(); - return false; + return LORAWAN_STATUS_NO_FREE_CHANNEL_FOUND; } else { if (delay_tx > 0) { // Delay transmission due to AggregatedTimeOff or to a band time off *time = next_tx_delay; - return true; + return LORAWAN_STATUS_DUTYCYCLE_RESTRICTED; } // Datarate not supported by any channel, restore defaults channel_mask[0] |= LC( 1 ) + LC( 2 ); *time = 0; - return false; + return LORAWAN_STATUS_NO_CHANNEL_FOUND; } } diff --git a/features/lorawan/lorastack/phy/LoRaPHYAS923.h b/features/lorawan/lorastack/phy/LoRaPHYAS923.h index 17f943dbce1..88030339ad1 100644 --- a/features/lorawan/lorastack/phy/LoRaPHYAS923.h +++ b/features/lorawan/lorastack/phy/LoRaPHYAS923.h @@ -55,9 +55,9 @@ class LoRaPHYAS923 : public LoRaPHY { virtual int8_t get_alternate_DR(uint8_t nb_trials); - virtual bool set_next_channel(channel_selection_params_t* nextChanParams, - uint8_t* channel, lorawan_time_t* time, - lorawan_time_t* aggregatedTimeOff ); + virtual lorawan_status_t set_next_channel(channel_selection_params_t* nextChanParams, + uint8_t* channel, lorawan_time_t* time, + lorawan_time_t* aggregatedTimeOff ); virtual uint8_t apply_DR_offset(int8_t dr, int8_t drOffset ); diff --git a/features/lorawan/lorastack/phy/LoRaPHYAU915.cpp b/features/lorawan/lorastack/phy/LoRaPHYAU915.cpp index 9c262a9a628..7964abdd4a1 100644 --- a/features/lorawan/lorastack/phy/LoRaPHYAU915.cpp +++ b/features/lorawan/lorastack/phy/LoRaPHYAU915.cpp @@ -555,9 +555,9 @@ int8_t LoRaPHYAU915::get_alternate_DR(uint8_t nb_trials) return datarate; } -bool LoRaPHYAU915::set_next_channel(channel_selection_params_t* next_chan_params, - uint8_t* channel, lorawan_time_t* time, - lorawan_time_t* aggregated_timeOff) +lorawan_status_t LoRaPHYAU915::set_next_channel(channel_selection_params_t* next_chan_params, + uint8_t* channel, lorawan_time_t* time, + lorawan_time_t* aggregated_timeOff) { uint8_t nb_enabled_channels = 0; uint8_t delay_tx = 0; @@ -605,16 +605,16 @@ bool LoRaPHYAU915::set_next_channel(channel_selection_params_t* next_chan_params AU915_MAX_NB_CHANNELS - 8); *time = 0; - return true; + return LORAWAN_STATUS_OK; } else { if (delay_tx > 0) { // Delay transmission due to AggregatedTimeOff or to a band time off *time = next_tx_delay; - return true; + return LORAWAN_STATUS_DUTYCYCLE_RESTRICTED; } // Datarate not supported by any channel *time = 0; - return false; + return LORAWAN_STATUS_NO_CHANNEL_FOUND; } } diff --git a/features/lorawan/lorastack/phy/LoRaPHYAU915.h b/features/lorawan/lorastack/phy/LoRaPHYAU915.h index 5c7c358f610..027a3fcdb1e 100644 --- a/features/lorawan/lorastack/phy/LoRaPHYAU915.h +++ b/features/lorawan/lorastack/phy/LoRaPHYAU915.h @@ -70,9 +70,9 @@ class LoRaPHYAU915 : public LoRaPHY{ virtual int8_t get_alternate_DR(uint8_t nb_trials); - virtual bool set_next_channel(channel_selection_params_t* next_chan_params, - uint8_t* channel, lorawan_time_t* time, - lorawan_time_t* aggregate_timeoff); + virtual lorawan_status_t set_next_channel(channel_selection_params_t* next_chan_params, + uint8_t* channel, lorawan_time_t* time, + lorawan_time_t* aggregate_timeoff); virtual uint8_t apply_DR_offset(int8_t dr, int8_t dr_offset); diff --git a/features/lorawan/lorastack/phy/LoRaPHYKR920.cpp b/features/lorawan/lorastack/phy/LoRaPHYKR920.cpp index b8afc36b7c0..4c653a85ffa 100644 --- a/features/lorawan/lorastack/phy/LoRaPHYKR920.cpp +++ b/features/lorawan/lorastack/phy/LoRaPHYKR920.cpp @@ -404,9 +404,9 @@ bool LoRaPHYKR920::tx_config(tx_config_params_t* config, int8_t* tx_power, return true; } -bool LoRaPHYKR920::set_next_channel(channel_selection_params_t* params, - uint8_t* channel, lorawan_time_t* time, - lorawan_time_t* aggregate_timeoff) +lorawan_status_t LoRaPHYKR920::set_next_channel(channel_selection_params_t* params, + uint8_t* channel, lorawan_time_t* time, + lorawan_time_t* aggregate_timeoff) { uint8_t next_channel_idx = 0; uint8_t nb_enabled_channels = 0; @@ -455,26 +455,26 @@ bool LoRaPHYKR920::set_next_channel(channel_selection_params_t* params, *channel = next_channel_idx; *time = 0; _radio->unlock(); - return true; + return LORAWAN_STATUS_OK; } _radio->unlock(); } - return false; + return LORAWAN_STATUS_NO_FREE_CHANNEL_FOUND; } else { if (delay_tx > 0) { // Delay transmission due to AggregatedTimeOff or to a band time off *time = nextTxDelay; - return true; + return LORAWAN_STATUS_DUTYCYCLE_RESTRICTED; } // Datarate not supported by any channel, restore defaults channel_mask[0] |= LC(1) + LC(2) + LC(3); *time = 0; - return false; + return LORAWAN_STATUS_NO_CHANNEL_FOUND; } } diff --git a/features/lorawan/lorastack/phy/LoRaPHYKR920.h b/features/lorawan/lorastack/phy/LoRaPHYKR920.h index b95c902a143..717cb791150 100644 --- a/features/lorawan/lorastack/phy/LoRaPHYKR920.h +++ b/features/lorawan/lorastack/phy/LoRaPHYKR920.h @@ -59,9 +59,9 @@ class LoRaPHYKR920 : public LoRaPHY { virtual bool tx_config(tx_config_params_t* config, int8_t* tx_power, lorawan_time_t* tx_toa); - virtual bool set_next_channel(channel_selection_params_t* params, uint8_t* channel, - lorawan_time_t* time, - lorawan_time_t* aggregate_timeOff); + virtual lorawan_status_t set_next_channel(channel_selection_params_t* params, uint8_t* channel, + lorawan_time_t* time, + lorawan_time_t* aggregate_timeOff); virtual void set_tx_cont_mode(cw_mode_params_t* continuousWave, uint32_t frequency = 0); diff --git a/features/lorawan/lorastack/phy/LoRaPHYUS915.cpp b/features/lorawan/lorastack/phy/LoRaPHYUS915.cpp index 13a33a339bf..bf73b53fb68 100644 --- a/features/lorawan/lorastack/phy/LoRaPHYUS915.cpp +++ b/features/lorawan/lorastack/phy/LoRaPHYUS915.cpp @@ -602,9 +602,9 @@ int8_t LoRaPHYUS915::get_alternate_DR(uint8_t nb_trials) return datarate; } -bool LoRaPHYUS915::set_next_channel(channel_selection_params_t* params, - uint8_t* channel, lorawan_time_t* time, - lorawan_time_t* aggregate_timeOff) +lorawan_status_t LoRaPHYUS915::set_next_channel(channel_selection_params_t* params, + uint8_t* channel, lorawan_time_t* time, + lorawan_time_t* aggregate_timeOff) { uint8_t nb_enabled_channels = 0; uint8_t delay_tx = 0; @@ -649,19 +649,19 @@ bool LoRaPHYUS915::set_next_channel(channel_selection_params_t* params, disable_channel(current_channel_mask, *channel, US915_MAX_NB_CHANNELS - 8); *time = 0; - return true; + return LORAWAN_STATUS_OK; } else { if (delay_tx > 0) { // Delay transmission due to AggregatedTimeOff or to a band time off *time = next_tx_delay; - return true; + return LORAWAN_STATUS_DUTYCYCLE_RESTRICTED; } // Datarate not supported by any channel *time = 0; - return false; + return LORAWAN_STATUS_NO_CHANNEL_FOUND; } } diff --git a/features/lorawan/lorastack/phy/LoRaPHYUS915.h b/features/lorawan/lorastack/phy/LoRaPHYUS915.h index f08944e6e7e..479695f651e 100644 --- a/features/lorawan/lorastack/phy/LoRaPHYUS915.h +++ b/features/lorawan/lorastack/phy/LoRaPHYUS915.h @@ -70,8 +70,8 @@ class LoRaPHYUS915 : public LoRaPHY { virtual int8_t get_alternate_DR(uint8_t nb_trials); - virtual bool set_next_channel(channel_selection_params_t* params, uint8_t* channel, - lorawan_time_t* time, lorawan_time_t* aggregate_timeOff); + virtual lorawan_status_t set_next_channel(channel_selection_params_t* params, uint8_t* channel, + lorawan_time_t* time, lorawan_time_t* aggregate_timeOff); virtual void set_tx_cont_mode(cw_mode_params_t* continuousWave, uint32_t frequency = 0); diff --git a/features/lorawan/lorastack/phy/LoRaPHYUS915Hybrid.cpp b/features/lorawan/lorastack/phy/LoRaPHYUS915Hybrid.cpp index babac4d70f9..99a28585023 100644 --- a/features/lorawan/lorastack/phy/LoRaPHYUS915Hybrid.cpp +++ b/features/lorawan/lorastack/phy/LoRaPHYUS915Hybrid.cpp @@ -601,9 +601,9 @@ int8_t LoRaPHYUS915Hybrid::get_alternate_DR(uint8_t nb_trials) return datarate; } -bool LoRaPHYUS915Hybrid::set_next_channel(channel_selection_params_t* params, - uint8_t* channel, lorawan_time_t* time, - lorawan_time_t* aggregate_timeOff) +lorawan_status_t LoRaPHYUS915Hybrid::set_next_channel(channel_selection_params_t* params, + uint8_t* channel, lorawan_time_t* time, + lorawan_time_t* aggregate_timeOff) { uint8_t nb_enabled_channels = 0; uint8_t delay_tx = 0; @@ -650,19 +650,19 @@ bool LoRaPHYUS915Hybrid::set_next_channel(channel_selection_params_t* params, disable_channel(current_channel_mask, *channel, US915_HYBRID_MAX_NB_CHANNELS - 8); *time = 0; - return true; + return LORAWAN_STATUS_OK; } else { if (delay_tx > 0) { // Delay transmission due to AggregatedTimeOff or to a band time off *time = next_tx_delay; - return true; + return LORAWAN_STATUS_DUTYCYCLE_RESTRICTED; } // Datarate not supported by any channel *time = 0; - return false; + return LORAWAN_STATUS_NO_CHANNEL_FOUND; } } diff --git a/features/lorawan/lorastack/phy/LoRaPHYUS915Hybrid.h b/features/lorawan/lorastack/phy/LoRaPHYUS915Hybrid.h index 08f1b58a719..357ee326dc4 100644 --- a/features/lorawan/lorastack/phy/LoRaPHYUS915Hybrid.h +++ b/features/lorawan/lorastack/phy/LoRaPHYUS915Hybrid.h @@ -74,9 +74,9 @@ class LoRaPHYUS915Hybrid : public LoRaPHY { virtual int8_t get_alternate_DR(uint8_t nb_trials); - virtual bool set_next_channel(channel_selection_params_t* params, - uint8_t* channel, lorawan_time_t* time, - lorawan_time_t* aggregate_timeoff); + virtual lorawan_status_t set_next_channel(channel_selection_params_t* params, + uint8_t* channel, lorawan_time_t* time, + lorawan_time_t* aggregate_timeoff); virtual void set_tx_cont_mode(cw_mode_params_t* continuousWave, uint32_t frequency = 0); diff --git a/features/lorawan/system/lorawan_data_structures.h b/features/lorawan/system/lorawan_data_structures.h index 183e1f9968b..4dfc9ebf654 100644 --- a/features/lorawan/system/lorawan_data_structures.h +++ b/features/lorawan/system/lorawan_data_structures.h @@ -1575,6 +1575,9 @@ typedef enum lorawan_status { #if defined(LORAWAN_COMPLIANCE_TEST) LORAWAN_STATUS_COMPLIANCE_TEST_ON = -1019, /**< Compliance test - is on-going */ #endif + LORAWAN_STATUS_DUTYCYCLE_RESTRICTED = -1020, + LORAWAN_STATUS_NO_CHANNEL_FOUND = -1021, + LORAWAN_STATUS_NO_FREE_CHANNEL_FOUND = -1022, } lorawan_status_t; /*! From 6114f2b3d5be74abeb45e4f34ec9bfda82f46322 Mon Sep 17 00:00:00 2001 From: Kimmo Vaisanen Date: Fri, 16 Feb 2018 12:20:34 +0200 Subject: [PATCH 04/25] Fix an issue with sequence calls. This issue is only present for a device in class c mode, which has perform unconfirmed uplinks. https://github.com/Lora-net/LoRaMac-node/issues/327 --- features/lorawan/lorastack/mac/LoRaMac.cpp | 86 ++++++++++++++-------- features/lorawan/lorastack/mac/LoRaMac.h | 17 +++++ 2 files changed, 71 insertions(+), 32 deletions(-) diff --git a/features/lorawan/lorastack/mac/LoRaMac.cpp b/features/lorawan/lorastack/mac/LoRaMac.cpp index 42535277183..39ed23cec75 100644 --- a/features/lorawan/lorastack/mac/LoRaMac.cpp +++ b/features/lorawan/lorastack/mac/LoRaMac.cpp @@ -299,7 +299,6 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, loramac_mhdr_t mac_hdr; loramac_frame_ctrl_t fctrl; cflist_params_t cflist; - bool skip_indication = false; uint8_t pkt_header_len = 0; uint32_t address = 0; @@ -549,8 +548,8 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, // In this case, the MAC layer shall accept the MAC commands // which are included in the downlink retransmission. // It should not provide the same frame to the application - // layer again. - skip_indication = true; + // layer again. The MAC layer accepts the acknowledgement. + _params.flags.bits.mcps_ind_skip = 1; } } else { _params.is_srv_ack_requested = false; @@ -575,6 +574,9 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, if (fctrl.bits.ack == 1) { // Reset MacCommandsBufferIndex when we have received an ACK. mac_commands.clear_command_buffer(); + // Update aknowledgement information + mcps.get_confirmation().ack_received = fctrl.bits.ack; + mcps.get_indication().is_ack_recvd = fctrl.bits.ack; } } else { // Reset the variable if we have received any valid frame. @@ -611,7 +613,10 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, mac_commands.clear_sticky_mac_cmd(); } } else { - skip_indication = true; + _params.flags.bits.mcps_ind_skip = 1; + // This is not a valid frame. Drop it and reset the ACK bits + mcps.get_confirmation().ack_received = false; + mcps.get_indication().is_ack_recvd = false; } } else { if (fctrl.bits.fopts_len > 0) { @@ -636,11 +641,9 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, mcps.get_indication().status = LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL; } - if (skip_indication == false) { - mcps.get_indication().buffer = _params.payload; - mcps.get_indication().buffer_size = frame_len; - mcps.get_indication().is_data_recvd = true; - } + mcps.get_indication().buffer = _params.payload; + mcps.get_indication().buffer_size = frame_len; + mcps.get_indication().is_data_recvd = true; } } else { if (fctrl.bits.fopts_len > 0) { @@ -657,29 +660,9 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, } } - if (skip_indication == false) { - // Check if the frame is an acknowledgement - if (fctrl.bits.ack == 1) { - mcps.get_confirmation().ack_received = true; - mcps.get_indication().is_ack_recvd = true; - - // Stop the AckTimeout timer as no more retransmissions - // are needed. - _lora_time.stop(_params.timers.ack_timeout_timer); - } else { - mcps.get_confirmation().ack_received = false; - - if (_params.ack_timeout_retry_counter > _params.max_ack_timeout_retries) { - // Stop the AckTimeout timer as no more retransmissions - // are needed. - _lora_time.stop( _params.timers.ack_timeout_timer ); - } - } - } // Provide always an indication, skip the callback to the user application, // in case of a confirmed downlink retransmission. _params.flags.bits.mcps_ind = 1; - _params.flags.bits.mcps_ind_skip = skip_indication; } else { mcps.get_indication().status = LORAMAC_EVENT_INFO_STATUS_MIC_FAIL; @@ -687,7 +670,6 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, return; } } - break; case FRAME_TYPE_PROPRIETARY: @@ -707,9 +689,16 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, prepare_rx_done_abort(); break; } - _params.flags.bits.mac_done = 1; - _lora_time.start(_params.timers.mac_state_check_timer, 1); + // Verify if we need to disable the AckTimeoutTimer + check_to_disable_ack_timeout(_params.is_node_ack_requested, _params.dev_class, mcps.get_confirmation().ack_received, + _params.ack_timeout_retry_counter, _params.max_ack_timeout_retries ); + + if(_params.timers.ack_timeout_timer.timer_id == 0) { + _params.flags.bits.mac_done = 1; + + _lora_time.start(_params.timers.mac_state_check_timer, 1); + } } void LoRaMac::on_radio_tx_timeout( void ) @@ -1072,6 +1061,39 @@ void LoRaMac::on_rx_window2_timer_event(void) } } +void LoRaMac::check_to_disable_ack_timeout(bool node_ack_requested, + device_class_t dev_class, + bool ack_received, + uint8_t ack_timeout_retries_counter, + uint8_t ack_timeout_retries) +{ + // There are three cases where we need to stop the AckTimeoutTimer: + if( node_ack_requested == false ) { + if( dev_class == CLASS_C ) { + // FIRST CASE + // We have performed an unconfirmed uplink in class c mode + // and have received a downlink in RX1 or RX2. + _lora_time.stop(_params.timers.ack_timeout_timer); + } + } else { + if( ack_received == 1 ) { + // SECOND CASE + // We have performed a confirmed uplink and have received a + // downlink with a valid ACK. + _lora_time.stop(_params.timers.ack_timeout_timer); + } else { + // THIRD CASE + if( ack_timeout_retries_counter > ack_timeout_retries ) { + // We have performed a confirmed uplink and have not + // received a downlink with a valid ACK. In this case + // we need to verify if the maximum retries have been + // elapsed. If so, stop the timer. + _lora_time.stop(_params.timers.ack_timeout_timer); + } + } + } +} + void LoRaMac::on_ack_timeout_timer_event(void) { _lora_time.stop(_params.timers.ack_timeout_timer); diff --git a/features/lorawan/lorastack/mac/LoRaMac.h b/features/lorawan/lorastack/mac/LoRaMac.h index 73d352c793d..0b333e972c9 100644 --- a/features/lorawan/lorastack/mac/LoRaMac.h +++ b/features/lorawan/lorastack/mac/LoRaMac.h @@ -482,6 +482,23 @@ class LoRaMac { */ void on_rx_window2_timer_event(void); + + /*! + * \brief Check if the OnAckTimeoutTimer has do be disabled. If so, the + * function disables it. + * + * \param [in] node_ack_requested Set to true, if the node has requested an ACK + * \param [in] dev_class The device class + * \param [in] ack_received Set to true, if the node has received an ACK + * \param [in] ack_timeout_retries_counter Retries counter for confirmed uplinks + * \param [in] ack_timeout_retries Maximum retries for confirmed uplinks + */ + void check_to_disable_ack_timeout(bool node_ack_requested, + device_class_t dev_class, + bool ack_received, + uint8_t ack_timeout_retries_counter, + uint8_t ack_timeout_retries); + /** * Function executed on AckTimeout timer event */ From fc1696b74f8850387f9e7fee0b585105ad2398ee Mon Sep 17 00:00:00 2001 From: Kimmo Vaisanen Date: Fri, 16 Feb 2018 13:53:07 +0200 Subject: [PATCH 05/25] Do only set the MacDone if the MAC is not in class c --- features/lorawan/lorastack/mac/LoRaMac.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/features/lorawan/lorastack/mac/LoRaMac.cpp b/features/lorawan/lorastack/mac/LoRaMac.cpp index 39ed23cec75..8739a6c022c 100644 --- a/features/lorawan/lorastack/mac/LoRaMac.cpp +++ b/features/lorawan/lorastack/mac/LoRaMac.cpp @@ -744,7 +744,9 @@ void LoRaMac::on_radio_rx_error( void ) mlme.get_confirmation().status = LORAMAC_EVENT_INFO_STATUS_RX2_ERROR; - _params.flags.bits.mac_done = 1; + if (_params.dev_class != CLASS_C) { + _params.flags.bits.mac_done = 1; + } } } From c1ea418ac417d14c67ad2dfc39d3042b90c21900 Mon Sep 17 00:00:00 2001 From: Kimmo Vaisanen Date: Fri, 16 Feb 2018 13:57:46 +0200 Subject: [PATCH 06/25] Fix rx slot handling Store the rx slot temporarily. When in class C, this variable will be changed in function OpenContinuousRx2Window. --- features/lorawan/lorastack/mac/LoRaMac.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/features/lorawan/lorastack/mac/LoRaMac.cpp b/features/lorawan/lorastack/mac/LoRaMac.cpp index 8739a6c022c..7a8cb8e626f 100644 --- a/features/lorawan/lorastack/mac/LoRaMac.cpp +++ b/features/lorawan/lorastack/mac/LoRaMac.cpp @@ -718,13 +718,15 @@ void LoRaMac::on_radio_tx_timeout( void ) void LoRaMac::on_radio_rx_error( void ) { + const rx_slot_t rx_slot = _params.rx_slot; + if (_params.dev_class != CLASS_C) { lora_phy->put_radio_to_sleep(); } else { open_continuous_rx2_window(); } - if (_params.rx_slot == RX_SLOT_WIN_1) { + if (rx_slot == RX_SLOT_WIN_1) { if (_params.is_node_ack_requested == true) { mcps.get_confirmation().status = LORAMAC_EVENT_INFO_STATUS_RX1_ERROR; } @@ -752,13 +754,15 @@ void LoRaMac::on_radio_rx_error( void ) void LoRaMac::on_radio_rx_timeout(void) { + const rx_slot_t rx_slot = _params.rx_slot; + if (_params.dev_class != CLASS_C) { lora_phy->put_radio_to_sleep(); } else { open_continuous_rx2_window(); } - if (_params.rx_slot == RX_SLOT_WIN_1) { + if (rx_slot == RX_SLOT_WIN_1) { if (_params.is_node_ack_requested == true) { mcps.get_confirmation().status = LORAMAC_EVENT_INFO_STATUS_RX1_TIMEOUT; } From 256a3a5842cdc0c02e49cb5a12aa8776b4856035 Mon Sep 17 00:00:00 2001 From: Kimmo Vaisanen Date: Fri, 16 Feb 2018 15:36:22 +0200 Subject: [PATCH 07/25] Fix calculation of the aggregated time-off. Perform only an assignment. https://github.com/Lora-net/LoRaMac-node/issues/282 --- features/lorawan/lorastack/mac/LoRaMac.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/features/lorawan/lorastack/mac/LoRaMac.cpp b/features/lorawan/lorastack/mac/LoRaMac.cpp index 7a8cb8e626f..6b6741c5933 100644 --- a/features/lorawan/lorastack/mac/LoRaMac.cpp +++ b/features/lorawan/lorastack/mac/LoRaMac.cpp @@ -1273,10 +1273,10 @@ void LoRaMac::calculate_backOff(uint8_t channel) // Update regional back-off lora_phy->calculate_backoff(&backoff_params); - // Update aggregated time-off - _params.timers.aggregated_timeoff = _params.timers.aggregated_timeoff - + (_params.timers.tx_toa * _params.sys_params.aggregated_duty_cycle - - _params.timers.tx_toa); + // Update aggregated time-off. This must be an assignment and no incremental + // update as we do only calculate the time-off based on the last transmission + _params.timers.aggregated_timeoff = (_params.timers.tx_toa * _params.sys_params.aggregated_duty_cycle + - _params.timers.tx_toa); } void LoRaMac::reset_mac_parameters(void) From 591bc7da1f21d20d0c6daf0330da8de02926a3d5 Mon Sep 17 00:00:00 2001 From: Kimmo Vaisanen Date: Fri, 16 Feb 2018 15:37:44 +0200 Subject: [PATCH 08/25] Add the possibility to set the default antenna gain. --- features/lorawan/lorastack/mac/LoRaMacMib.cpp | 10 ++++++++++ .../lorawan/system/lorawan_data_structures.h | 16 +++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/features/lorawan/lorastack/mac/LoRaMacMib.cpp b/features/lorawan/lorastack/mac/LoRaMacMib.cpp index b80ddcf2d4e..98bda6471d5 100644 --- a/features/lorawan/lorastack/mac/LoRaMacMib.cpp +++ b/features/lorawan/lorastack/mac/LoRaMacMib.cpp @@ -241,6 +241,11 @@ lorawan_status_t LoRaMacMib::set_request(loramac_mib_req_confirm_t *mibSet, params->sys_params.antenna_gain = mibSet->param.antenna_gain; break; } + case MIB_DEFAULT_ANTENNA_GAIN: + { + params->sys_params.antenna_gain = mibSet->param.default_antenna_gain; + break; + } default: status = LORAWAN_STATUS_SERVICE_UNKNOWN; break; @@ -414,6 +419,11 @@ lorawan_status_t LoRaMacMib::get_request(loramac_mib_req_confirm_t *mibGet, mibGet->param.antenna_gain = params->sys_params.antenna_gain; break; } + case MIB_DEFAULT_ANTENNA_GAIN: + { + mibGet->param.default_antenna_gain = params->sys_params.antenna_gain; + break; + } default: status = LORAWAN_STATUS_SERVICE_UNKNOWN; break; diff --git a/features/lorawan/system/lorawan_data_structures.h b/features/lorawan/system/lorawan_data_structures.h index 4dfc9ebf654..af43aba4d30 100644 --- a/features/lorawan/system/lorawan_data_structures.h +++ b/features/lorawan/system/lorawan_data_structures.h @@ -1127,6 +1127,7 @@ typedef struct { * \ref MIB_SYSTEM_MAX_RX_ERROR | YES | YES * \ref MIB_MIN_RX_SYMBOLS | YES | YES * \ref MIB_ANTENNA_GAIN | YES | YES + * \ref MIB_DEFAULT_ANTENNA_GAIN | YES | YES * * The following table provides links to the function implementations of the * related MIB primitives: @@ -1332,7 +1333,14 @@ typedef enum { * The formula is: * radioTxPower = ( int8_t )floor( maxEirp - antennaGain ) */ - MIB_ANTENNA_GAIN + MIB_ANTENNA_GAIN, + /*! + * Default antenna gain of the node. Default value is region specific. + * The antenna gain is used to calculate the TX power of the node. + * The formula is: + * radioTxPower = ( int8_t )floor( maxEirp - antennaGain ) + */ + MIB_DEFAULT_ANTENNA_GAIN } mib_type_t; /*! @@ -1519,6 +1527,12 @@ typedef union { * Related MIB type: \ref MIB_ANTENNA_GAIN */ float antenna_gain; + /*! + * Default antenna gain + * + * Related MIB type: \ref MIB_DEFAULT_ANTENNA_GAIN + */ + float default_antenna_gain; } mib_params_t; /*! From a9e10765729f75eeeee2d6d4ded0a7ab55330355 Mon Sep 17 00:00:00 2001 From: Kimmo Vaisanen Date: Mon, 19 Feb 2018 08:42:43 +0200 Subject: [PATCH 09/25] Bug fix in RX timeout and RX error handling for class c nodes. 1. Do not stop the 2nd window timer, as it is not running. 2. Wait for the OnAckTimeout event, before setting MacDone 3. Process for class c also the 2nd window timeout part, as we do not have a 2nd window timer. --- features/lorawan/lorastack/mac/LoRaMac.cpp | 29 +++++++++++++++------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/features/lorawan/lorastack/mac/LoRaMac.cpp b/features/lorawan/lorastack/mac/LoRaMac.cpp index 6b6741c5933..e8eda9000a8 100644 --- a/features/lorawan/lorastack/mac/LoRaMac.cpp +++ b/features/lorawan/lorastack/mac/LoRaMac.cpp @@ -733,12 +733,17 @@ void LoRaMac::on_radio_rx_error( void ) mlme.get_confirmation().status = LORAMAC_EVENT_INFO_STATUS_RX1_ERROR; - if (_lora_time.get_elapsed_time(_params.timers.aggregated_last_tx_time) >= _params.rx_window2_delay) { - _lora_time.stop(_params.timers.rx_window2_timer); - _params.flags.bits.mac_done = 1; + if (_params.dev_class != CLASS_C) { + if (_lora_time.get_elapsed_time(_params.timers.aggregated_last_tx_time) >= _params.rx_window2_delay) { + _lora_time.stop(_params.timers.rx_window2_timer); + _params.flags.bits.mac_done = 1; + } } - - } else { + } + if ((rx_slot == RX_SLOT_WIN_2) || (_params.dev_class == CLASS_C)) { + // We need to process this case if the MAC is in class A or B for the 2nd RX window timeout. + // If the MAC is in class C, we need to process this part also for the 1st RX window timeout, + // as the 2nd window timer is not running. if (_params.is_node_ack_requested == true) { mcps.get_confirmation().status = LORAMAC_EVENT_INFO_STATUS_RX2_ERROR; @@ -768,12 +773,18 @@ void LoRaMac::on_radio_rx_timeout(void) } mlme.get_confirmation().status = LORAMAC_EVENT_INFO_STATUS_RX1_TIMEOUT; - if (_lora_time.get_elapsed_time(_params.timers.aggregated_last_tx_time ) >= _params.rx_window2_delay) { - _lora_time.stop(_params.timers.rx_window2_timer); - _params.flags.bits.mac_done = 1; + if (_params.dev_class != CLASS_C) { + if (_lora_time.get_elapsed_time(_params.timers.aggregated_last_tx_time ) >= _params.rx_window2_delay) { + _lora_time.stop(_params.timers.rx_window2_timer); + _params.flags.bits.mac_done = 1; + } } + } - } else { + if ((rx_slot == RX_SLOT_WIN_2) || (_params.dev_class == CLASS_C)) { + // We need to process this case if the MAC is in class A or B for the 2nd RX window timeout. + // If the MAC is in class C, we need to process this part also for the 1st RX window timeout, + // as the 2nd window timer is not running. if (_params.is_node_ack_requested == true) { mcps.get_confirmation().status = LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT; From e097429b6929a402283f90e8c9b1ea4929f84c75 Mon Sep 17 00:00:00 2001 From: Kimmo Vaisanen Date: Mon, 19 Feb 2018 08:46:41 +0200 Subject: [PATCH 10/25] Remove unused is_fPort_allowed method --- features/lorawan/lorastack/mac/LoRaMac.cpp | 8 -------- features/lorawan/lorastack/mac/LoRaMac.h | 5 ----- 2 files changed, 13 deletions(-) diff --git a/features/lorawan/lorastack/mac/LoRaMac.cpp b/features/lorawan/lorastack/mac/LoRaMac.cpp index e8eda9000a8..f686d569a29 100644 --- a/features/lorawan/lorastack/mac/LoRaMac.cpp +++ b/features/lorawan/lorastack/mac/LoRaMac.cpp @@ -1331,14 +1331,6 @@ void LoRaMac::reset_mac_parameters(void) _params.last_channel_idx = _params.channel; } -bool LoRaMac::is_fPort_allowed (uint8_t fPort) -{ - if ((fPort == 0) || (fPort > 224)) { - return false; - } - return true; -} - void LoRaMac::open_continuous_rx2_window (void) { handle_rx2_timer_event(); diff --git a/features/lorawan/lorastack/mac/LoRaMac.h b/features/lorawan/lorastack/mac/LoRaMac.h index 0b333e972c9..5e9c233a222 100644 --- a/features/lorawan/lorastack/mac/LoRaMac.h +++ b/features/lorawan/lorastack/mac/LoRaMac.h @@ -540,11 +540,6 @@ class LoRaMac { */ lorawan_status_t send_frame_on_channel(uint8_t channel); - /** - * Checks for Port validity. - */ - bool is_fPort_allowed(uint8_t fPort); - /** * Prototypes for ISR handlers */ From 6c165e0f1950efefe1465f7d49ff7af9fbff87ee Mon Sep 17 00:00:00 2001 From: Kimmo Vaisanen Date: Mon, 19 Feb 2018 08:52:02 +0200 Subject: [PATCH 11/25] Changed mcps confirmation ul_frequency to channel --- features/lorawan/lorastack/mac/LoRaMac.cpp | 1 + features/lorawan/system/lorawan_data_structures.h | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/features/lorawan/lorastack/mac/LoRaMac.cpp b/features/lorawan/lorastack/mac/LoRaMac.cpp index f686d569a29..36b1f2abf37 100644 --- a/features/lorawan/lorastack/mac/LoRaMac.cpp +++ b/features/lorawan/lorastack/mac/LoRaMac.cpp @@ -1544,6 +1544,7 @@ lorawan_status_t LoRaMac::send_frame_on_channel(uint8_t channel) mcps.get_confirmation().status = LORAMAC_EVENT_INFO_STATUS_ERROR; mcps.get_confirmation().data_rate = _params.sys_params.channel_data_rate; mcps.get_confirmation().tx_power = tx_power; + mcps.get_confirmation().channel = channel; // Store the time on air mcps.get_confirmation().tx_toa = _params.timers.tx_toa; diff --git a/features/lorawan/system/lorawan_data_structures.h b/features/lorawan/system/lorawan_data_structures.h index af43aba4d30..33e37795c63 100644 --- a/features/lorawan/system/lorawan_data_structures.h +++ b/features/lorawan/system/lorawan_data_structures.h @@ -856,9 +856,9 @@ typedef struct { */ uint32_t ul_frame_counter; /*! - * The uplink frequency related to the frame. + * The uplink channel related to the frame. */ - uint32_t ul_frequency; + uint32_t channel; } loramac_mcps_confirm_t; /*! From e1fff2e73811c2984532428349038c667948dab5 Mon Sep 17 00:00:00 2001 From: Kimmo Vaisanen Date: Mon, 19 Feb 2018 09:14:07 +0200 Subject: [PATCH 12/25] Update handling for functions OnRadioRxError and OnRadioRxTimout. This is especially important for class c devices. --- features/lorawan/lorastack/mac/LoRaMac.cpp | 35 ++++++++-------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/features/lorawan/lorastack/mac/LoRaMac.cpp b/features/lorawan/lorastack/mac/LoRaMac.cpp index 36b1f2abf37..e80fda1267c 100644 --- a/features/lorawan/lorastack/mac/LoRaMac.cpp +++ b/features/lorawan/lorastack/mac/LoRaMac.cpp @@ -718,15 +718,11 @@ void LoRaMac::on_radio_tx_timeout( void ) void LoRaMac::on_radio_rx_error( void ) { - const rx_slot_t rx_slot = _params.rx_slot; - if (_params.dev_class != CLASS_C) { lora_phy->put_radio_to_sleep(); - } else { - open_continuous_rx2_window(); } - if (rx_slot == RX_SLOT_WIN_1) { + if (_params.rx_slot == RX_SLOT_WIN_1) { if (_params.is_node_ack_requested == true) { mcps.get_confirmation().status = LORAMAC_EVENT_INFO_STATUS_RX1_ERROR; } @@ -739,12 +735,7 @@ void LoRaMac::on_radio_rx_error( void ) _params.flags.bits.mac_done = 1; } } - } - if ((rx_slot == RX_SLOT_WIN_2) || (_params.dev_class == CLASS_C)) { - // We need to process this case if the MAC is in class A or B for the 2nd RX window timeout. - // If the MAC is in class C, we need to process this part also for the 1st RX window timeout, - // as the 2nd window timer is not running. - + } else { if (_params.is_node_ack_requested == true) { mcps.get_confirmation().status = LORAMAC_EVENT_INFO_STATUS_RX2_ERROR; } @@ -755,19 +746,19 @@ void LoRaMac::on_radio_rx_error( void ) _params.flags.bits.mac_done = 1; } } + + if (_params.dev_class == CLASS_C) { + open_continuous_rx2_window(); + } } void LoRaMac::on_radio_rx_timeout(void) { - const rx_slot_t rx_slot = _params.rx_slot; - if (_params.dev_class != CLASS_C) { lora_phy->put_radio_to_sleep(); - } else { - open_continuous_rx2_window(); } - if (rx_slot == RX_SLOT_WIN_1) { + if (_params.rx_slot == RX_SLOT_WIN_1) { if (_params.is_node_ack_requested == true) { mcps.get_confirmation().status = LORAMAC_EVENT_INFO_STATUS_RX1_TIMEOUT; } @@ -779,13 +770,7 @@ void LoRaMac::on_radio_rx_timeout(void) _params.flags.bits.mac_done = 1; } } - } - - if ((rx_slot == RX_SLOT_WIN_2) || (_params.dev_class == CLASS_C)) { - // We need to process this case if the MAC is in class A or B for the 2nd RX window timeout. - // If the MAC is in class C, we need to process this part also for the 1st RX window timeout, - // as the 2nd window timer is not running. - + } else { if (_params.is_node_ack_requested == true) { mcps.get_confirmation().status = LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT; } @@ -796,6 +781,10 @@ void LoRaMac::on_radio_rx_timeout(void) _params.flags.bits.mac_done = 1; } } + + if (_params.dev_class == CLASS_C) { + open_continuous_rx2_window(); + } } /*************************************************************************** From 65b2dbc7dc2d1dc604f8f645a62a58c630b10597 Mon Sep 17 00:00:00 2001 From: Kimmo Vaisanen Date: Mon, 19 Feb 2018 09:16:44 +0200 Subject: [PATCH 13/25] Update DevStatusAnd format In the DevStatusAns format, the protocol requires RFU(7:6) value = 0 --- features/lorawan/lorastack/mac/LoRaMacCommand.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/lorawan/lorastack/mac/LoRaMacCommand.cpp b/features/lorawan/lorastack/mac/LoRaMacCommand.cpp index c3c632d271a..f383cfa7db0 100644 --- a/features/lorawan/lorastack/mac/LoRaMacCommand.cpp +++ b/features/lorawan/lorastack/mac/LoRaMacCommand.cpp @@ -341,7 +341,7 @@ lorawan_status_t LoRaMacCommand::process_mac_commands(uint8_t *payload, uint8_t // we don't have a mechanism at the moment to measure // battery levels ret_value = add_mac_command(MOTE_MAC_DEV_STATUS_ANS, - batteryLevel, snr); + batteryLevel, snr & 0x3F); break; } case SRV_MAC_NEW_CHANNEL_REQ: { From 4aba3434f48323a5a18da63bb970ad3d3757929c Mon Sep 17 00:00:00 2001 From: Kimmo Vaisanen Date: Mon, 19 Feb 2018 09:19:13 +0200 Subject: [PATCH 14/25] Change minimum required channels from 6 to 2 (US915Hybrid) https://github.com/Lora-net/LoRaMac-node/issues/362 --- features/lorawan/lorastack/phy/LoRaPHYUS915Hybrid.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/lorawan/lorastack/phy/LoRaPHYUS915Hybrid.cpp b/features/lorawan/lorastack/phy/LoRaPHYUS915Hybrid.cpp index 99a28585023..d7299016427 100644 --- a/features/lorawan/lorastack/phy/LoRaPHYUS915Hybrid.cpp +++ b/features/lorawan/lorastack/phy/LoRaPHYUS915Hybrid.cpp @@ -757,7 +757,7 @@ bool LoRaPHYUS915Hybrid::validate_channel_mask(uint16_t* channel_masks) block1 = temp_channel_masks[i] & 0x00FF; block2 = temp_channel_masks[i] & 0xFF00; - if (count_bits(block1, 16) > 5) { + if (count_bits(block1, 16) > 1) { temp_channel_masks[i] &= block1; temp_channel_masks[4] = 1 << ( i * 2 ); @@ -765,7 +765,7 @@ bool LoRaPHYUS915Hybrid::validate_channel_mask(uint16_t* channel_masks) index = i; break; - } else if( count_bits( block2, 16 ) > 5 ) { + } else if( count_bits( block2, 16 ) > 1 ) { temp_channel_masks[i] &= block2; temp_channel_masks[4] = 1 << ( i * 2 + 1 ); From a26fca8bf50bebca109be2b5436fe960708bb06e Mon Sep 17 00:00:00 2001 From: Kimmo Vaisanen Date: Tue, 20 Feb 2018 15:48:08 +0200 Subject: [PATCH 15/25] Add set_device_class API to change active device class This API can be used to runtime change device class. Please note that only class A and C are supported at the moment. Trying to set class B will return LORAWAN_STATUS_UNSUPPORTED. Fix set_device_class documentation fix documentation --- features/lorawan/LoRaWANBase.h | 12 ++++++++++++ features/lorawan/LoRaWANInterface.cpp | 11 ++++++++--- features/lorawan/LoRaWANInterface.h | 12 ++++++++++++ features/lorawan/LoRaWANStack.cpp | 8 ++++++++ features/lorawan/LoRaWANStack.h | 12 ++++++++++++ features/lorawan/lorastack/mac/LoRaMacMib.cpp | 1 + 6 files changed, 53 insertions(+), 3 deletions(-) diff --git a/features/lorawan/LoRaWANBase.h b/features/lorawan/LoRaWANBase.h index f4b3354f5bb..02397f3b49f 100644 --- a/features/lorawan/LoRaWANBase.h +++ b/features/lorawan/LoRaWANBase.h @@ -331,6 +331,18 @@ class LoRaWANBase { * callbacks. */ virtual lorawan_status_t add_app_callbacks(lorawan_app_callbacks_t *callbacks) = 0; + + /** Change device class + * + * Change current device class. + * + * @param device_class The device class + * + * @return LORAWAN_STATUS_OK on success, + * LORAWAN_STATUS_UNSUPPORTED is requested class is not supported, + * or other negative error code if request failed. + */ + virtual lorawan_status_t set_device_class(const device_class_t device_class) = 0; }; #endif /* LORAWAN_BASE_H_ */ diff --git a/features/lorawan/LoRaWANInterface.cpp b/features/lorawan/LoRaWANInterface.cpp index a8f1654e941..a47bff98653 100644 --- a/features/lorawan/LoRaWANInterface.cpp +++ b/features/lorawan/LoRaWANInterface.cpp @@ -121,6 +121,11 @@ int16_t LoRaWANInterface::receive(uint8_t port, uint8_t* data, uint16_t length, } lorawan_status_t LoRaWANInterface::add_app_callbacks(lorawan_app_callbacks_t *callbacks) - { - return stk_obj().set_lora_callbacks(callbacks); - } +{ + return stk_obj().set_lora_callbacks(callbacks); +} + +lorawan_status_t LoRaWANInterface::set_device_class(const device_class_t device_class) +{ + return stk_obj().set_device_class(device_class); +} diff --git a/features/lorawan/LoRaWANInterface.h b/features/lorawan/LoRaWANInterface.h index ffec1d93442..87fd5736d45 100644 --- a/features/lorawan/LoRaWANInterface.h +++ b/features/lorawan/LoRaWANInterface.h @@ -428,6 +428,18 @@ class LoRaWANInterface: public LoRaWANBase { * callbacks. */ virtual lorawan_status_t add_app_callbacks(lorawan_app_callbacks_t *callbacks); + + /** Change device class + * + * Change current device class. + * + * @param device_class The device class + * + * @return LORAWAN_STATUS_OK on success, + * LORAWAN_STATUS_UNSUPPORTED is requested class is not supported, + * or other negative error code if request failed. + */ + virtual lorawan_status_t set_device_class(const device_class_t device_class); }; #endif /* LORAWANINTERFACE_H_ */ diff --git a/features/lorawan/LoRaWANStack.cpp b/features/lorawan/LoRaWANStack.cpp index 9a5faae3a41..59255448377 100644 --- a/features/lorawan/LoRaWANStack.cpp +++ b/features/lorawan/LoRaWANStack.cpp @@ -1093,6 +1093,14 @@ lorawan_status_t LoRaWANStack::shutdown() return lora_state_machine(DEVICE_STATE_SHUTDOWN); } +lorawan_status_t LoRaWANStack::set_device_class(const device_class_t device_class) +{ + loramac_mib_req_confirm_t mib_req; + mib_req.type = MIB_DEVICE_CLASS; + mib_req.param.dev_class = device_class; + return mib_set_request(&mib_req); +} + lorawan_status_t LoRaWANStack::lora_state_machine(device_states_t new_state) { loramac_mib_req_confirm_t mib_req; diff --git a/features/lorawan/LoRaWANStack.h b/features/lorawan/LoRaWANStack.h index 0d2f3f013dd..8d3957859de 100644 --- a/features/lorawan/LoRaWANStack.h +++ b/features/lorawan/LoRaWANStack.h @@ -360,6 +360,18 @@ class LoRaWANStack: private mbed::NonCopyable { */ lorawan_status_t shutdown(); + /** Change device class + * + * Change current device class. + * + * @param device_class The device class + * + * @return LORAWAN_STATUS_OK on success, + * LORAWAN_STATUS_UNSUPPORTED is requested class is not supported, + * or other negative error code if request failed. + */ + lorawan_status_t set_device_class(const device_class_t device_class); + private: LoRaWANStack(); ~LoRaWANStack(); diff --git a/features/lorawan/lorastack/mac/LoRaMacMib.cpp b/features/lorawan/lorastack/mac/LoRaMacMib.cpp index 98bda6471d5..bc0b26a1773 100644 --- a/features/lorawan/lorastack/mac/LoRaMacMib.cpp +++ b/features/lorawan/lorastack/mac/LoRaMacMib.cpp @@ -59,6 +59,7 @@ lorawan_status_t LoRaMacMib::set_request(loramac_mib_req_confirm_t *mibSet, break; } case CLASS_B: { + status = LORAWAN_STATUS_UNSUPPORTED; break; } case CLASS_C: { From 32075b91b547a5715e9c3544c01820035b92ac43 Mon Sep 17 00:00:00 2001 From: Kimmo Vaisanen Date: Thu, 22 Feb 2018 15:24:44 +0200 Subject: [PATCH 16/25] Fix reception of class C messages - Do not put radio into sleep when message is received in class c mode - Experimental feature for acknowledging confirmed downlink messages --- features/lorawan/LoRaWANStack.cpp | 18 ++++++++++++++++-- features/lorawan/lorastack/mac/LoRaMac.cpp | 6 ++++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/features/lorawan/LoRaWANStack.cpp b/features/lorawan/LoRaWANStack.cpp index 59255448377..d9662c719ec 100644 --- a/features/lorawan/LoRaWANStack.cpp +++ b/features/lorawan/LoRaWANStack.cpp @@ -888,8 +888,7 @@ void LoRaWANStack::mcps_indication_handler(loramac_mcps_indication_t *mcps_indic _rx_msg.msg.mcps_indication.port = mcps_indication->port; // no copy, just set the pointer for the user - _rx_msg.msg.mcps_indication.buffer = - mcps_indication->buffer; + _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); @@ -901,11 +900,26 @@ void LoRaWANStack::mcps_indication_handler(loramac_mcps_indication_t *mcps_indic (void)ret; } + loramac_mib_req_confirm_t mib_req; + mib_req.type = MIB_DEVICE_CLASS; + lorawan_status_t status = mib_get_request(&mib_req); + // 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 (mcps_indication->fpending_status) { + if (status != LORAWAN_STATUS_OK || mib_req.param.dev_class != CLASS_C) { + handle_tx(mcps_indication->port, NULL, 0, MSG_CONFIRMED_FLAG); + } + } + + // 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 (mib_req.param.dev_class == CLASS_C && mcps_indication->type == MCPS_CONFIRMED) { handle_tx(mcps_indication->port, NULL, 0, MSG_CONFIRMED_FLAG); } } else { diff --git a/features/lorawan/lorastack/mac/LoRaMac.cpp b/features/lorawan/lorastack/mac/LoRaMac.cpp index e80fda1267c..0c88e88ae31 100644 --- a/features/lorawan/lorastack/mac/LoRaMac.cpp +++ b/features/lorawan/lorastack/mac/LoRaMac.cpp @@ -334,7 +334,9 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, mcps.get_indication().dl_frame_counter = 0; mcps.get_indication().type = MCPS_UNCONFIRMED; - lora_phy->put_radio_to_sleep(); + if (_params.dev_class != CLASS_C) { + lora_phy->put_radio_to_sleep(); + } _lora_time.stop( _params.timers.rx_window2_timer ); @@ -962,7 +964,7 @@ void LoRaMac::on_mac_state_check_timer_event(void) if (_params.flags.bits.mcps_ind == 1) { _params.flags.bits.mcps_ind = 0; - if (_params.dev_class== CLASS_C) { + if (_params.dev_class == CLASS_C) { // Activate RX2 window for Class C open_continuous_rx2_window(); } From c6eee4fd984c15b7652b870ffe55386a1ea7a3b8 Mon Sep 17 00:00:00 2001 From: Kimmo Vaisanen Date: Wed, 28 Feb 2018 14:41:40 +0200 Subject: [PATCH 17/25] Simplify check for pending bit --- features/lorawan/LoRaWANStack.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/features/lorawan/LoRaWANStack.cpp b/features/lorawan/LoRaWANStack.cpp index d9662c719ec..11386462b3a 100644 --- a/features/lorawan/LoRaWANStack.cpp +++ b/features/lorawan/LoRaWANStack.cpp @@ -902,16 +902,14 @@ void LoRaWANStack::mcps_indication_handler(loramac_mcps_indication_t *mcps_indic loramac_mib_req_confirm_t mib_req; mib_req.type = MIB_DEVICE_CLASS; - lorawan_status_t status = mib_get_request(&mib_req); + mib_get_request(&mib_req); // 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 (mcps_indication->fpending_status) { - if (status != LORAWAN_STATUS_OK || mib_req.param.dev_class != CLASS_C) { - handle_tx(mcps_indication->port, NULL, 0, MSG_CONFIRMED_FLAG); - } + if (mcps_indication->fpending_status && mib_req.param.dev_class != CLASS_C) { + handle_tx(mcps_indication->port, NULL, 0, MSG_CONFIRMED_FLAG); } // Class C and node received a confirmed message so we need to From fe225a843085802e15d2064a663e21709918e92f Mon Sep 17 00:00:00 2001 From: Kimmo Vaisanen Date: Thu, 1 Mar 2018 10:01:41 +0200 Subject: [PATCH 18/25] Remove redundant event from timer callbacks Since our timers are now already using events, we no longer need to defer timer callback calls. --- features/lorawan/lorastack/mac/LoRaMac.cpp | 63 +++++++--------------- features/lorawan/lorastack/mac/LoRaMac.h | 9 +--- 2 files changed, 20 insertions(+), 52 deletions(-) diff --git a/features/lorawan/lorastack/mac/LoRaMac.cpp b/features/lorawan/lorastack/mac/LoRaMac.cpp index 0c88e88ae31..135305972e7 100644 --- a/features/lorawan/lorastack/mac/LoRaMac.cpp +++ b/features/lorawan/lorastack/mac/LoRaMac.cpp @@ -178,41 +178,6 @@ void LoRaMac::handle_fhss_change_channel(uint8_t cur_channel) //(void)ret; } -void LoRaMac::handle_mac_state_check_timer_event(void) -{ - const int ret = ev_queue->call(this, &LoRaMac::on_mac_state_check_timer_event); - MBED_ASSERT(ret != 0); - (void)ret; -} - -void LoRaMac::handle_delayed_tx_timer_event(void) -{ - const int ret = ev_queue->call(this, &LoRaMac::on_tx_delayed_timer_event); - MBED_ASSERT(ret != 0); - (void)ret; -} - -void LoRaMac::handle_ack_timeout() -{ - const int ret = ev_queue->call(this, &LoRaMac::on_ack_timeout_timer_event); - MBED_ASSERT(ret != 0); - (void)ret; -} - -void LoRaMac::handle_rx1_timer_event(void) -{ - const int ret = ev_queue->call(this, &LoRaMac::on_rx_window1_timer_event); - MBED_ASSERT(ret != 0); - (void)ret; -} - -void LoRaMac::handle_rx2_timer_event(void) -{ - const int ret = ev_queue->call(this, &LoRaMac::on_rx_window2_timer_event); - MBED_ASSERT(ret != 0); - (void)ret; -} - /*************************************************************************** * Radio event callbacks - delegated to Radio driver * **************************************************************************/ @@ -283,7 +248,9 @@ void LoRaMac::prepare_rx_done_abort(void) _params.mac_state |= LORAMAC_RX_ABORT; if (_params.is_node_ack_requested) { - handle_ack_timeout(); + const int ret = ev_queue->call(this, &LoRaMac::on_ack_timeout_timer_event); + MBED_ASSERT(ret != 0); + (void)ret; } _params.flags.bits.mcps_ind = 1; @@ -836,7 +803,10 @@ void LoRaMac::on_mac_state_check_timer_event(void) } else { _params.flags.bits.mac_done = 0; // Sends the same frame again - handle_delayed_tx_timer_event(); + const int ret = ev_queue->call(this, &LoRaMac::on_tx_delayed_timer_event); + MBED_ASSERT(ret != 0); + (void)ret; + } } } else { @@ -860,7 +830,9 @@ void LoRaMac::on_mac_state_check_timer_event(void) } else { _params.flags.bits.mac_done = 0; // Sends the same frame again - handle_delayed_tx_timer_event(); + const int ret = ev_queue->call(this, &LoRaMac::on_tx_delayed_timer_event); + MBED_ASSERT(ret != 0); + (void)ret; } } } @@ -1324,7 +1296,10 @@ void LoRaMac::reset_mac_parameters(void) void LoRaMac::open_continuous_rx2_window (void) { - handle_rx2_timer_event(); + const int ret = ev_queue->call(this, &LoRaMac::on_rx_window2_timer_event); + MBED_ASSERT(ret != 0); + (void)ret; + _params.rx_slot = RX_SLOT_WIN_CLASS_C; } @@ -1662,15 +1637,15 @@ lorawan_status_t LoRaMac::initialize(loramac_primitives_t *primitives, // Initialize timers _lora_time.init(_params.timers.mac_state_check_timer, - mbed::callback(this, &LoRaMac::handle_mac_state_check_timer_event)); + mbed::callback(this, &LoRaMac::on_mac_state_check_timer_event)); _lora_time.init(_params.timers.tx_delayed_timer, - mbed::callback(this, &LoRaMac::handle_delayed_tx_timer_event)); + mbed::callback(this, &LoRaMac::on_tx_delayed_timer_event)); _lora_time.init(_params.timers.rx_window1_timer, - mbed::callback(this, &LoRaMac::handle_rx1_timer_event)); + mbed::callback(this, &LoRaMac::on_rx_window1_timer_event)); _lora_time.init(_params.timers.rx_window2_timer, - mbed::callback(this, &LoRaMac::handle_rx2_timer_event)); + mbed::callback(this, &LoRaMac::on_rx_window2_timer_event)); _lora_time.init(_params.timers.ack_timeout_timer, - mbed::callback(this, &LoRaMac::handle_ack_timeout)); + mbed::callback(this, &LoRaMac::on_ack_timeout_timer_event)); // Store the current initialization time _params.timers.mac_init_time = _lora_time.get_current_time(); diff --git a/features/lorawan/lorastack/mac/LoRaMac.h b/features/lorawan/lorastack/mac/LoRaMac.h index 5e9c233a222..03b41dd0a72 100644 --- a/features/lorawan/lorastack/mac/LoRaMac.h +++ b/features/lorawan/lorastack/mac/LoRaMac.h @@ -545,18 +545,11 @@ class LoRaMac { */ void handle_cad_done(bool cad); void handle_tx_done(void); - void handle_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, - int8_t snr); + void handle_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr); void handle_rx_error(void); void handle_rx_timeout(void); void handle_tx_timeout(void); void handle_fhss_change_channel(uint8_t cur_channel); - void handle_rx1_timer_event(void); - void handle_rx2_timer_event(void); - void handle_ack_timeout(void); - void handle_delayed_tx_timer_event(void); - void handle_mac_state_check_timer_event(void); - void handle_next_tx_timer_event(void); private: /** From b63c98e1038bbb4f2e89eef1b6b294d4e4772671 Mon Sep 17 00:00:00 2001 From: Antti Kauppila Date: Thu, 15 Mar 2018 10:43:31 +0200 Subject: [PATCH 19/25] LoRa: LoRaPHY dependency removed from LoRaMacStack - This is internal change, no functionality has been changed - LoRaWanInterface cleaned up and code moved to LoRaMacStack - Compliance code in LoRaMacStack moved to EOF - Green tea tests have been run manually - Doxygen updated accordingly LoRA: reorder class members --- features/lorawan/LoRaWANStack.cpp | 513 +++++++----------- features/lorawan/LoRaWANStack.h | 26 +- features/lorawan/lorastack/mac/LoRaMac.cpp | 321 +++++++---- features/lorawan/lorastack/mac/LoRaMac.h | 96 +++- .../lorawan/system/lorawan_data_structures.h | 14 - 5 files changed, 463 insertions(+), 507 deletions(-) diff --git a/features/lorawan/LoRaWANStack.cpp b/features/lorawan/LoRaWANStack.cpp index 11386462b3a..55e3d7a3025 100644 --- a/features/lorawan/LoRaWANStack.cpp +++ b/features/lorawan/LoRaWANStack.cpp @@ -98,7 +98,6 @@ LoRaWANStack::LoRaWANStack() #endif memset(&_lw_session, 0, sizeof(_lw_session)); - memset(&_tx_msg, 0, sizeof(_tx_msg)); memset(&_rx_msg, 0, sizeof(_rx_msg)); LoRaMacPrimitives.mcps_confirm = callback(this, &LoRaWANStack::mcps_confirm_handler); @@ -122,12 +121,7 @@ LoRaWANStack& LoRaWANStack::get_lorawan_stack() void LoRaWANStack::bind_radio_driver(LoRaRadio& radio) { - //Move these to LoRaMAC class - radio_events_t *events = _loramac.get_phy_event_handlers(); - _lora_phy.set_radio_instance(radio); - radio.lock(); - radio.init_radio(events); - radio.unlock(); + _loramac.bind_radio_driver(radio); } lorawan_status_t LoRaWANStack::connect() @@ -209,7 +203,7 @@ lorawan_status_t LoRaWANStack::initialize_mac_layer(EventQueue *queue) _compliance_test.app_data_buffer = compliance_test_buffer; #endif - _loramac.initialize(&LoRaMacPrimitives, &_lora_phy, queue); + _loramac.initialize(&LoRaMacPrimitives, queue); // Reset counters to zero. Will change in future with 1.1 support. _lw_session.downlink_counter = 0; @@ -218,81 +212,6 @@ lorawan_status_t LoRaWANStack::initialize_mac_layer(EventQueue *queue) return lora_state_machine(DEVICE_STATE_INIT); } -uint16_t LoRaWANStack::check_possible_tx_size(uint16_t size) -{ - loramac_tx_info_t tx_info; - if (_loramac.query_tx_possible(size, &tx_info) == LORAWAN_STATUS_LENGTH_ERROR) { - // Cannot transmit this much. Return how much data can be sent - // at the moment - return tx_info.max_possible_payload_size; - } - - return tx_info.current_payload_size; -} - -/** Hands over the frame to MAC layer - * - * \return returns the state of the LoRa MAC - */ -lorawan_status_t LoRaWANStack::send_frame_to_mac() -{ - loramac_mcps_req_t mcps_req; - lorawan_status_t status; - loramac_mib_req_confirm_t mib_get_params; - - mcps_req.type = _tx_msg.type; - - if (MCPS_UNCONFIRMED == mcps_req.type) { - mcps_req.f_buffer = _tx_msg.f_buffer; - mcps_req.f_buffer_size = _tx_msg.f_buffer_size; - - mcps_req.fport = _tx_msg.fport; - mcps_req.nb_trials = 1; - mib_get_params.type = MIB_CHANNELS_DATARATE; - if(mib_get_request(&mib_get_params) != LORAWAN_STATUS_OK) { - tr_debug("Couldn't get MIB parameters: Using default data rate"); - mcps_req.data_rate = _lora_phy.get_default_tx_datarate(); - } else { - mcps_req.data_rate = mib_get_params.param.channel_data_rate; - } - - } else if (mcps_req.type == MCPS_CONFIRMED) { - mcps_req.f_buffer = _tx_msg.f_buffer; - mcps_req.f_buffer_size = _tx_msg.f_buffer_size; - mcps_req.fport = _tx_msg.fport; - mcps_req.nb_trials = _tx_msg.nb_trials; - - mib_get_params.type = MIB_CHANNELS_DATARATE; - if(mib_get_request(&mib_get_params) != LORAWAN_STATUS_OK) { - tr_debug("Couldn't get MIB parameters: Using default data rate"); - mcps_req.data_rate = _lora_phy.get_default_tx_datarate(); - } else { - mcps_req.data_rate = mib_get_params.param.channel_data_rate; - } - - } else if ( mcps_req.type == MCPS_PROPRIETARY) { - mcps_req.f_buffer = _tx_msg.f_buffer; - mcps_req.f_buffer_size = _tx_msg.f_buffer_size; - mcps_req.fport = 0; - mcps_req.nb_trials = 1; - - mib_get_params.type = MIB_CHANNELS_DATARATE; - if(mib_get_request(&mib_get_params) != LORAWAN_STATUS_OK) { - tr_debug("Couldn't get MIB parameters: Using default data rate"); - mcps_req.data_rate = _lora_phy.get_default_tx_datarate(); - } else { - mcps_req.data_rate = mib_get_params.param.channel_data_rate; - } - - } else { - return LORAWAN_STATUS_SERVICE_UNKNOWN; - } - - status = mcps_request_handler(&mcps_req); - - return status; -} - lorawan_status_t LoRaWANStack::set_confirmed_msg_retry(uint8_t count) { if (count >= MAX_CONFIRMED_MSG_RETRIES) { @@ -396,6 +315,8 @@ lorawan_status_t LoRaWANStack::enable_adaptive_datarate(bool adr_enabled) return LORAWAN_STATUS_NOT_INITIALIZED; } + //return _loramac.enable_adaptive_datarate(adr_enabled); + loramac_mib_req_confirm_t adr_mib_params; adr_mib_params.type = MIB_ADR; @@ -489,11 +410,14 @@ lorawan_status_t LoRaWANStack::activation_by_personalization(const lorawan_conne } int16_t LoRaWANStack::handle_tx(uint8_t port, const uint8_t* data, - uint16_t length, uint8_t flags) + uint16_t length, uint8_t flags, bool null_allowed) { + if (!null_allowed && !data) { + return LORAWAN_STATUS_PARAMETER_INVALID; + } + // add a link check request with normal data, until the application + // explicitly removes it. if (_link_check_requested) { - // add a link check request with normal data, until the application - // explicitly removes it. set_link_check_request(); } @@ -501,20 +425,17 @@ int16_t LoRaWANStack::handle_tx(uint8_t port, const uint8_t* data, return LORAWAN_STATUS_NO_ACTIVE_SESSIONS; } - if (_tx_msg.tx_ongoing) { + if(_loramac.tx_ongoing()) { return LORAWAN_STATUS_WOULD_BLOCK; } - if (!data && length > 0) { - return LORAWAN_STATUS_PARAMETER_INVALID; - } - #if defined(LORAWAN_COMPLIANCE_TEST) if (_compliance_test.running) { return LORAWAN_STATUS_COMPLIANCE_TEST_ON; } #endif + //TODO: Stack MUST know joining status!!!! loramac_mib_req_confirm_t mib_req; lorawan_status_t status; mib_req.type = MIB_NETWORK_JOINED; @@ -539,62 +460,14 @@ int16_t LoRaWANStack::handle_tx(uint8_t port, const uint8_t* data, return LORAWAN_STATUS_PARAMETER_INVALID; } - _tx_msg.port = port; - - uint16_t max_possible_size = check_possible_tx_size(length); - - if (max_possible_size > MBED_CONF_LORA_TX_MAX_SIZE) { - // LORAWAN_APP_DATA_MAX_SIZE should at least be - // either equal to or bigger than maximum possible - // tx size because our tx message buffer takes its - // length from that macro. Force maximum possible tx unit - // to be equal to the buffer size user chose. - max_possible_size = MBED_CONF_LORA_TX_MAX_SIZE; - } - - if (max_possible_size < length) { - tr_info("Cannot transmit %d bytes. Possible TX Size is %d bytes", - length, max_possible_size); - - _tx_msg.pending_size = length - max_possible_size; - _tx_msg.f_buffer_size = max_possible_size; - // copy user buffer upto the max_possible_size - memcpy(_tx_msg.f_buffer, data, _tx_msg.f_buffer_size); - } else { - // Whole message can be sent at one time - _tx_msg.f_buffer_size = length; - _tx_msg.pending_size = 0; - // copy user buffer upto the max_possible_size - if (length > 0) { - memcpy(_tx_msg.f_buffer, data, length); - } - } + int16_t len = _loramac.prepare_ongoing_tx(port, data, length, flags, _num_retry); - // Handles all unconfirmed messages, including proprietary and multicast - if ((flags & MSG_FLAG_MASK) == MSG_UNCONFIRMED_FLAG - || (flags & MSG_FLAG_MASK) == MSG_UNCONFIRMED_MULTICAST - || (flags & MSG_FLAG_MASK) == MSG_UNCONFIRMED_PROPRIETARY) { - - _tx_msg.type = MCPS_UNCONFIRMED; - _tx_msg.fport = _app_port; - } - - // Handles all confirmed messages, including proprietary and multicast - if ((flags & MSG_FLAG_MASK) == MSG_CONFIRMED_FLAG - || (flags & MSG_FLAG_MASK) == MSG_CONFIRMED_MULTICAST - || (flags & MSG_FLAG_MASK) == MSG_CONFIRMED_PROPRIETARY) { - - _tx_msg.type = MCPS_CONFIRMED; - _tx_msg.fport = _app_port; - _tx_msg.nb_trials = _num_retry; - } - tr_info("RTS = %u bytes, PEND = %u", _tx_msg.f_buffer_size, _tx_msg.pending_size); status = lora_state_machine(DEVICE_STATE_SEND); // send user the length of data which is scheduled now. // user should take care of the pending data. - return (status == LORAWAN_STATUS_OK) ? _tx_msg.f_buffer_size : (int16_t) status; + return (status == LORAWAN_STATUS_OK) ? len : (int16_t) status; } int16_t LoRaWANStack::handle_rx(const uint8_t port, uint8_t* data, @@ -766,9 +639,7 @@ void LoRaWANStack::mcps_confirm_handler(loramac_mcps_confirm_t *mcps_confirm) // Couldn't schedule packet, ack not recieved in CONFIRMED case // or some other error happened. Discard buffer, unset the tx-ongoing // flag and let the application know - _tx_msg.tx_ongoing = false; - memset(_tx_msg.f_buffer, 0, MBED_CONF_LORA_TX_MAX_SIZE); - _tx_msg.f_buffer_size = MBED_CONF_LORA_TX_MAX_SIZE; + _loramac.reset_ongoing_tx(); tr_error("mcps_confirm_handler: Error code = %d", mcps_confirm->status); @@ -808,7 +679,7 @@ void LoRaWANStack::mcps_confirm_handler(loramac_mcps_confirm_t *mcps_confirm) // Tell the application about successful transmission and store // data rate plus frame counter. _lw_session.uplink_counter = mcps_confirm->ul_frame_counter; - _tx_msg.tx_ongoing = false; + _loramac.set_tx_ongoing(false); if (_callbacks.events) { const int ret = _queue->call(_callbacks.events, TX_DONE); MBED_ASSERT(ret != 0); @@ -909,7 +780,7 @@ void LoRaWANStack::mcps_indication_handler(loramac_mcps_indication_t *mcps_indic // that we could retry a certain number of times if the uplink // failed for some reason if (mcps_indication->fpending_status && mib_req.param.dev_class != CLASS_C) { - handle_tx(mcps_indication->port, NULL, 0, MSG_CONFIRMED_FLAG); + handle_tx(mcps_indication->port, NULL, 0, MSG_CONFIRMED_FLAG, true); } // Class C and node received a confirmed message so we need to @@ -918,7 +789,7 @@ void LoRaWANStack::mcps_indication_handler(loramac_mcps_indication_t *mcps_indic // but version 1.1.0 says that network SHALL not send any new // confirmed messages until ack has been sent if (mib_req.param.dev_class == CLASS_C && mcps_indication->type == MCPS_CONFIRMED) { - handle_tx(mcps_indication->port, NULL, 0, MSG_CONFIRMED_FLAG); + handle_tx(mcps_indication->port, NULL, 0, MSG_CONFIRMED_FLAG, true); } } else { // Invalid port, ports 0, 224 and 225-255 are reserved. @@ -928,144 +799,6 @@ void LoRaWANStack::mcps_indication_handler(loramac_mcps_indication_t *mcps_indic } } -#if defined(LORAWAN_COMPLIANCE_TEST) -/** Compliance testing function - * - * \param mcps_indication Pointer to the indication structure, - * containing indication attributes. - */ -void LoRaWANStack::compliance_test_handler(loramac_mcps_indication_t *mcps_indication) -{ - if (_compliance_test.running == false) { - // Check compliance test enable command (i) - if ((mcps_indication->buffer_size == 4) && - (mcps_indication->buffer[0] == 0x01) && - (mcps_indication->buffer[1] == 0x01) && - (mcps_indication->buffer[2] == 0x01) && - (mcps_indication->buffer[3] == 0x01)) { - _compliance_test.is_tx_confirmed = false; - _compliance_test.app_port = 224; - _compliance_test.app_data_size = 2; - _compliance_test.downlink_counter = 0; - _compliance_test.link_check = false; - _compliance_test.demod_margin = 0; - _compliance_test.nb_gateways = 0; - _compliance_test.running = true; - _compliance_test.state = 1; - - loramac_mib_req_confirm_t mib_req; - mib_req.type = MIB_ADR; - mib_req.param.is_adr_enable = true; - mib_set_request(&mib_req); - -#if MBED_CONF_LORA_PHY == 0 - _loramac.LoRaMacTestSetDutyCycleOn(false); -#endif - //5000ms - _loramac.LoRaMacSetTxTimer(5000); - - //TODO: Should we call lora_state_machine here instead of just setting the state? - _device_current_state = DEVICE_STATE_COMPLIANCE_TEST; -// lora_state_machine(DEVICE_STATE_COMPLIANCE_TEST); - tr_debug("Compliance test activated."); - } - } else { - _compliance_test.state = mcps_indication->buffer[0]; - switch (_compliance_test.state) { - case 0: // Check compliance test disable command (ii) - _compliance_test.is_tx_confirmed = true; - _compliance_test.app_port = MBED_CONF_LORA_APP_PORT; - _compliance_test.app_data_size = LORAWAN_COMPLIANCE_TEST_DATA_SIZE; - _compliance_test.downlink_counter = 0; - _compliance_test.running = false; - - loramac_mib_req_confirm_t mib_req; - mib_req.type = MIB_ADR; - mib_req.param.is_adr_enable = MBED_CONF_LORA_ADR_ON; - mib_set_request(&mib_req); -#if MBED_CONF_LORA_PHY == 0 - _loramac.LoRaMacTestSetDutyCycleOn(MBED_CONF_LORA_DUTY_CYCLE_ON); -#endif - // Go to idle state after compliance test mode. - tr_debug("Compliance test disabled."); - _loramac.LoRaMacStopTxTimer(); - - // Clear any compliance test message stuff before going back to normal operation. - memset(&_tx_msg, 0, sizeof(_tx_msg)); - lora_state_machine(DEVICE_STATE_IDLE); - break; - case 1: // (iii, iv) - _compliance_test.app_data_size = 2; - break; - case 2: // Enable confirmed messages (v) - _compliance_test.is_tx_confirmed = true; - _compliance_test.state = 1; - break; - case 3: // Disable confirmed messages (vi) - _compliance_test.is_tx_confirmed = false; - _compliance_test.state = 1; - break; - case 4: // (vii) - _compliance_test.app_data_size = mcps_indication->buffer_size; - - _compliance_test.app_data_buffer[0] = 4; - for(uint8_t i = 1; i < MIN(_compliance_test.app_data_size, LORAMAC_PHY_MAXPAYLOAD); ++i) { - _compliance_test.app_data_buffer[i] = mcps_indication->buffer[i] + 1; - } - - send_compliance_test_frame_to_mac(); - break; - case 5: // (viii) - loramac_mlme_req_t mlme_req; - mlme_req.type = MLME_LINK_CHECK; - _loramac.mlme_request(&mlme_req); - break; - case 6: // (ix) - loramac_mlme_req_t mlme_request; - loramac_mib_req_confirm_t mib_request; - - // Disable TestMode and revert back to normal operation - _compliance_test.is_tx_confirmed = true; - _compliance_test.app_port = MBED_CONF_LORA_APP_PORT; - _compliance_test.app_data_size = LORAWAN_COMPLIANCE_TEST_DATA_SIZE; - _compliance_test.downlink_counter = 0; - _compliance_test.running = false; - - mib_request.type = MIB_ADR; - mib_request.param.is_adr_enable = MBED_CONF_LORA_ADR_ON; - mib_set_request(&mib_request); -#if MBED_CONF_LORA_PHY == 0 - _loramac.LoRaMacTestSetDutyCycleOn(MBED_CONF_LORA_DUTY_CYCLE_ON); -#endif - mlme_request.type = MLME_JOIN; - mlme_request.req.join.dev_eui = _lw_session.connection.connection_u.otaa.dev_eui; - mlme_request.req.join.app_eui = _lw_session.connection.connection_u.otaa.app_eui; - mlme_request.req.join.app_key = _lw_session.connection.connection_u.otaa.app_key; - mlme_request.req.join.nb_trials = _lw_session.connection.connection_u.otaa.nb_trials; - _loramac.mlme_request(&mlme_request); - break; - case 7: // (x) - if (mcps_indication->buffer_size == 3) { - loramac_mlme_req_t mlme_req; - mlme_req.type = MLME_TXCW; - mlme_req.req.cw_tx_mode.timeout = (uint16_t)((mcps_indication->buffer[1] << 8) | mcps_indication->buffer[2]); - _loramac.mlme_request(&mlme_req); - } else if (mcps_indication->buffer_size == 7) { - loramac_mlme_req_t mlme_req; - mlme_req.type = MLME_TXCW_1; - mlme_req.req.cw_tx_mode.timeout = (uint16_t)((mcps_indication->buffer[1] << 8) | mcps_indication->buffer[2]); - mlme_req.req.cw_tx_mode.frequency = (uint32_t)((mcps_indication->buffer[3] << 16) | (mcps_indication->buffer[4] << 8) - | mcps_indication->buffer[5]) * 100; - mlme_req.req.cw_tx_mode.power = mcps_indication->buffer[6]; - _loramac.mlme_request(&mlme_req); - } - _compliance_test.state = 1; - break; - } - } -} -#endif - lorawan_status_t LoRaWANStack::mib_set_request(loramac_mib_req_confirm_t *mib_set_params) { if (NULL == mib_set_params) { @@ -1140,10 +873,8 @@ lorawan_status_t LoRaWANStack::lora_state_machine(device_states_t new_state) mib_set_request(&mib_req); // reset buffers to original state - memset(_tx_msg.f_buffer, 0, MBED_CONF_LORA_TX_MAX_SIZE); - _tx_msg.pending_size = 0; - _tx_msg.f_buffer_size = 0; - _tx_msg.tx_ongoing = false; + _loramac.reset_ongoing_tx(true); + _rx_msg.msg.mcps_indication.buffer = NULL; _rx_msg.receive_ready = false; _rx_msg.prev_read_size = 0; @@ -1243,11 +974,11 @@ lorawan_status_t LoRaWANStack::lora_state_machine(device_states_t new_state) break; case DEVICE_STATE_SEND: // If a transmission is ongoing, don't interrupt - if (_tx_msg.tx_ongoing) { + if (_loramac.tx_ongoing()) { status = LORAWAN_STATUS_OK; } else { - _tx_msg.tx_ongoing = true; - status = send_frame_to_mac(); + _loramac.set_tx_ongoing(true); + status = _loramac.send_ongoing_tx(); switch (status) { case LORAWAN_STATUS_OK: @@ -1300,63 +1031,53 @@ lorawan_status_t LoRaWANStack::lora_state_machine(device_states_t new_state) } #if defined(LORAWAN_COMPLIANCE_TEST) -/** - * - * Prepares the upload message to reserved ports - * - * \param port Application port - */ -void LoRaWANStack::prepare_special_tx_frame(uint8_t port) + +lorawan_status_t LoRaWANStack::send_compliance_test_frame_to_mac() { - if (port == 224) { + loramac_mcps_req_t mcps_req; + +// prepare_special_tx_frame(_compliance_test.app_port); + //TODO: What if the port is not 224 ??? + if (_compliance_test.app_port == 224) { // Clear any normal message stuff before compliance test. - memset(&_tx_msg, 0, sizeof(_tx_msg)); + memset(&mcps_req, 0, sizeof(mcps_req)); if (_compliance_test.link_check == true) { _compliance_test.link_check = false; _compliance_test.state = 1; - _tx_msg.f_buffer_size = 3; - _tx_msg.f_buffer[0] = 5; - _tx_msg.f_buffer[1] = _compliance_test.demod_margin; - _tx_msg.f_buffer[2] = _compliance_test.nb_gateways; + mcps_req.f_buffer_size = 3; + mcps_req.f_buffer[0] = 5; + mcps_req.f_buffer[1] = _compliance_test.demod_margin; + mcps_req.f_buffer[2] = _compliance_test.nb_gateways; } else { switch (_compliance_test.state) { case 4: _compliance_test.state = 1; - _tx_msg.f_buffer_size = _compliance_test.app_data_size; + mcps_req.f_buffer_size = _compliance_test.app_data_size; - _tx_msg.f_buffer[0] = _compliance_test.app_data_buffer[0]; + mcps_req.f_buffer[0] = _compliance_test.app_data_buffer[0]; for(uint8_t i = 1; i < MIN(_compliance_test.app_data_size, MBED_CONF_LORA_TX_MAX_SIZE); ++i) { - _tx_msg.f_buffer[i] = _compliance_test.app_data_buffer[i]; + mcps_req.f_buffer[i] = _compliance_test.app_data_buffer[i]; } break; case 1: - _tx_msg.f_buffer_size = 2; - _tx_msg.f_buffer[0] = _compliance_test.downlink_counter >> 8; - _tx_msg.f_buffer[1] = _compliance_test.downlink_counter; + mcps_req.f_buffer_size = 2; + mcps_req.f_buffer[0] = _compliance_test.downlink_counter >> 8; + mcps_req.f_buffer[1] = _compliance_test.downlink_counter; break; } } } -} - -/** Hands over the compliance test frame to MAC layer - * - * \return returns the state of the LoRa MAC - */ -lorawan_status_t LoRaWANStack::send_compliance_test_frame_to_mac() -{ - loramac_mcps_req_t mcps_req; - - prepare_special_tx_frame(_compliance_test.app_port); + //TODO: If port is not 224, this might not work! + //Is there a test case where same _tx_msg's buffer would be used, when port is not 224??? if (!_compliance_test.is_tx_confirmed) { mcps_req.type = MCPS_UNCONFIRMED; - mcps_req.f_buffer = _tx_msg.f_buffer; - mcps_req.f_buffer_size = _tx_msg.f_buffer_size; +// mcps_req.f_buffer = _tx_msg.f_buffer; +// mcps_req.f_buffer_size = _tx_msg.f_buffer_size; mcps_req.fport = _compliance_test.app_port; mcps_req.nb_trials = 1; - mcps_req.data_rate = _lora_phy.get_default_tx_datarate(); + mcps_req.data_rate = _loramac.get_default_tx_datarate(); tr_info("Transmit unconfirmed compliance test frame %d bytes.", mcps_req.f_buffer_size); @@ -1365,11 +1086,11 @@ lorawan_status_t LoRaWANStack::send_compliance_test_frame_to_mac() } } else if (_compliance_test.is_tx_confirmed) { mcps_req.type = MCPS_CONFIRMED; - mcps_req.f_buffer = _tx_msg.f_buffer; - mcps_req.f_buffer_size = _tx_msg.f_buffer_size; +// mcps_req.f_buffer = _tx_msg.f_buffer; +// mcps_req.f_buffer_size = _tx_msg.f_buffer_size; mcps_req.fport = _compliance_test.app_port; mcps_req.nb_trials = _num_retry; - mcps_req.data_rate = _lora_phy.get_default_tx_datarate(); + mcps_req.data_rate = _loramac.get_default_tx_datarate(); tr_info("Transmit confirmed compliance test frame %d bytes.", mcps_req.f_buffer_size); @@ -1382,5 +1103,141 @@ lorawan_status_t LoRaWANStack::send_compliance_test_frame_to_mac() return mcps_request_handler(&mcps_req); } + +/** Compliance testing function + * + * \param mcps_indication Pointer to the indication structure, + * containing indication attributes. + */ +void LoRaWANStack::compliance_test_handler(loramac_mcps_indication_t *mcps_indication) +{ + if (_compliance_test.running == false) { + // Check compliance test enable command (i) + if ((mcps_indication->buffer_size == 4) && + (mcps_indication->buffer[0] == 0x01) && + (mcps_indication->buffer[1] == 0x01) && + (mcps_indication->buffer[2] == 0x01) && + (mcps_indication->buffer[3] == 0x01)) { + _compliance_test.is_tx_confirmed = false; + _compliance_test.app_port = 224; + _compliance_test.app_data_size = 2; + _compliance_test.downlink_counter = 0; + _compliance_test.link_check = false; + _compliance_test.demod_margin = 0; + _compliance_test.nb_gateways = 0; + _compliance_test.running = true; + _compliance_test.state = 1; + + loramac_mib_req_confirm_t mib_req; + mib_req.type = MIB_ADR; + mib_req.param.is_adr_enable = true; + mib_set_request(&mib_req); + +#if MBED_CONF_LORA_PHY == 0 + _loramac.LoRaMacTestSetDutyCycleOn(false); +#endif + //5000ms + _loramac.LoRaMacSetTxTimer(5000); + + //TODO: Should we call lora_state_machine here instead of just setting the state? + _device_current_state = DEVICE_STATE_COMPLIANCE_TEST; +// lora_state_machine(DEVICE_STATE_COMPLIANCE_TEST); + tr_debug("Compliance test activated."); + } + } else { + _compliance_test.state = mcps_indication->buffer[0]; + switch (_compliance_test.state) { + case 0: // Check compliance test disable command (ii) + _compliance_test.is_tx_confirmed = true; + _compliance_test.app_port = MBED_CONF_LORA_APP_PORT; + _compliance_test.app_data_size = LORAWAN_COMPLIANCE_TEST_DATA_SIZE; + _compliance_test.downlink_counter = 0; + _compliance_test.running = false; + + loramac_mib_req_confirm_t mib_req; + mib_req.type = MIB_ADR; + mib_req.param.is_adr_enable = MBED_CONF_LORA_ADR_ON; + mib_set_request(&mib_req); +#if MBED_CONF_LORA_PHY == 0 + _loramac.LoRaMacTestSetDutyCycleOn(MBED_CONF_LORA_DUTY_CYCLE_ON); +#endif + // Go to idle state after compliance test mode. + tr_debug("Compliance test disabled."); + _loramac.LoRaMacStopTxTimer(); + + // Clear any compliance test message stuff before going back to normal operation. + _loramac.reset_ongoing_tx(); + lora_state_machine(DEVICE_STATE_IDLE); + break; + case 1: // (iii, iv) + _compliance_test.app_data_size = 2; + break; + case 2: // Enable confirmed messages (v) + _compliance_test.is_tx_confirmed = true; + _compliance_test.state = 1; + break; + case 3: // Disable confirmed messages (vi) + _compliance_test.is_tx_confirmed = false; + _compliance_test.state = 1; + break; + case 4: // (vii) + _compliance_test.app_data_size = mcps_indication->buffer_size; + + _compliance_test.app_data_buffer[0] = 4; + for(uint8_t i = 1; i < MIN(_compliance_test.app_data_size, LORAMAC_PHY_MAXPAYLOAD); ++i) { + _compliance_test.app_data_buffer[i] = mcps_indication->buffer[i] + 1; + } + + send_compliance_test_frame_to_mac(); + break; + case 5: // (viii) + loramac_mlme_req_t mlme_req; + mlme_req.type = MLME_LINK_CHECK; + _loramac.mlme_request(&mlme_req); + break; + case 6: // (ix) + loramac_mlme_req_t mlme_request; + loramac_mib_req_confirm_t mib_request; + + // Disable TestMode and revert back to normal operation + _compliance_test.is_tx_confirmed = true; + _compliance_test.app_port = MBED_CONF_LORA_APP_PORT; + _compliance_test.app_data_size = LORAWAN_COMPLIANCE_TEST_DATA_SIZE; + _compliance_test.downlink_counter = 0; + _compliance_test.running = false; + + mib_request.type = MIB_ADR; + mib_request.param.is_adr_enable = MBED_CONF_LORA_ADR_ON; + mib_set_request(&mib_request); +#if MBED_CONF_LORA_PHY == 0 + _loramac.LoRaMacTestSetDutyCycleOn(MBED_CONF_LORA_DUTY_CYCLE_ON); +#endif + mlme_request.type = MLME_JOIN; + mlme_request.req.join.dev_eui = _lw_session.connection.connection_u.otaa.dev_eui; + mlme_request.req.join.app_eui = _lw_session.connection.connection_u.otaa.app_eui; + mlme_request.req.join.app_key = _lw_session.connection.connection_u.otaa.app_key; + mlme_request.req.join.nb_trials = _lw_session.connection.connection_u.otaa.nb_trials; + _loramac.mlme_request(&mlme_request); + break; + case 7: // (x) + if (mcps_indication->buffer_size == 3) { + loramac_mlme_req_t mlme_req; + mlme_req.type = MLME_TXCW; + mlme_req.req.cw_tx_mode.timeout = (uint16_t)((mcps_indication->buffer[1] << 8) | mcps_indication->buffer[2]); + _loramac.mlme_request(&mlme_req); + } else if (mcps_indication->buffer_size == 7) { + loramac_mlme_req_t mlme_req; + mlme_req.type = MLME_TXCW_1; + mlme_req.req.cw_tx_mode.timeout = (uint16_t)((mcps_indication->buffer[1] << 8) | mcps_indication->buffer[2]); + mlme_req.req.cw_tx_mode.frequency = (uint32_t)((mcps_indication->buffer[3] << 16) | (mcps_indication->buffer[4] << 8) + | mcps_indication->buffer[5]) * 100; + mlme_req.req.cw_tx_mode.power = mcps_indication->buffer[6]; + _loramac.mlme_request(&mlme_req); + } + _compliance_test.state = 1; + break; + } + } +} #endif diff --git a/features/lorawan/LoRaWANStack.h b/features/lorawan/LoRaWANStack.h index 8d3957859de..618a27c8930 100644 --- a/features/lorawan/LoRaWANStack.h +++ b/features/lorawan/LoRaWANStack.h @@ -34,7 +34,6 @@ SPDX-License-Identifier: BSD-3-Clause #include "lorastack/mac/LoRaMac.h" #include "lorawan/system/lorawan_data_structures.h" #include "LoRaRadio.h" -#include "loraphy_target.h" /** * A mask for the network ID. @@ -279,13 +278,15 @@ class LoRaWANStack: private mbed::NonCopyable { * MSG_CONFIRMED_FLAG and MSG_UNCONFIRMED_FLAG are * mutually exclusive. * + * @param null_allowed Internal use only. Needed for sending empty packet + * having CONFIRMED bit on. * * @return The number of bytes sent, or * LORAWAN_STATUS_WOULD_BLOCK if another TX is * ongoing, or a negative error code on failure. */ int16_t handle_tx(uint8_t port, const uint8_t* data, - uint16_t length, uint8_t flags); + uint16_t length, uint8_t flags, bool null_allowed = false); /** Receives a message from the Network Server. * @@ -386,11 +387,6 @@ class LoRaWANStack: private mbed::NonCopyable { */ lorawan_status_t lora_state_machine(device_states_t new_state); - /** - * Hands over the packet to Mac layer by posting an MCPS request. - */ - lorawan_status_t send_frame_to_mac(); - /** * Callback function for MLME indication. Mac layer calls this function once * an MLME indication is received. This method translates Mac layer data @@ -443,16 +439,6 @@ class LoRaWANStack: private mbed::NonCopyable { */ lorawan_status_t set_application_port(uint8_t port); - /** - * Helper function to figure out if the user defined data size is possible - * to send or not. The allowed size for transmission depends on the current - * data rate set for the channel. If its not possible to send user defined - * packet size, this method returns the maximum possible size at the moment, - * otherwise the user defined size is returned which means all of user data - * can be sent. - */ - uint16_t check_possible_tx_size(uint16_t size); - /** End device OTAA join. * * Based on the LoRaWAN standard 1.0.2. @@ -481,9 +467,7 @@ class LoRaWANStack: private mbed::NonCopyable { private: - LoRaWANTimeHandler _lora_time; LoRaMac _loramac; - LoRaPHY_region _lora_phy; loramac_primitives_t LoRaMacPrimitives; device_states_t _device_current_state; @@ -498,10 +482,6 @@ class LoRaWANStack: private mbed::NonCopyable { events::EventQueue *_queue; #if defined(LORAWAN_COMPLIANCE_TEST) - /** - * This function is used only for compliance testing - */ - void prepare_special_tx_frame(uint8_t port); /** * Used only for compliance testing diff --git a/features/lorawan/lorastack/mac/LoRaMac.cpp b/features/lorawan/lorastack/mac/LoRaMac.cpp index 135305972e7..96a3ee991ef 100644 --- a/features/lorawan/lorastack/mac/LoRaMac.cpp +++ b/features/lorawan/lorastack/mac/LoRaMac.cpp @@ -77,10 +77,9 @@ using namespace events; #define DOWN_LINK 1 -LoRaMac::LoRaMac(LoRaWANTimeHandler &lora_time) - : mac_commands(), _lora_time(lora_time) +LoRaMac::LoRaMac() + : _lora_phy(_lora_time), mac_commands() { - lora_phy = NULL; //radio_events_t RadioEvents; _params.keys.dev_eui = NULL; _params.keys.app_eui = NULL; @@ -88,6 +87,7 @@ LoRaMac::LoRaMac(LoRaWANTimeHandler &lora_time) memset(_params.keys.nwk_skey, 0, sizeof(_params.keys.nwk_skey)); memset(_params.keys.app_skey, 0, sizeof(_params.keys.app_skey)); + memset(&_ongoing_tx_msg, 0, sizeof(_ongoing_tx_msg)); _params.dev_nonce = 0; _params.net_id = 0; @@ -188,7 +188,7 @@ void LoRaMac::on_radio_tx_done( void ) loramac_mlme_confirm_t mlme_confirm = mlme.get_confirmation(); if (_params.dev_class != CLASS_C) { - lora_phy->put_radio_to_sleep(); + _lora_phy.put_radio_to_sleep(); } else { open_continuous_rx2_window(); } @@ -204,7 +204,7 @@ void LoRaMac::on_radio_tx_done( void ) if ((_params.dev_class == CLASS_C ) || (_params.is_node_ack_requested == true)) { _lora_time.start(_params.timers.ack_timeout_timer, - _params.rx_window2_delay + lora_phy->get_ack_timeout()); + _params.rx_window2_delay + _lora_phy.get_ack_timeout()); } } else { mcps.get_confirmation().status = LORAMAC_EVENT_INFO_STATUS_OK; @@ -232,7 +232,7 @@ void LoRaMac::on_radio_tx_done( void ) tx_done_params.channel = _params.channel; tx_done_params.joined = _params.is_nwk_joined; tx_done_params.last_tx_done_time = cur_time; - lora_phy->set_last_tx_done(&tx_done_params); + _lora_phy.set_last_tx_done(&tx_done_params); // Update Aggregated last tx done time _params.timers.aggregated_last_tx_time = cur_time; @@ -302,7 +302,7 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, mcps.get_indication().type = MCPS_UNCONFIRMED; if (_params.dev_class != CLASS_C) { - lora_phy->put_radio_to_sleep(); + _lora_phy.put_radio_to_sleep(); } _lora_time.stop( _params.timers.rx_window2_timer ); @@ -377,7 +377,7 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, // Size of the regular payload is 12. Plus 1 byte MHDR and 4 bytes MIC cflist.size = size - 17; - lora_phy->apply_cf_list(&cflist); + _lora_phy.apply_cf_list(&cflist); mlme.get_confirmation().status = LORAMAC_EVENT_INFO_STATUS_OK; _params.is_nwk_joined = true; @@ -390,7 +390,7 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, case FRAME_TYPE_DATA_CONFIRMED_DOWN: case FRAME_TYPE_DATA_UNCONFIRMED_DOWN: { - uint8_t value = lora_phy->get_max_payload(mcps.get_indication().rx_datarate, _params.is_repeater_supported); + uint8_t value = _lora_phy.get_max_payload(mcps.get_indication().rx_datarate, _params.is_repeater_supported); if (MAX(0, (int16_t) ((int16_t)size - (int16_t)LORA_MAC_FRMPAYLOAD_OVERHEAD )) > (int32_t)value) { mcps.get_indication().status = LORAMAC_EVENT_INFO_STATUS_ERROR; @@ -469,7 +469,7 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, } } - if (sequence_counter_diff >= lora_phy->get_maximum_frame_counter_gap()) { + if (sequence_counter_diff >= _lora_phy.get_maximum_frame_counter_gap()) { mcps.get_indication().status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_TOO_MANY_FRAMES_LOSS; mcps.get_indication().dl_frame_counter = downlink_counter; prepare_rx_done_abort( ); @@ -575,7 +575,7 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, // Decode frame payload MAC commands if (LORAWAN_STATUS_OK != mac_commands.process_mac_commands( _params.payload, 0, frame_len, snr, - mlme.get_confirmation(), _params.sys_params, *lora_phy)) { + mlme.get_confirmation(), _params.sys_params, _lora_phy)) { mcps.get_indication().status = LORAMAC_EVENT_INFO_STATUS_ERROR; } else if (mac_commands.has_sticky_mac_cmd()) { set_mlme_schedule_ul_indication(); @@ -592,7 +592,7 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, // Decode Options field MAC commands. Omit the fPort. if (LORAWAN_STATUS_OK != mac_commands.process_mac_commands( payload, 8, app_payload_start_index - 1, snr, - mlme.get_confirmation(), _params.sys_params, *lora_phy )) { + mlme.get_confirmation(), _params.sys_params, _lora_phy )) { mcps.get_indication().status = LORAMAC_EVENT_INFO_STATUS_ERROR; } else if (mac_commands.has_sticky_mac_cmd()) { set_mlme_schedule_ul_indication(); @@ -620,7 +620,7 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, if (LORAWAN_STATUS_OK != mac_commands.process_mac_commands( payload, 8, app_payload_start_index, snr, mlme.get_confirmation(), - _params.sys_params, *lora_phy)) { + _params.sys_params, _lora_phy)) { mcps.get_indication().status = LORAMAC_EVENT_INFO_STATUS_ERROR; } else if (mac_commands.has_sticky_mac_cmd()) { set_mlme_schedule_ul_indication(); @@ -673,7 +673,7 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, void LoRaMac::on_radio_tx_timeout( void ) { if (_params.dev_class != CLASS_C) { - lora_phy->put_radio_to_sleep(); + _lora_phy.put_radio_to_sleep(); } else { open_continuous_rx2_window(); } @@ -688,7 +688,7 @@ void LoRaMac::on_radio_tx_timeout( void ) void LoRaMac::on_radio_rx_error( void ) { if (_params.dev_class != CLASS_C) { - lora_phy->put_radio_to_sleep(); + _lora_phy.put_radio_to_sleep(); } if (_params.rx_slot == RX_SLOT_WIN_1) { @@ -724,7 +724,7 @@ void LoRaMac::on_radio_rx_error( void ) void LoRaMac::on_radio_rx_timeout(void) { if (_params.dev_class != CLASS_C) { - lora_phy->put_radio_to_sleep(); + _lora_phy.put_radio_to_sleep(); } if (_params.rx_slot == RX_SLOT_WIN_1) { @@ -864,7 +864,7 @@ void LoRaMac::on_mac_state_check_timer_event(void) _params.ack_timeout_retry_counter++; if ((_params.ack_timeout_retry_counter % 2) == 1) { - _params.sys_params.channel_data_rate = lora_phy->get_next_lower_tx_datarate( + _params.sys_params.channel_data_rate = _lora_phy.get_next_lower_tx_datarate( _params.sys_params.channel_data_rate); } @@ -887,7 +887,7 @@ void LoRaMac::on_mac_state_check_timer_event(void) } } } else { - lora_phy->restore_default_channels(); + _lora_phy.restore_default_channels(); _params.mac_state &= ~LORAMAC_TX_RUNNING; @@ -970,7 +970,7 @@ void LoRaMac::on_tx_delayed_timer_event(void) reset_mac_parameters(); - _params.sys_params.channel_data_rate = lora_phy->get_alternate_DR(_params.join_request_trial_counter + 1); + _params.sys_params.channel_data_rate = _lora_phy.get_alternate_DR(_params.join_request_trial_counter + 1); mac_hdr.value = 0; mac_hdr.bits.mtype = FRAME_TYPE_JOIN_REQ; @@ -1004,10 +1004,10 @@ void LoRaMac::on_rx_window1_timer_event(void) _params.rx_window1_config.rx_slot = _params.rx_slot; if (_params.dev_class == CLASS_C) { - lora_phy->put_radio_to_standby(); + _lora_phy.put_radio_to_standby(); } - lora_phy->rx_config(&_params.rx_window1_config, + _lora_phy.rx_config(&_params.rx_window1_config, (int8_t*) &mcps.get_indication().rx_datarate); rx_window_setup(_params.rx_window1_config.is_rx_continuous, @@ -1031,7 +1031,7 @@ void LoRaMac::on_rx_window2_timer_event(void) _params.rx_window2_config.is_rx_continuous = true; } - if (lora_phy->rx_config(&_params.rx_window2_config, + if (_lora_phy.rx_config(&_params.rx_window2_config, (int8_t*) &mcps.get_indication().rx_datarate) == true) { rx_window_setup(_params.rx_window2_config.is_rx_continuous, @@ -1089,7 +1089,7 @@ 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); + _lora_phy.setup_rx_window(rx_continuous, max_rx_window_time); } bool LoRaMac::validate_payload_length(uint8_t length, int8_t datarate, @@ -1098,7 +1098,7 @@ bool LoRaMac::validate_payload_length(uint8_t length, int8_t datarate, uint16_t max_value = 0; uint16_t payloadSize = 0; - max_value = lora_phy->get_max_payload(datarate, _params.is_repeater_supported); + max_value = _lora_phy.get_max_payload(datarate, _params.is_repeater_supported); // Calculate the resulting payload size payloadSize = (length + fopts_len); @@ -1176,7 +1176,7 @@ lorawan_status_t LoRaMac::schedule_tx(void) nextChan.last_aggregate_tx_time = _params.timers.aggregated_last_tx_time; // Select channel - status = lora_phy->set_next_channel(&nextChan, &_params.channel, + status = _lora_phy.set_next_channel(&nextChan, &_params.channel, &dutyCycleTimeOff, &_params.timers.aggregated_timeoff); switch (status) { @@ -1198,15 +1198,15 @@ lorawan_status_t LoRaMac::schedule_tx(void) tr_debug("Next Channel Idx=%d, DR=%d", _params.channel, nextChan.current_datarate); // Compute Rx1 windows parameters - uint8_t dr_offset = lora_phy->apply_DR_offset(_params.sys_params.channel_data_rate, + uint8_t dr_offset = _lora_phy.apply_DR_offset(_params.sys_params.channel_data_rate, _params.sys_params.rx1_dr_offset); - lora_phy->compute_rx_win_params(dr_offset, _params.sys_params.min_rx_symb, + _lora_phy.compute_rx_win_params(dr_offset, _params.sys_params.min_rx_symb, _params.sys_params.max_sys_rx_error, &_params.rx_window1_config); // Compute Rx2 windows parameters - lora_phy->compute_rx_win_params(_params.sys_params.rx2_channel.datarate, + _lora_phy.compute_rx_win_params(_params.sys_params.rx2_channel.datarate, _params.sys_params.min_rx_symb, _params.sys_params.max_sys_rx_error, &_params.rx_window2_config); @@ -1245,7 +1245,7 @@ void LoRaMac::calculate_backOff(uint8_t channel) backoff_params.last_tx_was_join_req = _params.is_last_tx_join_request; // Update regional back-off - lora_phy->calculate_backoff(&backoff_params); + _lora_phy.calculate_backoff(&backoff_params); // Update aggregated time-off. This must be an assignment and no incremental // update as we do only calculate the time-off based on the last transmission @@ -1277,7 +1277,7 @@ void LoRaMac::reset_mac_parameters(void) _params.is_rx_window_enabled = true; - lora_phy->reset_to_default_values(&_params, false); + _lora_phy.reset_to_default_values(&_params, false); _params.is_node_ack_requested = false; _params.is_srv_ack_requested = false; @@ -1303,6 +1303,150 @@ void LoRaMac::open_continuous_rx2_window (void) _params.rx_slot = RX_SLOT_WIN_CLASS_C; } +uint8_t LoRaMac::get_default_tx_datarate() +{ + return _lora_phy.get_default_tx_datarate(); +} + +bool LoRaMac::tx_ongoing() +{ + return _ongoing_tx_msg.tx_ongoing; +} + +void LoRaMac::set_tx_ongoing(bool ongoing) +{ + _ongoing_tx_msg.tx_ongoing = ongoing; +} + +void LoRaMac::reset_ongoing_tx(bool reset_pending) +{ + _ongoing_tx_msg.tx_ongoing = false; + memset(_ongoing_tx_msg.f_buffer, 0, MBED_CONF_LORA_TX_MAX_SIZE); + _ongoing_tx_msg.f_buffer_size = 0; + if (reset_pending) { + _ongoing_tx_msg.pending_size = 0; + } +} + +int16_t LoRaMac::prepare_ongoing_tx(uint8_t port, const uint8_t* data, + uint16_t length, uint8_t flags, uint8_t num_retries) +{ + _ongoing_tx_msg.port = port; + + uint8_t max_possible_size = query_tx_possible(length); + + //TODO: refactor following 20 lines or so. There must be a better way for this + if (max_possible_size > MBED_CONF_LORA_TX_MAX_SIZE) { + // LORAWAN_APP_DATA_MAX_SIZE should at least be + // either equal to or bigger than maximum possible + // tx size because our tx message buffer takes its + // length from that macro. Force maximum possible tx unit + // to be equal to the buffer size user chose. + max_possible_size = MBED_CONF_LORA_TX_MAX_SIZE; + } + + if (max_possible_size < length) { + tr_info("Cannot transmit %d bytes. Possible TX Size is %d bytes", + length, max_possible_size); + + _ongoing_tx_msg.pending_size = length - max_possible_size; + _ongoing_tx_msg.f_buffer_size = max_possible_size; + // copy user buffer upto the max_possible_size + memcpy(_ongoing_tx_msg.f_buffer, data, _ongoing_tx_msg.f_buffer_size); + } else { + // Whole message can be sent at one time + _ongoing_tx_msg.f_buffer_size = length; + _ongoing_tx_msg.pending_size = 0; + // copy user buffer upto the max_possible_size + if (length > 0) { + memcpy(_ongoing_tx_msg.f_buffer, data, length); + } + } + + // Handles all unconfirmed messages, including proprietary and multicast + if ((flags & MSG_FLAG_MASK) == MSG_UNCONFIRMED_FLAG + || (flags & MSG_FLAG_MASK) == MSG_UNCONFIRMED_MULTICAST + || (flags & MSG_FLAG_MASK) == MSG_UNCONFIRMED_PROPRIETARY) { + + _ongoing_tx_msg.type = MCPS_UNCONFIRMED; + _ongoing_tx_msg.fport = port; + _ongoing_tx_msg.nb_trials = 1; + } + + // Handles all confirmed messages, including proprietary and multicast + if ((flags & MSG_FLAG_MASK) == MSG_CONFIRMED_FLAG + || (flags & MSG_FLAG_MASK) == MSG_CONFIRMED_MULTICAST + || (flags & MSG_FLAG_MASK) == MSG_CONFIRMED_PROPRIETARY) { + + _ongoing_tx_msg.type = MCPS_CONFIRMED; + _ongoing_tx_msg.fport = port; + _ongoing_tx_msg.nb_trials = num_retries; + } + + tr_info("RTS = %u bytes, PEND = %u", _ongoing_tx_msg.f_buffer_size, _ongoing_tx_msg.pending_size); + return _ongoing_tx_msg.f_buffer_size; +} + +lorawan_status_t LoRaMac::send_ongoing_tx() +{ + lorawan_status_t status; + loramac_mib_req_confirm_t mib_get_params; + + if (_params.mac_state != LORAMAC_IDLE) { + return LORAWAN_STATUS_BUSY; + } + + int8_t datarate = get_default_tx_datarate(); + + mib_get_params.type = MIB_CHANNELS_DATARATE; + if(mib_get_request_confirm(&mib_get_params) == LORAWAN_STATUS_OK) { + datarate = mib_get_params.param.channel_data_rate; + } + // TODO: The comment is different than the code??? + // Apply the minimum possible datarate. + // Some regions have limitations for the minimum datarate. + datarate = MAX(datarate, (int8_t)_lora_phy.get_minimum_tx_datarate()); + + loramac_mhdr_t machdr; + machdr.value = 0; + + mcps.reset_confirmation(); + + _params.ack_timeout_retry_counter = 1; + _params.max_ack_timeout_retries = 1; + + if (MCPS_UNCONFIRMED == _ongoing_tx_msg.type) { + machdr.bits.mtype = FRAME_TYPE_DATA_UNCONFIRMED_UP; + } else if (_ongoing_tx_msg.type == MCPS_CONFIRMED) { + machdr.bits.mtype = FRAME_TYPE_DATA_CONFIRMED_UP; + _params.max_ack_timeout_retries = _ongoing_tx_msg.nb_trials; + } else if ( _ongoing_tx_msg.type == MCPS_PROPRIETARY) { + //Is this dead code currently??? Nobody sets this type + machdr.bits.mtype = FRAME_TYPE_PROPRIETARY; + } else { + return LORAWAN_STATUS_SERVICE_UNKNOWN; + } + + if (_params.sys_params.adr_on == false) { + if (_lora_phy.verify_tx_datarate(datarate, false) == true) { + _params.sys_params.channel_data_rate = datarate; + } else { + return LORAWAN_STATUS_PARAMETER_INVALID; + } + } + + status = send(&machdr, _ongoing_tx_msg.fport, _ongoing_tx_msg.f_buffer, + _ongoing_tx_msg.f_buffer_size); + if (status == LORAWAN_STATUS_OK) { + mcps.get_confirmation().req_type = _ongoing_tx_msg.type; + _params.flags.bits.mcps_req = 1; + } else { + _params.is_node_ack_requested = false; + } + + return status; +} + static void memcpy_convert_endianess(uint8_t *dst, const uint8_t *src, uint16_t size) { @@ -1348,7 +1492,7 @@ lorawan_status_t LoRaMac::prepare_frame(loramac_mhdr_t *machdr, _params.keys.dev_eui, 8); _params.buffer_pkt_len += 8; - _params.dev_nonce = lora_phy->get_radio_rng(); + _params.dev_nonce = _lora_phy.get_radio_rng(); _params.buffer[_params.buffer_pkt_len++] = _params.dev_nonce & 0xFF; _params.buffer[_params.buffer_pkt_len++] = (_params.dev_nonce >> 8) & 0xFF; @@ -1375,7 +1519,7 @@ lorawan_status_t LoRaMac::prepare_frame(loramac_mhdr_t *machdr, } if (_params.sys_params.adr_on) { - if (lora_phy->get_next_ADR(true, + if (_lora_phy.get_next_ADR(true, _params.sys_params.channel_data_rate, _params.sys_params.channel_tx_power, _params.adr_ack_counter)) { @@ -1503,7 +1647,7 @@ lorawan_status_t LoRaMac::send_frame_on_channel(uint8_t channel) tx_config.antenna_gain = _params.sys_params.antenna_gain; tx_config.pkt_len = _params.buffer_pkt_len; - lora_phy->tx_config(&tx_config, &tx_power, &_params.timers.tx_toa); + _lora_phy.tx_config(&tx_config, &tx_power, &_params.timers.tx_toa); mlme.get_confirmation().status = LORAMAC_EVENT_INFO_STATUS_ERROR; @@ -1525,61 +1669,15 @@ lorawan_status_t LoRaMac::send_frame_on_channel(uint8_t channel) } // Send now - lora_phy->handle_send(_params.buffer, _params.buffer_pkt_len); + _lora_phy.handle_send(_params.buffer, _params.buffer_pkt_len); _params.mac_state |= LORAMAC_TX_RUNNING; return LORAWAN_STATUS_OK; } -//lorawan_status_t LoRaMac::set_tx_continuous_wave(uint16_t timeout) -//{ -// cw_mode_params_t continuous_wave; - -// continuous_wave.channel = _params.channel; -// continuous_wave.datarate = _params.sys_params.channel_data_rate; -// continuous_wave.tx_power = _params.sys_params.channel_tx_power; -// continuous_wave.max_eirp = _params.sys_params.max_eirp; -// continuous_wave.antenna_gain = _params.sys_params.antenna_gain; -// continuous_wave.timeout = timeout; - -// lora_phy->set_tx_cont_mode(&continuous_wave); - -// // Starts the MAC layer status check timer -// _lora_time.start(_params.timers.mac_state_check_timer, -// MAC_STATE_CHECK_TIMEOUT); - -// _params.mac_state |= LORAMAC_TX_RUNNING; - -// return LORAWAN_STATUS_OK; -//} - -//lorawan_status_t LoRaMac::set_tx_continuous_wave1(uint16_t timeout, -// uint32_t frequency, -// uint8_t power) -//{ -// cw_mode_params_t continuous_wave; - -// continuous_wave.channel = 0; -// continuous_wave.datarate = 0; -// continuous_wave.tx_power = power; -// continuous_wave.max_eirp = 0; -// continuous_wave.antenna_gain = 0; -// continuous_wave.timeout = timeout; - -// lora_phy->set_tx_cont_mode(&continuous_wave); - -// // Starts the MAC layer status check timer -// _lora_time.start(_params.timers.mac_state_check_timer, -// MAC_STATE_CHECK_TIMEOUT); - -// _params.mac_state |= LORAMAC_TX_RUNNING; - -// return LORAWAN_STATUS_OK; -//} - lorawan_status_t LoRaMac::initialize(loramac_primitives_t *primitives, - LoRaPHY *phy, EventQueue *queue) + EventQueue *queue) { _lora_time.activate_timer_subsystem(queue); @@ -1590,19 +1688,17 @@ lorawan_status_t LoRaMac::initialize(loramac_primitives_t *primitives, return LORAWAN_STATUS_PARAMETER_INVALID; } - lora_phy = phy; - // Activate MLME subsystem - mlme.activate_mlme_subsystem(lora_phy); + mlme.activate_mlme_subsystem(&_lora_phy); // Activate MCPS subsystem mcps.activate_mcps_subsystem(); // Activate MIB subsystem - mib.activate_mib_subsystem(lora_phy); + mib.activate_mib_subsystem(&_lora_phy); // Activate channel planning subsystem - channel_plan.activate_channelplan_subsystem(lora_phy); + channel_plan.activate_channelplan_subsystem(&_lora_phy); mac_primitives = primitives; @@ -1619,7 +1715,7 @@ lorawan_status_t LoRaMac::initialize(loramac_primitives_t *primitives, _params.timers.aggregated_last_tx_time = 0; _params.timers.aggregated_timeoff = 0; - lora_phy->reset_to_default_values(&_params, true); + _lora_phy.reset_to_default_values(&_params, true); // Init parameters which are not set in function ResetMacParameters _params.sys_params.max_sys_rx_error = 10; @@ -1629,11 +1725,11 @@ lorawan_status_t LoRaMac::initialize(loramac_primitives_t *primitives, reset_mac_parameters(); // Random seed initialization - srand(lora_phy->get_radio_rng()); + srand(_lora_phy.get_radio_rng()); _params.is_nwk_public = MBED_CONF_LORA_PUBLIC_NETWORK; - lora_phy->setup_public_network_mode(_params.is_nwk_public); - lora_phy->put_radio_to_sleep(); + _lora_phy.setup_public_network_mode(_params.is_nwk_public); + _lora_phy.put_radio_to_sleep(); // Initialize timers _lora_time.init(_params.timers.mac_state_check_timer, @@ -1673,7 +1769,7 @@ void LoRaMac::disconnect() _lora_time.stop(_params.timers.ack_timeout_timer); // Put radio to sleep - lora_phy->put_radio_to_sleep(); + _lora_phy.put_radio_to_sleep(); // Reset internal state _params.is_nwk_joined = false; @@ -1693,31 +1789,27 @@ void LoRaMac::disconnect() _params.mac_state = LORAMAC_IDLE; } -lorawan_status_t LoRaMac::query_tx_possible(uint8_t size, - loramac_tx_info_t* tx_info) +uint8_t LoRaMac::query_tx_possible(uint8_t size) { + uint8_t max_possible_payload_size = 0; + uint8_t current_payload_size = 0; uint8_t fopt_len = mac_commands.get_mac_cmd_length() + mac_commands.get_repeat_commands_length(); - if (tx_info == NULL) { - return LORAWAN_STATUS_PARAMETER_INVALID; - } - - // if applicaion has turned on ADR, we want to opt it out + // if application has turned on ADR, we want to opt it out 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, _params.sys_params.channel_tx_power, _params.adr_ack_counter); } - tx_info->current_payload_size = lora_phy->get_max_payload(_params.sys_params.channel_data_rate, _params.is_repeater_supported); - + current_payload_size = _lora_phy.get_max_payload(_params.sys_params.channel_data_rate, _params.is_repeater_supported); // Verify if the fOpts fit into the maximum payload - if (tx_info->current_payload_size >= fopt_len) { - tx_info->max_possible_payload_size = tx_info->current_payload_size - fopt_len; + if (current_payload_size >= fopt_len) { + max_possible_payload_size = current_payload_size - fopt_len; } else { - tx_info->max_possible_payload_size = tx_info->current_payload_size; + max_possible_payload_size = current_payload_size; // The fOpts don't fit into the maximum payload. Omit the MAC commands to // ensure that another uplink is possible. fopt_len = 0; @@ -1728,9 +1820,9 @@ lorawan_status_t LoRaMac::query_tx_possible(uint8_t size, // Verify if the fOpts and the payload fit into the maximum payload if (validate_payload_length(size, _params.sys_params.channel_data_rate, fopt_len) == false) { - return LORAWAN_STATUS_LENGTH_ERROR; + return max_possible_payload_size; } - return LORAWAN_STATUS_OK; + return current_payload_size; } lorawan_status_t LoRaMac::add_channel_plan(const lorawan_channelplan_t& plan) @@ -1876,7 +1968,7 @@ lorawan_status_t LoRaMac::mlme_request( loramac_mlme_req_t *mlmeRequest ) _params.keys.app_key = mlmeRequest->req.join.app_key; _params.max_join_request_trials = mlmeRequest->req.join.nb_trials; - if (!lora_phy->verify_nb_join_trials(mlmeRequest->req.join.nb_trials)) { + if (!_lora_phy.verify_nb_join_trials(mlmeRequest->req.join.nb_trials)) { // Value not supported, get default _params.max_join_request_trials = MBED_CONF_LORA_NB_TRIALS; } @@ -1886,7 +1978,7 @@ lorawan_status_t LoRaMac::mlme_request( loramac_mlme_req_t *mlmeRequest ) reset_mac_parameters(); _params.sys_params.channel_data_rate = - lora_phy->get_alternate_DR(_params.join_request_trial_counter + 1); + _lora_phy.get_alternate_DR(_params.join_request_trial_counter + 1); loramac_mhdr_t machdr; machdr.value = 0; @@ -1929,7 +2021,7 @@ lorawan_status_t LoRaMac::mcps_request( loramac_mcps_req_t *mcpsRequest ) // TODO: The comment is different than the code??? // Apply the minimum possible datarate. // Some regions have limitations for the minimum datarate. - datarate = MAX(datarate, (int8_t)lora_phy->get_minimum_tx_datarate()); + datarate = MAX(datarate, (int8_t)_lora_phy.get_minimum_tx_datarate()); machdr.value = 0; @@ -1963,7 +2055,7 @@ lorawan_status_t LoRaMac::mcps_request( loramac_mcps_req_t *mcpsRequest ) // } if (_params.sys_params.adr_on == false) { - if (lora_phy->verify_tx_datarate(datarate, false) == true) { + if (_lora_phy.verify_tx_datarate(datarate, false) == true) { _params.sys_params.channel_data_rate = datarate; } else { return LORAWAN_STATUS_PARAMETER_INVALID; @@ -1997,7 +2089,7 @@ lorawan_status_t LoRaMac::mib_set_request_confirm( loramac_mib_req_confirm_t *mi return status; } -radio_events_t *LoRaMac::get_phy_event_handlers() +void LoRaMac::bind_radio_driver(LoRaRadio& radio) { radio_events.tx_done = mbed::callback(this, &LoRaMac::handle_tx_done); radio_events.rx_done = mbed::callback(this, &LoRaMac::handle_rx_done); @@ -2005,7 +2097,10 @@ radio_events_t *LoRaMac::get_phy_event_handlers() radio_events.tx_timeout = mbed::callback(this, &LoRaMac::handle_tx_timeout); radio_events.rx_timeout = mbed::callback(this, &LoRaMac::handle_rx_timeout); - return &radio_events; + _lora_phy.set_radio_instance(radio); + radio.lock(); + radio.init_radio(&radio_events); + radio.unlock(); } #if defined(LORAWAN_COMPLIANCE_TEST) @@ -2038,7 +2133,7 @@ void LoRaMac::LoRaMacTestSetMic( uint16_t txPacketCounter ) 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; } diff --git a/features/lorawan/lorastack/mac/LoRaMac.h b/features/lorawan/lorastack/mac/LoRaMac.h index 03b41dd0a72..7dc2488aaea 100644 --- a/features/lorawan/lorastack/mac/LoRaMac.h +++ b/features/lorawan/lorastack/mac/LoRaMac.h @@ -49,6 +49,7 @@ #include "lorastack/mac/LoRaMacMcps.h" #include "lorastack/mac/LoRaMacMib.h" #include "lorastack/mac/LoRaMacChannelPlan.h" +#include "loraphy_target.h" class LoRaMac { @@ -57,7 +58,7 @@ class LoRaMac { /** * Constructor */ - LoRaMac(LoRaWANTimeHandler &lora_time); + LoRaMac(); /** * Destructor @@ -75,15 +76,13 @@ class LoRaMac { * @param primitives [in] A pointer to the structure defining the LoRaMAC * event functions. Refer to \ref loramac_primitives_t. * - * @param phy [in] A pointer to the selected PHY layer. - * * @param queue [in] A pointer to the application provided EventQueue. * * @return `lorawan_status_t` The status of the operation. The possible values are: * \ref LORAWAN_STATUS_OK * \ref LORAWAN_STATUS_PARAMETER_INVALID */ - lorawan_status_t initialize(loramac_primitives_t *primitives, LoRaPHY *phy, + lorawan_status_t initialize(loramac_primitives_t *primitives, events::EventQueue *queue); /** @@ -97,26 +96,16 @@ class LoRaMac { /** * @brief Queries the LoRaMAC whether it is possible to send the next frame with * a given payload size. The LoRaMAC takes the scheduled MAC commands into - * account and reports when the frame can be sent. + * account and returns corresponding value. * * @param size [in] The size of the applicable payload to be sent next. - * @param tx_info [out] The structure \ref loramac_tx_info_t contains - * information on the actual maximum payload possible - * (according to the configured datarate or the next - * datarate according to ADR), and the maximum frame - * size, taking the scheduled MAC commands into account. - * - * @return `lorawan_status_t` The status of the operation. When the parameters are - * not valid, the function returns \ref LORAWAN_STATUS_PARAMETER_INVALID. - * In case of a length error caused by the applicable payload in combination - * with the MAC commands, the function returns \ref LORAWAN_STATUS_LENGTH_ERROR. + * + * @return Size of the biggest packet that can be sent. * Please note that if the size of the MAC commands in the queue do * not fit into the payload size on the related datarate, the LoRaMAC will * omit the MAC commands. - * If the query is valid, and the LoRaMAC is able to send the frame, - * the function returns \ref LORAWAN_STATUS_OK. */ - lorawan_status_t query_tx_possible(uint8_t size, loramac_tx_info_t* tx_info); + uint8_t query_tx_possible(uint8_t size); /** * @brief Adds a channel plan to the system. @@ -358,13 +347,18 @@ class LoRaMac { */ lorawan_status_t mcps_request(loramac_mcps_req_t *request); - /** - * @brief LoRaMAC layer provides its callback functions for - * PHY layer. + /** Binds radio driver to PHY layer. + * + * MAC layer is totally detached from the PHY layer so the stack layer + * needs to play the role of an arbitrator. This API gets a radio driver + * object from the application (via LoRaWANInterface), binds it to the PHY + * layer and initialises radio callback handles which the radio driver will + * use in order to report events. + * + * @param radio LoRaRadio object, i.e., the radio driver * - * @return Pointer to callback functions for radio events */ - radio_events_t *get_phy_event_handlers(); + void bind_radio_driver(LoRaRadio& radio); /** * @brief Configures the events to trigger an MLME-Indication with @@ -427,7 +421,49 @@ class LoRaMac { */ void open_continuous_rx2_window(void); + /** + * @brief get_default_tx_datarate Gets the default TX datarate + * @return default TX datarate. + */ + uint8_t get_default_tx_datarate(); + + /** + * @brief tx_ongoing Check whether a prepare is done or not. + * @return True if prepare_ongoing_tx is called, false otherwise. + */ + bool tx_ongoing(); + + /** + * @brief set_tx_ongoing Changes the ongoing status for prepared message. + * @param ongoing The value indicating the status. + */ + void set_tx_ongoing(bool ongoing); + + /** + * @brief reset_ongoing_tx Resets _ongoing_tx_msg. + * @param reset_pending If true resets pending size also. + */ + void reset_ongoing_tx(bool reset_pending = false); + + /** + * @brief prepare_ongoing_tx This will prepare (and override) ongoing_tx_msg. + * @param port The application port number. + * @param data A pointer to the data being sent. The ownership of the + * buffer is not transferred. + * @param length The size of data in bytes. + * @param flags A flag used to determine what type of + * message is being sent. + * @param num_retries Number of retries for a confirmed type message + * @return The number of bytes prepared for sending. + */ + int16_t prepare_ongoing_tx(uint8_t port, const uint8_t* data, + uint16_t length, uint8_t flags, uint8_t num_retries); + /** + * @brief send_ongoing_tx Sends the ongoing_tx_msg + * @return LORAWAN_STATUS_OK or a negative error code on failure. + */ + lorawan_status_t send_ongoing_tx(); private: /** @@ -552,10 +588,15 @@ class LoRaMac { void handle_fhss_change_channel(uint8_t cur_channel); private: + /** + * Timer subsystem handle + */ + LoRaWANTimeHandler _lora_time; + /** * LoRa PHY layer object storage */ - LoRaPHY *lora_phy; + LoRaPHY_region _lora_phy; /** * MAC command handle @@ -582,11 +623,6 @@ class LoRaMac { */ LoRaMacChannelPlan channel_plan; - /** - * Timer subsystem handle - */ - LoRaWANTimeHandler &_lora_time; - /** * Central MAC layer data storage */ @@ -607,6 +643,8 @@ class LoRaMac { */ events::EventQueue *ev_queue; + loramac_tx_message_t _ongoing_tx_msg; + #if defined(LORAWAN_COMPLIANCE_TEST) public: // Test interface diff --git a/features/lorawan/system/lorawan_data_structures.h b/features/lorawan/system/lorawan_data_structures.h index 33e37795c63..ec167be9de5 100644 --- a/features/lorawan/system/lorawan_data_structures.h +++ b/features/lorawan/system/lorawan_data_structures.h @@ -1550,20 +1550,6 @@ typedef struct { mib_params_t param; }loramac_mib_req_confirm_t; -/*! - * LoRaMAC TX information - */ -typedef struct { - /*! - * Defines the size of the applicable payload that can be processed. - */ - uint8_t max_possible_payload_size; - /*! - * The current payload size, dependent on the current datarate. - */ - uint8_t current_payload_size; -} loramac_tx_info_t; - /** LoRaMAC status. * */ From 6b54478af4c615020c5a8defbac8a55fb2473790 Mon Sep 17 00:00:00 2001 From: Antti Kauppila Date: Fri, 16 Mar 2018 13:12:50 +0200 Subject: [PATCH 20/25] LoRaWANStack is made independent of MAC sublayers - Only internal changes, no API has been broke. - Tested by manually running Green tea tests --- features/lorawan/LoRaWANStack.cpp | 410 ++++-------- features/lorawan/LoRaWANStack.h | 24 +- features/lorawan/lorastack/mac/LoRaMac.cpp | 319 +++++---- features/lorawan/lorastack/mac/LoRaMac.h | 288 ++++---- .../lorastack/mac/LoRaMacChannelPlan.cpp | 18 +- .../lorastack/mac/LoRaMacChannelPlan.h | 5 +- features/lorawan/lorastack/mac/LoRaMacMib.cpp | 434 ------------ features/lorawan/lorastack/mac/LoRaMacMib.h | 100 --- .../lorawan/system/lorawan_data_structures.h | 625 ++---------------- 9 files changed, 516 insertions(+), 1707 deletions(-) delete mode 100644 features/lorawan/lorastack/mac/LoRaMacMib.cpp delete mode 100644 features/lorawan/lorastack/mac/LoRaMacMib.h diff --git a/features/lorawan/LoRaWANStack.cpp b/features/lorawan/LoRaWANStack.cpp index 55e3d7a3025..79ed87485bb 100644 --- a/features/lorawan/LoRaWANStack.cpp +++ b/features/lorawan/LoRaWANStack.cpp @@ -45,10 +45,6 @@ using namespace mbed; using namespace events; #if defined(LORAWAN_COMPLIANCE_TEST) - /** - * - * User application data buffer size if compliance test is used - */ #if (MBED_CONF_LORA_PHY == 0 || MBED_CONF_LORA_PHY == 4 || MBED_CONF_LORA_PHY == 6 || MBED_CONF_LORA_PHY == 7) #define LORAWAN_COMPLIANCE_TEST_DATA_SIZE 16 #elif (MBED_CONF_LORA_PHY == 1 || MBED_CONF_LORA_PHY == 2 || MBED_CONF_LORA_PHY == 8 || MBED_CONF_LORA_PHY == 9) @@ -134,39 +130,33 @@ lorawan_status_t LoRaWANStack::connect() lorawan_connect_t connection_params; - if (MBED_CONF_LORA_OVER_THE_AIR_ACTIVATION) { - static uint8_t dev_eui[] = MBED_CONF_LORA_DEVICE_EUI; - static uint8_t app_eui[] = MBED_CONF_LORA_APPLICATION_EUI; - static uint8_t app_key[] = MBED_CONF_LORA_APPLICATION_KEY; - /** - * - * OTAA join - */ - connection_params.connect_type = LORAWAN_CONNECTION_OTAA; - connection_params.connection_u.otaa.app_eui = app_eui; - connection_params.connection_u.otaa.dev_eui = dev_eui; - connection_params.connection_u.otaa.app_key = app_key; - connection_params.connection_u.otaa.nb_trials = MBED_CONF_LORA_NB_TRIALS; - - return join_request_by_otaa(connection_params); - } else { - static uint8_t nwk_skey[] = MBED_CONF_LORA_NWKSKEY; - static uint8_t app_skey[] = MBED_CONF_LORA_APPSKEY; - static uint32_t dev_addr = MBED_CONF_LORA_DEVICE_ADDRESS; - static uint32_t nwk_id = (MBED_CONF_LORA_DEVICE_ADDRESS & LORAWAN_NETWORK_ID_MASK); - - /** - * - * ABP connection - */ - connection_params.connect_type = LORAWAN_CONNECTION_ABP; - connection_params.connection_u.abp.nwk_id = nwk_id; - connection_params.connection_u.abp.dev_addr = dev_addr; - connection_params.connection_u.abp.nwk_skey = nwk_skey; - connection_params.connection_u.abp.app_skey = app_skey; - - return activation_by_personalization(connection_params); - } + //TODO: LoRaWANStack don't need to know these values, move to LoRaMac (or below) +#if (1 == MBED_CONF_LORA_OVER_THE_AIR_ACTIVATION) + static uint8_t dev_eui[] = MBED_CONF_LORA_DEVICE_EUI; + static uint8_t app_eui[] = MBED_CONF_LORA_APPLICATION_EUI; + static uint8_t app_key[] = MBED_CONF_LORA_APPLICATION_KEY; + + connection_params.connect_type = LORAWAN_CONNECTION_OTAA; + connection_params.connection_u.otaa.app_eui = app_eui; + connection_params.connection_u.otaa.dev_eui = dev_eui; + connection_params.connection_u.otaa.app_key = app_key; + connection_params.connection_u.otaa.nb_trials = MBED_CONF_LORA_NB_TRIALS; + + return join_request_by_otaa(connection_params); +#else + static uint8_t nwk_skey[] = MBED_CONF_LORA_NWKSKEY; + static uint8_t app_skey[] = MBED_CONF_LORA_APPSKEY; + static uint32_t dev_addr = MBED_CONF_LORA_DEVICE_ADDRESS; + 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 = nwk_id; + connection_params.connection_u.abp.dev_addr = dev_addr; + connection_params.connection_u.abp.nwk_skey = nwk_skey; + connection_params.connection_u.abp.app_skey = app_skey; + + return activation_by_personalization(connection_params); +#endif } lorawan_status_t LoRaWANStack::connect(const lorawan_connect_t &connect) @@ -315,14 +305,7 @@ lorawan_status_t LoRaWANStack::enable_adaptive_datarate(bool adr_enabled) return LORAWAN_STATUS_NOT_INITIALIZED; } - //return _loramac.enable_adaptive_datarate(adr_enabled); - - loramac_mib_req_confirm_t adr_mib_params; - - adr_mib_params.type = MIB_ADR; - adr_mib_params.param.is_adr_enable = adr_enabled; - - return mib_set_request(&adr_mib_params); + return _loramac.enable_adaptive_datarate(adr_enabled); } lorawan_status_t LoRaWANStack::set_channel_data_rate(uint8_t data_rate) @@ -333,23 +316,9 @@ lorawan_status_t LoRaWANStack::set_channel_data_rate(uint8_t data_rate) return LORAWAN_STATUS_NOT_INITIALIZED; } - loramac_mib_req_confirm_t mib_params; - mib_params.type = MIB_ADR; - if (mib_get_request(&mib_params) != LORAWAN_STATUS_OK) { - tr_error("Cannot set data rate. Please turn off ADR first."); - return LORAWAN_STATUS_PARAMETER_INVALID; - } - - mib_params.type = MIB_CHANNELS_DATARATE; - mib_params.param.channel_data_rate = data_rate; - - return mib_set_request(&mib_params); + return _loramac.set_channel_data_rate(data_rate); } -/** - * - * Join OTAA - */ lorawan_status_t LoRaWANStack::join_request_by_otaa(const lorawan_connect_t ¶ms) { if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) @@ -375,10 +344,6 @@ lorawan_status_t LoRaWANStack::join_request_by_otaa(const lorawan_connect_t &par return lora_state_machine(DEVICE_STATE_JOINING); } -/** - * - * Connect ABP - */ lorawan_status_t LoRaWANStack::activation_by_personalization(const lorawan_connect_t ¶ms) { if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { @@ -435,16 +400,10 @@ int16_t LoRaWANStack::handle_tx(uint8_t port, const uint8_t* data, } #endif - //TODO: Stack MUST know joining status!!!! - loramac_mib_req_confirm_t mib_req; lorawan_status_t status; - mib_req.type = MIB_NETWORK_JOINED; - status = mib_get_request(&mib_req); - if (status == LORAWAN_STATUS_OK) { - if (mib_req.param.is_nwk_joined == false) { - return LORAWAN_STATUS_NO_NETWORK_JOINED; - } + if (_loramac.nwk_joined() == false) { + return LORAWAN_STATUS_NO_NETWORK_JOINED; } status = set_application_port(port); @@ -454,8 +413,8 @@ int16_t LoRaWANStack::handle_tx(uint8_t port, const uint8_t* data, return status; } - if (flags == 0 - || (flags & MSG_FLAG_MASK) == (MSG_CONFIRMED_FLAG|MSG_UNCONFIRMED_FLAG)) { + if (flags == 0 || + (flags & MSG_FLAG_MASK) == (MSG_CONFIRMED_FLAG|MSG_UNCONFIRMED_FLAG)) { tr_error("CONFIRMED and UNCONFIRMED are mutually exclusive for send()"); return LORAWAN_STATUS_PARAMETER_INVALID; } @@ -552,19 +511,8 @@ int16_t LoRaWANStack::handle_rx(const uint8_t port, uint8_t* data, return base_size; } -/** MLME-Confirm event function - * - * \param mlme_confirm Pointer to the confirm structure, - * containing confirm attributes. - */ void LoRaWANStack::mlme_confirm_handler(loramac_mlme_confirm_t *mlme_confirm) { - if (NULL == mlme_confirm) { - tr_error("mlme_confirm: struct [in] is null!"); - MBED_ASSERT(0); - return; - } - switch (mlme_confirm->req_type) { case MLME_JOIN: if (mlme_confirm->status == LORAMAC_EVENT_INFO_STATUS_OK) { @@ -613,37 +561,13 @@ void LoRaWANStack::mlme_confirm_handler(loramac_mlme_confirm_t *mlme_confirm) } } -lorawan_status_t LoRaWANStack::mcps_request_handler(loramac_mcps_req_t *mcps_request) -{ - if (mcps_request == NULL) { - return LORAWAN_STATUS_PARAMETER_INVALID; - } - - return _loramac.mcps_request(mcps_request); -} - -/** MCPS-Confirm event function - * - * \param mcps_confirm Pointer to the confirm structure, - * containing confirm attributes. - */ void LoRaWANStack::mcps_confirm_handler(loramac_mcps_confirm_t *mcps_confirm) { - if (mcps_confirm == NULL) { - tr_error("mcps_confirm: struct [in] is null!"); - MBED_ASSERT(0); - return; - } - if (mcps_confirm->status != LORAMAC_EVENT_INFO_STATUS_OK) { - // Couldn't schedule packet, ack not recieved in CONFIRMED case - // or some other error happened. Discard buffer, unset the tx-ongoing - // flag and let the application know _loramac.reset_ongoing_tx(); tr_error("mcps_confirm_handler: Error code = %d", mcps_confirm->status); - // If sending timed out, we have a special event for that if (mcps_confirm->status == LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT) { if (_callbacks.events) { const int ret = _queue->call(_callbacks.events, TX_TIMEOUT); @@ -651,11 +575,10 @@ void LoRaWANStack::mcps_confirm_handler(loramac_mcps_confirm_t *mcps_confirm) (void)ret; } return; - } if (mcps_confirm->status == LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT) { + } else if (mcps_confirm->status == LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT) { tr_debug("Did not receive Ack"); } - // Otherwise send a general TX_ERROR event if (_callbacks.events) { const int ret = _queue->call(_callbacks.events, TX_ERROR); MBED_ASSERT(ret != 0); @@ -664,20 +587,11 @@ void LoRaWANStack::mcps_confirm_handler(loramac_mcps_confirm_t *mcps_confirm) return; } - // If No errors encountered, let's proceed with the status. - // CONFIRMED needs special handling because of acks - if (mcps_confirm->req_type == MCPS_CONFIRMED) { - // In confirmed case, we need to check if we have received the Ack or not. - // This is actually just being paranoid about ack because LoRaMac.cpp doesn't - // call this callback until an ack is received. - if (mcps_confirm->ack_received) { + if (mcps_confirm->req_type == MCPS_CONFIRMED && + mcps_confirm->ack_received) { tr_debug("Ack received."); - } } - // This part is common to both CONFIRMED and UNCONFIRMED. - // Tell the application about successful transmission and store - // data rate plus frame counter. _lw_session.uplink_counter = mcps_confirm->ul_frame_counter; _loramac.set_tx_ongoing(false); if (_callbacks.events) { @@ -687,18 +601,8 @@ void LoRaWANStack::mcps_confirm_handler(loramac_mcps_confirm_t *mcps_confirm) } } -/** MCPS-Indication event function - * - * \param mcps_indication Pointer to the indication structure, - * containing indication attributes. - */ void LoRaWANStack::mcps_indication_handler(loramac_mcps_indication_t *mcps_indication) { - if (mcps_indication == NULL) { - tr_error("mcps_indication: struct [in] is null."); - return; - } - if (mcps_indication->status != LORAMAC_EVENT_INFO_STATUS_OK) { if (_callbacks.events) { const int ret = _queue->call(_callbacks.events, RX_ERROR); @@ -721,6 +625,7 @@ void LoRaWANStack::mcps_indication_handler(loramac_mcps_indication_t *mcps_indic break; } + //TODO: // Check Multicast // Check Port // Check Datarate @@ -741,80 +646,63 @@ void LoRaWANStack::mcps_indication_handler(loramac_mcps_indication_t *mcps_indic if (mcps_indication->is_data_recvd == true) { switch (mcps_indication->port) { - case 224: + 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_debug("Compliance test disabled."); + tr_info("Compliance test disabled."); #endif - 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; - - // no copy, just set the pointer for the user - _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; - - if (_callbacks.events) { - const int ret = _queue->call(_callbacks.events, RX_DONE); - MBED_ASSERT(ret != 0); - (void)ret; - } + 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; + + // 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; + } - loramac_mib_req_confirm_t mib_req; - mib_req.type = MIB_DEVICE_CLASS; - mib_get_request(&mib_req); + //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 (mcps_indication->fpending_status && mib_req.param.dev_class != CLASS_C) { - handle_tx(mcps_indication->port, NULL, 0, MSG_CONFIRMED_FLAG, true); - } + // 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 (mib_req.param.dev_class == CLASS_C && mcps_indication->type == MCPS_CONFIRMED) { - 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. } - } else { - // Invalid port, ports 0, 224 and 225-255 are reserved. + break; } - break; } } } -lorawan_status_t LoRaWANStack::mib_set_request(loramac_mib_req_confirm_t *mib_set_params) -{ - if (NULL == mib_set_params) { - return LORAWAN_STATUS_PARAMETER_INVALID; - } - return _loramac.mib_set_request_confirm(mib_set_params); -} - -lorawan_status_t LoRaWANStack::mib_get_request(loramac_mib_req_confirm_t *mib_get_params) -{ - if(NULL == mib_get_params) { - return LORAWAN_STATUS_PARAMETER_INVALID; - } - return _loramac.mib_get_request_confirm(mib_get_params); -} - lorawan_status_t LoRaWANStack::set_link_check_request() { _link_check_requested = true; @@ -823,9 +711,8 @@ lorawan_status_t LoRaWANStack::set_link_check_request() return LORAWAN_STATUS_PARAMETER_INVALID; } - loramac_mlme_req_t mlme_req; - mlme_req.type = MLME_LINK_CHECK; - return _loramac.mlme_request(&mlme_req); + _loramac.setup_link_check_request(); + return LORAWAN_STATUS_OK; } void LoRaWANStack::remove_link_check_request() @@ -838,17 +725,17 @@ lorawan_status_t LoRaWANStack::shutdown() return lora_state_machine(DEVICE_STATE_SHUTDOWN); } -lorawan_status_t LoRaWANStack::set_device_class(const device_class_t device_class) +lorawan_status_t LoRaWANStack::set_device_class(const device_class_t& device_class) { - loramac_mib_req_confirm_t mib_req; - mib_req.type = MIB_DEVICE_CLASS; - mib_req.param.dev_class = device_class; - return mib_set_request(&mib_req); + if (device_class == CLASS_B) { + return LORAWAN_STATUS_UNSUPPORTED; + } + _loramac.set_device_class(device_class); + return LORAWAN_STATUS_OK; } lorawan_status_t LoRaWANStack::lora_state_machine(device_states_t new_state) { - loramac_mib_req_confirm_t mib_req; lorawan_status_t status = LORAWAN_STATUS_DEVICE_OFF; _device_current_state = new_state; @@ -860,19 +747,13 @@ lorawan_status_t LoRaWANStack::lora_state_machine(device_states_t new_state) * Radio will be put to sleep by the APIs underneath */ drop_channel_list(); - - // Shutdown LoRaMac _loramac.disconnect(); - // Stop sending messages and set joined status to false. #if defined(LORAWAN_COMPLIANCE_TEST) _loramac.LoRaMacStopTxTimer(); #endif - mib_req.type = MIB_NETWORK_JOINED; - mib_req.param.is_nwk_joined = false; - mib_set_request(&mib_req); + _loramac.set_nwk_joined(false); - // reset buffers to original state _loramac.reset_ongoing_tx(true); _rx_msg.msg.mcps_indication.buffer = NULL; @@ -880,7 +761,6 @@ lorawan_status_t LoRaWANStack::lora_state_machine(device_states_t new_state) _rx_msg.prev_read_size = 0; _rx_msg.msg.mcps_indication.buffer_size = 0; - // disable the session _lw_session.active = false; tr_debug("LoRaWAN protocol has been shut down."); @@ -892,7 +772,6 @@ lorawan_status_t LoRaWANStack::lora_state_machine(device_states_t new_state) status = LORAWAN_STATUS_DEVICE_OFF; break; case DEVICE_STATE_NOT_INITIALIZED: - // Device is disconnected. status = LORAWAN_STATUS_DEVICE_OFF; break; case DEVICE_STATE_INIT: @@ -900,25 +779,13 @@ lorawan_status_t LoRaWANStack::lora_state_machine(device_states_t new_state) break; case DEVICE_STATE_JOINING: if (_lw_session.connection.connect_type == LORAWAN_CONNECTION_OTAA) { - /* - * OTAA join - */ tr_debug("Send Join-request.."); - loramac_mlme_req_t mlme_req; - mlme_req.type = MLME_JOIN; - - mlme_req.req.join.dev_eui = _lw_session.connection.connection_u.otaa.dev_eui; - mlme_req.req.join.app_eui = _lw_session.connection.connection_u.otaa.app_eui; - mlme_req.req.join.app_key = _lw_session.connection.connection_u.otaa.app_key; - mlme_req.req.join.nb_trials = _lw_session.connection.connection_u.otaa.nb_trials; - // Send join request to server. - status = _loramac.mlme_request(&mlme_req); + status = _loramac.join_by_otaa(_lw_session.connection.connection_u.otaa); if (status != LORAWAN_STATUS_OK) { return status; } - // Otherwise request was successful and OTAA connect is in - //progress + return LORAWAN_STATUS_CONNECT_IN_PROGRESS; } else { status = LORAWAN_STATUS_PARAMETER_INVALID; @@ -926,9 +793,9 @@ lorawan_status_t LoRaWANStack::lora_state_machine(device_states_t new_state) break; case DEVICE_STATE_JOINED: tr_debug("Join OK!"); - // Session is now active + _lw_session.active = true; - // Tell the application that we are connected + if (_callbacks.events) { const int ret = _queue->call(_callbacks.events, CONNECTED); MBED_ASSERT(ret != 0); @@ -937,34 +804,13 @@ lorawan_status_t LoRaWANStack::lora_state_machine(device_states_t new_state) status = LORAWAN_STATUS_OK; break; case DEVICE_STATE_ABP_CONNECTING: - /* - * ABP connection - */ - mib_req.type = MIB_NET_ID; - mib_req.param.net_id = _lw_session.connection.connection_u.abp.nwk_id; - mib_set_request(&mib_req); - - mib_req.type = MIB_DEV_ADDR; - mib_req.param.dev_addr = _lw_session.connection.connection_u.abp.dev_addr; - mib_set_request(&mib_req); - - mib_req.type = MIB_NWK_SKEY; - mib_req.param.nwk_skey = _lw_session.connection.connection_u.abp.nwk_skey; - mib_set_request(&mib_req); - mib_req.type = MIB_APP_SKEY; - mib_req.param.app_skey = _lw_session.connection.connection_u.abp.app_skey; - mib_set_request(&mib_req); + _loramac.join_by_abp(_lw_session.connection.connection_u.abp); - mib_req.type = MIB_NETWORK_JOINED; - mib_req.param.is_nwk_joined = true; - mib_set_request(&mib_req); tr_debug("ABP Connection OK!"); - // tell the application we are okay - // if users provide wrong keys, it's their responsibility - // there is no way to test ABP authentication success + status = LORAWAN_STATUS_OK; - // Session is now active + _lw_session.active = true; if (_callbacks.events) { const int ret = _queue->call(_callbacks.events, CONNECTED); @@ -973,7 +819,6 @@ lorawan_status_t LoRaWANStack::lora_state_machine(device_states_t new_state) } break; case DEVICE_STATE_SEND: - // If a transmission is ongoing, don't interrupt if (_loramac.tx_ongoing()) { status = LORAWAN_STATUS_OK; } else { @@ -1002,20 +847,17 @@ lorawan_status_t LoRaWANStack::lora_state_machine(device_states_t new_state) break; } } - // otherwise all done, put device in idle state + _device_current_state = DEVICE_STATE_IDLE; break; case DEVICE_STATE_IDLE: - //Do nothing status = LORAWAN_STATUS_IDLE; break; #if defined(LORAWAN_COMPLIANCE_TEST) case DEVICE_STATE_COMPLIANCE_TEST: - //Device is in compliance test mode tr_debug("Device is in compliance test mode."); - //5000ms - _loramac.LoRaMacSetTxTimer(5000); + _loramac.LoRaMacSetTxTimer(5000); //ms if (_compliance_test.running == true) { send_compliance_test_frame_to_mac(); } @@ -1104,11 +946,15 @@ lorawan_status_t LoRaWANStack::send_compliance_test_frame_to_mac() return mcps_request_handler(&mcps_req); } -/** Compliance testing function - * - * \param mcps_indication Pointer to the indication structure, - * containing indication attributes. - */ +lorawan_status_t LoRaWANStack::mcps_request_handler(loramac_mcps_req_t *mcps_request) +{ + if (mcps_request == NULL) { + return LORAWAN_STATUS_PARAMETER_INVALID; + } + + return _loramac.mcps_request(mcps_request); +} + void LoRaWANStack::compliance_test_handler(loramac_mcps_indication_t *mcps_indication) { if (_compliance_test.running == false) { @@ -1128,10 +974,7 @@ void LoRaWANStack::compliance_test_handler(loramac_mcps_indication_t *mcps_indic _compliance_test.running = true; _compliance_test.state = 1; - loramac_mib_req_confirm_t mib_req; - mib_req.type = MIB_ADR; - mib_req.param.is_adr_enable = true; - mib_set_request(&mib_req); + _loramac.enable_adaptive_datarate(true); #if MBED_CONF_LORA_PHY == 0 _loramac.LoRaMacTestSetDutyCycleOn(false); @@ -1154,10 +997,8 @@ void LoRaWANStack::compliance_test_handler(loramac_mcps_indication_t *mcps_indic _compliance_test.downlink_counter = 0; _compliance_test.running = false; - loramac_mib_req_confirm_t mib_req; - mib_req.type = MIB_ADR; - mib_req.param.is_adr_enable = MBED_CONF_LORA_ADR_ON; - mib_set_request(&mib_req); + _loramac.enable_adaptive_datarate(MBED_CONF_LORA_ADR_ON); + #if MBED_CONF_LORA_PHY == 0 _loramac.LoRaMacTestSetDutyCycleOn(MBED_CONF_LORA_DUTY_CYCLE_ON); #endif @@ -1191,13 +1032,10 @@ void LoRaWANStack::compliance_test_handler(loramac_mcps_indication_t *mcps_indic send_compliance_test_frame_to_mac(); break; case 5: // (viii) - loramac_mlme_req_t mlme_req; - mlme_req.type = MLME_LINK_CHECK; - _loramac.mlme_request(&mlme_req); + _loramac.setup_link_check_request(); break; case 6: // (ix) - loramac_mlme_req_t mlme_request; - loramac_mib_req_confirm_t mib_request; + loramac_mlme_req_t mlme_req; // Disable TestMode and revert back to normal operation _compliance_test.is_tx_confirmed = true; @@ -1206,32 +1044,26 @@ void LoRaWANStack::compliance_test_handler(loramac_mcps_indication_t *mcps_indic _compliance_test.downlink_counter = 0; _compliance_test.running = false; - mib_request.type = MIB_ADR; - mib_request.param.is_adr_enable = MBED_CONF_LORA_ADR_ON; - mib_set_request(&mib_request); + _loramac.enable_adaptive_datarate(MBED_CONF_LORA_ADR_ON); + #if MBED_CONF_LORA_PHY == 0 _loramac.LoRaMacTestSetDutyCycleOn(MBED_CONF_LORA_DUTY_CYCLE_ON); #endif - mlme_request.type = MLME_JOIN; - mlme_request.req.join.dev_eui = _lw_session.connection.connection_u.otaa.dev_eui; - mlme_request.req.join.app_eui = _lw_session.connection.connection_u.otaa.app_eui; - mlme_request.req.join.app_key = _lw_session.connection.connection_u.otaa.app_key; - mlme_request.req.join.nb_trials = _lw_session.connection.connection_u.otaa.nb_trials; - _loramac.mlme_request(&mlme_request); + _loramac.join_by_otaa(_lw_session.connection.connection_u.otaa); break; case 7: // (x) if (mcps_indication->buffer_size == 3) { loramac_mlme_req_t mlme_req; mlme_req.type = MLME_TXCW; - mlme_req.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) | mcps_indication->buffer[2]); _loramac.mlme_request(&mlme_req); } else if (mcps_indication->buffer_size == 7) { loramac_mlme_req_t mlme_req; mlme_req.type = MLME_TXCW_1; - mlme_req.req.cw_tx_mode.timeout = (uint16_t)((mcps_indication->buffer[1] << 8) | mcps_indication->buffer[2]); - mlme_req.req.cw_tx_mode.frequency = (uint32_t)((mcps_indication->buffer[3] << 16) | (mcps_indication->buffer[4] << 8) + mlme_req.cw_tx_mode.timeout = (uint16_t)((mcps_indication->buffer[1] << 8) | mcps_indication->buffer[2]); + 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.req.cw_tx_mode.power = mcps_indication->buffer[6]; + mlme_req.cw_tx_mode.power = mcps_indication->buffer[6]; _loramac.mlme_request(&mlme_req); } _compliance_test.state = 1; diff --git a/features/lorawan/LoRaWANStack.h b/features/lorawan/LoRaWANStack.h index 618a27c8930..31c8de2efc4 100644 --- a/features/lorawan/LoRaWANStack.h +++ b/features/lorawan/LoRaWANStack.h @@ -371,7 +371,7 @@ class LoRaWANStack: private mbed::NonCopyable { * LORAWAN_STATUS_UNSUPPORTED is requested class is not supported, * or other negative error code if request failed. */ - lorawan_status_t set_device_class(const device_class_t device_class); + lorawan_status_t set_device_class(const device_class_t& device_class); private: LoRaWANStack(); @@ -401,13 +401,6 @@ class LoRaWANStack: private mbed::NonCopyable { */ void mlme_confirm_handler(loramac_mlme_confirm_t *mlme_confirm); - /** - * Handles an MCPS request while attempting to hand over a packet from - * upper layers to Mac layer. For example in response to send_frame_to_mac(), - * an MCPS request is generated. - */ - lorawan_status_t mcps_request_handler(loramac_mcps_req_t *mcps_request); - /** * Handles an MCPS confirmation coming from the Mac layer in response to an * MCPS request. We take appropriate actions in response to the confirmation, @@ -424,16 +417,6 @@ class LoRaWANStack: private mbed::NonCopyable { */ void mcps_indication_handler(loramac_mcps_indication_t *mcps_indication); - /** - * Sets a MIB request, i.e., update a particular parameter etc. - */ - lorawan_status_t mib_set_request(loramac_mib_req_confirm_t *mib_set_params); - - /** - * Requests the MIB to inquire about a particular parameter. - */ - lorawan_status_t mib_get_request(loramac_mib_req_confirm_t *mib_get_params); - /** * Sets up user application port */ @@ -488,6 +471,11 @@ class LoRaWANStack: private mbed::NonCopyable { */ void compliance_test_handler(loramac_mcps_indication_t *mcps_indication); + /** + * Used only for compliance testing + */ + lorawan_status_t mcps_request_handler(loramac_mcps_req_t *mcps_request); + /** * Used only for compliance testing */ diff --git a/features/lorawan/lorastack/mac/LoRaMac.cpp b/features/lorawan/lorastack/mac/LoRaMac.cpp index 96a3ee991ef..02fa0e3b35d 100644 --- a/features/lorawan/lorastack/mac/LoRaMac.cpp +++ b/features/lorawan/lorastack/mac/LoRaMac.cpp @@ -78,7 +78,7 @@ using namespace events; LoRaMac::LoRaMac() - : _lora_phy(_lora_time), mac_commands() + : _lora_phy(_lora_time), mac_commands(), _is_nwk_joined(false) { //radio_events_t RadioEvents; _params.keys.dev_eui = NULL; @@ -98,7 +98,6 @@ LoRaMac::LoRaMac() _params.dl_frame_counter = 0; _params.is_ul_frame_counter_fixed = false; _params.is_rx_window_enabled = true; - _params.is_nwk_joined = false; _params.adr_ack_counter = 0; _params.is_node_ack_requested = false; _params.is_srv_ack_requested = false; @@ -187,7 +186,7 @@ void LoRaMac::on_radio_tx_done( void ) lorawan_time_t cur_time = _lora_time.get_current_time( ); loramac_mlme_confirm_t mlme_confirm = mlme.get_confirmation(); - if (_params.dev_class != CLASS_C) { + if (_device_class != CLASS_C) { _lora_phy.put_radio_to_sleep(); } else { open_continuous_rx2_window(); @@ -197,11 +196,11 @@ void LoRaMac::on_radio_tx_done( void ) if(_params.is_rx_window_enabled == true) { _lora_time.start(_params.timers.rx_window1_timer, _params.rx_window1_delay); - if (_params.dev_class != CLASS_C) { + if (_device_class != CLASS_C) { _lora_time.start(_params.timers.rx_window2_timer, _params.rx_window2_delay); } - if ((_params.dev_class == CLASS_C ) || + if ((_device_class == CLASS_C ) || (_params.is_node_ack_requested == true)) { _lora_time.start(_params.timers.ack_timeout_timer, _params.rx_window2_delay + _lora_phy.get_ack_timeout()); @@ -230,7 +229,7 @@ void LoRaMac::on_radio_tx_done( void ) // Update last tx done time for the current channel tx_done_params.channel = _params.channel; - tx_done_params.joined = _params.is_nwk_joined; + tx_done_params.joined = _is_nwk_joined; tx_done_params.last_tx_done_time = cur_time; _lora_phy.set_last_tx_done(&tx_done_params); @@ -301,7 +300,7 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, mcps.get_indication().dl_frame_counter = 0; mcps.get_indication().type = MCPS_UNCONFIRMED; - if (_params.dev_class != CLASS_C) { + if (_device_class != CLASS_C) { _lora_phy.put_radio_to_sleep(); } @@ -312,7 +311,7 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, switch (mac_hdr.bits.mtype) { case FRAME_TYPE_JOIN_ACCEPT: - if (_params.is_nwk_joined == true) { + if (_is_nwk_joined) { mcps.get_indication().status = LORAMAC_EVENT_INFO_STATUS_ERROR; prepare_rx_done_abort(); return; @@ -380,7 +379,7 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, _lora_phy.apply_cf_list(&cflist); mlme.get_confirmation().status = LORAMAC_EVENT_INFO_STATUS_OK; - _params.is_nwk_joined = true; + _is_nwk_joined = true; } else { mlme.get_confirmation().status = LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL; } @@ -660,7 +659,7 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, } // Verify if we need to disable the AckTimeoutTimer - check_to_disable_ack_timeout(_params.is_node_ack_requested, _params.dev_class, mcps.get_confirmation().ack_received, + check_to_disable_ack_timeout(_params.is_node_ack_requested, _device_class, mcps.get_confirmation().ack_received, _params.ack_timeout_retry_counter, _params.max_ack_timeout_retries ); if(_params.timers.ack_timeout_timer.timer_id == 0) { @@ -672,7 +671,7 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, void LoRaMac::on_radio_tx_timeout( void ) { - if (_params.dev_class != CLASS_C) { + if (_device_class != CLASS_C) { _lora_phy.put_radio_to_sleep(); } else { open_continuous_rx2_window(); @@ -687,7 +686,7 @@ void LoRaMac::on_radio_tx_timeout( void ) void LoRaMac::on_radio_rx_error( void ) { - if (_params.dev_class != CLASS_C) { + if (_device_class != CLASS_C) { _lora_phy.put_radio_to_sleep(); } @@ -698,7 +697,7 @@ void LoRaMac::on_radio_rx_error( void ) mlme.get_confirmation().status = LORAMAC_EVENT_INFO_STATUS_RX1_ERROR; - if (_params.dev_class != CLASS_C) { + if (_device_class != CLASS_C) { if (_lora_time.get_elapsed_time(_params.timers.aggregated_last_tx_time) >= _params.rx_window2_delay) { _lora_time.stop(_params.timers.rx_window2_timer); _params.flags.bits.mac_done = 1; @@ -711,19 +710,19 @@ void LoRaMac::on_radio_rx_error( void ) mlme.get_confirmation().status = LORAMAC_EVENT_INFO_STATUS_RX2_ERROR; - if (_params.dev_class != CLASS_C) { + if (_device_class != CLASS_C) { _params.flags.bits.mac_done = 1; } } - if (_params.dev_class == CLASS_C) { + if (_device_class == CLASS_C) { open_continuous_rx2_window(); } } void LoRaMac::on_radio_rx_timeout(void) { - if (_params.dev_class != CLASS_C) { + if (_device_class != CLASS_C) { _lora_phy.put_radio_to_sleep(); } @@ -733,7 +732,7 @@ void LoRaMac::on_radio_rx_timeout(void) } mlme.get_confirmation().status = LORAMAC_EVENT_INFO_STATUS_RX1_TIMEOUT; - if (_params.dev_class != CLASS_C) { + if (_device_class != CLASS_C) { if (_lora_time.get_elapsed_time(_params.timers.aggregated_last_tx_time ) >= _params.rx_window2_delay) { _lora_time.stop(_params.timers.rx_window2_timer); _params.flags.bits.mac_done = 1; @@ -746,12 +745,12 @@ void LoRaMac::on_radio_rx_timeout(void) mlme.get_confirmation().status = LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT; - if (_params.dev_class != CLASS_C) { + if (_device_class != CLASS_C) { _params.flags.bits.mac_done = 1; } } - if (_params.dev_class == CLASS_C) { + if (_device_class == CLASS_C) { open_continuous_rx2_window(); } } @@ -936,7 +935,7 @@ void LoRaMac::on_mac_state_check_timer_event(void) if (_params.flags.bits.mcps_ind == 1) { _params.flags.bits.mcps_ind = 0; - if (_params.dev_class == CLASS_C) { + if (_device_class == CLASS_C) { // Activate RX2 window for Class C open_continuous_rx2_window(); } @@ -1003,7 +1002,7 @@ void LoRaMac::on_rx_window1_timer_event(void) _params.rx_window1_config.is_rx_continuous = false; _params.rx_window1_config.rx_slot = _params.rx_slot; - if (_params.dev_class == CLASS_C) { + if (_device_class == CLASS_C) { _lora_phy.put_radio_to_standby(); } @@ -1024,7 +1023,7 @@ 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; - if (_params.dev_class != CLASS_C) { + if (_device_class != CLASS_C) { _params.rx_window2_config.is_rx_continuous = false; } else { // Setup continuous listening for class c @@ -1082,7 +1081,7 @@ void LoRaMac::on_ack_timeout_timer_event(void) _params.is_ack_retry_timeout_expired = true; _params.mac_state &= ~LORAMAC_ACK_REQ; } - if (_params.dev_class == CLASS_C) { + if (_device_class == CLASS_C) { _params.flags.bits.mac_done = 1; } } @@ -1172,7 +1171,7 @@ lorawan_status_t LoRaMac::schedule_tx(void) nextChan.current_datarate = _params.sys_params.channel_data_rate; _params.is_dutycycle_on = MBED_CONF_LORA_DUTY_CYCLE_ON; nextChan.dc_enabled = _params.is_dutycycle_on; - nextChan.joined = _params.is_nwk_joined; + nextChan.joined = _is_nwk_joined; nextChan.last_aggregate_tx_time = _params.timers.aggregated_last_tx_time; // Select channel @@ -1211,7 +1210,7 @@ lorawan_status_t LoRaMac::schedule_tx(void) _params.sys_params.max_sys_rx_error, &_params.rx_window2_config); - if (_params.is_nwk_joined == false) { + if (!_is_nwk_joined) { _params.rx_window1_delay = _params.sys_params.join_accept_delay1 + _params.rx_window1_config.window_offset; _params.rx_window2_delay = _params.sys_params.join_accept_delay2 @@ -1236,7 +1235,7 @@ void LoRaMac::calculate_backOff(uint8_t channel) { backoff_params_t backoff_params; - backoff_params.joined = _params.is_nwk_joined; + backoff_params.joined = _is_nwk_joined; _params.is_dutycycle_on = MBED_CONF_LORA_DUTY_CYCLE_ON; backoff_params.dc_enabled = _params.is_dutycycle_on; backoff_params.channel = channel; @@ -1255,7 +1254,7 @@ void LoRaMac::calculate_backOff(uint8_t channel) void LoRaMac::reset_mac_parameters(void) { - _params.is_nwk_joined = false; + _is_nwk_joined = false; // Counters _params.ul_frame_counter = 0; @@ -1308,6 +1307,29 @@ uint8_t LoRaMac::get_default_tx_datarate() return _lora_phy.get_default_tx_datarate(); } +lorawan_status_t LoRaMac::enable_adaptive_datarate(bool adr_enabled) +{ + _params.sys_params.adr_on = adr_enabled; + + return LORAWAN_STATUS_OK; +} + +lorawan_status_t LoRaMac::set_channel_data_rate(uint8_t data_rate) +{ + if (_params.sys_params.adr_on) { + tr_error("Cannot set data rate. Please turn off ADR first."); + return LORAWAN_STATUS_PARAMETER_INVALID; + } + + if (_lora_phy.verify_tx_datarate(data_rate, false) == true) { + _params.sys_params.channel_data_rate = data_rate; + } else { + return LORAWAN_STATUS_PARAMETER_INVALID; + } + + return LORAWAN_STATUS_OK; +} + bool LoRaMac::tx_ongoing() { return _ongoing_tx_msg.tx_ongoing; @@ -1390,18 +1412,13 @@ int16_t LoRaMac::prepare_ongoing_tx(uint8_t port, const uint8_t* data, lorawan_status_t LoRaMac::send_ongoing_tx() { lorawan_status_t status; - loramac_mib_req_confirm_t mib_get_params; if (_params.mac_state != LORAMAC_IDLE) { return LORAWAN_STATUS_BUSY; } - int8_t datarate = get_default_tx_datarate(); + int8_t datarate = _params.sys_params.channel_data_rate; - mib_get_params.type = MIB_CHANNELS_DATARATE; - if(mib_get_request_confirm(&mib_get_params) == LORAWAN_STATUS_OK) { - datarate = mib_get_params.param.channel_data_rate; - } // TODO: The comment is different than the code??? // Apply the minimum possible datarate. // Some regions have limitations for the minimum datarate. @@ -1447,6 +1464,103 @@ lorawan_status_t LoRaMac::send_ongoing_tx() return status; } +device_class_t LoRaMac::get_device_class() const +{ + return _device_class; +} + +void LoRaMac::set_device_class(const device_class_t& device_class) +{ + _device_class = device_class; + + if (CLASS_A == _device_class) { + // Set the radio into sleep to setup a defined state + _lora_phy.put_radio_to_sleep(); + } else if (CLASS_C == _device_class) { + // Set the is_node_ack_requested indicator to default + _params.is_node_ack_requested = false; + // Set the radio into sleep mode in case we are still in RX mode + _lora_phy.put_radio_to_sleep(); + // Compute Rx2 windows parameters in case the RX2 datarate has changed + _lora_phy.compute_rx_win_params( + _params.sys_params.rx2_channel.datarate, + _params.sys_params.min_rx_symb, + _params.sys_params.max_sys_rx_error, + &_params.rx_window2_config); + } + if (CLASS_C == _device_class) { + open_continuous_rx2_window(); + } +} + +void LoRaMac::setup_link_check_request() +{ + mlme.reset_confirmation(); + + mlme.get_confirmation().req_type = MLME_LINK_CHECK; + _params.flags.bits.mlme_req = 1; + 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) +{ + if (LORAMAC_IDLE != _params.mac_state) { + return LORAWAN_STATUS_BUSY; + } + + mlme.reset_confirmation(); + + mlme.get_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) { @@ -1513,7 +1627,7 @@ lorawan_status_t LoRaMac::prepare_frame(loramac_mhdr_t *machdr, _params.is_node_ack_requested = true; //Intentional fallthrough case FRAME_TYPE_DATA_UNCONFIRMED_UP: { - if (_params.is_nwk_joined == false) { + if (!_is_nwk_joined) { // No network has been joined yet return LORAWAN_STATUS_NO_NETWORK_JOINED; } @@ -1664,7 +1778,7 @@ lorawan_status_t LoRaMac::send_frame_on_channel(uint8_t channel) _lora_time.start(_params.timers.mac_state_check_timer, MAC_STATE_CHECK_TIMEOUT); - if (_params.is_nwk_joined == false) { + if (!_is_nwk_joined) { _params.join_request_trial_counter++; } @@ -1694,9 +1808,6 @@ lorawan_status_t LoRaMac::initialize(loramac_primitives_t *primitives, // Activate MCPS subsystem mcps.activate_mcps_subsystem(); - // Activate MIB subsystem - mib.activate_mib_subsystem(&_lora_phy); - // Activate channel planning subsystem channel_plan.activate_channelplan_subsystem(&_lora_phy); @@ -1704,7 +1815,7 @@ lorawan_status_t LoRaMac::initialize(loramac_primitives_t *primitives, _params.flags.value = 0; - _params.dev_class = CLASS_A; + _device_class = CLASS_A; _params.mac_state = LORAMAC_IDLE; _params.join_request_trial_counter = 0; @@ -1746,15 +1857,10 @@ lorawan_status_t LoRaMac::initialize(loramac_primitives_t *primitives, // Store the current initialization time _params.timers.mac_init_time = _lora_time.get_current_time(); - loramac_mib_req_confirm_t mib_req; + _params.sys_params.adr_on = MBED_CONF_LORA_ADR_ON; - mib_req.type = MIB_ADR; - mib_req.param.is_adr_enable = MBED_CONF_LORA_ADR_ON; - mib_set_request_confirm(&mib_req); - - mib_req.type = MIB_PUBLIC_NETWORK; - mib_req.param.enable_public_nwk = MBED_CONF_LORA_PUBLIC_NETWORK; - mib_set_request_confirm(&mib_req); + _params.is_nwk_public = MBED_CONF_LORA_PUBLIC_NETWORK; + _lora_phy.setup_public_network_mode(MBED_CONF_LORA_PUBLIC_NETWORK); return LORAWAN_STATUS_OK; } @@ -1772,7 +1878,7 @@ void LoRaMac::disconnect() _lora_phy.put_radio_to_sleep(); // Reset internal state - _params.is_nwk_joined = false; + _is_nwk_joined = false; _params.is_ack_retry_timeout_expired = false; _params.is_rx_window_enabled = true; _params.is_node_ack_requested = false; @@ -1825,6 +1931,16 @@ uint8_t LoRaMac::query_tx_possible(uint8_t size) return current_payload_size; } +bool LoRaMac::nwk_joined() +{ + return _is_nwk_joined; +} + +void LoRaMac::set_nwk_joined(bool joined) +{ + _is_nwk_joined = joined; +} + lorawan_status_t LoRaMac::add_channel_plan(const lorawan_channelplan_t& plan) { // Validate if the MAC is in a correct state @@ -1851,18 +1967,7 @@ lorawan_status_t LoRaMac::remove_channel_plan() lorawan_status_t LoRaMac::get_channel_plan(lorawan_channelplan_t& plan) { - // Request Mib to get channels - loramac_mib_req_confirm_t mib_confirm; - memset(&mib_confirm, 0, sizeof(mib_confirm)); - mib_confirm.type = MIB_CHANNELS; - - lorawan_status_t status = mib.get_request(&mib_confirm, &_params); - - if (status != LORAWAN_STATUS_OK) { - return status; - } - - return channel_plan.get_plan(plan, &mib_confirm); + return channel_plan.get_plan(plan, _lora_phy.get_phy_channels()); } lorawan_status_t LoRaMac::remove_single_channel(uint8_t id) @@ -1937,6 +2042,26 @@ lorawan_status_t LoRaMac::multicast_channel_unlink( return LORAWAN_STATUS_OK; } +void LoRaMac::bind_radio_driver(LoRaRadio& radio) +{ + radio_events.tx_done = mbed::callback(this, &LoRaMac::handle_tx_done); + radio_events.rx_done = mbed::callback(this, &LoRaMac::handle_rx_done); + radio_events.rx_error = mbed::callback(this, &LoRaMac::handle_rx_error); + radio_events.tx_timeout = mbed::callback(this, &LoRaMac::handle_tx_timeout); + radio_events.rx_timeout = mbed::callback(this, &LoRaMac::handle_rx_timeout); + + _lora_phy.set_radio_instance(radio); + radio.lock(); + radio.init_radio(&radio_events); + radio.unlock(); +} + +#if defined(LORAWAN_COMPLIANCE_TEST) +/*************************************************************************** + * Compliance testing * + **************************************************************************/ + + lorawan_status_t LoRaMac::mlme_request( loramac_mlme_req_t *mlmeRequest ) { if (LORAMAC_IDLE != _params.mac_state) { @@ -1950,50 +2075,16 @@ lorawan_status_t LoRaMac::mlme_request( loramac_mlme_req_t *mlmeRequest ) lorawan_status_t status = LORAWAN_STATUS_SERVICE_UNKNOWN; - if (MLME_LINK_CHECK == mlmeRequest->type) { - status = mac_commands.add_mac_command(MOTE_MAC_LINK_CHECK_REQ, 0, 0); - } else if (MLME_JOIN == mlmeRequest->type) { - if ((_params.mac_state & LORAMAC_TX_DELAYED) == LORAMAC_TX_DELAYED) { - return LORAWAN_STATUS_BUSY; - } - - if ((mlmeRequest->req.join.dev_eui == NULL) - || (mlmeRequest->req.join.app_eui == NULL) - || (mlmeRequest->req.join.app_key == NULL) - || (mlmeRequest->req.join.nb_trials == 0)) { - return LORAWAN_STATUS_PARAMETER_INVALID; - } - _params.keys.dev_eui = mlmeRequest->req.join.dev_eui; - _params.keys.app_eui = mlmeRequest->req.join.app_eui; - _params.keys.app_key = mlmeRequest->req.join.app_key; - _params.max_join_request_trials = mlmeRequest->req.join.nb_trials; - - if (!_lora_phy.verify_nb_join_trials(mlmeRequest->req.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; - status = send(&machdr, 0, NULL, 0); - } else if (MLME_TXCW == mlmeRequest->type) { + if (MLME_TXCW == mlmeRequest->type) { mlme.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->req.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, MAC_STATE_CHECK_TIMEOUT); _params.mac_state |= LORAMAC_TX_RUNNING; status = LORAWAN_STATUS_OK; } else if (MLME_TXCW_1 == mlmeRequest->type) { - mlme.set_tx_continuous_wave(0, 0, mlmeRequest->req.cw_tx_mode.power, 0, 0, mlmeRequest->req.cw_tx_mode.timeout); + mlme.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, MAC_STATE_CHECK_TIMEOUT); @@ -2074,40 +2165,6 @@ lorawan_status_t LoRaMac::mcps_request( loramac_mcps_req_t *mcpsRequest ) return status; } -lorawan_status_t LoRaMac::mib_get_request_confirm( loramac_mib_req_confirm_t *mibGet ) -{ - return mib.get_request(mibGet, &_params); -} - -lorawan_status_t LoRaMac::mib_set_request_confirm( loramac_mib_req_confirm_t *mibSet ) -{ - lorawan_status_t status = mib.set_request(mibSet, &_params); - if (LORAWAN_STATUS_OK == status && CLASS_C == _params.dev_class && (MIB_DEVICE_CLASS == mibSet->type || - (MIB_RX2_CHANNEL == mibSet->type && _params.is_nwk_joined))) { - open_continuous_rx2_window(); - } - return status; -} - -void LoRaMac::bind_radio_driver(LoRaRadio& radio) -{ - radio_events.tx_done = mbed::callback(this, &LoRaMac::handle_tx_done); - radio_events.rx_done = mbed::callback(this, &LoRaMac::handle_rx_done); - radio_events.rx_error = mbed::callback(this, &LoRaMac::handle_rx_error); - radio_events.tx_timeout = mbed::callback(this, &LoRaMac::handle_tx_timeout); - radio_events.rx_timeout = mbed::callback(this, &LoRaMac::handle_rx_timeout); - - _lora_phy.set_radio_instance(radio); - radio.lock(); - radio.init_radio(&radio_events); - radio.unlock(); -} - -#if defined(LORAWAN_COMPLIANCE_TEST) -/*************************************************************************** - * Compliance testing * - **************************************************************************/ - lorawan_status_t LoRaMac::LoRaMacSetTxTimer( uint32_t TxDutyCycleTime ) { _lora_time.start(tx_next_packet_timer, TxDutyCycleTime); diff --git a/features/lorawan/lorastack/mac/LoRaMac.h b/features/lorawan/lorastack/mac/LoRaMac.h index 7dc2488aaea..eda2c152adc 100644 --- a/features/lorawan/lorastack/mac/LoRaMac.h +++ b/features/lorawan/lorastack/mac/LoRaMac.h @@ -43,12 +43,11 @@ #include "lorawan/system/LoRaWANTimer.h" #include "lorastack/phy/LoRaPHY.h" #include "lorawan/system/lorawan_data_structures.h" -#include "lorastack/mac/LoRaMacCommand.h" +#include "LoRaMacCommand.h" #include "events/EventQueue.h" -#include "lorastack/mac/LoRaMacMlme.h" -#include "lorastack/mac/LoRaMacMcps.h" -#include "lorastack/mac/LoRaMacMib.h" -#include "lorastack/mac/LoRaMacChannelPlan.h" +#include "LoRaMacMlme.h" +#include "LoRaMacMcps.h" +#include "LoRaMacChannelPlan.h" #include "loraphy_target.h" class LoRaMac { @@ -107,6 +106,18 @@ class LoRaMac { */ uint8_t query_tx_possible(uint8_t size); + /** + * @brief nwk_joined Checks if device has joined to network + * @return True if joined to network, false otherwise + */ + bool nwk_joined(); + + /** + * @brief set_nwk_joined This is used for ABP mode for which real joining does not happen + * @param joined True if device has joined in network, false otherwise + */ + void set_nwk_joined(bool joined); + /** * @brief Adds a channel plan to the system. * @@ -198,155 +209,6 @@ class LoRaMac { */ lorawan_status_t multicast_channel_unlink(multicast_params_t *channel_param); - /** - * @brief Get parameter values from MIB service. - * - * @details The MAC information base service to get the attributes of the LoRaMac layer. - * - * The following code-snippet shows how to use the API to get the - * parameter `AdrEnable`, defined by the enumeration type - * \ref MIB_ADR. - * - * @code - * - * loramac_mib_req_confirm_t mib_get; - * mib_get.type = MIB_ADR; - * - * if (mib_get_request_confirm(&mib_get) == LORAWAN_STATUS_OK) { - * // LoRaMAC updated the parameter mibParam.AdrEnable - * } - * - * @endcode - * - * @param [in] mib_get The MIB-GET request to perform. Refer to - * \ref loramac_mib_req_confirm_t. - * - * @return `lorawan_status_t` The status of the operation. - * The possible values are: - * \ref LORAWAN_STATUS_OK - * \ref LORAWAN_STATUS_SERVICE_UNKNOWN - * \ref LORAWAN_STATUS_PARAMETER_INVALID - */ - lorawan_status_t mib_get_request_confirm(loramac_mib_req_confirm_t *mib_get); - - /** - * @brief Set attributes for MAC layer using MIB service. - * - * @details The MAC information base service to set the attributes of the LoRaMac layer. - * - * The following code-snippet shows how to use the API to set the - * parameter `adr_enable`, defined by the enumeration type - * \ref MIB_ADR. - * - * @code - * - * loramac_mib_req_confirm_t mib_set; - * mib_set.Type = MIB_ADR; - * mib_set.param.adr_enable = true; - * - * if (mib_set_request_confirm(&mib_set) == LORAWAN_STATUS_OK) { - * // LoRaMAC updated the parameter - * } - * - * @endcode - * - * @param [in] mib_set The MIB-SET request to perform. Refer to - * \ref loramac_mib_req_confirm_t. - * - * @return `lorawan_status_t` The status of the operation. The possible values are: - * \ref LORAWAN_STATUS_OK - * \ref LORAWAN_STATUS_BUSY - * \ref LORAWAN_STATUS_SERVICE_UNKNOWN - * \ref LORAWAN_STATUS_PARAMETER_INVALID - */ - lorawan_status_t mib_set_request_confirm(loramac_mib_req_confirm_t *mib_set); - - /** - * @brief Set forth an MLME request. - * - * @details The MAC layer management entity handles the management services. The - * following code-snippet shows how to use the API to perform a - * network join request. - * - * @code - * - * static uint8_t dev_eui[] = - * { - * 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - * }; - * static uint8_t app_eui[] = - * { - * 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - * }; - * static uint8_t app_key[] = - * { - * 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, - * 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C - * }; - * - * loramac_mlme_req_t mlme_req; - * mlme_req.Type = MLME_JOIN; - * mlme_req.req.join.dev_eui = dev_eui; - * mlme_req.req.join.app_eui = app_eui; - * mlme_req.req.join.app_key = app_key; - * - * if (LoRaMacMlmeRequest(&mlme_req) == LORAWAN_STATUS_OK) { - * // Service started successfully. Waiting for the Mlme-Confirm event - * } - * - * @endcode - * - * @param [in] request The MLME request to perform. - * Refer to \ref loramac_mlme_req_t. - * - * @return `lorawan_status_t` The status of the operation. The possible values are: - * \ref LORAWAN_STATUS_OK - * \ref LORAWAN_STATUS_BUSY - * \ref LORAWAN_STATUS_SERVICE_UNKNOWN - * \ref LORAWAN_STATUS_PARAMETER_INVALID - * \ref LORAWAN_STATUS_NO_NETWORK_JOINED - * \ref LORAWAN_STATUS_LENGTH_ERROR - * \ref LORAWAN_STATUS_DEVICE_OFF - */ - lorawan_status_t mlme_request(loramac_mlme_req_t *request); - - /** - * @brief Set forth an MCPS request. - * - * @details The MAC Common Part Sublayer handles the data services. The following - * code-snippet shows how to use the API to send an unconfirmed - * LoRaMAC frame. - * - * @code - * - * uint8_t buffer[] = {1, 2, 3}; - * - * loramac_mcps_req_t request; - * request.type = MCPS_UNCONFIRMED; - * request.fport = 1; - * request.f_buffer = buffer; - * request.f_buffer_size = sizeof(buffer); - * - * if (mcps_request(&request) == LORAWAN_STATUS_OK) { - * // Service started successfully. Waiting for the MCPS-Confirm event - * } - * - * @endcode - * - * @param [in] request The MCPS request to perform. - * Refer to \ref loramac_mcps_req_t. - * - * @return `lorawan_status_t` The status of the operation. The possible values are: - * \ref LORAWAN_STATUS_OK - * \ref LORAWAN_STATUS_BUSY - * \ref LORAWAN_STATUS_SERVICE_UNKNOWN - * \ref LORAWAN_STATUS_PARAMETER_INVALID - * \ref LORAWAN_STATUS_NO_NETWORK_JOINED - * \ref LORAWAN_STATUS_LENGTH_ERROR - * \ref LORAWAN_STATUS_DEVICE_OFF - */ - lorawan_status_t mcps_request(loramac_mcps_req_t *request); - /** Binds radio driver to PHY layer. * * MAC layer is totally detached from the PHY layer so the stack layer @@ -427,6 +289,27 @@ class LoRaMac { */ uint8_t get_default_tx_datarate(); + /** + * @brief enable_adaptive_datarate Enables or disables adaptive datarate. + * @param adr_enabled Flag indicating is adr enabled or disabled. + * @return LORAWAN_STATUS_OK or a negative error code on failure. + */ + lorawan_status_t enable_adaptive_datarate(bool adr_enabled); + + /** Sets up the data rate. + * + * `set_datarate()` first verifies whether the data rate given is valid or not. + * If it is valid, the system sets the given data rate to the channel. + * + * @param data_rate The intended data rate, for example DR_0 or DR_1. + * Note that the macro DR_* can mean different + * things in different regions. + * + * @return LORAWAN_STATUS_OK if everything goes well, otherwise + * a negative error code. + */ + lorawan_status_t set_channel_data_rate(uint8_t data_rate); + /** * @brief tx_ongoing Check whether a prepare is done or not. * @return True if prepare_ongoing_tx is called, false otherwise. @@ -465,6 +348,38 @@ class LoRaMac { */ lorawan_status_t send_ongoing_tx(); + /** + * @brief device_class Returns active device class + * @return Device class in use. + */ + device_class_t get_device_class() const; + + /** + * @brief set_device_class Sets active device class. + * @param device_class Device class to use. + */ + void set_device_class(const device_class_t& device_class); + + /** + * @brief setup_link_check_request Adds link check request command + * to be put on next outgoing message (when it fits) + */ + void setup_link_check_request(); + + /** + * @brief join_by_otaa Sends OTAA join message + * @param otaa_join Joining parameters + * + * @return LORAWAN_STATUS_OK or a negative error code on failure. + */ + lorawan_status_t join_by_otaa(const lorawan_connect_otaa_t& otaa_join); + + /** + * @brief join_by_abp Sets up ABP connectivity parameters. + * @param abp_join Connectivity parameters. + */ + void join_by_abp(const lorawan_connect_abp_t& abp_join); + private: /** * Function to be executed on Radio Tx Done event @@ -613,11 +528,6 @@ class LoRaMac { */ LoRaMacMcps mcps; - /** - * MCPS subsystem handle - */ - LoRaMacMib mib; - /** * Channel planning subsystem */ @@ -645,9 +555,69 @@ class LoRaMac { loramac_tx_message_t _ongoing_tx_msg; + bool _is_nwk_joined; + + device_class_t _device_class; + #if defined(LORAWAN_COMPLIANCE_TEST) public: // Test interface + /** + * @brief Set forth an MLME request. + * + * @details The MAC layer management entity handles the management services. + * + * @param [in] request The MLME request to perform. + * Refer to \ref loramac_mlme_req_t. + * + * @return `lorawan_status_t` The status of the operation. The possible values are: + * \ref LORAWAN_STATUS_OK + * \ref LORAWAN_STATUS_BUSY + * \ref LORAWAN_STATUS_SERVICE_UNKNOWN + * \ref LORAWAN_STATUS_PARAMETER_INVALID + * \ref LORAWAN_STATUS_NO_NETWORK_JOINED + * \ref LORAWAN_STATUS_LENGTH_ERROR + * \ref LORAWAN_STATUS_DEVICE_OFF + */ + lorawan_status_t mlme_request(loramac_mlme_req_t *request); + + /** + * @brief Set forth an MCPS request. + * + * @details The MAC Common Part Sublayer handles the data services. The following + * code-snippet shows how to use the API to send an unconfirmed + * LoRaMAC frame. + * + * @code + * + * uint8_t buffer[] = {1, 2, 3}; + * + * loramac_mcps_req_t request; + * request.type = MCPS_UNCONFIRMED; + * request.fport = 1; + * request.f_buffer = buffer; + * request.f_buffer_size = sizeof(buffer); + * + * if (mcps_request(&request) == LORAWAN_STATUS_OK) { + * // Service started successfully. Waiting for the MCPS-Confirm event + * } + * + * @endcode + * + * @param [in] request The MCPS request to perform. + * Refer to \ref loramac_mcps_req_t. + * + * @return `lorawan_status_t` The status of the operation. The possible values are: + * \ref LORAWAN_STATUS_OK + * \ref LORAWAN_STATUS_BUSY + * \ref LORAWAN_STATUS_SERVICE_UNKNOWN + * \ref LORAWAN_STATUS_PARAMETER_INVALID + * \ref LORAWAN_STATUS_NO_NETWORK_JOINED + * \ref LORAWAN_STATUS_LENGTH_ERROR + * \ref LORAWAN_STATUS_DEVICE_OFF + */ + lorawan_status_t mcps_request(loramac_mcps_req_t *request); + /** * \brief LoRaMAC set tx timer. * diff --git a/features/lorawan/lorastack/mac/LoRaMacChannelPlan.cpp b/features/lorawan/lorastack/mac/LoRaMacChannelPlan.cpp index 4caac0f736d..ff75df2a4a5 100644 --- a/features/lorawan/lorastack/mac/LoRaMacChannelPlan.cpp +++ b/features/lorawan/lorastack/mac/LoRaMacChannelPlan.cpp @@ -77,12 +77,8 @@ lorawan_status_t LoRaMacChannelPlan::set_plan(const lorawan_channelplan_t& plan) } lorawan_status_t LoRaMacChannelPlan::get_plan(lorawan_channelplan_t& plan, - const loramac_mib_req_confirm_t* mib_confirm) + const channel_params_t* channel_list) { - if (mib_confirm == NULL) { - return LORAWAN_STATUS_PARAMETER_INVALID; - } - uint8_t max_num_channels; uint16_t *channel_mask; uint8_t count = 0; @@ -103,12 +99,12 @@ lorawan_status_t LoRaMacChannelPlan::get_plan(lorawan_channelplan_t& plan, // otherwise add them to the channel_plan struct plan.channels[count].id = i; - plan.channels[count].ch_param.frequency = mib_confirm->param.channel_list[i].frequency; - plan.channels[count].ch_param.dr_range.value = mib_confirm->param.channel_list[i].dr_range.value; - plan.channels[count].ch_param.dr_range.fields.min = mib_confirm->param.channel_list[i].dr_range.fields.min; - plan.channels[count].ch_param.dr_range.fields.max = mib_confirm->param.channel_list[i].dr_range.fields.max; - plan.channels[count].ch_param.band = mib_confirm->param.channel_list[i].band; - plan.channels[count].ch_param.rx1_frequency = mib_confirm->param.channel_list[i].rx1_frequency; + plan.channels[count].ch_param.frequency = channel_list[i].frequency; + plan.channels[count].ch_param.dr_range.value = channel_list[i].dr_range.value; + plan.channels[count].ch_param.dr_range.fields.min = channel_list[i].dr_range.fields.min; + plan.channels[count].ch_param.dr_range.fields.max = channel_list[i].dr_range.fields.max; + plan.channels[count].ch_param.band = channel_list[i].band; + plan.channels[count].ch_param.rx1_frequency = channel_list[i].rx1_frequency; count++; } diff --git a/features/lorawan/lorastack/mac/LoRaMacChannelPlan.h b/features/lorawan/lorastack/mac/LoRaMacChannelPlan.h index 23a08cdc0ba..7114957f6c9 100644 --- a/features/lorawan/lorastack/mac/LoRaMacChannelPlan.h +++ b/features/lorawan/lorastack/mac/LoRaMacChannelPlan.h @@ -30,7 +30,6 @@ SPDX-License-Identifier: BSD-3-Clause #include "lorawan/system/lorawan_data_structures.h" #include "lorastack/phy/LoRaPHY.h" -#include "lorastack/mac/LoRaMacMib.h" class LoRaMacChannelPlan { @@ -77,12 +76,12 @@ class LoRaMacChannelPlan { * @param plan a reference to application provided channel plan structure * which gets filled in with active channel plan data. * - * @param mib_confirm pointer to MIB request structure containing channel information + * @param channel_list pointer to structure containing channel information * * @return LORAWAN_STATUS_OK if everything goes well otherwise * a negative error code is returned. */ - lorawan_status_t get_plan(lorawan_channelplan_t& plan, const loramac_mib_req_confirm_t *mib_confirm); + lorawan_status_t get_plan(lorawan_channelplan_t& plan, const channel_params_t* channel_list); /** Remove the active channel plan * diff --git a/features/lorawan/lorastack/mac/LoRaMacMib.cpp b/features/lorawan/lorastack/mac/LoRaMacMib.cpp deleted file mode 100644 index bc0b26a1773..00000000000 --- a/features/lorawan/lorastack/mac/LoRaMacMib.cpp +++ /dev/null @@ -1,434 +0,0 @@ -/** - / _____) _ | | -( (____ _____ ____ _| |_ _____ ____| |__ - \____ \| ___ | (_ _) ___ |/ ___) _ \ - _____) ) ____| | | || |_| ____( (___| | | | -(______/|_____)_|_|_| \__)_____)\____)_| |_| - (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 -*/ - -#include "lorastack/mac/LoRaMac.h" -#include "lorastack/mac/LoRaMacMib.h" - -LoRaMacMib::LoRaMacMib() -: _lora_phy(NULL) -{ -} - -LoRaMacMib::~LoRaMacMib() -{ -} - -void LoRaMacMib::activate_mib_subsystem(LoRaPHY *phy) -{ - _lora_phy = phy; -} - -lorawan_status_t LoRaMacMib::set_request(loramac_mib_req_confirm_t *mibSet, - loramac_protocol_params *params) -{ - if (mibSet == NULL || _lora_phy == NULL) { - return LORAWAN_STATUS_PARAMETER_INVALID; - } - - lorawan_status_t status = LORAWAN_STATUS_OK; - - switch (mibSet->type) { - case MIB_DEVICE_CLASS: { - params->dev_class = mibSet->param.dev_class; - switch (params->dev_class) { - case CLASS_A: { - // Set the radio into sleep to setup a defined state - _lora_phy->put_radio_to_sleep(); - break; - } - case CLASS_B: { - status = LORAWAN_STATUS_UNSUPPORTED; - break; - } - case CLASS_C: { - // Set the is_node_ack_requested indicator to default - params->is_node_ack_requested = false; - // Set the radio into sleep mode in case we are still in RX mode - _lora_phy->put_radio_to_sleep(); - // Compute Rx2 windows parameters in case the RX2 datarate has changed - _lora_phy->compute_rx_win_params( - params->sys_params.rx2_channel.datarate, - params->sys_params.min_rx_symb, - params->sys_params.max_sys_rx_error, - ¶ms->rx_window2_config); - break; - } - } - break; - } - case MIB_NETWORK_JOINED: { - params->is_nwk_joined = mibSet->param.is_nwk_joined; - break; - } - case MIB_ADR: { - params->sys_params.adr_on = mibSet->param.is_adr_enable; - break; - } - case MIB_NET_ID: { - params->net_id = mibSet->param.net_id; - break; - } - case MIB_DEV_ADDR: { - params->dev_addr = mibSet->param.dev_addr; - break; - } - case MIB_NWK_SKEY: { - if (mibSet->param.nwk_skey != NULL) { - memcpy(params->keys.nwk_skey, mibSet->param.nwk_skey, - sizeof(params->keys.nwk_skey)); - } else { - status = LORAWAN_STATUS_PARAMETER_INVALID; - } - break; - } - case MIB_APP_SKEY: { - if (mibSet->param.app_skey != NULL) { - memcpy(params->keys.app_skey, mibSet->param.app_skey, - sizeof(params->keys.app_skey)); - } else { - status = LORAWAN_STATUS_PARAMETER_INVALID; - } - break; - } - case MIB_PUBLIC_NETWORK: { - params->is_nwk_public = mibSet->param.enable_public_nwk; - _lora_phy->setup_public_network_mode(params->is_nwk_public); - break; - } - case MIB_REPEATER_SUPPORT: { - params->is_repeater_supported = mibSet->param.enable_repeater_support; - break; - } - case MIB_RX2_CHANNEL: { - if (_lora_phy->verify_rx_datarate(mibSet->param.rx2_channel.datarate) == true) { - params->sys_params.rx2_channel = mibSet->param.rx2_channel; - - if ((params->dev_class == CLASS_C) - && (params->is_nwk_joined == true)) { - // We can only compute the RX window parameters directly, if we are already - // in class c mode and joined. We cannot setup an RX window in case of any other - // class type. - // Set the radio into sleep mode in case we are still in RX mode - _lora_phy->put_radio_to_sleep(); - // Compute Rx2 windows parameters - _lora_phy->compute_rx_win_params( - params->sys_params.rx2_channel.datarate, - params->sys_params.min_rx_symb, - params->sys_params.max_sys_rx_error, - ¶ms->rx_window2_config); - } - } else { - status = LORAWAN_STATUS_PARAMETER_INVALID; - } - break; - } - case MIB_RX2_DEFAULT_CHANNEL: { - if (_lora_phy->verify_rx_datarate(mibSet->param.rx2_channel.datarate) == true) { - params->sys_params.rx2_channel = mibSet->param.default_rx2_channel; - } else { - status = LORAWAN_STATUS_PARAMETER_INVALID; - } - break; - } - case MIB_CHANNELS_DEFAULT_MASK: - case MIB_CHANNELS_MASK: { - // channel masks must not be tempered with. - // They should be manipulated only on request with certain - // APIs like add_channel() and remove_channel() - // You should be able to get these MIB parameters, not set - status = LORAWAN_STATUS_SERVICE_UNKNOWN; - break; - } - case MIB_CHANNELS_NB_REP: { - if ((mibSet->param.channel_nb_rep >= 1) - && (mibSet->param.channel_nb_rep <= 15)) { - params->sys_params.retry_num = mibSet->param.channel_nb_rep; - } else { - status = LORAWAN_STATUS_PARAMETER_INVALID; - } - break; - } - case MIB_MAX_RX_WINDOW_DURATION: { - params->sys_params.max_rx_win_time = mibSet->param.max_rx_window; - break; - } - case MIB_RECEIVE_DELAY_1: { - params->sys_params.recv_delay1 = mibSet->param.recv_delay1; - break; - } - case MIB_RECEIVE_DELAY_2: { - params->sys_params.recv_delay2 = mibSet->param.recv_delay2; - break; - } - case MIB_JOIN_ACCEPT_DELAY_1: { - params->sys_params.join_accept_delay1 = mibSet->param.join_accept_delay1; - break; - } - case MIB_JOIN_ACCEPT_DELAY_2: { - params->sys_params.join_accept_delay2 = mibSet->param.join_accept_delay2; - break; - } - case MIB_CHANNELS_DEFAULT_DATARATE: { - if (_lora_phy->verify_tx_datarate(mibSet->param.default_channel_data_rate, true)) { - params->sys_params.channel_data_rate = mibSet->param.default_channel_data_rate; - } else { - status = LORAWAN_STATUS_PARAMETER_INVALID; - } - break; - } - case MIB_CHANNELS_DATARATE: { - if (_lora_phy->verify_tx_datarate(mibSet->param.channel_data_rate, false) == true) { - params->sys_params.channel_data_rate = mibSet->param.channel_data_rate; - } else { - status = LORAWAN_STATUS_PARAMETER_INVALID; - } - break; - } - case MIB_CHANNELS_DEFAULT_TX_POWER: { - if (_lora_phy->verify_tx_power(mibSet->param.default_channel_tx_pwr)) { - params->sys_params.channel_tx_power = mibSet->param.default_channel_tx_pwr; - } else { - status = LORAWAN_STATUS_PARAMETER_INVALID; - } - break; - } - case MIB_CHANNELS_TX_POWER: { - if (_lora_phy->verify_tx_power(mibSet->param.channel_tx_pwr)) { - params->sys_params.channel_tx_power = mibSet->param.channel_tx_pwr; - } else { - status = LORAWAN_STATUS_PARAMETER_INVALID; - } - break; - } - case MIB_UPLINK_COUNTER: { - params->ul_frame_counter = mibSet->param.ul_frame_counter; - break; - } - case MIB_DOWNLINK_COUNTER: { - params->dl_frame_counter = mibSet->param.dl_frame_counter; - break; - } - case MIB_SYSTEM_MAX_RX_ERROR: { - params->sys_params.max_sys_rx_error = mibSet->param.max_rx_sys_error; - break; - } - case MIB_MIN_RX_SYMBOLS: { - params->sys_params.min_rx_symb = mibSet->param.min_rx_symb; - break; - } - case MIB_ANTENNA_GAIN: { - params->sys_params.antenna_gain = mibSet->param.antenna_gain; - break; - } - case MIB_DEFAULT_ANTENNA_GAIN: - { - params->sys_params.antenna_gain = mibSet->param.default_antenna_gain; - break; - } - default: - status = LORAWAN_STATUS_SERVICE_UNKNOWN; - break; - } - - return status; -} - -lorawan_status_t LoRaMacMib::get_request(loramac_mib_req_confirm_t *mibGet, - loramac_protocol_params *params) -{ - lorawan_status_t status = LORAWAN_STATUS_OK; - rx2_channel_params rx2_channel; - - if( mibGet == NULL ) - { - return LORAWAN_STATUS_PARAMETER_INVALID; - } - - switch( mibGet->type ) - { - case MIB_DEVICE_CLASS: - { - mibGet->param.dev_class = params->dev_class; - break; - } - case MIB_NETWORK_JOINED: - { - mibGet->param.is_nwk_joined = params->is_nwk_joined; - break; - } - case MIB_ADR: - { - mibGet->param.is_adr_enable = params->sys_params.adr_on; - break; - } - case MIB_NET_ID: - { - mibGet->param.net_id = params->net_id; - break; - } - case MIB_DEV_ADDR: - { - mibGet->param.dev_addr = params->dev_addr; - break; - } - case MIB_NWK_SKEY: - { - mibGet->param.nwk_skey =params->keys.nwk_skey; - break; - } - case MIB_APP_SKEY: - { - mibGet->param.app_skey = params->keys.app_skey; - break; - } - case MIB_PUBLIC_NETWORK: - { - mibGet->param.enable_public_nwk = params->is_nwk_public; - break; - } - case MIB_REPEATER_SUPPORT: - { - mibGet->param.enable_repeater_support = params->is_repeater_supported; - break; - } - case MIB_CHANNELS: - { - mibGet->param.channel_list = _lora_phy->get_phy_channels(); - break; - } - case MIB_RX2_CHANNEL: - { - mibGet->param.rx2_channel = params->sys_params.rx2_channel; - break; - } - case MIB_RX2_DEFAULT_CHANNEL: - { - rx2_channel.datarate = _lora_phy->get_default_rx2_datarate(); - rx2_channel.frequency = _lora_phy->get_default_rx2_frequency(); - mibGet->param.rx2_channel = rx2_channel; - break; - } - case MIB_CHANNELS_DEFAULT_MASK: - { - mibGet->param.default_channel_mask = _lora_phy->get_channel_mask(true); - break; - } - case MIB_CHANNELS_MASK: - { - mibGet->param.channel_mask = _lora_phy->get_channel_mask(false); - break; - } - case MIB_CHANNELS_NB_REP: - { - mibGet->param.channel_nb_rep = params->sys_params.retry_num; - break; - } - case MIB_MAX_RX_WINDOW_DURATION: - { - mibGet->param.max_rx_window = params->sys_params.max_rx_win_time; - break; - } - case MIB_RECEIVE_DELAY_1: - { - mibGet->param.recv_delay1 = params->sys_params.recv_delay1; - break; - } - case MIB_RECEIVE_DELAY_2: - { - mibGet->param.recv_delay2 = params->sys_params.recv_delay2; - break; - } - case MIB_JOIN_ACCEPT_DELAY_1: - { - mibGet->param.join_accept_delay1 = params->sys_params.join_accept_delay1; - break; - } - case MIB_JOIN_ACCEPT_DELAY_2: - { - mibGet->param.join_accept_delay2 = params->sys_params.join_accept_delay2; - break; - } - case MIB_CHANNELS_DEFAULT_DATARATE: - { - mibGet->param.default_channel_data_rate = _lora_phy->get_default_tx_datarate(); - break; - } - case MIB_CHANNELS_DATARATE: - { - mibGet->param.channel_data_rate = params->sys_params.channel_data_rate; - break; - } - case MIB_CHANNELS_DEFAULT_TX_POWER: - { - mibGet->param.default_channel_tx_pwr = _lora_phy->get_default_tx_power(); - break; - } - case MIB_CHANNELS_TX_POWER: - { - mibGet->param.channel_tx_pwr = params->sys_params.channel_tx_power; - break; - } - case MIB_UPLINK_COUNTER: - { - mibGet->param.ul_frame_counter = params->ul_frame_counter; - break; - } - case MIB_DOWNLINK_COUNTER: - { - mibGet->param.dl_frame_counter = params->dl_frame_counter; - break; - } - case MIB_MULTICAST_CHANNEL: - { - mibGet->param.multicast_list = params->multicast_channels; - break; - } - case MIB_SYSTEM_MAX_RX_ERROR: - { - mibGet->param.max_rx_sys_error = params->sys_params.max_sys_rx_error; - break; - } - case MIB_MIN_RX_SYMBOLS: - { - mibGet->param.min_rx_symb = params->sys_params.min_rx_symb; - break; - } - case MIB_ANTENNA_GAIN: - { - mibGet->param.antenna_gain = params->sys_params.antenna_gain; - break; - } - case MIB_DEFAULT_ANTENNA_GAIN: - { - mibGet->param.default_antenna_gain = params->sys_params.antenna_gain; - break; - } - default: - status = LORAWAN_STATUS_SERVICE_UNKNOWN; - break; - } - - return status; -} diff --git a/features/lorawan/lorastack/mac/LoRaMacMib.h b/features/lorawan/lorastack/mac/LoRaMacMib.h deleted file mode 100644 index a442ad6ab47..00000000000 --- a/features/lorawan/lorastack/mac/LoRaMacMib.h +++ /dev/null @@ -1,100 +0,0 @@ -/** - / _____) _ | | -( (____ _____ ____ _| |_ _____ ____| |__ - \____ \| ___ | (_ _) ___ |/ ___) _ \ - _____) ) ____| | | || |_| ____( (___| | | | -(______/|_____)_|_|_| \__)_____)\____)_| |_| - (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 -*/ - -#ifndef MBED_OS_LORAWAN_MAC_MIB_H_ -#define MBED_OS_LORAWAN_MAC_MIB_H_ - -#include "lorawan/system/lorawan_data_structures.h" -#include "lorastack/phy/LoRaPHY.h" - -// forward declaration -class LoRaMac; - -class LoRaMacMib { - -public: - - /** Constructor - * - * Sets local handles to NULL. These handles will be set when the subsystem - * is activated by the MAC layer. - */ - LoRaMacMib(); - - /** Destructor - * - * Does nothing - */ - ~LoRaMacMib(); - - /** Activating MLME subsystem - * - * Stores pointers to MAC and PHY layer handles - * - * @param phy pointer to PHY layer - */ - void activate_mib_subsystem(LoRaPHY *phy); - - /** Sets up a MIB Request - * - * Used to configure MAC protocol parameters using appropriate - * key/value pair in the MIB request structure. Use this API to set - * any system wide configurable parameter exposed by MIB service. - * - * @param mibSet [in] pointer to MIB request structure - * @param params pointer to MAC protocol parameters which will be modified - * - * @return LORAWAN_STATUS_OK if everything goes well otherwise - * a negative error code is returned. - */ - lorawan_status_t set_request(loramac_mib_req_confirm_t *mibSet, - loramac_protocol_params *params); - - /** Provides access to the given MIB parameter - * - * Used to extract information about system wide MAC protocol parameters - * which are exposed by MIB service. - * - * @param mibGet [out] pointer to MIB request structure which will be filled in - * @param params pointer to MAC protocol parameters - * - * @return LORAWAN_STATUS_OK if everything goes well otherwise - * a negative error code is returned. - */ - lorawan_status_t get_request(loramac_mib_req_confirm_t *mibGet, - loramac_protocol_params *params); - -private: - - /** - * Pointer PHY handle - */ - LoRaPHY *_lora_phy; -}; - - - - -#endif /* MBED_OS_LORAWAN_MAC_MIB_H_ */ diff --git a/features/lorawan/system/lorawan_data_structures.h b/features/lorawan/system/lorawan_data_structures.h index ec167be9de5..8c760187c60 100644 --- a/features/lorawan/system/lorawan_data_structures.h +++ b/features/lorawan/system/lorawan_data_structures.h @@ -55,21 +55,6 @@ typedef uint32_t lorawan_time_t; #define MSG_MULTICAST_FLAG 0x04 #define MSG_PROPRIETARY_FLAG 0x08 -/** - * A macro to test a if a bit is on in a channel mask or not. - */ -//#define MASK_BIT_TEST(mask, bit) (mask & (1U << bit)) -//#define MASK_BIT_TEST(mask, bit) ((mask)[(bit) / 16] & (1U << ((bit) % 16))) -/** - * A macro to clear a bit in a channel mask. - */ -//#define MASK_BIT_CLEAR(mask, bit) (mask &= ~(1 << bit)) - -/** - * A macro to clear a bit in a channel mask. - */ -//#define MASK_BIT_SET(mask, bit) (mask |= (1 << bit)) - /** * Bit mask for message flags */ @@ -762,62 +747,6 @@ typedef enum { MCPS_PROPRIETARY, } mcps_type_t; -/*! - * LoRaMAC MCPS-Request structure. - */ -typedef struct { - /*! - * MCPS-Request type. - */ - mcps_type_t type; - - /*! - * Frame port field. Must be set if the payload is not empty. Use the - * application-specific frame port values: [1...223]. - * - * LoRaWAN Specification V1.0.2, chapter 4.3.2. - */ - uint8_t fport; - - /*! - * Uplink datarate, if ADR is off. - */ - int8_t data_rate; - /*! - * The number of trials to transmit the frame, if the LoRaMAC layer did not - * receive an acknowledgment. The MAC performs a datarate adaptation - * according to the LoRaWAN Specification V1.0.2, chapter 18.4, as in - * the following table: - * - * Transmission nb | Data Rate - * ----------------|----------- - * 1 (first) | DR - * 2 | DR - * 3 | max(DR-1,0) - * 4 | max(DR-1,0) - * 5 | max(DR-2,0) - * 6 | max(DR-2,0) - * 7 | max(DR-3,0) - * 8 | max(DR-3,0) - * - * Note that if nb_trials is set to 1 or 2, the MAC will not decrease - * the datarate, if the LoRaMAC layer did not receive an acknowledgment. - */ - uint8_t nb_trials; - - /** Payload data - * - * A pointer to the buffer of the frame payload. - */ - void *f_buffer; - /** Payload size - * - * The size of the frame payload. - */ - uint16_t f_buffer_size; - -} loramac_mcps_req_t; - /*! * LoRaMAC MCPS-Confirm. */ @@ -1025,29 +954,6 @@ typedef struct { uint8_t power; } mlme_cw_tx_mode_t; -/*! - * LoRaMAC MLME-Request structure. - */ -typedef struct { - /*! - * MLME-Request type. - */ - mlme_type_t type; - - /*! - * MLME-Request parameters. - */ - union { - /*! - * MLME-Request parameters for a join request. - */ - mlme_join_req_t join; - /*! - * MLME-Request parameters for TX continuous mode request. - */ - mlme_cw_tx_mode_t cw_tx_mode; - } req; -} loramac_mlme_req_t; /*! * LoRaMAC MLME-Confirm primitive. @@ -1091,465 +997,6 @@ typedef struct { mlme_type_t indication_type; } loramac_mlme_indication_t; -/*! - * LoRa MAC Information Base (MIB). - * - * The following table lists the MIB parameters and the related attributes: - * - * Attribute | Get | Set - * --------------------------------- | :-: | :-: - * \ref MIB_DEVICE_CLASS | YES | YES - * \ref MIB_NETWORK_JOINED | YES | YES - * \ref MIB_ADR | YES | YES - * \ref MIB_NET_ID | YES | YES - * \ref MIB_DEV_ADDR | YES | YES - * \ref MIB_NWK_SKEY | YES | YES - * \ref MIB_APP_SKEY | YES | YES - * \ref MIB_PUBLIC_NETWORK | YES | YES - * \ref MIB_REPEATER_SUPPORT | YES | YES - * \ref MIB_CHANNELS | YES | NO - * \ref MIB_RX2_CHANNEL | YES | YES - * \ref MIB_CHANNELS_MASK | YES | YES - * \ref MIB_CHANNELS_DEFAULT_MASK | YES | YES - * \ref MIB_CHANNELS_NB_REP | YES | YES - * \ref MIB_MAX_RX_WINDOW_DURATION | YES | YES - * \ref MIB_RECEIVE_DELAY_1 | YES | YES - * \ref MIB_RECEIVE_DELAY_2 | YES | YES - * \ref MIB_JOIN_ACCEPT_DELAY_1 | YES | YES - * \ref MIB_JOIN_ACCEPT_DELAY_2 | YES | YES - * \ref MIB_CHANNELS_DATARATE | YES | YES - * \ref MIB_CHANNELS_DEFAULT_DATARATE| YES | YES - * \ref MIB_CHANNELS_TX_POWER | YES | YES - * \ref MIB_CHANNELS_DEFAULT_TX_POWER| YES | YES - * \ref MIB_UPLINK_COUNTER | YES | YES - * \ref MIB_DOWNLINK_COUNTER | YES | YES - * \ref MIB_MULTICAST_CHANNEL | YES | NO - * \ref MIB_SYSTEM_MAX_RX_ERROR | YES | YES - * \ref MIB_MIN_RX_SYMBOLS | YES | YES - * \ref MIB_ANTENNA_GAIN | YES | YES - * \ref MIB_DEFAULT_ANTENNA_GAIN | YES | YES - * - * The following table provides links to the function implementations of the - * related MIB primitives: - * - * Primitive | Function - * ---------------- | :---------------------: - * MIB-Set | LoRaMacMibSetRequestConfirm - * MIB-Get | LoRaMacMibGetRequestConfirm - */ -typedef enum { - /*! - * LoRaWAN device class. - * - * LoRaWAN Specification V1.0.2. - */ - MIB_DEVICE_CLASS, - /*! - * LoRaWAN Network joined attribute. - * - * LoRaWAN Specification V1.0.2. - */ - MIB_NETWORK_JOINED, - /*! - * Adaptive data rate. - * - * LoRaWAN Specification V1.0.2, chapter 4.3.1.1. - * - * [true: ADR enabled, false: ADR disabled]. - */ - MIB_ADR, - /*! - * Network identifier. - * - * LoRaWAN Specification V1.0.2, chapter 6.1.1. - */ - MIB_NET_ID, - /*! - * End-device address. - * - * LoRaWAN Specification V1.0.2, chapter 6.1.1. - */ - MIB_DEV_ADDR, - /*! - * Network session key. - * - * LoRaWAN Specification V1.0.2, chapter 6.1.3. - */ - MIB_NWK_SKEY, - /*! - * Application session key. - * - * LoRaWAN Specification V1.0.2, chapter 6.1.4. - */ - MIB_APP_SKEY, - /*! - * Set the network type to public or private. - * - * LoRaWAN Regional Parameters V1.0.2rB. - * - * [true: public network, false: private network] - */ - MIB_PUBLIC_NETWORK, - /*! - * Support the operation with repeaters. - * - * LoRaWAN Regional Parameters V1.0.2rB. - * - * [true: repeater support enabled, false: repeater support disabled] - */ - MIB_REPEATER_SUPPORT, - /*! - * Communication channels. A GET request will return a - * pointer that references the first entry of the channel list. The - * list is of size LORA_MAX_NB_CHANNELS. - * - * LoRaWAN Regional Parameters V1.0.2rB. - */ - MIB_CHANNELS, - /*! - * Set receive window 2 channel. - * - * LoRaWAN Specification V1.0.2, chapter 3.3.1. - */ - MIB_RX2_CHANNEL, - /*! - * Set receive window 2 channel. - * - * LoRaWAN Specification V1.0.2, chapter 3.3.2. - */ - MIB_RX2_DEFAULT_CHANNEL, - /*! - * LoRaWAN channels mask. - * - * LoRaWAN Regional Parameters V1.0.2rB. - */ - MIB_CHANNELS_MASK, - /*! - * LoRaWAN default channels mask. - * - * LoRaWAN Regional Parameters V1.0.2rB. - */ - MIB_CHANNELS_DEFAULT_MASK, - /*! - * Set the number of repetitions on a channel. - * - * LoRaWAN Specification V1.0.2, chapter 5.2. - */ - MIB_CHANNELS_NB_REP, - /*! - * The maximum receive window duration in [ms]. - * - * LoRaWAN Specification V1.0.2, chapter 3.3.3. - */ - MIB_MAX_RX_WINDOW_DURATION, - /*! - * The receive delay 1 in [ms]. - * - * LoRaWAN Regional Parameters V1.0.2rB. - */ - MIB_RECEIVE_DELAY_1, - /*! - * The receive delay 2 in [ms]. - * - * LoRaWAN Regional Parameters V1.0.2rB. - */ - MIB_RECEIVE_DELAY_2, - /*! - * The join accept delay 1 in [ms]. - * - * LoRaWAN Regional Parameters V1.0.2rB. - */ - MIB_JOIN_ACCEPT_DELAY_1, - /*! - * The join accept delay 2 in [ms]. - * - * LoRaWAN Regional Parameters V1.0.2rB. - */ - MIB_JOIN_ACCEPT_DELAY_2, - /*! - * The default data rate of a channel. - * - * LoRaWAN Regional Parameters V1.0.2rB. - * - * The allowed ranges are region-specific. Please refer to \ref DR_0 to \ref DR_15 for details. - */ - MIB_CHANNELS_DEFAULT_DATARATE, - /*! - * The data rate of a channel. - * - * LoRaWAN Regional Parameters V1.0.2rB. - * - * The allowed ranges are region-specific. Please refer to \ref DR_0 to \ref DR_15 for details. - */ - MIB_CHANNELS_DATARATE, - /*! - * The transmission power of a channel. - * - * LoRaWAN Regional Parameters V1.0.2rB. - * - * The allowed ranges are region-specific. Please refer to \ref TX_POWER_0 to \ref TX_POWER_15 for details. - */ - MIB_CHANNELS_TX_POWER, - /*! - * The transmission power of a channel. - * - * LoRaWAN Regional Parameters V1.0.2rB. - * - * The allowed ranges are region-specific. Please refer to \ref TX_POWER_0 to \ref TX_POWER_15 for details. - */ - MIB_CHANNELS_DEFAULT_TX_POWER, - /*! - * LoRaWAN uplink counter. - * - * LoRaWAN Specification V1.0.2, chapter 4.3.1.5. - */ - MIB_UPLINK_COUNTER, - /*! - * LoRaWAN downlink counter. - * - * LoRaWAN Specification V1.0.2, chapter 4.3.1.5. - */ - MIB_DOWNLINK_COUNTER, - /*! - * Multicast channels. A GET request will return a pointer to the first - * entry of the multicast channel linked list. If the pointer is equal to - * NULL, the list is empty. - */ - MIB_MULTICAST_CHANNEL, - /*! - * System overall timing error in milliseconds. - * [-SystemMaxRxError : +SystemMaxRxError] - * Default: +/-10 ms - */ - MIB_SYSTEM_MAX_RX_ERROR, - /*! - * The minimum number of symbols required to detect an RX frame. - * Default: 6 symbols - */ - MIB_MIN_RX_SYMBOLS, - /*! - * The antenna gain of the node. The default value is region-specific. - * The antenna gain is used to calculate the TX power of the node. - * The formula is: - * radioTxPower = ( int8_t )floor( maxEirp - antennaGain ) - */ - MIB_ANTENNA_GAIN, - /*! - * Default antenna gain of the node. Default value is region specific. - * The antenna gain is used to calculate the TX power of the node. - * The formula is: - * radioTxPower = ( int8_t )floor( maxEirp - antennaGain ) - */ - MIB_DEFAULT_ANTENNA_GAIN -} mib_type_t; - -/*! - * LoRaMAC MIB parameters. - */ -typedef union { - /*! - * LoRaWAN device class. - * - * Related MIB type: \ref MIB_DEVICE_CLASS - */ - device_class_t dev_class; - /*! - * LoRaWAN network joined attribute - * - * Related MIB type: \ref MIB_NETWORK_JOINED - */ - bool is_nwk_joined; - /*! - * Activation state of ADR - * - * Related MIB type: \ref MIB_ADR - */ - bool is_adr_enable; - /*! - * Network identifier - * - * Related MIB type: \ref MIB_NET_ID - */ - uint32_t net_id; - /*! - * End-device address - * - * Related MIB type: \ref MIB_DEV_ADDR - */ - uint32_t dev_addr; - /*! - * Network session key - * - * Related MIB type: \ref MIB_NWK_SKEY - */ - uint8_t *nwk_skey; - /*! - * Application session key - * - * Related MIB type: \ref MIB_APP_SKEY - */ - uint8_t *app_skey; - /*! - * Enable or disable a public network - * - * Related MIB type: \ref MIB_PUBLIC_NETWORK - */ - bool enable_public_nwk; - /*! - * Enable or disable repeater support - * - * Related MIB type: \ref MIB_REPEATER_SUPPORT - */ - bool enable_repeater_support; - /*! - * LoRaWAN channel - * - * Related MIB type: \ref MIB_CHANNELS - */ - channel_params_t* channel_list; - /*! - * Channel for the receive window 2 - * - * Related MIB type: \ref MIB_RX2_CHANNEL - */ - rx2_channel_params rx2_channel; - /*! - * Channel for the receive window 2 - * - * Related MIB type: \ref MIB_RX2_DEFAULT_CHANNEL - */ - rx2_channel_params default_rx2_channel; - /*! - * Channel mask - * - * Related MIB type: \ref MIB_CHANNELS_MASK - */ - uint16_t* channel_mask; - /*! - * Default channel mask - * - * Related MIB type: \ref MIB_CHANNELS_DEFAULT_MASK - */ - uint16_t* default_channel_mask; - /*! - * Number of frame repetitions - * - * Related MIB type: \ref MIB_CHANNELS_NB_REP - */ - uint8_t channel_nb_rep; - /*! - * Maximum receive window duration - * - * Related MIB type: \ref MIB_MAX_RX_WINDOW_DURATION - */ - uint32_t max_rx_window; - /*! - * Receive delay 1 - * - * Related MIB type: \ref MIB_RECEIVE_DELAY_1 - */ - uint32_t recv_delay1; - /*! - * Receive delay 2 - * - * Related MIB type: \ref MIB_RECEIVE_DELAY_2 - */ - uint32_t recv_delay2; - /*! - * Join accept delay 1 - * - * Related MIB type: \ref MIB_JOIN_ACCEPT_DELAY_1 - */ - uint32_t join_accept_delay1; - /*! - * Join accept delay 2 - * - * Related MIB type: \ref MIB_JOIN_ACCEPT_DELAY_2 - */ - uint32_t join_accept_delay2; - /*! - * Channels data rate - * - * Related MIB type: \ref MIB_CHANNELS_DEFAULT_DATARATE - */ - int8_t default_channel_data_rate; - /*! - * Channels data rate - * - * Related MIB type: \ref MIB_CHANNELS_DATARATE - */ - int8_t channel_data_rate; - /*! - * Channels TX power - * - * Related MIB type: \ref MIB_CHANNELS_DEFAULT_TX_POWER - */ - int8_t default_channel_tx_pwr; - /*! - * Channels TX power - * - * Related MIB type: \ref MIB_CHANNELS_TX_POWER - */ - int8_t channel_tx_pwr; - /*! - * LoRaWAN uplink counter - * - * Related MIB type: \ref MIB_UPLINK_COUNTER - */ - uint32_t ul_frame_counter; - /*! - * LoRaWAN downlink counter - * - * Related MIB type: \ref MIB_DOWNLINK_COUNTER - */ - uint32_t dl_frame_counter; - /*! - * Multicast channel - * - * Related MIB type: \ref MIB_MULTICAST_CHANNEL - */ - multicast_params_t* multicast_list; - /*! - * System overall timing error in milliseconds - * - * Related MIB type: \ref MIB_SYSTEM_MAX_RX_ERROR - */ - uint32_t max_rx_sys_error; - /*! - * Minimum required number of symbols to detect an RX frame - * - * Related MIB type: \ref MIB_MIN_RX_SYMBOLS - */ - uint8_t min_rx_symb; - /*! - * Antenna gain - * - * Related MIB type: \ref MIB_ANTENNA_GAIN - */ - float antenna_gain; - /*! - * Default antenna gain - * - * Related MIB type: \ref MIB_DEFAULT_ANTENNA_GAIN - */ - float default_antenna_gain; -} mib_params_t; - -/*! - * LoRaMAC MIB-RequestConfirm structure - */ -typedef struct { - /*! - * MIB-Request type - */ - mib_type_t type; - - /*! - * MLME-RequestConfirm parameters - */ - mib_params_t param; -}loramac_mib_req_confirm_t; - /** LoRaMAC status. * */ @@ -1830,14 +1277,10 @@ typedef struct lorawan_session { lorawan_connect_t connection; /** * LoRaWAN uplink counter - * - * Related MIB type: LORA_MIB_UPLINK_COUNTER */ uint32_t uplink_counter; /** * LoRaWAN downlink counter - * - * Related MIB type: LORA_MIB_DOWNLINK_COUNTER */ uint32_t downlink_counter; } lorawan_session_t; @@ -2051,11 +1494,6 @@ typedef struct { typedef struct { - /*! - * Actual device class - */ - device_class_t dev_class; - /*! * Holds the type of current Receive window slot */ @@ -2288,6 +1726,69 @@ typedef struct lora_channelplan { } lorawan_channelplan_t; #if defined(LORAWAN_COMPLIANCE_TEST) + +typedef struct { + /*! + * MLME-Request type. + */ + mlme_type_t type; + + mlme_cw_tx_mode_t cw_tx_mode; +} loramac_mlme_req_t; + +typedef struct { + /*! + * MCPS-Request type. + */ + mcps_type_t type; + + /*! + * Frame port field. Must be set if the payload is not empty. Use the + * application-specific frame port values: [1...223]. + * + * LoRaWAN Specification V1.0.2, chapter 4.3.2. + */ + uint8_t fport; + + /*! + * Uplink datarate, if ADR is off. + */ + int8_t data_rate; + /*! + * The number of trials to transmit the frame, if the LoRaMAC layer did not + * receive an acknowledgment. The MAC performs a datarate adaptation + * according to the LoRaWAN Specification V1.0.2, chapter 18.4, as in + * the following table: + * + * Transmission nb | Data Rate + * ----------------|----------- + * 1 (first) | DR + * 2 | DR + * 3 | max(DR-1,0) + * 4 | max(DR-1,0) + * 5 | max(DR-2,0) + * 6 | max(DR-2,0) + * 7 | max(DR-3,0) + * 8 | max(DR-3,0) + * + * Note that if nb_trials is set to 1 or 2, the MAC will not decrease + * the datarate, if the LoRaMAC layer did not receive an acknowledgment. + */ + uint8_t nb_trials; + + /** Payload data + * + * A pointer to the buffer of the frame payload. + */ + void *f_buffer; + /** Payload size + * + * The size of the frame payload. + */ + uint16_t f_buffer_size; + +} loramac_mcps_req_t; + /** LoRaWAN compliance tests support data * */ From 489eecf7df6ffe491e9fe8ddd2f99d1d088f23dc Mon Sep 17 00:00:00 2001 From: Antti Kauppila Date: Fri, 16 Mar 2018 15:40:02 +0200 Subject: [PATCH 21/25] LoRa: LoRaMAC class refactored - Internal change only, no functional changes - Tested by running Green tea tests manually --- features/lorawan/LoRaWANStack.cpp | 4 +- features/lorawan/lorastack/mac/LoRaMac.cpp | 439 +++++++----------- features/lorawan/lorastack/mac/LoRaMac.h | 59 ++- .../lorawan/lorastack/mac/LoRaMacMcps.cpp | 57 --- features/lorawan/lorastack/mac/LoRaMacMcps.h | 88 ---- .../lorawan/lorastack/mac/LoRaMacMlme.cpp | 73 --- features/lorawan/lorastack/mac/LoRaMacMlme.h | 107 ----- features/lorawan/lorastack/phy/LoRaPHY.h | 9 +- 8 files changed, 224 insertions(+), 612 deletions(-) delete mode 100644 features/lorawan/lorastack/mac/LoRaMacMcps.cpp delete mode 100644 features/lorawan/lorastack/mac/LoRaMacMcps.h delete mode 100644 features/lorawan/lorastack/mac/LoRaMacMlme.cpp delete mode 100644 features/lorawan/lorastack/mac/LoRaMacMlme.h diff --git a/features/lorawan/LoRaWANStack.cpp b/features/lorawan/LoRaWANStack.cpp index 79ed87485bb..fc62aa43630 100644 --- a/features/lorawan/LoRaWANStack.cpp +++ b/features/lorawan/LoRaWANStack.cpp @@ -304,8 +304,8 @@ lorawan_status_t LoRaWANStack::enable_adaptive_datarate(bool adr_enabled) tr_error("Stack not initialized!"); return LORAWAN_STATUS_NOT_INITIALIZED; } - - return _loramac.enable_adaptive_datarate(adr_enabled); + _loramac.enable_adaptive_datarate(adr_enabled); + return LORAWAN_STATUS_OK; } lorawan_status_t LoRaWANStack::set_channel_data_rate(uint8_t data_rate) diff --git a/features/lorawan/lorastack/mac/LoRaMac.cpp b/features/lorawan/lorastack/mac/LoRaMac.cpp index 02fa0e3b35d..a5f38579487 100644 --- a/features/lorawan/lorastack/mac/LoRaMac.cpp +++ b/features/lorawan/lorastack/mac/LoRaMac.cpp @@ -184,7 +184,6 @@ void LoRaMac::on_radio_tx_done( void ) { set_band_txdone_params_t tx_done_params; lorawan_time_t cur_time = _lora_time.get_current_time( ); - loramac_mlme_confirm_t mlme_confirm = mlme.get_confirmation(); if (_device_class != CLASS_C) { _lora_phy.put_radio_to_sleep(); @@ -192,7 +191,6 @@ void LoRaMac::on_radio_tx_done( void ) open_continuous_rx2_window(); } - // Setup timers if(_params.is_rx_window_enabled == true) { _lora_time.start(_params.timers.rx_window1_timer, _params.rx_window1_delay); @@ -206,8 +204,8 @@ void LoRaMac::on_radio_tx_done( void ) _params.rx_window2_delay + _lora_phy.get_ack_timeout()); } } else { - mcps.get_confirmation().status = LORAMAC_EVENT_INFO_STATUS_OK; - mlme_confirm.status = LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT; + _mcps_confirmation.status = LORAMAC_EVENT_INFO_STATUS_OK; + _mlme_confirmation.status = LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT; if (_params.flags.value == 0) { _params.flags.bits.mcps_req = 1; @@ -216,28 +214,24 @@ void LoRaMac::on_radio_tx_done( void ) _params.flags.bits.mac_done = 1; } - // Verify if the last uplink was a join request if ((_params.flags.bits.mlme_req == 1) && - (mlme_confirm.req_type == MLME_JOIN)) { + (_mlme_confirmation.req_type == MLME_JOIN)) { _params.is_last_tx_join_request = true; } else { _params.is_last_tx_join_request = false; } - // Store last Tx channel _params.last_channel_idx = _params.channel; - // Update last tx done time for the current channel tx_done_params.channel = _params.channel; tx_done_params.joined = _is_nwk_joined; tx_done_params.last_tx_done_time = cur_time; _lora_phy.set_last_tx_done(&tx_done_params); - // Update Aggregated last tx done time _params.timers.aggregated_last_tx_time = cur_time; if (_params.is_node_ack_requested == false) { - mcps.get_confirmation().status = LORAMAC_EVENT_INFO_STATUS_OK; + _mcps_confirmation.status = LORAMAC_EVENT_INFO_STATUS_OK; _params.ul_nb_rep_counter++; } } @@ -255,7 +249,6 @@ void LoRaMac::prepare_rx_done_abort(void) _params.flags.bits.mcps_ind = 1; _params.flags.bits.mac_done = 1; - // Trigger MAC state check event timer as soon as possible _lora_time.start(_params.timers.mac_state_check_timer, 1); } @@ -286,19 +279,19 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, bool is_mic_ok = false; - mcps.get_confirmation().ack_received = false; - mcps.get_indication().rssi = rssi; - mcps.get_indication().snr = snr; - mcps.get_indication().rx_slot = _params.rx_slot; - mcps.get_indication().port = 0; - mcps.get_indication().multicast = 0; - mcps.get_indication().fpending_status = 0; - mcps.get_indication().buffer = NULL; - mcps.get_indication().buffer_size = 0; - mcps.get_indication().is_data_recvd = false; - mcps.get_indication().is_ack_recvd = false; - mcps.get_indication().dl_frame_counter = 0; - mcps.get_indication().type = MCPS_UNCONFIRMED; + _mcps_confirmation.ack_received = false; + _mcps_indication.rssi = rssi; + _mcps_indication.snr = snr; + _mcps_indication.rx_slot = _params.rx_slot; + _mcps_indication.port = 0; + _mcps_indication.multicast = 0; + _mcps_indication.fpending_status = 0; + _mcps_indication.buffer = NULL; + _mcps_indication.buffer_size = 0; + _mcps_indication.is_data_recvd = false; + _mcps_indication.is_ack_recvd = false; + _mcps_indication.dl_frame_counter = 0; + _mcps_indication.type = MCPS_UNCONFIRMED; if (_device_class != CLASS_C) { _lora_phy.put_radio_to_sleep(); @@ -309,10 +302,9 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, mac_hdr.value = payload[pkt_header_len++]; switch (mac_hdr.bits.mtype) { - case FRAME_TYPE_JOIN_ACCEPT: if (_is_nwk_joined) { - mcps.get_indication().status = LORAMAC_EVENT_INFO_STATUS_ERROR; + _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_ERROR; prepare_rx_done_abort(); return; } @@ -320,7 +312,7 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, if (0 != decrypt_join_frame(payload + 1, size - 1, _params.keys.app_key, _params.payload + 1)) { - mcps.get_indication().status = LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL; + _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL; return; } @@ -328,7 +320,7 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, if (0 != compute_join_frame_mic(_params.payload, size - LORAMAC_MFR_LEN, _params.keys.app_key, &mic)) { - mcps.get_indication().status = LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL; + _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL; return; } @@ -344,7 +336,7 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, _params.dev_nonce, _params.keys.nwk_skey, _params.keys.app_skey)) { - mcps.get_indication().status = LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL; + _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL; return; } @@ -357,11 +349,9 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, _params.dev_addr |= ((uint32_t) _params.payload[9] << 16); _params.dev_addr |= ((uint32_t) _params.payload[10] << 24); - // DLSettings _params.sys_params.rx1_dr_offset = (_params.payload[11] >> 4) & 0x07; _params.sys_params.rx2_channel.datarate = _params.payload[11] & 0x0F; - // RxDelay _params.sys_params.recv_delay1 = (_params.payload[12] & 0x0F); if (_params.sys_params.recv_delay1 == 0) { @@ -371,17 +361,16 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, _params.sys_params.recv_delay1 *= 1000; _params.sys_params.recv_delay2 = _params.sys_params.recv_delay1 + 1000; - // Apply CF list cflist.payload = &_params.payload[13]; // Size of the regular payload is 12. Plus 1 byte MHDR and 4 bytes MIC cflist.size = size - 17; _lora_phy.apply_cf_list(&cflist); - mlme.get_confirmation().status = LORAMAC_EVENT_INFO_STATUS_OK; + _mlme_confirmation.status = LORAMAC_EVENT_INFO_STATUS_OK; _is_nwk_joined = true; } else { - mlme.get_confirmation().status = LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL; + _mlme_confirmation.status = LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL; } break; @@ -389,10 +378,10 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, case FRAME_TYPE_DATA_CONFIRMED_DOWN: case FRAME_TYPE_DATA_UNCONFIRMED_DOWN: { - uint8_t value = _lora_phy.get_max_payload(mcps.get_indication().rx_datarate, _params.is_repeater_supported); + uint8_t value = _lora_phy.get_max_payload(_mcps_indication.rx_datarate, _params.is_repeater_supported); if (MAX(0, (int16_t) ((int16_t)size - (int16_t)LORA_MAC_FRMPAYLOAD_OVERHEAD )) > (int32_t)value) { - mcps.get_indication().status = LORAMAC_EVENT_INFO_STATUS_ERROR; + _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_ERROR; prepare_rx_done_abort(); return; } @@ -407,7 +396,6 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, cur_multicast_params = _params.multicast_channels; while (cur_multicast_params != NULL) { - if (address == cur_multicast_params->address) { multicast = 1; nwk_skey = cur_multicast_params->nwk_skey; @@ -421,7 +409,7 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, if (multicast == 0) { // We are not the destination of this frame. - mcps.get_indication().status = LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL; + _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL; prepare_rx_done_abort(); return; } @@ -448,16 +436,13 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, sequence_counter_diff = (sequence_counter - sequence_counter_prev); if (sequence_counter_diff < (1 << 15)) { - downlink_counter += sequence_counter_diff; compute_mic(payload, size - LORAMAC_MFR_LEN, nwk_skey, address, DOWN_LINK, downlink_counter, &mic); if (mic_rx == mic) { is_mic_ok = true; } - } else { - // check for sequence roll-over uint32_t downlink_counter_tmp = downlink_counter + 0x10000 + (int16_t)sequence_counter_diff; compute_mic(payload, size - LORAMAC_MFR_LEN, nwk_skey, address, DOWN_LINK, downlink_counter_tmp, &mic); @@ -469,34 +454,33 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, } if (sequence_counter_diff >= _lora_phy.get_maximum_frame_counter_gap()) { - mcps.get_indication().status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_TOO_MANY_FRAMES_LOSS; - mcps.get_indication().dl_frame_counter = downlink_counter; + _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_TOO_MANY_FRAMES_LOSS; + _mcps_indication.dl_frame_counter = downlink_counter; prepare_rx_done_abort( ); return; } if (is_mic_ok == true) { - mcps.get_indication().status = LORAMAC_EVENT_INFO_STATUS_OK; - mcps.get_indication().multicast = multicast; - mcps.get_indication().fpending_status = fctrl.bits.fpending; - mcps.get_indication().buffer = NULL; - mcps.get_indication().buffer_size = 0; - mcps.get_indication().dl_frame_counter = downlink_counter; + _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_OK; + _mcps_indication.multicast = multicast; + _mcps_indication.fpending_status = fctrl.bits.fpending; + _mcps_indication.buffer = NULL; + _mcps_indication.buffer_size = 0; + _mcps_indication.dl_frame_counter = downlink_counter; - mcps.get_confirmation().status = LORAMAC_EVENT_INFO_STATUS_OK; + _mcps_confirmation.status = LORAMAC_EVENT_INFO_STATUS_OK; _params.adr_ack_counter = 0; mac_commands.clear_repeat_buffer(); - // Update 32 bits downlink counter if (multicast == 1) { - mcps.get_indication().type = MCPS_MULTICAST; + _mcps_indication.type = MCPS_MULTICAST; if ((cur_multicast_params->dl_frame_counter == downlink_counter) && (cur_multicast_params->dl_frame_counter != 0)) { - mcps.get_indication().status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED; - mcps.get_indication().dl_frame_counter = downlink_counter; + _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED; + _mcps_indication.dl_frame_counter = downlink_counter; prepare_rx_done_abort(); return; @@ -508,7 +492,7 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, if (mac_hdr.bits.mtype == FRAME_TYPE_DATA_CONFIRMED_DOWN) { _params.is_srv_ack_requested = true; - mcps.get_indication().type = MCPS_CONFIRMED; + _mcps_indication.type = MCPS_CONFIRMED; if ((_params.dl_frame_counter == downlink_counter ) && (_params.dl_frame_counter != 0)) { @@ -521,12 +505,12 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, } } else { _params.is_srv_ack_requested = false; - mcps.get_indication().type = MCPS_UNCONFIRMED; + _mcps_indication.type = MCPS_UNCONFIRMED; if ((_params.dl_frame_counter == downlink_counter) && (_params.dl_frame_counter != 0)) { - mcps.get_indication().status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED; - mcps.get_indication().dl_frame_counter = downlink_counter; + _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED; + _mcps_indication.dl_frame_counter = downlink_counter; prepare_rx_done_abort(); return; } @@ -538,28 +522,23 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, // We need to reset the MacCommandsBufferIndex here, since we need // to take retransmissions and repetitions into account. Error cases // will be handled in function OnMacStateCheckTimerEvent. - if (mcps.get_confirmation().req_type == MCPS_CONFIRMED) { + if (_mcps_confirmation.req_type == MCPS_CONFIRMED) { if (fctrl.bits.ack == 1) { - // Reset MacCommandsBufferIndex when we have received an ACK. mac_commands.clear_command_buffer(); - // Update aknowledgement information - mcps.get_confirmation().ack_received = fctrl.bits.ack; - mcps.get_indication().is_ack_recvd = fctrl.bits.ack; + _mcps_confirmation.ack_received = fctrl.bits.ack; + _mcps_indication.is_ack_recvd = fctrl.bits.ack; } } else { - // Reset the variable if we have received any valid frame. mac_commands.clear_command_buffer(); } - // Process payload and MAC commands if (((size - 4) - app_payload_start_index) > 0) { uint8_t port = payload[app_payload_start_index++]; frame_len = (size - 4) - app_payload_start_index; - mcps.get_indication().port = port; + _mcps_indication.port = port; if (port == 0) { - // Only allow frames which do not have fOpts if (fctrl.bits.fopts_len == 0) { if (0 != decrypt_payload(payload + app_payload_start_index, frame_len, @@ -568,31 +547,29 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, DOWN_LINK, downlink_counter, _params.payload)) { - mcps.get_indication().status = LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL; + _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL; } - // Decode frame payload MAC commands if (LORAWAN_STATUS_OK != mac_commands.process_mac_commands( _params.payload, 0, frame_len, snr, - mlme.get_confirmation(), _params.sys_params, _lora_phy)) { - mcps.get_indication().status = LORAMAC_EVENT_INFO_STATUS_ERROR; + _mlme_confirmation, _params.sys_params, _lora_phy)) { + _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_ERROR; } else if (mac_commands.has_sticky_mac_cmd()) { set_mlme_schedule_ul_indication(); mac_commands.clear_sticky_mac_cmd(); } } else { _params.flags.bits.mcps_ind_skip = 1; - // This is not a valid frame. Drop it and reset the ACK bits - mcps.get_confirmation().ack_received = false; - mcps.get_indication().is_ack_recvd = false; + _mcps_confirmation.ack_received = false; + _mcps_indication.is_ack_recvd = false; } } else { if (fctrl.bits.fopts_len > 0) { // Decode Options field MAC commands. Omit the fPort. if (LORAWAN_STATUS_OK != mac_commands.process_mac_commands( payload, 8, app_payload_start_index - 1, snr, - mlme.get_confirmation(), _params.sys_params, _lora_phy )) { - mcps.get_indication().status = LORAMAC_EVENT_INFO_STATUS_ERROR; + _mlme_confirmation, _params.sys_params, _lora_phy )) { + _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_ERROR; } else if (mac_commands.has_sticky_mac_cmd()) { set_mlme_schedule_ul_indication(); mac_commands.clear_sticky_mac_cmd(); @@ -606,21 +583,20 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, DOWN_LINK, downlink_counter, _params.payload)) { - mcps.get_indication().status = LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL; + _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL; } - mcps.get_indication().buffer = _params.payload; - mcps.get_indication().buffer_size = frame_len; - mcps.get_indication().is_data_recvd = true; + _mcps_indication.buffer = _params.payload; + _mcps_indication.buffer_size = frame_len; + _mcps_indication.is_data_recvd = true; } } else { if (fctrl.bits.fopts_len > 0) { - // Decode Options field MAC commands if (LORAWAN_STATUS_OK != mac_commands.process_mac_commands( payload, 8, app_payload_start_index, snr, - mlme.get_confirmation(), + _mlme_confirmation, _params.sys_params, _lora_phy)) { - mcps.get_indication().status = LORAMAC_EVENT_INFO_STATUS_ERROR; + _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_ERROR; } else if (mac_commands.has_sticky_mac_cmd()) { set_mlme_schedule_ul_indication(); mac_commands.clear_sticky_mac_cmd(); @@ -632,7 +608,7 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, // in case of a confirmed downlink retransmission. _params.flags.bits.mcps_ind = 1; } else { - mcps.get_indication().status = LORAMAC_EVENT_INFO_STATUS_MIC_FAIL; + _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_MIC_FAIL; prepare_rx_done_abort( ); return; @@ -644,22 +620,21 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, { memcpy(_params.payload, &payload[pkt_header_len], size); - mcps.get_indication().type = MCPS_PROPRIETARY; - mcps.get_indication().status = LORAMAC_EVENT_INFO_STATUS_OK; - mcps.get_indication().buffer = _params.payload; - mcps.get_indication().buffer_size = size - pkt_header_len; + _mcps_indication.type = MCPS_PROPRIETARY; + _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_OK; + _mcps_indication.buffer = _params.payload; + _mcps_indication.buffer_size = size - pkt_header_len; _params.flags.bits.mcps_ind = 1; break; } default: - mcps.get_indication().status = LORAMAC_EVENT_INFO_STATUS_ERROR; + _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_ERROR; prepare_rx_done_abort(); break; } - // Verify if we need to disable the AckTimeoutTimer - check_to_disable_ack_timeout(_params.is_node_ack_requested, _device_class, mcps.get_confirmation().ack_received, + check_to_disable_ack_timeout(_params.is_node_ack_requested, _device_class, _mcps_confirmation.ack_received, _params.ack_timeout_retry_counter, _params.max_ack_timeout_retries ); if(_params.timers.ack_timeout_timer.timer_id == 0) { @@ -677,9 +652,8 @@ void LoRaMac::on_radio_tx_timeout( void ) open_continuous_rx2_window(); } - mcps.get_confirmation().status = LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT; - - mlme.get_confirmation().status = LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT; + _mcps_confirmation.status = LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT; + _mlme_confirmation.status = LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT; _params.flags.bits.mac_done = 1; } @@ -692,10 +666,10 @@ void LoRaMac::on_radio_rx_error( void ) if (_params.rx_slot == RX_SLOT_WIN_1) { if (_params.is_node_ack_requested == true) { - mcps.get_confirmation().status = LORAMAC_EVENT_INFO_STATUS_RX1_ERROR; + _mcps_confirmation.status = LORAMAC_EVENT_INFO_STATUS_RX1_ERROR; } - mlme.get_confirmation().status = LORAMAC_EVENT_INFO_STATUS_RX1_ERROR; + _mlme_confirmation.status = LORAMAC_EVENT_INFO_STATUS_RX1_ERROR; if (_device_class != CLASS_C) { if (_lora_time.get_elapsed_time(_params.timers.aggregated_last_tx_time) >= _params.rx_window2_delay) { @@ -705,10 +679,10 @@ void LoRaMac::on_radio_rx_error( void ) } } else { if (_params.is_node_ack_requested == true) { - mcps.get_confirmation().status = LORAMAC_EVENT_INFO_STATUS_RX2_ERROR; + _mcps_confirmation.status = LORAMAC_EVENT_INFO_STATUS_RX2_ERROR; } - mlme.get_confirmation().status = LORAMAC_EVENT_INFO_STATUS_RX2_ERROR; + _mlme_confirmation.status = LORAMAC_EVENT_INFO_STATUS_RX2_ERROR; if (_device_class != CLASS_C) { _params.flags.bits.mac_done = 1; @@ -728,9 +702,9 @@ void LoRaMac::on_radio_rx_timeout(void) if (_params.rx_slot == RX_SLOT_WIN_1) { if (_params.is_node_ack_requested == true) { - mcps.get_confirmation().status = LORAMAC_EVENT_INFO_STATUS_RX1_TIMEOUT; + _mcps_confirmation.status = LORAMAC_EVENT_INFO_STATUS_RX1_TIMEOUT; } - mlme.get_confirmation().status = LORAMAC_EVENT_INFO_STATUS_RX1_TIMEOUT; + _mlme_confirmation.status = LORAMAC_EVENT_INFO_STATUS_RX1_TIMEOUT; if (_device_class != CLASS_C) { if (_lora_time.get_elapsed_time(_params.timers.aggregated_last_tx_time ) >= _params.rx_window2_delay) { @@ -740,10 +714,10 @@ void LoRaMac::on_radio_rx_timeout(void) } } else { if (_params.is_node_ack_requested == true) { - mcps.get_confirmation().status = LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT; + _mcps_confirmation.status = LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT; } - mlme.get_confirmation().status = LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT; + _mlme_confirmation.status = LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT; if (_device_class != CLASS_C) { _params.flags.bits.mac_done = 1; @@ -773,25 +747,23 @@ void LoRaMac::on_mac_state_check_timer_event(void) if ((_params.flags.bits.mlme_req == 1) || (_params.flags.bits.mcps_req == 1)) { - if ((mcps.get_confirmation().status == LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT) || - ( mlme.get_confirmation().status == LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT)) { - // Stop transmit cycle due to tx timeout. + if ((_mcps_confirmation.status == LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT) || + (_mlme_confirmation.status == LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT)) { _params.mac_state &= ~LORAMAC_TX_RUNNING; mac_commands.clear_command_buffer(); - mcps.get_confirmation().nb_retries = _params.ack_timeout_retry_counter; - mcps.get_confirmation().ack_received = false; - mcps.get_confirmation().tx_toa = 0; + _mcps_confirmation.nb_retries = _params.ack_timeout_retry_counter; + _mcps_confirmation.ack_received = false; + _mcps_confirmation.tx_toa = 0; tx_timeout = true; } } if ((_params.is_node_ack_requested == false) && (tx_timeout == false)) { if ((_params.flags.bits.mlme_req == 1) || ((_params.flags.bits.mcps_req == 1))) { - if ((_params.flags.bits.mlme_req == 1) && (mlme.get_confirmation().req_type == MLME_JOIN)) { - // Procedure for the join request - mlme.get_confirmation().nb_retries = _params.join_request_trial_counter; + if ((_params.flags.bits.mlme_req == 1) && (_mlme_confirmation.req_type == MLME_JOIN)) { + _mlme_confirmation.nb_retries = _params.join_request_trial_counter; - if (mlme.get_confirmation().status == LORAMAC_EVENT_INFO_STATUS_OK) { + if (_mlme_confirmation.status == LORAMAC_EVENT_INFO_STATUS_OK) { // Node joined successfully _params.ul_frame_counter = 0; _params.ul_nb_rep_counter = 0; @@ -801,7 +773,7 @@ void LoRaMac::on_mac_state_check_timer_event(void) _params.mac_state &= ~LORAMAC_TX_RUNNING; } else { _params.flags.bits.mac_done = 0; - // Sends the same frame again + // Schedule a retry const int ret = ev_queue->call(this, &LoRaMac::on_tx_delayed_timer_event); MBED_ASSERT(ret != 0); (void)ret; @@ -809,11 +781,10 @@ void LoRaMac::on_mac_state_check_timer_event(void) } } } else { - // Procedure for all other frames if ((_params.ul_nb_rep_counter >= _params.sys_params.retry_num) || (_params.flags.bits.mcps_ind == 1)) { if (_params.flags.bits.mcps_ind == 0) { - // Maximum repetitions without downlink. Reset MacCommandsBufferIndex. Increase ADR Ack counter. + // Maximum repetitions without downlink. // Only process the case when the MAC did not receive a downlink. mac_commands.clear_command_buffer(); _params.adr_ack_counter++; @@ -828,7 +799,7 @@ void LoRaMac::on_mac_state_check_timer_event(void) _params.mac_state &= ~LORAMAC_TX_RUNNING; } else { _params.flags.bits.mac_done = 0; - // Sends the same frame again + // Schedule a retry const int ret = ev_queue->call(this, &LoRaMac::on_tx_delayed_timer_event); MBED_ASSERT(ret != 0); (void)ret; @@ -838,15 +809,14 @@ void LoRaMac::on_mac_state_check_timer_event(void) } if (_params.flags.bits.mcps_ind == 1) { - // Procedure if we received a frame - if ((mcps.get_confirmation().ack_received == true) || + if ((_mcps_confirmation.ack_received == true) || (_params.ack_timeout_retry_counter > _params.max_ack_timeout_retries)) { _params.is_ack_retry_timeout_expired = false; _params.is_node_ack_requested = false; if (_params.is_ul_frame_counter_fixed == false) { _params.ul_frame_counter++; } - mcps.get_confirmation().nb_retries = _params.ack_timeout_retry_counter; + _mcps_confirmation.nb_retries = _params.ack_timeout_retry_counter; _params.mac_state &= ~LORAMAC_TX_RUNNING; } @@ -872,14 +842,14 @@ void LoRaMac::on_mac_state_check_timer_event(void) _params.flags.bits.mac_done = 0; } else { // The DR is not applicable for the payload size - mcps.get_confirmation().status = LORAMAC_EVENT_INFO_STATUS_TX_DR_PAYLOAD_SIZE_ERROR; + _mcps_confirmation.status = LORAMAC_EVENT_INFO_STATUS_TX_DR_PAYLOAD_SIZE_ERROR; mac_commands.clear_command_buffer(); _params.mac_state &= ~LORAMAC_TX_RUNNING; _params.is_node_ack_requested = false; - mcps.get_confirmation().ack_received = false; - mcps.get_confirmation().nb_retries = _params.ack_timeout_retry_counter; - mcps.get_confirmation().data_rate = _params.sys_params.channel_data_rate; + _mcps_confirmation.ack_received = false; + _mcps_confirmation.nb_retries = _params.ack_timeout_retry_counter; + _mcps_confirmation.data_rate = _params.sys_params.channel_data_rate; if (_params.is_ul_frame_counter_fixed == false) { _params.ul_frame_counter++; @@ -892,8 +862,8 @@ void LoRaMac::on_mac_state_check_timer_event(void) mac_commands.clear_command_buffer(); _params.is_node_ack_requested = false; - mcps.get_confirmation().ack_received = false; - mcps.get_confirmation().nb_retries = _params.ack_timeout_retry_counter; + _mcps_confirmation.ack_received = false; + _mcps_confirmation.nb_retries = _params.ack_timeout_retry_counter; if (_params.is_ul_frame_counter_fixed == false) { _params.ul_frame_counter++; @@ -910,47 +880,40 @@ void LoRaMac::on_mac_state_check_timer_event(void) if (_params.mac_state == LORAMAC_IDLE) { if (_params.flags.bits.mcps_req == 1) { _params.flags.bits.mcps_req = 0; - mac_primitives->mcps_confirm(&mcps.get_confirmation()); + mac_primitives->mcps_confirm(&_mcps_confirmation); } if (_params.flags.bits.mlme_req == 1) { _params.flags.bits.mlme_req = 0; - mac_primitives->mlme_confirm(&mlme.get_confirmation()); + mac_primitives->mlme_confirm(&_mlme_confirmation); } - // Verify if sticky MAC commands are pending or not if (mac_commands.is_sticky_mac_command_pending() == true) { - // Setup MLME indication set_mlme_schedule_ul_indication(); } - // Procedure done. Reset variables. _params.flags.bits.mac_done = 0; } else { - // Operation not finished restart timer _lora_time.start(_params.timers.mac_state_check_timer, MAC_STATE_CHECK_TIMEOUT); } - // Handle MCPS indication if (_params.flags.bits.mcps_ind == 1) { _params.flags.bits.mcps_ind = 0; if (_device_class == CLASS_C) { - // Activate RX2 window for Class C open_continuous_rx2_window(); } if (_params.flags.bits.mcps_ind_skip == 0) { - mac_primitives->mcps_indication(&mcps.get_indication()); + mac_primitives->mcps_indication(&_mcps_indication); } _params.flags.bits.mcps_ind_skip = 0; } - // Handle MLME indication if (_params.flags.bits.mlme_ind == 1) { _params.flags.bits.mlme_ind = 0; - mac_primitives->mlme_indication(&mlme.get_indication()); + mac_primitives->mlme_indication(&_mlme_indication); } } @@ -965,7 +928,7 @@ void LoRaMac::on_tx_delayed_timer_event(void) _params.mac_state &= ~LORAMAC_TX_DELAYED; if ((_params.flags.bits.mlme_req == 1 ) && - (mlme.get_confirmation().req_type == MLME_JOIN)) { + (_mlme_confirmation.req_type == MLME_JOIN)) { reset_mac_parameters(); @@ -1007,7 +970,7 @@ void LoRaMac::on_rx_window1_timer_event(void) } _lora_phy.rx_config(&_params.rx_window1_config, - (int8_t*) &mcps.get_indication().rx_datarate); + (int8_t*) &_mcps_indication.rx_datarate); rx_window_setup(_params.rx_window1_config.is_rx_continuous, _params.sys_params.max_rx_win_time); @@ -1031,7 +994,7 @@ void LoRaMac::on_rx_window2_timer_event(void) } if (_lora_phy.rx_config(&_params.rx_window2_config, - (int8_t*) &mcps.get_indication().rx_datarate) == true) { + (int8_t*) &_mcps_indication.rx_datarate) == true) { rx_window_setup(_params.rx_window2_config.is_rx_continuous, _params.sys_params.max_rx_win_time); @@ -1057,16 +1020,12 @@ void LoRaMac::check_to_disable_ack_timeout(bool node_ack_requested, } else { if( ack_received == 1 ) { // SECOND CASE - // We have performed a confirmed uplink and have received a - // downlink with a valid ACK. + // We received an ACK for previously sent confirmable message _lora_time.stop(_params.timers.ack_timeout_timer); } else { // THIRD CASE + // Max number of retries exceeded for confirmable message if( ack_timeout_retries_counter > ack_timeout_retries ) { - // We have performed a confirmed uplink and have not - // received a downlink with a valid ACK. In this case - // we need to verify if the maximum retries have been - // elapsed. If so, stop the timer. _lora_time.stop(_params.timers.ack_timeout_timer); } } @@ -1112,7 +1071,7 @@ bool LoRaMac::validate_payload_length(uint8_t length, int8_t datarate, void LoRaMac::set_mlme_schedule_ul_indication(void) { - mlme.get_indication().indication_type = MLME_SCHEDULE_UPLINK; + _mlme_indication.indication_type = MLME_SCHEDULE_UPLINK; _params.flags.bits.mlme_ind = 1; } @@ -1130,19 +1089,17 @@ lorawan_status_t LoRaMac::send(loramac_mhdr_t *machdr, uint8_t fport, fctrl.bits.adr_ack_req = false; fctrl.bits.adr = _params.sys_params.adr_on; - // Prepare the frame lorawan_status_t status = prepare_frame(machdr, &fctrl, fport, fbuffer, fbuffer_size); - // Validate status if (status != LORAWAN_STATUS_OK) { return status; } // Reset confirm parameters - mcps.get_confirmation().nb_retries = 0; - mcps.get_confirmation().ack_received = false; - mcps.get_confirmation().ul_frame_counter = _params.ul_frame_counter; + _mcps_confirmation.nb_retries = 0; + _mcps_confirmation.ack_received = false; + _mcps_confirmation.ul_frame_counter = _params.ul_frame_counter; status = schedule_tx(); @@ -1155,7 +1112,6 @@ lorawan_status_t LoRaMac::schedule_tx(void) channel_selection_params_t nextChan; lorawan_status_t status = LORAWAN_STATUS_PARAMETER_INVALID; - // Check if the device is off if (_params.sys_params.max_duty_cycle == 255) { return LORAWAN_STATUS_DEVICE_OFF; } @@ -1164,7 +1120,6 @@ lorawan_status_t LoRaMac::schedule_tx(void) _params.timers.aggregated_timeoff = 0; } - // Update Backoff calculate_backOff(_params.last_channel_idx); nextChan.aggregate_timeoff = _params.timers.aggregated_timeoff; @@ -1174,7 +1129,6 @@ lorawan_status_t LoRaMac::schedule_tx(void) nextChan.joined = _is_nwk_joined; nextChan.last_aggregate_tx_time = _params.timers.aggregated_last_tx_time; - // Select channel status = _lora_phy.set_next_channel(&nextChan, &_params.channel, &dutyCycleTimeOff, &_params.timers.aggregated_timeoff); @@ -1184,7 +1138,6 @@ lorawan_status_t LoRaMac::schedule_tx(void) return status; case LORAWAN_STATUS_DUTYCYCLE_RESTRICTED: if (dutyCycleTimeOff != 0) { - // Send later - prepare timer tr_debug("Next Transmission in %lu ms", dutyCycleTimeOff); _params.mac_state |= LORAMAC_TX_DELAYED; _lora_time.start(_params.timers.tx_delayed_timer, dutyCycleTimeOff); @@ -1193,10 +1146,8 @@ lorawan_status_t LoRaMac::schedule_tx(void) default: break; } - tr_debug("Next Channel Idx=%d, DR=%d", _params.channel, nextChan.current_datarate); - // Compute Rx1 windows parameters uint8_t dr_offset = _lora_phy.apply_DR_offset(_params.sys_params.channel_data_rate, _params.sys_params.rx1_dr_offset); @@ -1204,7 +1155,6 @@ lorawan_status_t LoRaMac::schedule_tx(void) _params.sys_params.max_sys_rx_error, &_params.rx_window1_config); - // Compute Rx2 windows parameters _lora_phy.compute_rx_win_params(_params.sys_params.rx2_channel.datarate, _params.sys_params.min_rx_symb, _params.sys_params.max_sys_rx_error, @@ -1227,7 +1177,6 @@ lorawan_status_t LoRaMac::schedule_tx(void) + _params.rx_window2_config.window_offset; } - // Try to send now return send_frame_on_channel(_params.channel); } @@ -1243,7 +1192,6 @@ void LoRaMac::calculate_backOff(uint8_t channel) backoff_params.tx_toa = _params.timers.tx_toa; backoff_params.last_tx_was_join_req = _params.is_last_tx_join_request; - // Update regional back-off _lora_phy.calculate_backoff(&backoff_params); // Update aggregated time-off. This must be an assignment and no incremental @@ -1256,7 +1204,6 @@ void LoRaMac::reset_mac_parameters(void) { _is_nwk_joined = false; - // Counters _params.ul_frame_counter = 0; _params.dl_frame_counter = 0; _params.adr_ack_counter = 0; @@ -1281,14 +1228,11 @@ void LoRaMac::reset_mac_parameters(void) _params.is_node_ack_requested = false; _params.is_srv_ack_requested = false; - // Reset Multicast downlink counters multicast_params_t *cur = _params.multicast_channels; while (cur != NULL) { cur->dl_frame_counter = 0; cur = cur->next; } - - // Initialize channel index. _params.channel = 0; _params.last_channel_idx = _params.channel; } @@ -1307,11 +1251,9 @@ uint8_t LoRaMac::get_default_tx_datarate() return _lora_phy.get_default_tx_datarate(); } -lorawan_status_t LoRaMac::enable_adaptive_datarate(bool adr_enabled) +void LoRaMac::enable_adaptive_datarate(bool adr_enabled) { _params.sys_params.adr_on = adr_enabled; - - return LORAWAN_STATUS_OK; } lorawan_status_t LoRaMac::set_channel_data_rate(uint8_t data_rate) @@ -1355,15 +1297,9 @@ int16_t LoRaMac::prepare_ongoing_tx(uint8_t port, const uint8_t* data, { _ongoing_tx_msg.port = port; - uint8_t max_possible_size = query_tx_possible(length); + uint8_t max_possible_size = get_max_possible_tx_size(length); - //TODO: refactor following 20 lines or so. There must be a better way for this if (max_possible_size > MBED_CONF_LORA_TX_MAX_SIZE) { - // LORAWAN_APP_DATA_MAX_SIZE should at least be - // either equal to or bigger than maximum possible - // tx size because our tx message buffer takes its - // length from that macro. Force maximum possible tx unit - // to be equal to the buffer size user chose. max_possible_size = MBED_CONF_LORA_TX_MAX_SIZE; } @@ -1373,13 +1309,10 @@ int16_t LoRaMac::prepare_ongoing_tx(uint8_t port, const uint8_t* data, _ongoing_tx_msg.pending_size = length - max_possible_size; _ongoing_tx_msg.f_buffer_size = max_possible_size; - // copy user buffer upto the max_possible_size memcpy(_ongoing_tx_msg.f_buffer, data, _ongoing_tx_msg.f_buffer_size); } else { - // Whole message can be sent at one time _ongoing_tx_msg.f_buffer_size = length; _ongoing_tx_msg.pending_size = 0; - // copy user buffer upto the max_possible_size if (length > 0) { memcpy(_ongoing_tx_msg.f_buffer, data, length); } @@ -1427,7 +1360,7 @@ lorawan_status_t LoRaMac::send_ongoing_tx() loramac_mhdr_t machdr; machdr.value = 0; - mcps.reset_confirmation(); + reset_mcps_confirmation(); _params.ack_timeout_retry_counter = 1; _params.max_ack_timeout_retries = 1; @@ -1438,7 +1371,7 @@ lorawan_status_t LoRaMac::send_ongoing_tx() machdr.bits.mtype = FRAME_TYPE_DATA_CONFIRMED_UP; _params.max_ack_timeout_retries = _ongoing_tx_msg.nb_trials; } else if ( _ongoing_tx_msg.type == MCPS_PROPRIETARY) { - //Is this dead code currently??? Nobody sets this type + //TODO: Is this dead code currently??? Nobody sets this type machdr.bits.mtype = FRAME_TYPE_PROPRIETARY; } else { return LORAWAN_STATUS_SERVICE_UNKNOWN; @@ -1455,7 +1388,7 @@ lorawan_status_t LoRaMac::send_ongoing_tx() status = send(&machdr, _ongoing_tx_msg.fport, _ongoing_tx_msg.f_buffer, _ongoing_tx_msg.f_buffer_size); if (status == LORAWAN_STATUS_OK) { - mcps.get_confirmation().req_type = _ongoing_tx_msg.type; + _mcps_confirmation.req_type = _ongoing_tx_msg.type; _params.flags.bits.mcps_req = 1; } else { _params.is_node_ack_requested = false; @@ -1474,14 +1407,10 @@ void LoRaMac::set_device_class(const device_class_t& device_class) _device_class = device_class; if (CLASS_A == _device_class) { - // Set the radio into sleep to setup a defined state _lora_phy.put_radio_to_sleep(); } else if (CLASS_C == _device_class) { - // Set the is_node_ack_requested indicator to default _params.is_node_ack_requested = false; - // Set the radio into sleep mode in case we are still in RX mode _lora_phy.put_radio_to_sleep(); - // Compute Rx2 windows parameters in case the RX2 datarate has changed _lora_phy.compute_rx_win_params( _params.sys_params.rx2_channel.datarate, _params.sys_params.min_rx_symb, @@ -1495,9 +1424,9 @@ void LoRaMac::set_device_class(const device_class_t& device_class) void LoRaMac::setup_link_check_request() { - mlme.reset_confirmation(); + reset_mlme_confirmation(); - mlme.get_confirmation().req_type = MLME_LINK_CHECK; + _mlme_confirmation.req_type = MLME_LINK_CHECK; _params.flags.bits.mlme_req = 1; mac_commands.add_mac_command(MOTE_MAC_LINK_CHECK_REQ, 0, 0); } @@ -1508,19 +1437,19 @@ lorawan_status_t LoRaMac::join_by_otaa(const lorawan_connect_otaa_t& otaa_join) return LORAWAN_STATUS_BUSY; } - mlme.reset_confirmation(); + reset_mlme_confirmation(); - mlme.get_confirmation().req_type = MLME_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)) { + 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; @@ -1549,7 +1478,6 @@ lorawan_status_t LoRaMac::join_by_otaa(const lorawan_connect_otaa_t& otaa_join) 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, @@ -1628,7 +1556,6 @@ lorawan_status_t LoRaMac::prepare_frame(loramac_mhdr_t *machdr, //Intentional fallthrough case FRAME_TYPE_DATA_UNCONFIRMED_UP: { if (!_is_nwk_joined) { - // No network has been joined yet return LORAWAN_STATUS_NO_NETWORK_JOINED; } @@ -1657,7 +1584,6 @@ lorawan_status_t LoRaMac::prepare_frame(loramac_mhdr_t *machdr, _params.buffer[pkt_header_len++] = (_params.ul_frame_counter >> 8) & 0xFF; - // Copy the MAC commands which must be re-send into the MAC command buffer mac_commands.copy_repeat_commands_to_buffer(); const uint8_t mac_commands_len = mac_commands.get_mac_cmd_length(); @@ -1690,40 +1616,29 @@ lorawan_status_t LoRaMac::prepare_frame(loramac_mhdr_t *machdr, } } - // Store MAC commands which must be re-send in case the device does not receive a downlink anymore mac_commands.parse_mac_commands_to_repeat(); if ((payload != NULL) && (_params.payload_length > 0)) { _params.buffer[pkt_header_len++] = frame_port; + uint8_t *key = _params.keys.app_skey; if (frame_port == 0) { - // Reset buffer index as the mac commands are being sent on port 0 mac_commands.clear_command_buffer(); - if (0 != encrypt_payload((uint8_t*) payload, _params.payload_length, - _params.keys.nwk_skey, _params.dev_addr, - UP_LINK, - _params.ul_frame_counter, - &_params.buffer[pkt_header_len])) { - status = LORAWAN_STATUS_CRYPTO_FAIL; - } - } else { - if (0 != encrypt_payload((uint8_t*) payload, _params.payload_length, - _params.keys.app_skey, _params.dev_addr, - UP_LINK, - _params.ul_frame_counter, - &_params.buffer[pkt_header_len])) { - status = LORAWAN_STATUS_CRYPTO_FAIL; - } + key = _params.keys.nwk_skey; + } + if (0 != encrypt_payload((uint8_t*) payload, _params.payload_length, + key, _params.dev_addr, UP_LINK, + _params.ul_frame_counter, + &_params.buffer[pkt_header_len])) { + status = LORAWAN_STATUS_CRYPTO_FAIL; } } _params.buffer_pkt_len = pkt_header_len + _params.payload_length; if (0 != compute_mic(_params.buffer, _params.buffer_pkt_len, - _params.keys.nwk_skey, - _params.dev_addr, - UP_LINK, - _params.ul_frame_counter, &mic)) { + _params.keys.nwk_skey, _params.dev_addr, + UP_LINK, _params.ul_frame_counter, &mic)) { status = LORAWAN_STATUS_CRYPTO_FAIL; } @@ -1763,18 +1678,16 @@ lorawan_status_t LoRaMac::send_frame_on_channel(uint8_t channel) _lora_phy.tx_config(&tx_config, &tx_power, &_params.timers.tx_toa); - mlme.get_confirmation().status = LORAMAC_EVENT_INFO_STATUS_ERROR; + _mlme_confirmation.status = LORAMAC_EVENT_INFO_STATUS_ERROR; - mcps.get_confirmation().status = LORAMAC_EVENT_INFO_STATUS_ERROR; - mcps.get_confirmation().data_rate = _params.sys_params.channel_data_rate; - mcps.get_confirmation().tx_power = tx_power; - mcps.get_confirmation().channel = channel; + _mcps_confirmation.status = LORAMAC_EVENT_INFO_STATUS_ERROR; + _mcps_confirmation.data_rate = _params.sys_params.channel_data_rate; + _mcps_confirmation.tx_power = tx_power; + _mcps_confirmation.channel = channel; - // Store the time on air - mcps.get_confirmation().tx_toa = _params.timers.tx_toa; - mlme.get_confirmation().tx_toa = _params.timers.tx_toa; + _mcps_confirmation.tx_toa = _params.timers.tx_toa; + _mlme_confirmation.tx_toa = _params.timers.tx_toa; - // Starts the MAC layer status check timer _lora_time.start(_params.timers.mac_state_check_timer, MAC_STATE_CHECK_TIMEOUT); @@ -1782,7 +1695,6 @@ lorawan_status_t LoRaMac::send_frame_on_channel(uint8_t channel) _params.join_request_trial_counter++; } - // Send now _lora_phy.handle_send(_params.buffer, _params.buffer_pkt_len); _params.mac_state |= LORAMAC_TX_RUNNING; @@ -1790,25 +1702,44 @@ lorawan_status_t LoRaMac::send_frame_on_channel(uint8_t channel) return LORAWAN_STATUS_OK; } +void LoRaMac::reset_mcps_confirmation() +{ + memset((uint8_t*) &_mcps_confirmation, 0, sizeof(_mcps_confirmation)); + _mcps_confirmation.status = LORAMAC_EVENT_INFO_STATUS_ERROR; +} + +void LoRaMac::reset_mlme_confirmation() +{ + memset((uint8_t*) &_mlme_confirmation, 0, sizeof(_mlme_confirmation)); + _mlme_confirmation.status = LORAMAC_EVENT_INFO_STATUS_ERROR; +} + +void LoRaMac::set_tx_continuous_wave(uint8_t channel, int8_t datarate, int8_t tx_power, + float max_eirp, float antenna_gain, uint16_t timeout) +{ + cw_mode_params_t continuous_wave; + + continuous_wave.channel = channel; + continuous_wave.datarate = datarate; + continuous_wave.tx_power = tx_power; + continuous_wave.max_eirp = max_eirp; + continuous_wave.antenna_gain = antenna_gain; + continuous_wave.timeout = timeout; + + _lora_phy.set_tx_cont_mode(&continuous_wave); +} + lorawan_status_t LoRaMac::initialize(loramac_primitives_t *primitives, EventQueue *queue) { _lora_time.activate_timer_subsystem(queue); - //store event queue pointer ev_queue = queue; if (!primitives) { return LORAWAN_STATUS_PARAMETER_INVALID; } - // Activate MLME subsystem - mlme.activate_mlme_subsystem(&_lora_phy); - - // Activate MCPS subsystem - mcps.activate_mcps_subsystem(); - - // Activate channel planning subsystem channel_plan.activate_channelplan_subsystem(&_lora_phy); mac_primitives = primitives; @@ -1822,27 +1753,23 @@ lorawan_status_t LoRaMac::initialize(loramac_primitives_t *primitives, _params.max_join_request_trials = 1; _params.is_repeater_supported = false; - // Reset duty cycle times _params.timers.aggregated_last_tx_time = 0; _params.timers.aggregated_timeoff = 0; _lora_phy.reset_to_default_values(&_params, true); - // Init parameters which are not set in function ResetMacParameters _params.sys_params.max_sys_rx_error = 10; _params.sys_params.min_rx_symb = 6; _params.sys_params.retry_num = 1; reset_mac_parameters(); - // Random seed initialization srand(_lora_phy.get_radio_rng()); _params.is_nwk_public = MBED_CONF_LORA_PUBLIC_NETWORK; _lora_phy.setup_public_network_mode(_params.is_nwk_public); _lora_phy.put_radio_to_sleep(); - // Initialize timers _lora_time.init(_params.timers.mac_state_check_timer, mbed::callback(this, &LoRaMac::on_mac_state_check_timer_event)); _lora_time.init(_params.timers.tx_delayed_timer, @@ -1854,7 +1781,6 @@ lorawan_status_t LoRaMac::initialize(loramac_primitives_t *primitives, _lora_time.init(_params.timers.ack_timeout_timer, mbed::callback(this, &LoRaMac::on_ack_timeout_timer_event)); - // Store the current initialization time _params.timers.mac_init_time = _lora_time.get_current_time(); _params.sys_params.adr_on = MBED_CONF_LORA_ADR_ON; @@ -1867,17 +1793,14 @@ lorawan_status_t LoRaMac::initialize(loramac_primitives_t *primitives, void LoRaMac::disconnect() { - // Cancel all timers _lora_time.stop(_params.timers.mac_state_check_timer); _lora_time.stop(_params.timers.tx_delayed_timer); _lora_time.stop(_params.timers.rx_window1_timer); _lora_time.stop(_params.timers.rx_window2_timer); _lora_time.stop(_params.timers.ack_timeout_timer); - // Put radio to sleep _lora_phy.put_radio_to_sleep(); - // Reset internal state _is_nwk_joined = false; _params.is_ack_retry_timeout_expired = false; _params.is_rx_window_enabled = true; @@ -1886,23 +1809,20 @@ void LoRaMac::disconnect() _params.flags.value = 0; _params.mac_state = 0; - // Clear MAC commands mac_commands.clear_command_buffer(); mac_commands.clear_repeat_buffer(); mac_commands.clear_mac_commands_in_next_tx(); - // Set internal state to idle. _params.mac_state = LORAMAC_IDLE; } -uint8_t LoRaMac::query_tx_possible(uint8_t size) +uint8_t LoRaMac::get_max_possible_tx_size(uint8_t size) { uint8_t max_possible_payload_size = 0; uint8_t current_payload_size = 0; uint8_t fopt_len = mac_commands.get_mac_cmd_length() + mac_commands.get_repeat_commands_length(); - // if application has turned on ADR, we want to opt it out if (_params.sys_params.adr_on) { _lora_phy.get_next_ADR(false, _params.sys_params.channel_data_rate, _params.sys_params.channel_tx_power, @@ -1911,19 +1831,15 @@ uint8_t LoRaMac::query_tx_possible(uint8_t size) current_payload_size = _lora_phy.get_max_payload(_params.sys_params.channel_data_rate, _params.is_repeater_supported); - // Verify if the fOpts fit into the maximum payload if (current_payload_size >= fopt_len) { max_possible_payload_size = current_payload_size - fopt_len; } else { max_possible_payload_size = current_payload_size; - // The fOpts don't fit into the maximum payload. Omit the MAC commands to - // ensure that another uplink is possible. fopt_len = 0; mac_commands.clear_command_buffer(); mac_commands.clear_repeat_buffer(); } - // Verify if the fOpts and the payload fit into the maximum payload if (validate_payload_length(size, _params.sys_params.channel_data_rate, fopt_len) == false) { return max_possible_payload_size; @@ -1943,7 +1859,6 @@ void LoRaMac::set_nwk_joined(bool joined) lorawan_status_t LoRaMac::add_channel_plan(const lorawan_channelplan_t& plan) { - // Validate if the MAC is in a correct state if ((_params.mac_state & LORAMAC_TX_RUNNING) == LORAMAC_TX_RUNNING) { if ((_params.mac_state & LORAMAC_TX_CONFIG) != LORAMAC_TX_CONFIG) { return LORAWAN_STATUS_BUSY; @@ -1962,7 +1877,6 @@ lorawan_status_t LoRaMac::remove_channel_plan() } return channel_plan.remove_plan(); - } lorawan_status_t LoRaMac::get_channel_plan(lorawan_channelplan_t& plan) @@ -1990,20 +1904,15 @@ lorawan_status_t LoRaMac::multicast_channel_link(multicast_params_t *channel_par return LORAWAN_STATUS_BUSY; } - // Reset downlink counter channel_param->dl_frame_counter = 0; if (_params.multicast_channels == NULL) { - // New node is the fist element _params.multicast_channels = channel_param; } else { multicast_params_t *cur = _params.multicast_channels; - - // Search the last node in the list while (cur->next != NULL) { cur = cur->next; } - // This function always finds the last node cur->next = channel_param; } @@ -2022,16 +1931,14 @@ lorawan_status_t LoRaMac::multicast_channel_unlink( if (_params.multicast_channels != NULL) { if (_params.multicast_channels == channel_param) { - // First element _params.multicast_channels = channel_param->next; } else { multicast_params_t *cur = _params.multicast_channels; - // Search the node in the list while (cur->next && cur->next != channel_param) { cur = cur->next; } - // If we found the node, remove it + if (cur->next) { cur->next = channel_param->next; } @@ -2068,15 +1975,15 @@ lorawan_status_t LoRaMac::mlme_request( loramac_mlme_req_t *mlmeRequest ) return LORAWAN_STATUS_BUSY; } - mlme.reset_confirmation(); + reset_mlme_confirmation(); - mlme.get_confirmation().req_type = mlmeRequest->type; + _mlme_confirmation.req_type = mlmeRequest->type; _params.flags.bits.mlme_req = 1; lorawan_status_t status = LORAWAN_STATUS_SERVICE_UNKNOWN; if (MLME_TXCW == mlmeRequest->type) { - mlme.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); _lora_time.start(_params.timers.mac_state_check_timer, MAC_STATE_CHECK_TIMEOUT); @@ -2084,7 +1991,7 @@ lorawan_status_t LoRaMac::mlme_request( loramac_mlme_req_t *mlmeRequest ) _params.mac_state |= LORAMAC_TX_RUNNING; status = LORAWAN_STATUS_OK; } else if (MLME_TXCW_1 == mlmeRequest->type) { - mlme.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, MAC_STATE_CHECK_TIMEOUT); @@ -2116,7 +2023,7 @@ lorawan_status_t LoRaMac::mcps_request( loramac_mcps_req_t *mcpsRequest ) machdr.value = 0; - mcps.reset_confirmation(); + reset_mcps_confirmation(); _params.ack_timeout_retry_counter = 1; _params.max_ack_timeout_retries = 1; @@ -2156,7 +2063,7 @@ lorawan_status_t LoRaMac::mcps_request( loramac_mcps_req_t *mcpsRequest ) lorawan_status_t status = send(&machdr, mcpsRequest->fport, mcpsRequest->f_buffer, mcpsRequest->f_buffer_size); if (status == LORAWAN_STATUS_OK) { - mcps.get_confirmation().req_type = mcpsRequest->type; + _mcps_confirmation.req_type = mcpsRequest->type; _params.flags.bits.mcps_req = 1; } else { _params.is_node_ack_requested = false; diff --git a/features/lorawan/lorastack/mac/LoRaMac.h b/features/lorawan/lorastack/mac/LoRaMac.h index eda2c152adc..3b92b843592 100644 --- a/features/lorawan/lorastack/mac/LoRaMac.h +++ b/features/lorawan/lorastack/mac/LoRaMac.h @@ -45,8 +45,6 @@ #include "lorawan/system/lorawan_data_structures.h" #include "LoRaMacCommand.h" #include "events/EventQueue.h" -#include "LoRaMacMlme.h" -#include "LoRaMacMcps.h" #include "LoRaMacChannelPlan.h" #include "loraphy_target.h" @@ -104,7 +102,7 @@ class LoRaMac { * not fit into the payload size on the related datarate, the LoRaMAC will * omit the MAC commands. */ - uint8_t query_tx_possible(uint8_t size); + uint8_t get_max_possible_tx_size(uint8_t size); /** * @brief nwk_joined Checks if device has joined to network @@ -292,9 +290,8 @@ class LoRaMac { /** * @brief enable_adaptive_datarate Enables or disables adaptive datarate. * @param adr_enabled Flag indicating is adr enabled or disabled. - * @return LORAWAN_STATUS_OK or a negative error code on failure. */ - lorawan_status_t enable_adaptive_datarate(bool adr_enabled); + void enable_adaptive_datarate(bool adr_enabled); /** Sets up the data rate. * @@ -491,6 +488,28 @@ class LoRaMac { */ lorawan_status_t send_frame_on_channel(uint8_t channel); + /** + * @brief reset_mcps_confirmation Resets the MCPS confirmation struct + */ + void reset_mcps_confirmation(); + + /** + * @brief reset_mlme_confirmation Resets the MLME confirmation struct + */ + void reset_mlme_confirmation(); + + /** + * @brief set_tx_continuous_wave Puts the system in continuous transmission mode + * @param [in] channel A Channel to use + * @param [in] datarate A datarate to use + * @param [in] tx_power A RF output power to use + * @param [in] max_eirp A maximum possible EIRP to use + * @param [in] antenna_gain Antenna gain to use + * @param [in] timeout Time in seconds while the radio is kept in continuous wave mode + */ + void set_tx_continuous_wave(uint8_t channel, int8_t datarate, int8_t tx_power, + float max_eirp, float antenna_gain, uint16_t timeout); + /** * Prototypes for ISR handlers */ @@ -518,16 +537,6 @@ class LoRaMac { */ LoRaMacCommand mac_commands; - /** - * MLME subsystem handle - */ - LoRaMacMlme mlme; - - /** - * MCPS subsystem handle - */ - LoRaMacMcps mcps; - /** * Channel planning subsystem */ @@ -553,6 +562,26 @@ class LoRaMac { */ events::EventQueue *ev_queue; + /** + * Structure to hold MCPS indication data. + */ + loramac_mcps_indication_t _mcps_indication; + + /** + * Structure to hold MCPS confirm data. + */ + loramac_mcps_confirm_t _mcps_confirmation; + + /** + * Structure to hold MLME indication data. + */ + loramac_mlme_indication_t _mlme_indication; + + /** + * Structure to hold MLME confirm data. + */ + loramac_mlme_confirm_t _mlme_confirmation; + loramac_tx_message_t _ongoing_tx_msg; bool _is_nwk_joined; diff --git a/features/lorawan/lorastack/mac/LoRaMacMcps.cpp b/features/lorawan/lorastack/mac/LoRaMacMcps.cpp deleted file mode 100644 index ab340e10d01..00000000000 --- a/features/lorawan/lorastack/mac/LoRaMacMcps.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/** - / _____) _ | | -( (____ _____ ____ _| |_ _____ ____| |__ - \____ \| ___ | (_ _) ___ |/ ___) _ \ - _____) ) ____| | | || |_| ____( (___| | | | -(______/|_____)_|_|_| \__)_____)\____)_| |_| - (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 -*/ - -#include "LoRaMac.h" -#include "lorastack/mac/LoRaMacMcps.h" - -LoRaMacMcps::LoRaMacMcps() -{ -} - -LoRaMacMcps::~LoRaMacMcps() -{ -} - -void LoRaMacMcps::reset_confirmation() -{ - memset((uint8_t*) &confirmation, 0, sizeof(confirmation)); - - confirmation.status = LORAMAC_EVENT_INFO_STATUS_ERROR; -} - -loramac_mcps_confirm_t& LoRaMacMcps::get_confirmation() -{ - return confirmation; -} - -loramac_mcps_indication_t& LoRaMacMcps::get_indication() -{ - return indication; -} - -void LoRaMacMcps::activate_mcps_subsystem() -{ -} - diff --git a/features/lorawan/lorastack/mac/LoRaMacMcps.h b/features/lorawan/lorastack/mac/LoRaMacMcps.h deleted file mode 100644 index 84093511e3b..00000000000 --- a/features/lorawan/lorastack/mac/LoRaMacMcps.h +++ /dev/null @@ -1,88 +0,0 @@ -/** - / _____) _ | | -( (____ _____ ____ _| |_ _____ ____| |__ - \____ \| ___ | (_ _) ___ |/ ___) _ \ - _____) ) ____| | | || |_| ____( (___| | | | -(______/|_____)_|_|_| \__)_____)\____)_| |_| - (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 -*/ - -#ifndef MBED_OS_LORAWAN_MAC_MCPS_H_ -#define MBED_OS_LORAWAN_MAC_MCPS_H_ - -#include "lorawan/system/lorawan_data_structures.h" -#include "lorastack/phy/LoRaPHY.h" - -// forward declaration -class LoRaMac; - -class LoRaMacMcps { - -public: - - /** Constructor - * - * Sets local handles to NULL. These handles will be set when the subsystem - * is activated by the MAC layer. - */ - LoRaMacMcps(); - - /** Destructor - * - * Does nothing - */ - ~LoRaMacMcps(); - - /** - * @brief reset_confirmation Resets the confirmation struct - */ - void reset_confirmation(); - - /** Activating MCPS subsystem - * - * Stores pointers to MAC and PHY layer handles - */ - void activate_mcps_subsystem(); - - /** Grants access to MCPS confirmation data - * - * @return a reference to MCPS confirm data structure - */ - loramac_mcps_confirm_t& get_confirmation(); - - /** Grants access to MCPS indication data - * - * @return a reference to MCPS indication data structure - */ - loramac_mcps_indication_t& get_indication(); - -private: - - /** - * Structure to hold MCPS indication data. - */ - loramac_mcps_indication_t indication; - - /** - * Structure to hold MCPS confirm data. - */ - loramac_mcps_confirm_t confirmation; -}; - -#endif /* MBED_OS_LORAWAN_MAC_MCPS_H_ */ diff --git a/features/lorawan/lorastack/mac/LoRaMacMlme.cpp b/features/lorawan/lorastack/mac/LoRaMacMlme.cpp deleted file mode 100644 index 9153fa0d541..00000000000 --- a/features/lorawan/lorastack/mac/LoRaMacMlme.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/** - / _____) _ | | -( (____ _____ ____ _| |_ _____ ____| |__ - \____ \| ___ | (_ _) ___ |/ ___) _ \ - _____) ) ____| | | || |_| ____( (___| | | | -(______/|_____)_|_|_| \__)_____)\____)_| |_| - (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 -*/ - -#include "LoRaMac.h" -#include "lorastack/mac/LoRaMacMlme.h" - -LoRaMacMlme::LoRaMacMlme() -: _lora_phy(NULL) -{ -} - -LoRaMacMlme::~LoRaMacMlme() -{ -} - -void LoRaMacMlme::reset_confirmation() -{ - memset((uint8_t*) &confirmation, 0, sizeof(confirmation)); - - confirmation.status = LORAMAC_EVENT_INFO_STATUS_ERROR; -} - -loramac_mlme_confirm_t& LoRaMacMlme::get_confirmation() -{ - return confirmation; -} - -loramac_mlme_indication_t& LoRaMacMlme::get_indication() -{ - return indication; -} - -void LoRaMacMlme::activate_mlme_subsystem(LoRaPHY *phy) -{ - _lora_phy = phy; -} - -void LoRaMacMlme::set_tx_continuous_wave(uint8_t channel, int8_t datarate, int8_t tx_power, - float max_eirp, float antenna_gain, uint16_t timeout) -{ - cw_mode_params_t continuous_wave; - - continuous_wave.channel = channel; - continuous_wave.datarate = datarate; - continuous_wave.tx_power = tx_power; - continuous_wave.max_eirp = max_eirp; - continuous_wave.antenna_gain = antenna_gain; - continuous_wave.timeout = timeout; - - _lora_phy->set_tx_cont_mode(&continuous_wave); -} diff --git a/features/lorawan/lorastack/mac/LoRaMacMlme.h b/features/lorawan/lorastack/mac/LoRaMacMlme.h deleted file mode 100644 index 82089d19c72..00000000000 --- a/features/lorawan/lorastack/mac/LoRaMacMlme.h +++ /dev/null @@ -1,107 +0,0 @@ -/** - / _____) _ | | -( (____ _____ ____ _| |_ _____ ____| |__ - \____ \| ___ | (_ _) ___ |/ ___) _ \ - _____) ) ____| | | || |_| ____( (___| | | | -(______/|_____)_|_|_| \__)_____)\____)_| |_| - (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 -*/ - -#ifndef MBED_OS_LORAWAN_MAC_MLME_H_ -#define MBED_OS_LORAWAN_MAC_MLME_H_ - -#include "lorawan/system/lorawan_data_structures.h" -#include "lorastack/phy/LoRaPHY.h" - -// forward declaration -class LoRaMac; - -class LoRaMacMlme { - -public: - - /** Constructor - * - * Sets local handles to NULL. These handles will be set when the subsystem - * is activated by the MAC layer. - */ - LoRaMacMlme(); - - /** Destructor - * - * Does nothing - */ - ~LoRaMacMlme(); - - /** - * @brief reset_confirmation Resets the confirmation struct - */ - void reset_confirmation(); - - /** Activating MLME subsystem - * - * Stores pointers to MAC and PHY layer handles - * - * @param phy pointer to PHY layer - */ - void activate_mlme_subsystem(LoRaPHY *phy); - - /** Grants access to MLME confirmation data - * - * @return a reference to MLME confirm data structure - */ - loramac_mlme_confirm_t& get_confirmation(); - - /** Grants access to MLME indication data - * - * @return a reference to MLME indication data structure - */ - loramac_mlme_indication_t& get_indication(); - - /** - * @brief set_tx_continuous_wave Puts the system in continuous transmission mode - * @param [in] channel A Channel to use - * @param [in] datarate A datarate to use - * @param [in] tx_power A RF output power to use - * @param [in] max_eirp A maximum possible EIRP to use - * @param [in] antenna_gain Antenna gain to use - * @param [in] timeout Time in seconds while the radio is kept in continuous wave mode - */ - void set_tx_continuous_wave(uint8_t channel, int8_t datarate, int8_t tx_power, - float max_eirp, float antenna_gain, uint16_t timeout); - -private: - - /** - * Pointer to PHY handle - */ - LoRaPHY *_lora_phy; - - /** - * Structure to hold MLME indication data. - */ - loramac_mlme_indication_t indication; - - /** - * Structure to hold MLME confirm data. - */ - loramac_mlme_confirm_t confirmation; -}; - -#endif /* MBED_OS_LORAWAN_MAC_MLME_H_ */ diff --git a/features/lorawan/lorastack/phy/LoRaPHY.h b/features/lorawan/lorastack/phy/LoRaPHY.h index ca895bde7d6..97fb2b8e8bf 100644 --- a/features/lorawan/lorastack/phy/LoRaPHY.h +++ b/features/lorawan/lorastack/phy/LoRaPHY.h @@ -512,10 +512,6 @@ class LoRaPHY : private mbed::NonCopyable { bool verify_nb_join_trials(uint8_t nb_join_trials); protected: - LoRaRadio *_radio; - LoRaWANTimeHandler &_lora_time; - loraphy_params_t phy_params; - LoRaPHY(LoRaWANTimeHandler &lora_time); /** @@ -616,6 +612,11 @@ class LoRaPHY : private mbed::NonCopyable { uint8_t* delayTx); bool is_datarate_supported(const int8_t datarate) const; + +protected: + LoRaRadio *_radio; + LoRaWANTimeHandler &_lora_time; + loraphy_params_t phy_params; }; #endif /* MBED_OS_LORAPHY_BASE_ */ From dc982281394bb9880148ae94ef41da71807669b5 Mon Sep 17 00:00:00 2001 From: Antti Kauppila Date: Tue, 20 Mar 2018 11:56:19 +0200 Subject: [PATCH 22/25] LoRa: Struct cleanups - Unneeded structs removed and replaced by variables in functions --- features/lorawan/lorastack/mac/LoRaMac.cpp | 23 +--- .../lorawan/lorastack/mac/LoRaMacCommand.cpp | 44 +++---- features/lorawan/lorastack/phy/LoRaPHY.cpp | 69 +++++----- features/lorawan/lorastack/phy/LoRaPHY.h | 72 +++++----- features/lorawan/lorastack/phy/lora_phy_ds.h | 124 +----------------- 5 files changed, 105 insertions(+), 227 deletions(-) diff --git a/features/lorawan/lorastack/mac/LoRaMac.cpp b/features/lorawan/lorastack/mac/LoRaMac.cpp index a5f38579487..6ccd2ba4000 100644 --- a/features/lorawan/lorastack/mac/LoRaMac.cpp +++ b/features/lorawan/lorastack/mac/LoRaMac.cpp @@ -182,7 +182,6 @@ void LoRaMac::handle_fhss_change_channel(uint8_t cur_channel) **************************************************************************/ void LoRaMac::on_radio_tx_done( void ) { - set_band_txdone_params_t tx_done_params; lorawan_time_t cur_time = _lora_time.get_current_time( ); if (_device_class != CLASS_C) { @@ -223,10 +222,7 @@ void LoRaMac::on_radio_tx_done( void ) _params.last_channel_idx = _params.channel; - tx_done_params.channel = _params.channel; - tx_done_params.joined = _is_nwk_joined; - tx_done_params.last_tx_done_time = cur_time; - _lora_phy.set_last_tx_done(&tx_done_params); + _lora_phy.set_last_tx_done(_params.channel, _is_nwk_joined, cur_time); _params.timers.aggregated_last_tx_time = cur_time; @@ -257,7 +253,6 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, { loramac_mhdr_t mac_hdr; loramac_frame_ctrl_t fctrl; - cflist_params_t cflist; uint8_t pkt_header_len = 0; uint32_t address = 0; @@ -361,11 +356,8 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, _params.sys_params.recv_delay1 *= 1000; _params.sys_params.recv_delay2 = _params.sys_params.recv_delay1 + 1000; - cflist.payload = &_params.payload[13]; // Size of the regular payload is 12. Plus 1 byte MHDR and 4 bytes MIC - cflist.size = size - 17; - - _lora_phy.apply_cf_list(&cflist); + _lora_phy.apply_cf_list(&_params.payload[13], size - 17); _mlme_confirmation.status = LORAMAC_EVENT_INFO_STATUS_OK; _is_nwk_joined = true; @@ -1182,17 +1174,12 @@ lorawan_status_t LoRaMac::schedule_tx(void) void LoRaMac::calculate_backOff(uint8_t channel) { - backoff_params_t backoff_params; + lorawan_time_t elapsed_time = _lora_time.get_elapsed_time(_params.timers.mac_init_time); - backoff_params.joined = _is_nwk_joined; _params.is_dutycycle_on = MBED_CONF_LORA_DUTY_CYCLE_ON; - backoff_params.dc_enabled = _params.is_dutycycle_on; - backoff_params.channel = channel; - backoff_params.elapsed_time = _lora_time.get_elapsed_time(_params.timers.mac_init_time); - backoff_params.tx_toa = _params.timers.tx_toa; - backoff_params.last_tx_was_join_req = _params.is_last_tx_join_request; - _lora_phy.calculate_backoff(&backoff_params); + _lora_phy.calculate_backoff(_is_nwk_joined, _params.is_last_tx_join_request, _params.is_dutycycle_on, + channel, elapsed_time, _params.timers.tx_toa); // Update aggregated time-off. This must be an assignment and no incremental // update as we do only calculate the time-off based on the last transmission diff --git a/features/lorawan/lorastack/mac/LoRaMacCommand.cpp b/features/lorawan/lorastack/mac/LoRaMacCommand.cpp index f383cfa7db0..5b6c724a201 100644 --- a/features/lorawan/lorastack/mac/LoRaMacCommand.cpp +++ b/features/lorawan/lorastack/mac/LoRaMacCommand.cpp @@ -345,11 +345,8 @@ lorawan_status_t LoRaMacCommand::process_mac_commands(uint8_t *payload, uint8_t break; } case SRV_MAC_NEW_CHANNEL_REQ: { - new_channel_req_params_t newChannelReq; channel_params_t chParam; - - newChannelReq.channel_id = payload[mac_index++]; - newChannelReq.new_channel = &chParam; + int8_t channel_id = payload[mac_index++]; chParam.frequency = (uint32_t) payload[mac_index++]; chParam.frequency |= (uint32_t) payload[mac_index++] << 8; @@ -358,7 +355,7 @@ lorawan_status_t LoRaMacCommand::process_mac_commands(uint8_t *payload, uint8_t chParam.rx1_frequency = 0; chParam.dr_range.value = payload[mac_index++]; - status = lora_phy.request_new_channel(&newChannelReq); + status = lora_phy.request_new_channel(channel_id, &chParam); ret_value = add_mac_command(MOTE_MAC_NEW_CHANNEL_ANS, status, 0); } @@ -375,44 +372,47 @@ lorawan_status_t LoRaMacCommand::process_mac_commands(uint8_t *payload, uint8_t } break; case SRV_MAC_TX_PARAM_SETUP_REQ: { - tx_param_setup_req_t txParamSetupReq; uint8_t eirpDwellTime = payload[mac_index++]; + uint8_t ul_dwell_time; + uint8_t dl_dwell_time; + uint8_t max_eirp; - txParamSetupReq.ul_dwell_time = 0; - txParamSetupReq.dl_dwell_time = 0; + ul_dwell_time = 0; + dl_dwell_time = 0; if ((eirpDwellTime & 0x20) == 0x20) { - txParamSetupReq.dl_dwell_time = 1; + dl_dwell_time = 1; } if ((eirpDwellTime & 0x10) == 0x10) { - txParamSetupReq.ul_dwell_time = 1; + ul_dwell_time = 1; } - txParamSetupReq.max_eirp = eirpDwellTime & 0x0F; + max_eirp = eirpDwellTime & 0x0F; // Check the status for correctness - if (lora_phy.accept_tx_param_setup_req(&txParamSetupReq)) { + if (lora_phy.accept_tx_param_setup_req(ul_dwell_time, dl_dwell_time)) { // Accept command mac_sys_params.uplink_dwell_time = - txParamSetupReq.ul_dwell_time; + ul_dwell_time; mac_sys_params.downlink_dwell_time = - txParamSetupReq.dl_dwell_time; + dl_dwell_time; mac_sys_params.max_eirp = - max_eirp_table[txParamSetupReq.max_eirp]; + max_eirp_table[max_eirp]; // Add command response ret_value = add_mac_command(MOTE_MAC_TX_PARAM_SETUP_ANS, 0, 0); } } break; case SRV_MAC_DL_CHANNEL_REQ: { - dl_channel_req_params_t dlChannelReq; - dlChannelReq.channel_id = payload[mac_index++]; - dlChannelReq.rx1_frequency = (uint32_t) payload[mac_index++]; - dlChannelReq.rx1_frequency |= (uint32_t) payload[mac_index++] << 8; - dlChannelReq.rx1_frequency |= (uint32_t) payload[mac_index++] << 16; - dlChannelReq.rx1_frequency *= 100; + uint8_t channel_id = payload[mac_index++]; + uint32_t rx1_frequency; + + rx1_frequency = (uint32_t) payload[mac_index++]; + rx1_frequency |= (uint32_t) payload[mac_index++] << 8; + rx1_frequency |= (uint32_t) payload[mac_index++] << 16; + rx1_frequency *= 100; - status = lora_phy.dl_channel_request(&dlChannelReq); + status = lora_phy.dl_channel_request(channel_id, rx1_frequency); ret_value = add_mac_command(MOTE_MAC_DL_CHANNEL_ANS, status, 0); } diff --git a/features/lorawan/lorastack/phy/LoRaPHY.cpp b/features/lorawan/lorastack/phy/LoRaPHY.cpp index 3af695778e2..949976ba964 100644 --- a/features/lorawan/lorastack/phy/LoRaPHY.cpp +++ b/features/lorawan/lorastack/phy/LoRaPHY.cpp @@ -112,7 +112,7 @@ void LoRaPHY::handle_send(uint8_t *buf, uint8_t size) _radio->unlock(); } -uint8_t LoRaPHY::request_new_channel(new_channel_req_params_t* params) +uint8_t LoRaPHY::request_new_channel(int8_t channel_id, channel_params_t* new_channel) { if (!phy_params.custom_channelplans_supported) { return 0; @@ -120,14 +120,14 @@ uint8_t LoRaPHY::request_new_channel(new_channel_req_params_t* params) uint8_t status = 0x03; - if (params->new_channel->frequency == 0) { + if (new_channel->frequency == 0) { // Remove - if (remove_channel(params->channel_id) == false) { + if (remove_channel(channel_id) == false) { status &= 0xFC; } } else { - switch (add_channel(params->new_channel, params->channel_id)) { + switch (add_channel(new_channel, channel_id)) { case LORAWAN_STATUS_OK: { break; @@ -175,7 +175,7 @@ bool LoRaPHY::verify_channel_DR(uint8_t nb_channels, uint16_t* channel_mask, if (mask_bit_test(channel_mask, i)) { // Check datarate validity for enabled channels if (val_in_range(dr, (channels[i].dr_range.fields.min & 0x0F), - (channels[i].dr_range.fields.max & 0x0F))) { + (channels[i].dr_range.fields.max & 0x0F))) { // At least 1 channel has been found we can return OK. return true; } @@ -247,22 +247,18 @@ void LoRaPHY::copy_channel_mask(uint16_t* dest_mask, uint16_t* src_mask, uint8_t } } -void LoRaPHY::set_last_tx_done(set_band_txdone_params_t* last_tx_params) +void LoRaPHY::set_last_tx_done(uint8_t channel, bool joined, lorawan_time_t last_tx_done_time) { - if (!last_tx_params) { - return; - } - band_t *band_table = (band_t *) phy_params.bands.table; channel_params_t *channel_list = phy_params.channels.channel_list; - if (last_tx_params->joined == true) { - band_table[channel_list[last_tx_params->channel].band].last_tx_time = last_tx_params->last_tx_done_time; + if (joined == true) { + band_table[channel_list[channel].band].last_tx_time = last_tx_done_time; return; } - band_table[channel_list[last_tx_params->channel].band].last_tx_time = last_tx_params->last_tx_done_time; - band_table[channel_list[last_tx_params->channel].band].last_join_tx_time = last_tx_params->last_tx_done_time; + band_table[channel_list[channel].band].last_tx_time = last_tx_done_time; + band_table[channel_list[channel].band].last_join_tx_time = last_tx_done_time; } @@ -692,7 +688,7 @@ bool LoRaPHY::verify_nb_join_trials(uint8_t nb_join_trials) return true; } -void LoRaPHY::apply_cf_list(cflist_params_t* cf_list) +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 (!phy_params.cflist_supported) { @@ -703,10 +699,10 @@ void LoRaPHY::apply_cf_list(cflist_params_t* cf_list) // Setup default datarate range 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 - if (cf_list->size != 16) { + if (size != 16) { return; } @@ -721,9 +717,9 @@ void LoRaPHY::apply_cf_list(cflist_params_t* cf_list) channel_id < phy_params.max_channel_cnt; i+=phy_params.default_channel_cnt, channel_id++) { if (channel_id < (phy_params.cflist_channel_cnt + phy_params.default_channel_cnt)) { // Channel frequency - new_channel.frequency = (uint32_t) cf_list->payload[i]; - new_channel.frequency |= ((uint32_t) cf_list->payload[i + 1] << 8); - new_channel.frequency |= ((uint32_t) cf_list->payload[i + 2] << 16); + new_channel.frequency = (uint32_t) payload[i]; + new_channel.frequency |= ((uint32_t) payload[i + 1] << 8); + new_channel.frequency |= ((uint32_t) payload[i + 2] << 16); new_channel.frequency *= 100; // Initialize alternative frequency to 0 @@ -1057,11 +1053,11 @@ uint8_t LoRaPHY::accept_rx_param_setup_req(rx_param_setup_req_t* params) return status; } -bool LoRaPHY::accept_tx_param_setup_req(tx_param_setup_req_t *params) +bool LoRaPHY::accept_tx_param_setup_req(uint8_t ul_dwell_time, uint8_t dl_dwell_time) { if (phy_params.accept_tx_param_setup_req) { - phy_params.ul_dwell_time_setting = params->ul_dwell_time; - phy_params.dl_dwell_time_setting = params->dl_dwell_time; + phy_params.ul_dwell_time_setting = ul_dwell_time; + phy_params.dl_dwell_time_setting = dl_dwell_time; } return phy_params.accept_tx_param_setup_req; @@ -1084,7 +1080,7 @@ bool LoRaPHY::verify_frequency(uint32_t freq) return false; } -uint8_t LoRaPHY::dl_channel_request(dl_channel_req_params_t* params) +uint8_t LoRaPHY::dl_channel_request(uint8_t channel_id, uint32_t rx1_frequency) { if (!phy_params.dl_channel_req_supported) { return 0; @@ -1093,18 +1089,18 @@ uint8_t LoRaPHY::dl_channel_request(dl_channel_req_params_t* params) uint8_t status = 0x03; // Verify if the frequency is supported - if (verify_frequency(params->rx1_frequency) == false) { + if (verify_frequency(rx1_frequency) == false) { status &= 0xFE; } // Verify if an uplink frequency exists - if (phy_params.channels.channel_list[params->channel_id].frequency == 0) { + if (phy_params.channels.channel_list[channel_id].frequency == 0) { status &= 0xFD; } // Apply Rx1 frequency, if the status is OK if (status == 0x03) { - phy_params.channels.channel_list[params->channel_id].rx1_frequency = params->rx1_frequency; + phy_params.channels.channel_list[channel_id].rx1_frequency = rx1_frequency; } return status; @@ -1158,23 +1154,24 @@ int8_t LoRaPHY::get_alternate_DR(uint8_t nb_trials) return datarate; } -void LoRaPHY::calculate_backoff(backoff_params_t* calc_backoff) +void LoRaPHY::calculate_backoff(bool joined, bool last_tx_was_join_req, bool dc_enabled, uint8_t channel, + lorawan_time_t elapsed_time, lorawan_time_t tx_toa) { band_t *band_table = (band_t *) phy_params.bands.table; channel_params_t *channel_list = phy_params.channels.channel_list; - uint8_t band_idx = channel_list[calc_backoff->channel].band; + uint8_t band_idx = channel_list[channel].band; uint16_t duty_cycle = band_table[band_idx].duty_cycle; uint16_t join_duty_cycle = 0; // Reset time-off to initial value. band_table[band_idx].off_time = 0; - if (calc_backoff->joined == false) { + if (joined == false) { // Get the join duty cycle - if (calc_backoff->elapsed_time < 3600000) { + if (elapsed_time < 3600000) { join_duty_cycle = BACKOFF_DC_1_HOUR; - } else if (calc_backoff->elapsed_time < (3600000 + 36000000)) { + } else if (elapsed_time < (3600000 + 36000000)) { join_duty_cycle = BACKOFF_DC_10_HOURS; } else { join_duty_cycle = BACKOFF_DC_24_HOURS; @@ -1186,12 +1183,12 @@ void LoRaPHY::calculate_backoff(backoff_params_t* calc_backoff) // No back-off if the last frame was not a join request and when the // duty cycle is not enabled - if (calc_backoff->dc_enabled == false && - calc_backoff->last_tx_was_join_req == false) { + if (dc_enabled == false && + last_tx_was_join_req == false) { band_table[band_idx].off_time = 0; } else { // Apply band time-off. - band_table[band_idx].off_time = calc_backoff->tx_toa * duty_cycle - calc_backoff->tx_toa; + band_table[band_idx].off_time = tx_toa * duty_cycle - tx_toa; } } @@ -1350,7 +1347,7 @@ bool LoRaPHY::remove_channel(uint8_t channel_id) // Remove the channel from the list of channels - const channel_params_t empty_channel = { 0, 0, { 0 }, 0 }; + const channel_params_t empty_channel = { 0, 0, {0}, 0 }; phy_params.channels.channel_list[channel_id] = empty_channel; return disable_channel(phy_params.channels.mask, channel_id, diff --git a/features/lorawan/lorastack/phy/LoRaPHY.h b/features/lorawan/lorastack/phy/LoRaPHY.h index 97fb2b8e8bf..69c602bdf6e 100644 --- a/features/lorawan/lorastack/phy/LoRaPHY.h +++ b/features/lorawan/lorastack/phy/LoRaPHY.h @@ -104,28 +104,34 @@ class LoRaPHY : private mbed::NonCopyable { */ uint32_t get_radio_rng(); - /** Calculates and applies duty cycle back-off time. - * - * Explicitly updates the band time-off. + /** + * @brief calculate_backoff Calculates and applies duty cycle back-off time. + * Explicitly updates the band time-off. * - * @param [in] backoff_params A pointer to backoff parameters. + * @param joined Set to true, if the node has already joined a network, otherwise false. + * @param last_tx_was_join_req Set to true, if the last uplink was a join request. + * @param dc_enabled Set to true, if the duty cycle is enabled, otherwise false. + * @param channel The current channel index. + * @param elapsed_time Elapsed time since the start of the node. + * @param tx_toa Time-on-air of the last transmission. */ - void calculate_backoff(backoff_params_t* backoff_params); + void calculate_backoff(bool joined, bool last_tx_was_join_req, bool dc_enabled, uint8_t channel, + lorawan_time_t elapsed_time, lorawan_time_t tx_toa); - /** + /** * Tests if a channel is on or off in the channel mask */ - bool mask_bit_test(const uint16_t *mask, unsigned bit); + bool mask_bit_test(const uint16_t *mask, unsigned bit); - /** + /** * Tests if a channel is on or off in the channel mask */ - void mask_bit_set(uint16_t *mask, unsigned bit); + void mask_bit_set(uint16_t *mask, unsigned bit); - /** + /** * Tests if a channel is on or off in the channel mask */ - void mask_bit_clear(uint16_t *mask, unsigned bit); + void mask_bit_clear(uint16_t *mask, unsigned bit); /** Entertain a new channel request MAC command. * @@ -133,20 +139,21 @@ class LoRaPHY : private mbed::NonCopyable { * the network server and then MAC layer asks the PHY layer to entertain * the request. * - * @param [in] new_channel_req A pointer to the new_channel_req_params_t. + * @param channel_id The channel ID. + * @param new_channel A pointer to the new channel's parameters. * * @return bit mask, according to the LoRaWAN spec 1.0.2. */ - virtual uint8_t request_new_channel(new_channel_req_params_t* new_channel_req); + virtual uint8_t request_new_channel(int8_t channel_id, channel_params_t* new_channel); /** Process PHY layer state after a successful transmission. - * - * Updates times of the last transmission for the particular channel and - * band upon which last transmission took place. - * - * @param [in] tx_done A pointer to set_band_txdone_params_t + * @brief set_last_tx_done Updates times of the last transmission for the particular channel and + * band upon which last transmission took place. + * @param channel The channel in use. + * @param joined Boolean telling if node has joined the network. + * @param last_tx_done_time The last TX done time. */ - virtual void set_last_tx_done(set_band_txdone_params_t* tx_done); + virtual void set_last_tx_done(uint8_t channel, bool joined, lorawan_time_t last_tx_done_time); /** Enables default channels only. * @@ -160,9 +167,11 @@ class LoRaPHY : private mbed::NonCopyable { * Handles the payload containing CF-list and enables channels defined * therein. * - * @param cflist_params A pointer to cflist_params_t. + * @param payload Payload to process. + * @param size Size of the payload. + * */ - virtual void apply_cf_list(cflist_params_t* cflist_params); + virtual void apply_cf_list(const uint8_t* payload, uint8_t size); /** Calculates the next datarate to set, when ADR is on or off. * @@ -259,7 +268,7 @@ class LoRaPHY : private mbed::NonCopyable { * @return True, if the configuration was applied successfully. */ virtual bool tx_config(tx_config_params_t* tx_config, int8_t* tx_power, - lorawan_time_t* tx_toa); + lorawan_time_t* tx_toa); /** Processes a Link ADR Request. * @@ -291,23 +300,26 @@ class LoRaPHY : private mbed::NonCopyable { */ virtual uint8_t accept_rx_param_setup_req(rx_param_setup_req_t* params); - /** Makes decision whether to accept or reject TxParamSetupReq MAC command + /** + * @brief accept_tx_param_setup_req Makes decision whether to accept or reject TxParamSetupReq MAC command. * - * @param [in] params A pointer to tx parameter setup request. + * @param ul_dwell_time The uplink dwell time. + * @param dl_dwell_time The downlink dwell time. * - * @return True to let the MAC know that the request is - * accepted and MAC can apply TX parameters received - * form Network Server. Otherwise false is returned. + * @return True to let the MAC know that the request is + * accepted and MAC can apply TX parameters received + * form Network Server. Otherwise false is returned. */ - virtual bool accept_tx_param_setup_req(tx_param_setup_req_t* params); + virtual bool accept_tx_param_setup_req(uint8_t ul_dwell_time, uint8_t dl_dwell_time); /** Processes a DlChannelReq MAC command. * - * @param [in] params A pointer to downlink channel request. + * @param channel_id The channel ID to add the frequency. + * @param rx1_frequency The alternative frequency for the Rx1 window. * * @return The status of the operation, according to the LoRaWAN specification. */ - virtual uint8_t dl_channel_request(dl_channel_req_params_t* params); + virtual uint8_t dl_channel_request(uint8_t channel_id, uint32_t rx1_frequency); /** Alternates the datarate of the channel for the join request. * diff --git a/features/lorawan/lorastack/phy/lora_phy_ds.h b/features/lorawan/lorastack/phy/lora_phy_ds.h index 3f00b95355d..5628bdba099 100644 --- a/features/lorawan/lorastack/phy/lora_phy_ds.h +++ b/features/lorawan/lorastack/phy/lora_phy_ds.h @@ -524,40 +524,6 @@ */ #define TX_POWER_15 15 -/** - * The parameter structure for the function RegionSetBandTxDone. - */ -typedef struct -{ - /** - * The channel to update. - */ - uint8_t channel; - /** - * Joined set to true, if the node has joined the network. - */ - bool joined; - /** - * The last TX done time. - */ - lorawan_time_t last_tx_done_time; -} set_band_txdone_params_t; - -/** - * The parameter structure for the function RegionApplyCFList. - */ -typedef struct -{ - /** - * The payload containing the CF list. - */ - uint8_t* payload; - /** - * The size of the payload. - */ - uint8_t size; -} cflist_params_t; - /** * TX configuration parameters. */ @@ -717,90 +683,6 @@ typedef struct rx_param_setup_req_s uint32_t frequency; } rx_param_setup_req_t; -/** - * Contains tx parameter setup request coming from - * network server. - */ -typedef struct tx_param_setup_req_s -{ - /** - * The uplink dwell time. - */ - uint8_t ul_dwell_time; - /** - * The downlink dwell time. - */ - uint8_t dl_dwell_time; - /** - * The max EIRP. - */ - uint8_t max_eirp; -} tx_param_setup_req_t; - -/** - * A structure that holds new channel parameters coming - * from the network server. - */ -typedef struct new_channel_req_params_s -{ - /** - * A pointer to the new channel's parameters. - */ - channel_params_t* new_channel; - /** - * The channel ID. - */ - int8_t channel_id; - -} new_channel_req_params_t; - -/** - * The parameter structure for the function RegionDlChannelReq. - */ -typedef struct dl_channel_req_params_s -{ - /** - * The channel ID to add the frequency. - */ - uint8_t channel_id; - /** - * The alternative frequency for the Rx1 window. - */ - uint32_t rx1_frequency; -} dl_channel_req_params_t; - -/*! - * The parameter structure for the function RegionCalcBackOff. - */ -typedef struct backoff_params_s -{ - /** - * Set to true, if the node has already joined a network, otherwise false. - */ - bool joined; - /** - * set to true, if the last uplink was a join request. - */ - bool last_tx_was_join_req; - /** - * Set to true, if the duty cycle is enabled, otherwise false. - */ - bool dc_enabled; - /** - * The current channel index. - */ - uint8_t channel; - /** - * Elapsed time since the start of the node. - */ - lorawan_time_t elapsed_time; - /** - * Time-on-air of the last transmission. - */ - lorawan_time_t tx_toa; - -} backoff_params_t; - /** * The parameter structure for the function RegionNextChannel. */ @@ -865,13 +747,13 @@ typedef struct { } loraphy_table_t; typedef struct { - channel_params_t *channel_list; + uint8_t channel_list_size; + uint8_t mask_size; uint16_t *mask; uint16_t *default_mask; - uint8_t mask_size; - + channel_params_t *channel_list; } loraphy_channels_t; typedef struct { From cbdeb7dc4ba79231ba519b07fa07b07adaf434bf Mon Sep 17 00:00:00 2001 From: Antti Kauppila Date: Tue, 20 Mar 2018 17:42:53 +0200 Subject: [PATCH 23/25] LoRa: Added API break warnings for lorawan_channelplan_t struct and it's components --- features/lorawan/system/lorawan_data_structures.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/features/lorawan/system/lorawan_data_structures.h b/features/lorawan/system/lorawan_data_structures.h index 8c760187c60..4fc543da9e3 100644 --- a/features/lorawan/system/lorawan_data_structures.h +++ b/features/lorawan/system/lorawan_data_structures.h @@ -142,6 +142,7 @@ typedef enum { /*! * LoRaMAC channel parameters definition. + * DO NOT MODIFY, WILL BREAK THE API! */ typedef union { /*! @@ -174,6 +175,7 @@ typedef union { /*! * LoRaMAC channel definition. + * DO NOT MODIFY, WILL BREAK THE API! */ typedef struct { /*! @@ -1233,6 +1235,7 @@ typedef struct { /** * Structure to hold A list of LoRa Channels + * DO NOT MODIFY, WILL BREAK THE API! */ typedef struct lora_channels_s { uint8_t id; @@ -1720,6 +1723,9 @@ typedef struct { mbed::Callback battery_level; } lorawan_app_callbacks_t; +/** + * DO NOT MODIFY, WILL BREAK THE API! + */ typedef struct lora_channelplan { uint8_t nb_channels; // number of channels loramac_channel_t *channels; From c1983570b46074e55bd149161002ffb67c58b1b2 Mon Sep 17 00:00:00 2001 From: Kimmo Vaisanen Date: Wed, 21 Mar 2018 14:39:18 +0200 Subject: [PATCH 24/25] Fix compilance test compilation Fix compilation of compilance test and at the same time refactor compliance test handler. Renamed mcps_request as test_request as it is only used for compliance test. Also fixed a bug with null buffer in send_compliance_test_frame_to_mac. --- features/lorawan/LoRaWANStack.cpp | 75 +++++++------------ features/lorawan/LoRaWANStack.h | 6 -- features/lorawan/lorastack/mac/LoRaMac.cpp | 2 +- features/lorawan/lorastack/mac/LoRaMac.h | 10 +-- .../lorawan/system/lorawan_data_structures.h | 19 ++--- 5 files changed, 43 insertions(+), 69 deletions(-) diff --git a/features/lorawan/LoRaWANStack.cpp b/features/lorawan/LoRaWANStack.cpp index fc62aa43630..803e13fbab6 100644 --- a/features/lorawan/LoRaWANStack.cpp +++ b/features/lorawan/LoRaWANStack.cpp @@ -189,10 +189,6 @@ lorawan_status_t LoRaWANStack::initialize_mac_layer(EventQueue *queue) tr_debug("Initializing MAC layer"); _queue = queue; -#if defined(LORAWAN_COMPLIANCE_TEST) - _compliance_test.app_data_buffer = compliance_test_buffer; -#endif - _loramac.initialize(&LoRaMacPrimitives, queue); // Reset counters to zero. Will change in future with 1.1 support. @@ -876,36 +872,34 @@ lorawan_status_t LoRaWANStack::lora_state_machine(device_states_t new_state) lorawan_status_t LoRaWANStack::send_compliance_test_frame_to_mac() { - loramac_mcps_req_t mcps_req; + loramac_compliance_test_req_t test_req; -// prepare_special_tx_frame(_compliance_test.app_port); //TODO: What if the port is not 224 ??? if (_compliance_test.app_port == 224) { // Clear any normal message stuff before compliance test. - memset(&mcps_req, 0, sizeof(mcps_req)); + memset(&test_req, 0, sizeof(test_req)); if (_compliance_test.link_check == true) { _compliance_test.link_check = false; _compliance_test.state = 1; - mcps_req.f_buffer_size = 3; - mcps_req.f_buffer[0] = 5; - mcps_req.f_buffer[1] = _compliance_test.demod_margin; - mcps_req.f_buffer[2] = _compliance_test.nb_gateways; + test_req.f_buffer_size = 3; + test_req.f_buffer[0] = 5; + test_req.f_buffer[1] = _compliance_test.demod_margin; + test_req.f_buffer[2] = _compliance_test.nb_gateways; } else { switch (_compliance_test.state) { case 4: _compliance_test.state = 1; - mcps_req.f_buffer_size = _compliance_test.app_data_size; - - mcps_req.f_buffer[0] = _compliance_test.app_data_buffer[0]; + test_req.f_buffer_size = _compliance_test.app_data_size; + test_req.f_buffer[0] = _compliance_test.app_data_buffer[0]; for(uint8_t i = 1; i < MIN(_compliance_test.app_data_size, MBED_CONF_LORA_TX_MAX_SIZE); ++i) { - mcps_req.f_buffer[i] = _compliance_test.app_data_buffer[i]; + test_req.f_buffer[i] = _compliance_test.app_data_buffer[i]; } break; case 1: - mcps_req.f_buffer_size = 2; - mcps_req.f_buffer[0] = _compliance_test.downlink_counter >> 8; - mcps_req.f_buffer[1] = _compliance_test.downlink_counter; + test_req.f_buffer_size = 2; + test_req.f_buffer[0] = _compliance_test.downlink_counter >> 8; + test_req.f_buffer[1] = _compliance_test.downlink_counter; break; } } @@ -914,45 +908,32 @@ lorawan_status_t LoRaWANStack::send_compliance_test_frame_to_mac() //TODO: If port is not 224, this might not work! //Is there a test case where same _tx_msg's buffer would be used, when port is not 224??? if (!_compliance_test.is_tx_confirmed) { - mcps_req.type = MCPS_UNCONFIRMED; -// mcps_req.f_buffer = _tx_msg.f_buffer; -// mcps_req.f_buffer_size = _tx_msg.f_buffer_size; - mcps_req.fport = _compliance_test.app_port; - mcps_req.nb_trials = 1; - mcps_req.data_rate = _loramac.get_default_tx_datarate(); + test_req.type = MCPS_UNCONFIRMED; + test_req.fport = _compliance_test.app_port; + test_req.nb_trials = 1; + test_req.data_rate = _loramac.get_default_tx_datarate(); - tr_info("Transmit unconfirmed compliance test frame %d bytes.", mcps_req.f_buffer_size); + tr_info("Transmit unconfirmed compliance test frame %d bytes.", test_req.f_buffer_size); - for (uint8_t i = 0; i < mcps_req.f_buffer_size; ++i) { - tr_info("Byte %d, data is 0x%x", i+1, ((uint8_t*)mcps_req.f_buffer)[i]); + for (uint8_t i = 0; i < test_req.f_buffer_size; ++i) { + tr_info("Byte %d, data is 0x%x", i+1, ((uint8_t*)test_req.f_buffer)[i]); } } else if (_compliance_test.is_tx_confirmed) { - mcps_req.type = MCPS_CONFIRMED; -// mcps_req.f_buffer = _tx_msg.f_buffer; -// mcps_req.f_buffer_size = _tx_msg.f_buffer_size; - mcps_req.fport = _compliance_test.app_port; - mcps_req.nb_trials = _num_retry; - mcps_req.data_rate = _loramac.get_default_tx_datarate(); + test_req.type = MCPS_CONFIRMED; + test_req.fport = _compliance_test.app_port; + test_req.nb_trials = _num_retry; + test_req.data_rate = _loramac.get_default_tx_datarate(); - tr_info("Transmit confirmed compliance test frame %d bytes.", mcps_req.f_buffer_size); + tr_info("Transmit confirmed compliance test frame %d bytes.", test_req.f_buffer_size); - for (uint8_t i = 0; i < mcps_req.f_buffer_size; ++i) { - tr_info("Byte %d, data is 0x%x", i+1, ((uint8_t*)mcps_req.f_buffer)[i]); + for (uint8_t i = 0; i < test_req.f_buffer_size; ++i) { + tr_info("Byte %d, data is 0x%x", i+1, ((uint8_t*)test_req.f_buffer)[i]); } } else { return LORAWAN_STATUS_SERVICE_UNKNOWN; } - return mcps_request_handler(&mcps_req); -} - -lorawan_status_t LoRaWANStack::mcps_request_handler(loramac_mcps_req_t *mcps_request) -{ - if (mcps_request == NULL) { - return LORAWAN_STATUS_PARAMETER_INVALID; - } - - return _loramac.mcps_request(mcps_request); + return _loramac.test_request(&test_req); } void LoRaWANStack::compliance_test_handler(loramac_mcps_indication_t *mcps_indication) @@ -1035,8 +1016,6 @@ void LoRaWANStack::compliance_test_handler(loramac_mcps_indication_t *mcps_indic _loramac.setup_link_check_request(); break; case 6: // (ix) - loramac_mlme_req_t mlme_req; - // Disable TestMode and revert back to normal operation _compliance_test.is_tx_confirmed = true; _compliance_test.app_port = MBED_CONF_LORA_APP_PORT; diff --git a/features/lorawan/LoRaWANStack.h b/features/lorawan/LoRaWANStack.h index 31c8de2efc4..d1cd724a6f9 100644 --- a/features/lorawan/LoRaWANStack.h +++ b/features/lorawan/LoRaWANStack.h @@ -471,17 +471,11 @@ class LoRaWANStack: private mbed::NonCopyable { */ void compliance_test_handler(loramac_mcps_indication_t *mcps_indication); - /** - * Used only for compliance testing - */ - lorawan_status_t mcps_request_handler(loramac_mcps_req_t *mcps_request); - /** * Used only for compliance testing */ lorawan_status_t send_compliance_test_frame_to_mac(); - uint8_t compliance_test_buffer[MBED_CONF_LORA_TX_MAX_SIZE]; compliance_test_t _compliance_test; #endif }; diff --git a/features/lorawan/lorastack/mac/LoRaMac.cpp b/features/lorawan/lorastack/mac/LoRaMac.cpp index 6ccd2ba4000..164887583d9 100644 --- a/features/lorawan/lorastack/mac/LoRaMac.cpp +++ b/features/lorawan/lorastack/mac/LoRaMac.cpp @@ -1995,7 +1995,7 @@ lorawan_status_t LoRaMac::mlme_request( loramac_mlme_req_t *mlmeRequest ) return status; } -lorawan_status_t LoRaMac::mcps_request( loramac_mcps_req_t *mcpsRequest ) +lorawan_status_t LoRaMac::test_request( loramac_compliance_test_req_t *mcpsRequest ) { if (_params.mac_state != LORAMAC_IDLE) { return LORAWAN_STATUS_BUSY; diff --git a/features/lorawan/lorastack/mac/LoRaMac.h b/features/lorawan/lorastack/mac/LoRaMac.h index 3b92b843592..c4825b35cff 100644 --- a/features/lorawan/lorastack/mac/LoRaMac.h +++ b/features/lorawan/lorastack/mac/LoRaMac.h @@ -621,20 +621,20 @@ class LoRaMac { * * uint8_t buffer[] = {1, 2, 3}; * - * loramac_mcps_req_t request; + * loramac_compliance_test_req_t request; * request.type = MCPS_UNCONFIRMED; * request.fport = 1; * request.f_buffer = buffer; * request.f_buffer_size = sizeof(buffer); * - * if (mcps_request(&request) == LORAWAN_STATUS_OK) { + * if (test_request(&request) == LORAWAN_STATUS_OK) { * // Service started successfully. Waiting for the MCPS-Confirm event * } * * @endcode * - * @param [in] request The MCPS request to perform. - * Refer to \ref loramac_mcps_req_t. + * @param [in] request The test request to perform. + * Refer to \ref loramac_compliance_test_req_t. * * @return `lorawan_status_t` The status of the operation. The possible values are: * \ref LORAWAN_STATUS_OK @@ -645,7 +645,7 @@ class LoRaMac { * \ref LORAWAN_STATUS_LENGTH_ERROR * \ref LORAWAN_STATUS_DEVICE_OFF */ - lorawan_status_t mcps_request(loramac_mcps_req_t *request); + lorawan_status_t test_request(loramac_compliance_test_req_t *request); /** * \brief LoRaMAC set tx timer. diff --git a/features/lorawan/system/lorawan_data_structures.h b/features/lorawan/system/lorawan_data_structures.h index 4fc543da9e3..446157c4cb6 100644 --- a/features/lorawan/system/lorawan_data_structures.h +++ b/features/lorawan/system/lorawan_data_structures.h @@ -1744,7 +1744,7 @@ typedef struct { typedef struct { /*! - * MCPS-Request type. + * Compiliance test request */ mcps_type_t type; @@ -1786,14 +1786,15 @@ typedef struct { * * A pointer to the buffer of the frame payload. */ - void *f_buffer; - /** Payload size - * - * The size of the frame payload. - */ - uint16_t f_buffer_size; + uint8_t f_buffer[LORAMAC_PHY_MAXPAYLOAD]; + + /** Payload size + * + * The size of the frame payload. + */ + uint16_t f_buffer_size; -} loramac_mcps_req_t; +} loramac_compliance_test_req_t; /** LoRaWAN compliance tests support data * @@ -1822,7 +1823,7 @@ typedef struct compliance_test { /** Data provided by application * */ - uint8_t *app_data_buffer; + uint8_t app_data_buffer[MBED_CONF_LORA_TX_MAX_SIZE]; /** Downlink counter * */ From 10ad1730914db21da70ce2f42a0d928cbf28ab22 Mon Sep 17 00:00:00 2001 From: Antti Kauppila Date: Tue, 3 Apr 2018 14:58:01 +0300 Subject: [PATCH 25/25] LoRa: Small fixes - changed few static variables to have const --- features/lorawan/LoRaWANBase.h | 2 +- features/lorawan/LoRaWANStack.cpp | 30 +++++++++---------- features/lorawan/lorastack/phy/LoRaPHY.cpp | 25 ++++++++-------- .../lorawan/system/lorawan_data_structures.h | 2 +- 4 files changed, 30 insertions(+), 29 deletions(-) diff --git a/features/lorawan/LoRaWANBase.h b/features/lorawan/LoRaWANBase.h index 02397f3b49f..40fe4839231 100644 --- a/features/lorawan/LoRaWANBase.h +++ b/features/lorawan/LoRaWANBase.h @@ -342,7 +342,7 @@ class LoRaWANBase { * LORAWAN_STATUS_UNSUPPORTED is requested class is not supported, * or other negative error code if request failed. */ - virtual lorawan_status_t set_device_class(const device_class_t device_class) = 0; + virtual lorawan_status_t set_device_class(device_class_t device_class) = 0; }; #endif /* LORAWAN_BASE_H_ */ diff --git a/features/lorawan/LoRaWANStack.cpp b/features/lorawan/LoRaWANStack.cpp index 803e13fbab6..0eee8876b74 100644 --- a/features/lorawan/LoRaWANStack.cpp +++ b/features/lorawan/LoRaWANStack.cpp @@ -131,29 +131,29 @@ lorawan_status_t LoRaWANStack::connect() lorawan_connect_t connection_params; //TODO: LoRaWANStack don't need to know these values, move to LoRaMac (or below) -#if (1 == MBED_CONF_LORA_OVER_THE_AIR_ACTIVATION) - static uint8_t dev_eui[] = MBED_CONF_LORA_DEVICE_EUI; - static uint8_t app_eui[] = MBED_CONF_LORA_APPLICATION_EUI; - static uint8_t app_key[] = MBED_CONF_LORA_APPLICATION_KEY; +#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; connection_params.connect_type = LORAWAN_CONNECTION_OTAA; - connection_params.connection_u.otaa.app_eui = app_eui; - connection_params.connection_u.otaa.dev_eui = dev_eui; - connection_params.connection_u.otaa.app_key = app_key; + 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 - static uint8_t nwk_skey[] = MBED_CONF_LORA_NWKSKEY; - static uint8_t app_skey[] = MBED_CONF_LORA_APPSKEY; - static uint32_t dev_addr = MBED_CONF_LORA_DEVICE_ADDRESS; - static uint32_t nwk_id = (MBED_CONF_LORA_DEVICE_ADDRESS & LORAWAN_NETWORK_ID_MASK); + 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 = nwk_id; - connection_params.connection_u.abp.dev_addr = dev_addr; - connection_params.connection_u.abp.nwk_skey = nwk_skey; - connection_params.connection_u.abp.app_skey = app_skey; + 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 diff --git a/features/lorawan/lorastack/phy/LoRaPHY.cpp b/features/lorawan/lorastack/phy/LoRaPHY.cpp index 949976ba964..368ecfed2fb 100644 --- a/features/lorawan/lorastack/phy/LoRaPHY.cpp +++ b/features/lorawan/lorastack/phy/LoRaPHY.cpp @@ -651,19 +651,20 @@ bool LoRaPHY::verify_rx_datarate(uint8_t datarate) bool LoRaPHY::verify_tx_datarate(uint8_t datarate, bool use_default) { - if (is_datarate_supported(datarate)) { - if (use_default) { - return val_in_range(datarate, phy_params.default_datarate, - phy_params.default_max_datarate); - } else if (phy_params.ul_dwell_time_setting == 0) { - return val_in_range(datarate, phy_params.min_tx_datarate, - phy_params.max_tx_datarate); - } else { - return val_in_range(datarate, phy_params.dwell_limit_datarate, - phy_params.max_tx_datarate); - } + if (!is_datarate_supported(datarate)) { + return false; + } + + if (use_default) { + return val_in_range(datarate, phy_params.default_datarate, + phy_params.default_max_datarate); + } else if (phy_params.ul_dwell_time_setting == 0) { + return val_in_range(datarate, phy_params.min_tx_datarate, + phy_params.max_tx_datarate); + } else { + return val_in_range(datarate, phy_params.dwell_limit_datarate, + phy_params.max_tx_datarate); } - return false; } bool LoRaPHY::verify_tx_power(uint8_t tx_power) diff --git a/features/lorawan/system/lorawan_data_structures.h b/features/lorawan/system/lorawan_data_structures.h index 446157c4cb6..be47685b649 100644 --- a/features/lorawan/system/lorawan_data_structures.h +++ b/features/lorawan/system/lorawan_data_structures.h @@ -1744,7 +1744,7 @@ typedef struct { typedef struct { /*! - * Compiliance test request + * Compliance test request */ mcps_type_t type;