Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
features/lorawan/LoRaWANStack.cpp@1:9db0e321a9f4, 2019-12-31 (annotated)
- Committer:
- kenjiArai
- Date:
- Tue Dec 31 06:02:27 2019 +0000
- Revision:
- 1:9db0e321a9f4
- Parent:
- 0:5b88d5760320
updated based on mbed-os5.15.0
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
kenjiArai | 0:5b88d5760320 | 1 | /** |
kenjiArai | 0:5b88d5760320 | 2 | / _____) _ | | |
kenjiArai | 0:5b88d5760320 | 3 | ( (____ _____ ____ _| |_ _____ ____| |__ |
kenjiArai | 0:5b88d5760320 | 4 | \____ \| ___ | (_ _) ___ |/ ___) _ \ |
kenjiArai | 0:5b88d5760320 | 5 | _____) ) ____| | | || |_| ____( (___| | | | |
kenjiArai | 0:5b88d5760320 | 6 | (______/|_____)_|_|_| \__)_____)\____)_| |_| |
kenjiArai | 0:5b88d5760320 | 7 | (C)2013 Semtech |
kenjiArai | 0:5b88d5760320 | 8 | ___ _____ _ ___ _ _____ ___ ___ ___ ___ |
kenjiArai | 0:5b88d5760320 | 9 | / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| |
kenjiArai | 0:5b88d5760320 | 10 | \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| |
kenjiArai | 0:5b88d5760320 | 11 | |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| |
kenjiArai | 0:5b88d5760320 | 12 | embedded.connectivity.solutions=============== |
kenjiArai | 0:5b88d5760320 | 13 | |
kenjiArai | 0:5b88d5760320 | 14 | Description: LoRaWAN stack layer that controls both MAC and PHY underneath |
kenjiArai | 0:5b88d5760320 | 15 | |
kenjiArai | 0:5b88d5760320 | 16 | License: Revised BSD License, see LICENSE.TXT file include in the project |
kenjiArai | 0:5b88d5760320 | 17 | |
kenjiArai | 0:5b88d5760320 | 18 | Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) |
kenjiArai | 0:5b88d5760320 | 19 | |
kenjiArai | 0:5b88d5760320 | 20 | |
kenjiArai | 0:5b88d5760320 | 21 | Copyright (c) 2017, Arm Limited and affiliates. |
kenjiArai | 0:5b88d5760320 | 22 | |
kenjiArai | 0:5b88d5760320 | 23 | SPDX-License-Identifier: BSD-3-Clause |
kenjiArai | 0:5b88d5760320 | 24 | */ |
kenjiArai | 0:5b88d5760320 | 25 | |
kenjiArai | 0:5b88d5760320 | 26 | #include <string.h> |
kenjiArai | 0:5b88d5760320 | 27 | #include <stdlib.h> |
kenjiArai | 0:5b88d5760320 | 28 | #include "platform/Callback.h" |
kenjiArai | 0:5b88d5760320 | 29 | #include "events/EventQueue.h" |
kenjiArai | 0:5b88d5760320 | 30 | |
kenjiArai | 0:5b88d5760320 | 31 | #include "LoRaWANStack.h" |
kenjiArai | 0:5b88d5760320 | 32 | |
kenjiArai | 0:5b88d5760320 | 33 | #include "mbed-trace/mbed_trace.h" |
kenjiArai | 0:5b88d5760320 | 34 | #define TRACE_GROUP "LSTK" |
kenjiArai | 0:5b88d5760320 | 35 | |
kenjiArai | 0:5b88d5760320 | 36 | #define INVALID_PORT 0xFF |
kenjiArai | 0:5b88d5760320 | 37 | #define MAX_CONFIRMED_MSG_RETRIES 255 |
kenjiArai | 0:5b88d5760320 | 38 | #define COMPLIANCE_TESTING_PORT 224 |
kenjiArai | 0:5b88d5760320 | 39 | /** |
kenjiArai | 0:5b88d5760320 | 40 | * Control flags for transient states |
kenjiArai | 0:5b88d5760320 | 41 | */ |
kenjiArai | 0:5b88d5760320 | 42 | #define IDLE_FLAG 0x00000000 |
kenjiArai | 0:5b88d5760320 | 43 | #define RETRY_EXHAUSTED_FLAG 0x00000001 |
kenjiArai | 0:5b88d5760320 | 44 | #define MSG_RECVD_FLAG 0x00000002 |
kenjiArai | 0:5b88d5760320 | 45 | #define CONNECTED_FLAG 0x00000004 |
kenjiArai | 0:5b88d5760320 | 46 | #define USING_OTAA_FLAG 0x00000008 |
kenjiArai | 0:5b88d5760320 | 47 | #define TX_DONE_FLAG 0x00000010 |
kenjiArai | 0:5b88d5760320 | 48 | #define CONN_IN_PROGRESS_FLAG 0x00000020 |
kenjiArai | 0:5b88d5760320 | 49 | |
kenjiArai | 0:5b88d5760320 | 50 | using namespace mbed; |
kenjiArai | 0:5b88d5760320 | 51 | using namespace events; |
kenjiArai | 0:5b88d5760320 | 52 | |
kenjiArai | 0:5b88d5760320 | 53 | /** |
kenjiArai | 0:5b88d5760320 | 54 | * Bit mask for message flags |
kenjiArai | 0:5b88d5760320 | 55 | */ |
kenjiArai | 0:5b88d5760320 | 56 | |
kenjiArai | 0:5b88d5760320 | 57 | #define MSG_FLAG_MASK 0x0F |
kenjiArai | 0:5b88d5760320 | 58 | |
kenjiArai | 0:5b88d5760320 | 59 | /***************************************************************************** |
kenjiArai | 0:5b88d5760320 | 60 | * Constructor * |
kenjiArai | 0:5b88d5760320 | 61 | ****************************************************************************/ |
kenjiArai | 0:5b88d5760320 | 62 | LoRaWANStack::LoRaWANStack() |
kenjiArai | 0:5b88d5760320 | 63 | : _loramac(), |
kenjiArai | 0:5b88d5760320 | 64 | _device_current_state(DEVICE_STATE_NOT_INITIALIZED), |
kenjiArai | 0:5b88d5760320 | 65 | _lw_session(), |
kenjiArai | 0:5b88d5760320 | 66 | _tx_msg(), |
kenjiArai | 0:5b88d5760320 | 67 | _rx_msg(), |
kenjiArai | 0:5b88d5760320 | 68 | _tx_metadata(), |
kenjiArai | 0:5b88d5760320 | 69 | _rx_metadata(), |
kenjiArai | 0:5b88d5760320 | 70 | _num_retry(1), |
kenjiArai | 0:5b88d5760320 | 71 | _qos_cnt(1), |
kenjiArai | 0:5b88d5760320 | 72 | _ctrl_flags(IDLE_FLAG), |
kenjiArai | 0:5b88d5760320 | 73 | _app_port(INVALID_PORT), |
kenjiArai | 0:5b88d5760320 | 74 | _link_check_requested(false), |
kenjiArai | 0:5b88d5760320 | 75 | _automatic_uplink_ongoing(false), |
kenjiArai | 0:5b88d5760320 | 76 | _queue(NULL) |
kenjiArai | 0:5b88d5760320 | 77 | { |
kenjiArai | 0:5b88d5760320 | 78 | _tx_metadata.stale = true; |
kenjiArai | 0:5b88d5760320 | 79 | _rx_metadata.stale = true; |
kenjiArai | 0:5b88d5760320 | 80 | core_util_atomic_flag_clear(&_rx_payload_in_use); |
kenjiArai | 0:5b88d5760320 | 81 | |
kenjiArai | 0:5b88d5760320 | 82 | #ifdef MBED_CONF_LORA_APP_PORT |
kenjiArai | 0:5b88d5760320 | 83 | if (is_port_valid(MBED_CONF_LORA_APP_PORT)) { |
kenjiArai | 0:5b88d5760320 | 84 | _app_port = MBED_CONF_LORA_APP_PORT; |
kenjiArai | 0:5b88d5760320 | 85 | } else { |
kenjiArai | 0:5b88d5760320 | 86 | tr_error("User defined port in .json is illegal."); |
kenjiArai | 0:5b88d5760320 | 87 | } |
kenjiArai | 0:5b88d5760320 | 88 | #endif |
kenjiArai | 0:5b88d5760320 | 89 | } |
kenjiArai | 0:5b88d5760320 | 90 | |
kenjiArai | 0:5b88d5760320 | 91 | /***************************************************************************** |
kenjiArai | 0:5b88d5760320 | 92 | * Public Methods * |
kenjiArai | 0:5b88d5760320 | 93 | ****************************************************************************/ |
kenjiArai | 0:5b88d5760320 | 94 | void LoRaWANStack::bind_phy_and_radio_driver(LoRaRadio &radio, LoRaPHY &phy) |
kenjiArai | 0:5b88d5760320 | 95 | { |
kenjiArai | 0:5b88d5760320 | 96 | radio_events.tx_done = mbed::callback(this, &LoRaWANStack::tx_interrupt_handler); |
kenjiArai | 0:5b88d5760320 | 97 | radio_events.rx_done = mbed::callback(this, &LoRaWANStack::rx_interrupt_handler); |
kenjiArai | 0:5b88d5760320 | 98 | radio_events.rx_error = mbed::callback(this, &LoRaWANStack::rx_error_interrupt_handler); |
kenjiArai | 0:5b88d5760320 | 99 | radio_events.tx_timeout = mbed::callback(this, &LoRaWANStack::tx_timeout_interrupt_handler); |
kenjiArai | 0:5b88d5760320 | 100 | radio_events.rx_timeout = mbed::callback(this, &LoRaWANStack::rx_timeout_interrupt_handler); |
kenjiArai | 0:5b88d5760320 | 101 | |
kenjiArai | 0:5b88d5760320 | 102 | phy.set_radio_instance(radio); |
kenjiArai | 0:5b88d5760320 | 103 | _loramac.bind_phy(phy); |
kenjiArai | 0:5b88d5760320 | 104 | |
kenjiArai | 0:5b88d5760320 | 105 | radio.lock(); |
kenjiArai | 0:5b88d5760320 | 106 | radio.init_radio(&radio_events); |
kenjiArai | 0:5b88d5760320 | 107 | radio.unlock(); |
kenjiArai | 0:5b88d5760320 | 108 | } |
kenjiArai | 0:5b88d5760320 | 109 | |
kenjiArai | 0:5b88d5760320 | 110 | lorawan_status_t LoRaWANStack::initialize_mac_layer(EventQueue *queue) |
kenjiArai | 0:5b88d5760320 | 111 | { |
kenjiArai | 0:5b88d5760320 | 112 | if (!queue) { |
kenjiArai | 0:5b88d5760320 | 113 | return LORAWAN_STATUS_PARAMETER_INVALID; |
kenjiArai | 0:5b88d5760320 | 114 | } |
kenjiArai | 0:5b88d5760320 | 115 | |
kenjiArai | 0:5b88d5760320 | 116 | tr_debug("Initializing MAC layer"); |
kenjiArai | 0:5b88d5760320 | 117 | _queue = queue; |
kenjiArai | 0:5b88d5760320 | 118 | |
kenjiArai | 0:5b88d5760320 | 119 | return state_controller(DEVICE_STATE_IDLE); |
kenjiArai | 0:5b88d5760320 | 120 | } |
kenjiArai | 0:5b88d5760320 | 121 | |
kenjiArai | 0:5b88d5760320 | 122 | lorawan_status_t LoRaWANStack::set_lora_callbacks(const lorawan_app_callbacks_t *callbacks) |
kenjiArai | 0:5b88d5760320 | 123 | { |
kenjiArai | 0:5b88d5760320 | 124 | if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { |
kenjiArai | 0:5b88d5760320 | 125 | return LORAWAN_STATUS_NOT_INITIALIZED; |
kenjiArai | 0:5b88d5760320 | 126 | } |
kenjiArai | 0:5b88d5760320 | 127 | |
kenjiArai | 0:5b88d5760320 | 128 | if (!callbacks || !callbacks->events) { |
kenjiArai | 0:5b88d5760320 | 129 | return LORAWAN_STATUS_PARAMETER_INVALID; |
kenjiArai | 0:5b88d5760320 | 130 | } |
kenjiArai | 0:5b88d5760320 | 131 | |
kenjiArai | 0:5b88d5760320 | 132 | _callbacks.events = callbacks->events; |
kenjiArai | 0:5b88d5760320 | 133 | |
kenjiArai | 0:5b88d5760320 | 134 | if (callbacks->link_check_resp) { |
kenjiArai | 0:5b88d5760320 | 135 | _callbacks.link_check_resp = callbacks->link_check_resp; |
kenjiArai | 0:5b88d5760320 | 136 | } |
kenjiArai | 0:5b88d5760320 | 137 | |
kenjiArai | 0:5b88d5760320 | 138 | if (callbacks->battery_level) { |
kenjiArai | 0:5b88d5760320 | 139 | _callbacks.battery_level = callbacks->battery_level; |
kenjiArai | 0:5b88d5760320 | 140 | _loramac.set_batterylevel_callback(callbacks->battery_level); |
kenjiArai | 0:5b88d5760320 | 141 | } |
kenjiArai | 0:5b88d5760320 | 142 | |
kenjiArai | 0:5b88d5760320 | 143 | return LORAWAN_STATUS_OK; |
kenjiArai | 0:5b88d5760320 | 144 | } |
kenjiArai | 0:5b88d5760320 | 145 | |
kenjiArai | 0:5b88d5760320 | 146 | lorawan_status_t LoRaWANStack::connect() |
kenjiArai | 0:5b88d5760320 | 147 | { |
kenjiArai | 0:5b88d5760320 | 148 | if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { |
kenjiArai | 0:5b88d5760320 | 149 | return LORAWAN_STATUS_NOT_INITIALIZED; |
kenjiArai | 0:5b88d5760320 | 150 | } |
kenjiArai | 0:5b88d5760320 | 151 | |
kenjiArai | 0:5b88d5760320 | 152 | if (_ctrl_flags & CONN_IN_PROGRESS_FLAG) { |
kenjiArai | 0:5b88d5760320 | 153 | return LORAWAN_STATUS_BUSY; |
kenjiArai | 0:5b88d5760320 | 154 | } |
kenjiArai | 0:5b88d5760320 | 155 | |
kenjiArai | 0:5b88d5760320 | 156 | if (_ctrl_flags & CONNECTED_FLAG) { |
kenjiArai | 0:5b88d5760320 | 157 | return LORAWAN_STATUS_ALREADY_CONNECTED; |
kenjiArai | 0:5b88d5760320 | 158 | } |
kenjiArai | 0:5b88d5760320 | 159 | |
kenjiArai | 0:5b88d5760320 | 160 | lorawan_status_t status = _loramac.prepare_join(NULL, MBED_CONF_LORA_OVER_THE_AIR_ACTIVATION); |
kenjiArai | 0:5b88d5760320 | 161 | |
kenjiArai | 0:5b88d5760320 | 162 | if (LORAWAN_STATUS_OK != status) { |
kenjiArai | 0:5b88d5760320 | 163 | return status; |
kenjiArai | 0:5b88d5760320 | 164 | } |
kenjiArai | 0:5b88d5760320 | 165 | |
kenjiArai | 0:5b88d5760320 | 166 | return handle_connect(MBED_CONF_LORA_OVER_THE_AIR_ACTIVATION); |
kenjiArai | 0:5b88d5760320 | 167 | } |
kenjiArai | 0:5b88d5760320 | 168 | |
kenjiArai | 0:5b88d5760320 | 169 | lorawan_status_t LoRaWANStack::connect(const lorawan_connect_t &connect) |
kenjiArai | 0:5b88d5760320 | 170 | { |
kenjiArai | 0:5b88d5760320 | 171 | if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { |
kenjiArai | 0:5b88d5760320 | 172 | return LORAWAN_STATUS_NOT_INITIALIZED; |
kenjiArai | 0:5b88d5760320 | 173 | } |
kenjiArai | 0:5b88d5760320 | 174 | |
kenjiArai | 0:5b88d5760320 | 175 | if (_ctrl_flags & CONN_IN_PROGRESS_FLAG) { |
kenjiArai | 0:5b88d5760320 | 176 | return LORAWAN_STATUS_BUSY; |
kenjiArai | 0:5b88d5760320 | 177 | } |
kenjiArai | 0:5b88d5760320 | 178 | |
kenjiArai | 0:5b88d5760320 | 179 | if (_ctrl_flags & CONNECTED_FLAG) { |
kenjiArai | 0:5b88d5760320 | 180 | return LORAWAN_STATUS_ALREADY_CONNECTED; |
kenjiArai | 0:5b88d5760320 | 181 | } |
kenjiArai | 0:5b88d5760320 | 182 | |
kenjiArai | 0:5b88d5760320 | 183 | if (!(connect.connect_type == LORAWAN_CONNECTION_OTAA) |
kenjiArai | 0:5b88d5760320 | 184 | && !(connect.connect_type == LORAWAN_CONNECTION_ABP)) { |
kenjiArai | 0:5b88d5760320 | 185 | return LORAWAN_STATUS_PARAMETER_INVALID; |
kenjiArai | 0:5b88d5760320 | 186 | } |
kenjiArai | 0:5b88d5760320 | 187 | |
kenjiArai | 0:5b88d5760320 | 188 | bool is_otaa = (connect.connect_type == LORAWAN_CONNECTION_OTAA); |
kenjiArai | 0:5b88d5760320 | 189 | |
kenjiArai | 0:5b88d5760320 | 190 | lorawan_status_t status = _loramac.prepare_join(&connect, is_otaa); |
kenjiArai | 0:5b88d5760320 | 191 | |
kenjiArai | 0:5b88d5760320 | 192 | if (LORAWAN_STATUS_OK != status) { |
kenjiArai | 0:5b88d5760320 | 193 | return status; |
kenjiArai | 0:5b88d5760320 | 194 | } |
kenjiArai | 0:5b88d5760320 | 195 | |
kenjiArai | 0:5b88d5760320 | 196 | return handle_connect(is_otaa); |
kenjiArai | 0:5b88d5760320 | 197 | } |
kenjiArai | 0:5b88d5760320 | 198 | |
kenjiArai | 0:5b88d5760320 | 199 | lorawan_status_t LoRaWANStack::add_channels(const lorawan_channelplan_t &channel_plan) |
kenjiArai | 0:5b88d5760320 | 200 | { |
kenjiArai | 0:5b88d5760320 | 201 | if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) { |
kenjiArai | 0:5b88d5760320 | 202 | return LORAWAN_STATUS_NOT_INITIALIZED; |
kenjiArai | 0:5b88d5760320 | 203 | } |
kenjiArai | 0:5b88d5760320 | 204 | |
kenjiArai | 0:5b88d5760320 | 205 | return _loramac.add_channel_plan(channel_plan); |
kenjiArai | 0:5b88d5760320 | 206 | } |
kenjiArai | 0:5b88d5760320 | 207 | |
kenjiArai | 0:5b88d5760320 | 208 | lorawan_status_t LoRaWANStack::remove_a_channel(uint8_t channel_id) |
kenjiArai | 0:5b88d5760320 | 209 | { |
kenjiArai | 0:5b88d5760320 | 210 | if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) { |
kenjiArai | 0:5b88d5760320 | 211 | return LORAWAN_STATUS_NOT_INITIALIZED; |
kenjiArai | 0:5b88d5760320 | 212 | } |
kenjiArai | 0:5b88d5760320 | 213 | |
kenjiArai | 0:5b88d5760320 | 214 | return _loramac.remove_single_channel(channel_id); |
kenjiArai | 0:5b88d5760320 | 215 | } |
kenjiArai | 0:5b88d5760320 | 216 | |
kenjiArai | 0:5b88d5760320 | 217 | lorawan_status_t LoRaWANStack::drop_channel_list() |
kenjiArai | 0:5b88d5760320 | 218 | { |
kenjiArai | 0:5b88d5760320 | 219 | if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) { |
kenjiArai | 0:5b88d5760320 | 220 | return LORAWAN_STATUS_NOT_INITIALIZED; |
kenjiArai | 0:5b88d5760320 | 221 | } |
kenjiArai | 0:5b88d5760320 | 222 | |
kenjiArai | 0:5b88d5760320 | 223 | return _loramac.remove_channel_plan(); |
kenjiArai | 0:5b88d5760320 | 224 | } |
kenjiArai | 0:5b88d5760320 | 225 | |
kenjiArai | 0:5b88d5760320 | 226 | lorawan_status_t LoRaWANStack::get_enabled_channels(lorawan_channelplan_t &channel_plan) |
kenjiArai | 0:5b88d5760320 | 227 | { |
kenjiArai | 0:5b88d5760320 | 228 | if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) { |
kenjiArai | 0:5b88d5760320 | 229 | return LORAWAN_STATUS_NOT_INITIALIZED; |
kenjiArai | 0:5b88d5760320 | 230 | } |
kenjiArai | 0:5b88d5760320 | 231 | |
kenjiArai | 0:5b88d5760320 | 232 | return _loramac.get_channel_plan(channel_plan); |
kenjiArai | 0:5b88d5760320 | 233 | } |
kenjiArai | 0:5b88d5760320 | 234 | |
kenjiArai | 0:5b88d5760320 | 235 | lorawan_status_t LoRaWANStack::set_confirmed_msg_retry(uint8_t count) |
kenjiArai | 0:5b88d5760320 | 236 | { |
kenjiArai | 0:5b88d5760320 | 237 | if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) { |
kenjiArai | 0:5b88d5760320 | 238 | return LORAWAN_STATUS_NOT_INITIALIZED; |
kenjiArai | 0:5b88d5760320 | 239 | } |
kenjiArai | 0:5b88d5760320 | 240 | |
kenjiArai | 0:5b88d5760320 | 241 | if (count >= MAX_CONFIRMED_MSG_RETRIES) { |
kenjiArai | 0:5b88d5760320 | 242 | return LORAWAN_STATUS_PARAMETER_INVALID; |
kenjiArai | 0:5b88d5760320 | 243 | } |
kenjiArai | 0:5b88d5760320 | 244 | |
kenjiArai | 0:5b88d5760320 | 245 | _num_retry = count; |
kenjiArai | 0:5b88d5760320 | 246 | |
kenjiArai | 0:5b88d5760320 | 247 | return LORAWAN_STATUS_OK; |
kenjiArai | 0:5b88d5760320 | 248 | } |
kenjiArai | 0:5b88d5760320 | 249 | |
kenjiArai | 0:5b88d5760320 | 250 | lorawan_status_t LoRaWANStack::set_channel_data_rate(uint8_t data_rate) |
kenjiArai | 0:5b88d5760320 | 251 | { |
kenjiArai | 0:5b88d5760320 | 252 | if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { |
kenjiArai | 0:5b88d5760320 | 253 | return LORAWAN_STATUS_NOT_INITIALIZED; |
kenjiArai | 0:5b88d5760320 | 254 | } |
kenjiArai | 0:5b88d5760320 | 255 | |
kenjiArai | 0:5b88d5760320 | 256 | return _loramac.set_channel_data_rate(data_rate); |
kenjiArai | 0:5b88d5760320 | 257 | } |
kenjiArai | 0:5b88d5760320 | 258 | |
kenjiArai | 0:5b88d5760320 | 259 | |
kenjiArai | 0:5b88d5760320 | 260 | lorawan_status_t LoRaWANStack::enable_adaptive_datarate(bool adr_enabled) |
kenjiArai | 0:5b88d5760320 | 261 | { |
kenjiArai | 0:5b88d5760320 | 262 | if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) { |
kenjiArai | 0:5b88d5760320 | 263 | return LORAWAN_STATUS_NOT_INITIALIZED; |
kenjiArai | 0:5b88d5760320 | 264 | } |
kenjiArai | 0:5b88d5760320 | 265 | |
kenjiArai | 0:5b88d5760320 | 266 | _loramac.enable_adaptive_datarate(adr_enabled); |
kenjiArai | 0:5b88d5760320 | 267 | return LORAWAN_STATUS_OK; |
kenjiArai | 0:5b88d5760320 | 268 | } |
kenjiArai | 0:5b88d5760320 | 269 | |
kenjiArai | 0:5b88d5760320 | 270 | lorawan_status_t LoRaWANStack::stop_sending(void) |
kenjiArai | 0:5b88d5760320 | 271 | { |
kenjiArai | 0:5b88d5760320 | 272 | if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) { |
kenjiArai | 0:5b88d5760320 | 273 | return LORAWAN_STATUS_NOT_INITIALIZED; |
kenjiArai | 0:5b88d5760320 | 274 | } |
kenjiArai | 0:5b88d5760320 | 275 | |
kenjiArai | 0:5b88d5760320 | 276 | lorawan_status_t status = _loramac.clear_tx_pipe(); |
kenjiArai | 0:5b88d5760320 | 277 | |
kenjiArai | 0:5b88d5760320 | 278 | if (status == LORAWAN_STATUS_OK) { |
kenjiArai | 0:5b88d5760320 | 279 | _ctrl_flags &= ~TX_DONE_FLAG; |
kenjiArai | 0:5b88d5760320 | 280 | _loramac.set_tx_ongoing(false); |
kenjiArai | 0:5b88d5760320 | 281 | _device_current_state = DEVICE_STATE_IDLE; |
kenjiArai | 0:5b88d5760320 | 282 | return LORAWAN_STATUS_OK; |
kenjiArai | 0:5b88d5760320 | 283 | } |
kenjiArai | 0:5b88d5760320 | 284 | |
kenjiArai | 0:5b88d5760320 | 285 | return status; |
kenjiArai | 0:5b88d5760320 | 286 | } |
kenjiArai | 0:5b88d5760320 | 287 | |
kenjiArai | 0:5b88d5760320 | 288 | int16_t LoRaWANStack::handle_tx(const uint8_t port, const uint8_t *data, |
kenjiArai | 0:5b88d5760320 | 289 | uint16_t length, uint8_t flags, |
kenjiArai | 0:5b88d5760320 | 290 | bool null_allowed, bool allow_port_0) |
kenjiArai | 0:5b88d5760320 | 291 | { |
kenjiArai | 0:5b88d5760320 | 292 | if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) { |
kenjiArai | 0:5b88d5760320 | 293 | return LORAWAN_STATUS_NOT_INITIALIZED; |
kenjiArai | 0:5b88d5760320 | 294 | } |
kenjiArai | 0:5b88d5760320 | 295 | |
kenjiArai | 0:5b88d5760320 | 296 | if (!null_allowed && !data) { |
kenjiArai | 0:5b88d5760320 | 297 | return LORAWAN_STATUS_PARAMETER_INVALID; |
kenjiArai | 0:5b88d5760320 | 298 | } |
kenjiArai | 0:5b88d5760320 | 299 | |
kenjiArai | 0:5b88d5760320 | 300 | if (!_lw_session.active) { |
kenjiArai | 0:5b88d5760320 | 301 | return LORAWAN_STATUS_NO_ACTIVE_SESSIONS; |
kenjiArai | 0:5b88d5760320 | 302 | } |
kenjiArai | 0:5b88d5760320 | 303 | |
kenjiArai | 0:5b88d5760320 | 304 | if (_loramac.tx_ongoing()) { |
kenjiArai | 0:5b88d5760320 | 305 | return LORAWAN_STATUS_WOULD_BLOCK; |
kenjiArai | 0:5b88d5760320 | 306 | } |
kenjiArai | 0:5b88d5760320 | 307 | |
kenjiArai | 0:5b88d5760320 | 308 | // add a link check request with normal data, until the application |
kenjiArai | 0:5b88d5760320 | 309 | // explicitly removes it. |
kenjiArai | 0:5b88d5760320 | 310 | if (_link_check_requested) { |
kenjiArai | 0:5b88d5760320 | 311 | _loramac.setup_link_check_request(); |
kenjiArai | 0:5b88d5760320 | 312 | } |
kenjiArai | 0:5b88d5760320 | 313 | _qos_cnt = 1; |
kenjiArai | 0:5b88d5760320 | 314 | |
kenjiArai | 0:5b88d5760320 | 315 | lorawan_status_t status; |
kenjiArai | 0:5b88d5760320 | 316 | |
kenjiArai | 0:5b88d5760320 | 317 | if (_loramac.nwk_joined() == false) { |
kenjiArai | 0:5b88d5760320 | 318 | return LORAWAN_STATUS_NO_NETWORK_JOINED; |
kenjiArai | 0:5b88d5760320 | 319 | } |
kenjiArai | 0:5b88d5760320 | 320 | |
kenjiArai | 0:5b88d5760320 | 321 | status = set_application_port(port, allow_port_0); |
kenjiArai | 0:5b88d5760320 | 322 | |
kenjiArai | 0:5b88d5760320 | 323 | if (status != LORAWAN_STATUS_OK) { |
kenjiArai | 0:5b88d5760320 | 324 | tr_error("Illegal application port definition."); |
kenjiArai | 0:5b88d5760320 | 325 | return status; |
kenjiArai | 0:5b88d5760320 | 326 | } |
kenjiArai | 0:5b88d5760320 | 327 | |
kenjiArai | 0:5b88d5760320 | 328 | // All the flags are mutually exclusive. In addition to that MSG_MULTICAST_FLAG cannot be |
kenjiArai | 0:5b88d5760320 | 329 | // used for uplink. |
kenjiArai | 0:5b88d5760320 | 330 | switch (flags & MSG_FLAG_MASK) { |
kenjiArai | 0:5b88d5760320 | 331 | case MSG_UNCONFIRMED_FLAG: |
kenjiArai | 0:5b88d5760320 | 332 | case MSG_CONFIRMED_FLAG: |
kenjiArai | 0:5b88d5760320 | 333 | case MSG_PROPRIETARY_FLAG: |
kenjiArai | 0:5b88d5760320 | 334 | break; |
kenjiArai | 0:5b88d5760320 | 335 | |
kenjiArai | 0:5b88d5760320 | 336 | default: |
kenjiArai | 0:5b88d5760320 | 337 | tr_error("Invalid send flags"); |
kenjiArai | 0:5b88d5760320 | 338 | return LORAWAN_STATUS_PARAMETER_INVALID; |
kenjiArai | 0:5b88d5760320 | 339 | } |
kenjiArai | 0:5b88d5760320 | 340 | |
kenjiArai | 0:5b88d5760320 | 341 | int16_t len = _loramac.prepare_ongoing_tx(port, data, length, flags, _num_retry); |
kenjiArai | 0:5b88d5760320 | 342 | |
kenjiArai | 0:5b88d5760320 | 343 | status = state_controller(DEVICE_STATE_SCHEDULING); |
kenjiArai | 0:5b88d5760320 | 344 | |
kenjiArai | 0:5b88d5760320 | 345 | // send user the length of data which is scheduled now. |
kenjiArai | 0:5b88d5760320 | 346 | // user should take care of the pending data. |
kenjiArai | 0:5b88d5760320 | 347 | return (status == LORAWAN_STATUS_OK) ? len : (int16_t) status; |
kenjiArai | 0:5b88d5760320 | 348 | } |
kenjiArai | 0:5b88d5760320 | 349 | |
kenjiArai | 0:5b88d5760320 | 350 | int16_t LoRaWANStack::handle_rx(uint8_t *data, uint16_t length, uint8_t &port, int &flags, bool validate_params) |
kenjiArai | 0:5b88d5760320 | 351 | { |
kenjiArai | 0:5b88d5760320 | 352 | if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) { |
kenjiArai | 0:5b88d5760320 | 353 | return LORAWAN_STATUS_NOT_INITIALIZED; |
kenjiArai | 0:5b88d5760320 | 354 | } |
kenjiArai | 0:5b88d5760320 | 355 | |
kenjiArai | 0:5b88d5760320 | 356 | if (!_lw_session.active) { |
kenjiArai | 0:5b88d5760320 | 357 | return LORAWAN_STATUS_NO_ACTIVE_SESSIONS; |
kenjiArai | 0:5b88d5760320 | 358 | } |
kenjiArai | 0:5b88d5760320 | 359 | |
kenjiArai | 0:5b88d5760320 | 360 | // No messages to read. |
kenjiArai | 0:5b88d5760320 | 361 | if (!_rx_msg.receive_ready) { |
kenjiArai | 0:5b88d5760320 | 362 | return LORAWAN_STATUS_WOULD_BLOCK; |
kenjiArai | 0:5b88d5760320 | 363 | } |
kenjiArai | 0:5b88d5760320 | 364 | |
kenjiArai | 0:5b88d5760320 | 365 | if (data == NULL || length == 0) { |
kenjiArai | 0:5b88d5760320 | 366 | return LORAWAN_STATUS_PARAMETER_INVALID; |
kenjiArai | 0:5b88d5760320 | 367 | } |
kenjiArai | 0:5b88d5760320 | 368 | |
kenjiArai | 0:5b88d5760320 | 369 | int received_flags = convert_to_msg_flag(_rx_msg.msg.mcps_indication.type); |
kenjiArai | 0:5b88d5760320 | 370 | if (validate_params) { |
kenjiArai | 0:5b88d5760320 | 371 | // Check received message port and flags match with the ones requested by user |
kenjiArai | 0:5b88d5760320 | 372 | received_flags &= MSG_FLAG_MASK; |
kenjiArai | 0:5b88d5760320 | 373 | |
kenjiArai | 0:5b88d5760320 | 374 | if (_rx_msg.msg.mcps_indication.port != port || !(flags & received_flags)) { |
kenjiArai | 0:5b88d5760320 | 375 | return LORAWAN_STATUS_WOULD_BLOCK; |
kenjiArai | 0:5b88d5760320 | 376 | } |
kenjiArai | 0:5b88d5760320 | 377 | } |
kenjiArai | 0:5b88d5760320 | 378 | |
kenjiArai | 0:5b88d5760320 | 379 | // Report values back to user |
kenjiArai | 0:5b88d5760320 | 380 | port = _rx_msg.msg.mcps_indication.port; |
kenjiArai | 0:5b88d5760320 | 381 | flags = received_flags; |
kenjiArai | 0:5b88d5760320 | 382 | |
kenjiArai | 0:5b88d5760320 | 383 | const uint8_t *base_ptr = _rx_msg.msg.mcps_indication.buffer; |
kenjiArai | 0:5b88d5760320 | 384 | uint16_t base_size = _rx_msg.msg.mcps_indication.buffer_size; |
kenjiArai | 0:5b88d5760320 | 385 | bool read_complete = false; |
kenjiArai | 0:5b88d5760320 | 386 | |
kenjiArai | 0:5b88d5760320 | 387 | if (_rx_msg.pending_size == 0) { |
kenjiArai | 0:5b88d5760320 | 388 | _rx_msg.pending_size = _rx_msg.msg.mcps_indication.buffer_size; |
kenjiArai | 0:5b88d5760320 | 389 | _rx_msg.prev_read_size = 0; |
kenjiArai | 0:5b88d5760320 | 390 | } |
kenjiArai | 0:5b88d5760320 | 391 | |
kenjiArai | 0:5b88d5760320 | 392 | // check the length of received message whether we can fit into user |
kenjiArai | 0:5b88d5760320 | 393 | // buffer completely or not |
kenjiArai | 0:5b88d5760320 | 394 | if (_rx_msg.prev_read_size == 0 && _rx_msg.msg.mcps_indication.buffer_size <= length) { |
kenjiArai | 0:5b88d5760320 | 395 | memcpy(data, base_ptr, base_size); |
kenjiArai | 0:5b88d5760320 | 396 | read_complete = true; |
kenjiArai | 0:5b88d5760320 | 397 | } else if (_rx_msg.pending_size > length) { |
kenjiArai | 0:5b88d5760320 | 398 | _rx_msg.pending_size = _rx_msg.pending_size - length; |
kenjiArai | 0:5b88d5760320 | 399 | base_size = length; |
kenjiArai | 0:5b88d5760320 | 400 | memcpy(data, base_ptr + _rx_msg.prev_read_size, base_size); |
kenjiArai | 0:5b88d5760320 | 401 | _rx_msg.prev_read_size += base_size; |
kenjiArai | 0:5b88d5760320 | 402 | } else { |
kenjiArai | 0:5b88d5760320 | 403 | base_size = _rx_msg.pending_size; |
kenjiArai | 0:5b88d5760320 | 404 | memcpy(data, base_ptr + _rx_msg.prev_read_size, base_size); |
kenjiArai | 0:5b88d5760320 | 405 | read_complete = true; |
kenjiArai | 0:5b88d5760320 | 406 | } |
kenjiArai | 0:5b88d5760320 | 407 | |
kenjiArai | 0:5b88d5760320 | 408 | if (read_complete) { |
kenjiArai | 0:5b88d5760320 | 409 | _rx_msg.msg.mcps_indication.buffer = NULL; |
kenjiArai | 0:5b88d5760320 | 410 | _rx_msg.msg.mcps_indication.buffer_size = 0; |
kenjiArai | 0:5b88d5760320 | 411 | _rx_msg.pending_size = 0; |
kenjiArai | 0:5b88d5760320 | 412 | _rx_msg.receive_ready = false; |
kenjiArai | 0:5b88d5760320 | 413 | } |
kenjiArai | 0:5b88d5760320 | 414 | |
kenjiArai | 0:5b88d5760320 | 415 | return base_size; |
kenjiArai | 0:5b88d5760320 | 416 | } |
kenjiArai | 0:5b88d5760320 | 417 | |
kenjiArai | 0:5b88d5760320 | 418 | lorawan_status_t LoRaWANStack::set_link_check_request() |
kenjiArai | 0:5b88d5760320 | 419 | { |
kenjiArai | 0:5b88d5760320 | 420 | if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { |
kenjiArai | 0:5b88d5760320 | 421 | return LORAWAN_STATUS_NOT_INITIALIZED; |
kenjiArai | 0:5b88d5760320 | 422 | } |
kenjiArai | 0:5b88d5760320 | 423 | |
kenjiArai | 0:5b88d5760320 | 424 | if (!_callbacks.link_check_resp) { |
kenjiArai | 0:5b88d5760320 | 425 | tr_error("Must assign a callback function for link check request. "); |
kenjiArai | 0:5b88d5760320 | 426 | return LORAWAN_STATUS_PARAMETER_INVALID; |
kenjiArai | 0:5b88d5760320 | 427 | } |
kenjiArai | 0:5b88d5760320 | 428 | |
kenjiArai | 0:5b88d5760320 | 429 | _link_check_requested = true; |
kenjiArai | 0:5b88d5760320 | 430 | return LORAWAN_STATUS_OK; |
kenjiArai | 0:5b88d5760320 | 431 | } |
kenjiArai | 0:5b88d5760320 | 432 | |
kenjiArai | 0:5b88d5760320 | 433 | void LoRaWANStack::remove_link_check_request() |
kenjiArai | 0:5b88d5760320 | 434 | { |
kenjiArai | 0:5b88d5760320 | 435 | _link_check_requested = false; |
kenjiArai | 0:5b88d5760320 | 436 | } |
kenjiArai | 0:5b88d5760320 | 437 | |
kenjiArai | 0:5b88d5760320 | 438 | lorawan_status_t LoRaWANStack::shutdown() |
kenjiArai | 0:5b88d5760320 | 439 | { |
kenjiArai | 0:5b88d5760320 | 440 | if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { |
kenjiArai | 0:5b88d5760320 | 441 | return LORAWAN_STATUS_NOT_INITIALIZED; |
kenjiArai | 0:5b88d5760320 | 442 | } |
kenjiArai | 0:5b88d5760320 | 443 | |
kenjiArai | 0:5b88d5760320 | 444 | return state_controller(DEVICE_STATE_SHUTDOWN); |
kenjiArai | 0:5b88d5760320 | 445 | } |
kenjiArai | 0:5b88d5760320 | 446 | |
kenjiArai | 0:5b88d5760320 | 447 | lorawan_status_t LoRaWANStack::set_device_class(const device_class_t &device_class) |
kenjiArai | 0:5b88d5760320 | 448 | { |
kenjiArai | 0:5b88d5760320 | 449 | if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { |
kenjiArai | 0:5b88d5760320 | 450 | return LORAWAN_STATUS_NOT_INITIALIZED; |
kenjiArai | 0:5b88d5760320 | 451 | } |
kenjiArai | 0:5b88d5760320 | 452 | |
kenjiArai | 0:5b88d5760320 | 453 | if (device_class == CLASS_B) { |
kenjiArai | 0:5b88d5760320 | 454 | return LORAWAN_STATUS_UNSUPPORTED; |
kenjiArai | 0:5b88d5760320 | 455 | } |
kenjiArai | 0:5b88d5760320 | 456 | _loramac.set_device_class(device_class, |
kenjiArai | 0:5b88d5760320 | 457 | mbed::callback(this, &LoRaWANStack::post_process_tx_no_reception)); |
kenjiArai | 0:5b88d5760320 | 458 | return LORAWAN_STATUS_OK; |
kenjiArai | 0:5b88d5760320 | 459 | } |
kenjiArai | 0:5b88d5760320 | 460 | |
kenjiArai | 0:5b88d5760320 | 461 | lorawan_status_t LoRaWANStack::acquire_tx_metadata(lorawan_tx_metadata &tx_metadata) |
kenjiArai | 0:5b88d5760320 | 462 | { |
kenjiArai | 0:5b88d5760320 | 463 | if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { |
kenjiArai | 0:5b88d5760320 | 464 | return LORAWAN_STATUS_NOT_INITIALIZED; |
kenjiArai | 0:5b88d5760320 | 465 | } |
kenjiArai | 0:5b88d5760320 | 466 | |
kenjiArai | 0:5b88d5760320 | 467 | if (!_tx_metadata.stale) { |
kenjiArai | 0:5b88d5760320 | 468 | tx_metadata = _tx_metadata; |
kenjiArai | 0:5b88d5760320 | 469 | _tx_metadata.stale = true; |
kenjiArai | 0:5b88d5760320 | 470 | return LORAWAN_STATUS_OK; |
kenjiArai | 0:5b88d5760320 | 471 | } |
kenjiArai | 0:5b88d5760320 | 472 | |
kenjiArai | 0:5b88d5760320 | 473 | return LORAWAN_STATUS_METADATA_NOT_AVAILABLE; |
kenjiArai | 0:5b88d5760320 | 474 | } |
kenjiArai | 0:5b88d5760320 | 475 | |
kenjiArai | 0:5b88d5760320 | 476 | lorawan_status_t LoRaWANStack::acquire_rx_metadata(lorawan_rx_metadata &metadata) |
kenjiArai | 0:5b88d5760320 | 477 | { |
kenjiArai | 0:5b88d5760320 | 478 | if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { |
kenjiArai | 0:5b88d5760320 | 479 | return LORAWAN_STATUS_NOT_INITIALIZED; |
kenjiArai | 0:5b88d5760320 | 480 | } |
kenjiArai | 0:5b88d5760320 | 481 | |
kenjiArai | 0:5b88d5760320 | 482 | if (!_rx_metadata.stale) { |
kenjiArai | 0:5b88d5760320 | 483 | metadata = _rx_metadata; |
kenjiArai | 0:5b88d5760320 | 484 | _rx_metadata.stale = true; |
kenjiArai | 0:5b88d5760320 | 485 | return LORAWAN_STATUS_OK; |
kenjiArai | 0:5b88d5760320 | 486 | } |
kenjiArai | 0:5b88d5760320 | 487 | |
kenjiArai | 0:5b88d5760320 | 488 | return LORAWAN_STATUS_METADATA_NOT_AVAILABLE; |
kenjiArai | 0:5b88d5760320 | 489 | } |
kenjiArai | 0:5b88d5760320 | 490 | |
kenjiArai | 0:5b88d5760320 | 491 | lorawan_status_t LoRaWANStack::acquire_backoff_metadata(int &backoff) |
kenjiArai | 0:5b88d5760320 | 492 | { |
kenjiArai | 0:5b88d5760320 | 493 | if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { |
kenjiArai | 0:5b88d5760320 | 494 | return LORAWAN_STATUS_NOT_INITIALIZED; |
kenjiArai | 0:5b88d5760320 | 495 | } |
kenjiArai | 0:5b88d5760320 | 496 | |
kenjiArai | 0:5b88d5760320 | 497 | int id = _loramac.get_backoff_timer_event_id(); |
kenjiArai | 0:5b88d5760320 | 498 | |
kenjiArai | 0:5b88d5760320 | 499 | if (_loramac.get_backoff_timer_event_id() > 0) { |
kenjiArai | 0:5b88d5760320 | 500 | backoff = _queue->time_left(id); |
kenjiArai | 0:5b88d5760320 | 501 | return LORAWAN_STATUS_OK; |
kenjiArai | 0:5b88d5760320 | 502 | } |
kenjiArai | 0:5b88d5760320 | 503 | |
kenjiArai | 0:5b88d5760320 | 504 | backoff = -1; |
kenjiArai | 0:5b88d5760320 | 505 | return LORAWAN_STATUS_METADATA_NOT_AVAILABLE; |
kenjiArai | 0:5b88d5760320 | 506 | } |
kenjiArai | 0:5b88d5760320 | 507 | |
kenjiArai | 0:5b88d5760320 | 508 | /***************************************************************************** |
kenjiArai | 0:5b88d5760320 | 509 | * Interrupt handlers * |
kenjiArai | 0:5b88d5760320 | 510 | ****************************************************************************/ |
kenjiArai | 0:5b88d5760320 | 511 | void LoRaWANStack::tx_interrupt_handler(void) |
kenjiArai | 0:5b88d5760320 | 512 | { |
kenjiArai | 0:5b88d5760320 | 513 | _tx_timestamp = _loramac.get_current_time(); |
kenjiArai | 0:5b88d5760320 | 514 | const int ret = _queue->call(this, &LoRaWANStack::process_transmission); |
kenjiArai | 0:5b88d5760320 | 515 | MBED_ASSERT(ret != 0); |
kenjiArai | 0:5b88d5760320 | 516 | (void)ret; |
kenjiArai | 0:5b88d5760320 | 517 | } |
kenjiArai | 0:5b88d5760320 | 518 | |
kenjiArai | 0:5b88d5760320 | 519 | void LoRaWANStack::rx_interrupt_handler(const uint8_t *payload, uint16_t size, |
kenjiArai | 0:5b88d5760320 | 520 | int16_t rssi, int8_t snr) |
kenjiArai | 0:5b88d5760320 | 521 | { |
kenjiArai | 0:5b88d5760320 | 522 | if (size > sizeof _rx_payload || core_util_atomic_flag_test_and_set(&_rx_payload_in_use)) { |
kenjiArai | 0:5b88d5760320 | 523 | return; |
kenjiArai | 0:5b88d5760320 | 524 | } |
kenjiArai | 0:5b88d5760320 | 525 | |
kenjiArai | 0:5b88d5760320 | 526 | memcpy(_rx_payload, payload, size); |
kenjiArai | 0:5b88d5760320 | 527 | |
kenjiArai | 0:5b88d5760320 | 528 | const uint8_t *ptr = _rx_payload; |
kenjiArai | 0:5b88d5760320 | 529 | const int ret = _queue->call(this, &LoRaWANStack::process_reception, |
kenjiArai | 0:5b88d5760320 | 530 | ptr, size, rssi, snr); |
kenjiArai | 0:5b88d5760320 | 531 | MBED_ASSERT(ret != 0); |
kenjiArai | 0:5b88d5760320 | 532 | (void)ret; |
kenjiArai | 0:5b88d5760320 | 533 | } |
kenjiArai | 0:5b88d5760320 | 534 | |
kenjiArai | 0:5b88d5760320 | 535 | void LoRaWANStack::rx_error_interrupt_handler(void) |
kenjiArai | 0:5b88d5760320 | 536 | { |
kenjiArai | 0:5b88d5760320 | 537 | const int ret = _queue->call(this, &LoRaWANStack::process_reception_timeout, |
kenjiArai | 0:5b88d5760320 | 538 | false); |
kenjiArai | 0:5b88d5760320 | 539 | MBED_ASSERT(ret != 0); |
kenjiArai | 0:5b88d5760320 | 540 | (void)ret; |
kenjiArai | 0:5b88d5760320 | 541 | } |
kenjiArai | 0:5b88d5760320 | 542 | |
kenjiArai | 0:5b88d5760320 | 543 | void LoRaWANStack::tx_timeout_interrupt_handler(void) |
kenjiArai | 0:5b88d5760320 | 544 | { |
kenjiArai | 0:5b88d5760320 | 545 | const int ret = _queue->call(this, &LoRaWANStack::process_transmission_timeout); |
kenjiArai | 0:5b88d5760320 | 546 | MBED_ASSERT(ret != 0); |
kenjiArai | 0:5b88d5760320 | 547 | (void)ret; |
kenjiArai | 0:5b88d5760320 | 548 | } |
kenjiArai | 0:5b88d5760320 | 549 | |
kenjiArai | 0:5b88d5760320 | 550 | void LoRaWANStack::rx_timeout_interrupt_handler(void) |
kenjiArai | 0:5b88d5760320 | 551 | { |
kenjiArai | 0:5b88d5760320 | 552 | const int ret = _queue->call(this, &LoRaWANStack::process_reception_timeout, |
kenjiArai | 0:5b88d5760320 | 553 | true); |
kenjiArai | 0:5b88d5760320 | 554 | MBED_ASSERT(ret != 0); |
kenjiArai | 0:5b88d5760320 | 555 | (void)ret; |
kenjiArai | 0:5b88d5760320 | 556 | } |
kenjiArai | 0:5b88d5760320 | 557 | |
kenjiArai | 0:5b88d5760320 | 558 | /***************************************************************************** |
kenjiArai | 0:5b88d5760320 | 559 | * Processors for deferred interrupts * |
kenjiArai | 0:5b88d5760320 | 560 | ****************************************************************************/ |
kenjiArai | 0:5b88d5760320 | 561 | void LoRaWANStack::process_transmission_timeout() |
kenjiArai | 0:5b88d5760320 | 562 | { |
kenjiArai | 0:5b88d5760320 | 563 | // this is a fatal error and should not happen |
kenjiArai | 0:5b88d5760320 | 564 | tr_debug("TX Timeout"); |
kenjiArai | 0:5b88d5760320 | 565 | _loramac.on_radio_tx_timeout(); |
kenjiArai | 0:5b88d5760320 | 566 | _ctrl_flags &= ~TX_DONE_FLAG; |
kenjiArai | 0:5b88d5760320 | 567 | if (_device_current_state == DEVICE_STATE_JOINING) { |
kenjiArai | 0:5b88d5760320 | 568 | mlme_confirm_handler(); |
kenjiArai | 0:5b88d5760320 | 569 | } else { |
kenjiArai | 0:5b88d5760320 | 570 | state_controller(DEVICE_STATE_STATUS_CHECK); |
kenjiArai | 0:5b88d5760320 | 571 | } |
kenjiArai | 0:5b88d5760320 | 572 | |
kenjiArai | 0:5b88d5760320 | 573 | state_machine_run_to_completion(); |
kenjiArai | 0:5b88d5760320 | 574 | } |
kenjiArai | 0:5b88d5760320 | 575 | |
kenjiArai | 0:5b88d5760320 | 576 | void LoRaWANStack::process_transmission(void) |
kenjiArai | 0:5b88d5760320 | 577 | { |
kenjiArai | 0:5b88d5760320 | 578 | tr_debug("Transmission completed"); |
kenjiArai | 0:5b88d5760320 | 579 | |
kenjiArai | 0:5b88d5760320 | 580 | if (_device_current_state == DEVICE_STATE_JOINING) { |
kenjiArai | 0:5b88d5760320 | 581 | _device_current_state = DEVICE_STATE_AWAITING_JOIN_ACCEPT; |
kenjiArai | 0:5b88d5760320 | 582 | } |
kenjiArai | 0:5b88d5760320 | 583 | |
kenjiArai | 0:5b88d5760320 | 584 | if (_device_current_state == DEVICE_STATE_SENDING) { |
kenjiArai | 0:5b88d5760320 | 585 | if (_loramac.get_mcps_confirmation()->req_type == MCPS_CONFIRMED) { |
kenjiArai | 0:5b88d5760320 | 586 | tr_debug("Awaiting ACK"); |
kenjiArai | 0:5b88d5760320 | 587 | _device_current_state = DEVICE_STATE_AWAITING_ACK; |
kenjiArai | 0:5b88d5760320 | 588 | } |
kenjiArai | 0:5b88d5760320 | 589 | } |
kenjiArai | 0:5b88d5760320 | 590 | |
kenjiArai | 0:5b88d5760320 | 591 | _loramac.on_radio_tx_done(_tx_timestamp); |
kenjiArai | 0:5b88d5760320 | 592 | } |
kenjiArai | 0:5b88d5760320 | 593 | |
kenjiArai | 0:5b88d5760320 | 594 | void LoRaWANStack::post_process_tx_with_reception() |
kenjiArai | 0:5b88d5760320 | 595 | { |
kenjiArai | 0:5b88d5760320 | 596 | if (_loramac.get_mcps_confirmation()->req_type == MCPS_CONFIRMED) { |
kenjiArai | 0:5b88d5760320 | 597 | // if ack was not received, we will try retransmission after |
kenjiArai | 0:5b88d5760320 | 598 | // ACK_TIMEOUT. handle_data_frame() already disables ACK_TIMEOUT timer |
kenjiArai | 0:5b88d5760320 | 599 | // if ack was received. Otherwise, following method will be called in |
kenjiArai | 0:5b88d5760320 | 600 | // LoRaMac.cpp, on_ack_timeout_timer_event(). |
kenjiArai | 0:5b88d5760320 | 601 | if (_loramac.get_mcps_indication()->is_ack_recvd) { |
kenjiArai | 0:5b88d5760320 | 602 | _ctrl_flags |= TX_DONE_FLAG; |
kenjiArai | 0:5b88d5760320 | 603 | _ctrl_flags &= ~RETRY_EXHAUSTED_FLAG; |
kenjiArai | 0:5b88d5760320 | 604 | tr_debug("Ack=OK, NbTrials=%d", |
kenjiArai | 0:5b88d5760320 | 605 | _loramac.get_mcps_confirmation()->nb_retries); |
kenjiArai | 0:5b88d5760320 | 606 | _loramac.post_process_mcps_req(); |
kenjiArai | 0:5b88d5760320 | 607 | make_tx_metadata_available(); |
kenjiArai | 0:5b88d5760320 | 608 | state_controller(DEVICE_STATE_STATUS_CHECK); |
kenjiArai | 0:5b88d5760320 | 609 | } else { |
kenjiArai | 0:5b88d5760320 | 610 | if (!_loramac.continue_sending_process() |
kenjiArai | 0:5b88d5760320 | 611 | && _loramac.get_current_slot() != RX_SLOT_WIN_1) { |
kenjiArai | 0:5b88d5760320 | 612 | tr_error("Retries exhausted for Class %s device", |
kenjiArai | 0:5b88d5760320 | 613 | _loramac.get_device_class() == CLASS_A ? "A" : "C"); |
kenjiArai | 0:5b88d5760320 | 614 | _ctrl_flags &= ~TX_DONE_FLAG; |
kenjiArai | 0:5b88d5760320 | 615 | _ctrl_flags |= RETRY_EXHAUSTED_FLAG; |
kenjiArai | 0:5b88d5760320 | 616 | _loramac.post_process_mcps_req(); |
kenjiArai | 0:5b88d5760320 | 617 | make_tx_metadata_available(); |
kenjiArai | 0:5b88d5760320 | 618 | state_controller(DEVICE_STATE_STATUS_CHECK); |
kenjiArai | 0:5b88d5760320 | 619 | } |
kenjiArai | 0:5b88d5760320 | 620 | } |
kenjiArai | 0:5b88d5760320 | 621 | } else { |
kenjiArai | 0:5b88d5760320 | 622 | // handle UNCONFIRMED case here, RX slots were turned off due to |
kenjiArai | 0:5b88d5760320 | 623 | // valid packet reception. |
kenjiArai | 0:5b88d5760320 | 624 | uint8_t prev_QOS_level = _loramac.get_prev_QOS_level(); |
kenjiArai | 0:5b88d5760320 | 625 | uint8_t QOS_level = _loramac.get_QOS_level(); |
kenjiArai | 0:5b88d5760320 | 626 | |
kenjiArai | 0:5b88d5760320 | 627 | // We will not apply QOS on the post-processing of the previous |
kenjiArai | 0:5b88d5760320 | 628 | // outgoing message as we would have received QOS instruction in response |
kenjiArai | 0:5b88d5760320 | 629 | // to that particular message |
kenjiArai | 0:5b88d5760320 | 630 | if (QOS_level > LORAWAN_DEFAULT_QOS && _qos_cnt < QOS_level |
kenjiArai | 0:5b88d5760320 | 631 | && (prev_QOS_level == QOS_level)) { |
kenjiArai | 0:5b88d5760320 | 632 | _ctrl_flags &= ~TX_DONE_FLAG; |
kenjiArai | 0:5b88d5760320 | 633 | const int ret = _queue->call(this, &LoRaWANStack::state_controller, |
kenjiArai | 0:5b88d5760320 | 634 | DEVICE_STATE_SCHEDULING); |
kenjiArai | 0:5b88d5760320 | 635 | MBED_ASSERT(ret != 0); |
kenjiArai | 0:5b88d5760320 | 636 | (void) ret; |
kenjiArai | 0:5b88d5760320 | 637 | _qos_cnt++; |
kenjiArai | 0:5b88d5760320 | 638 | tr_info("QOS: repeated transmission #%d queued", _qos_cnt); |
kenjiArai | 0:5b88d5760320 | 639 | } else { |
kenjiArai | 0:5b88d5760320 | 640 | _loramac.post_process_mcps_req(); |
kenjiArai | 0:5b88d5760320 | 641 | _ctrl_flags |= TX_DONE_FLAG; |
kenjiArai | 0:5b88d5760320 | 642 | make_tx_metadata_available(); |
kenjiArai | 0:5b88d5760320 | 643 | state_controller(DEVICE_STATE_STATUS_CHECK); |
kenjiArai | 0:5b88d5760320 | 644 | } |
kenjiArai | 0:5b88d5760320 | 645 | } |
kenjiArai | 0:5b88d5760320 | 646 | } |
kenjiArai | 0:5b88d5760320 | 647 | |
kenjiArai | 0:5b88d5760320 | 648 | void LoRaWANStack::post_process_tx_no_reception() |
kenjiArai | 0:5b88d5760320 | 649 | { |
kenjiArai | 0:5b88d5760320 | 650 | if (_loramac.get_mcps_confirmation()->req_type == MCPS_CONFIRMED) { |
kenjiArai | 0:5b88d5760320 | 651 | if (_loramac.continue_sending_process()) { |
kenjiArai | 0:5b88d5760320 | 652 | _ctrl_flags &= ~TX_DONE_FLAG; |
kenjiArai | 0:5b88d5760320 | 653 | _ctrl_flags &= ~RETRY_EXHAUSTED_FLAG; |
kenjiArai | 0:5b88d5760320 | 654 | return; |
kenjiArai | 0:5b88d5760320 | 655 | } |
kenjiArai | 0:5b88d5760320 | 656 | |
kenjiArai | 0:5b88d5760320 | 657 | tr_error("Retries exhausted for Class %s device", |
kenjiArai | 0:5b88d5760320 | 658 | _loramac.get_device_class() == CLASS_A ? "A" : "C"); |
kenjiArai | 0:5b88d5760320 | 659 | _ctrl_flags &= ~TX_DONE_FLAG; |
kenjiArai | 0:5b88d5760320 | 660 | _ctrl_flags |= RETRY_EXHAUSTED_FLAG; |
kenjiArai | 0:5b88d5760320 | 661 | } else { |
kenjiArai | 0:5b88d5760320 | 662 | _ctrl_flags |= TX_DONE_FLAG; |
kenjiArai | 0:5b88d5760320 | 663 | |
kenjiArai | 0:5b88d5760320 | 664 | uint8_t prev_QOS_level = _loramac.get_prev_QOS_level(); |
kenjiArai | 0:5b88d5760320 | 665 | uint8_t QOS_level = _loramac.get_QOS_level(); |
kenjiArai | 0:5b88d5760320 | 666 | |
kenjiArai | 0:5b88d5760320 | 667 | if (QOS_level > LORAWAN_DEFAULT_QOS && (prev_QOS_level == QOS_level)) { |
kenjiArai | 0:5b88d5760320 | 668 | if (_qos_cnt < QOS_level) { |
kenjiArai | 0:5b88d5760320 | 669 | const int ret = _queue->call(this, &LoRaWANStack::state_controller, |
kenjiArai | 0:5b88d5760320 | 670 | DEVICE_STATE_SCHEDULING); |
kenjiArai | 0:5b88d5760320 | 671 | MBED_ASSERT(ret != 0); |
kenjiArai | 0:5b88d5760320 | 672 | (void)ret; |
kenjiArai | 0:5b88d5760320 | 673 | _qos_cnt++; |
kenjiArai | 0:5b88d5760320 | 674 | tr_info("QOS: repeated transmission #%d queued", _qos_cnt); |
kenjiArai | 0:5b88d5760320 | 675 | state_machine_run_to_completion(); |
kenjiArai | 0:5b88d5760320 | 676 | return; |
kenjiArai | 0:5b88d5760320 | 677 | } |
kenjiArai | 0:5b88d5760320 | 678 | } |
kenjiArai | 0:5b88d5760320 | 679 | } |
kenjiArai | 0:5b88d5760320 | 680 | |
kenjiArai | 0:5b88d5760320 | 681 | _loramac.post_process_mcps_req(); |
kenjiArai | 0:5b88d5760320 | 682 | make_tx_metadata_available(); |
kenjiArai | 0:5b88d5760320 | 683 | state_controller(DEVICE_STATE_STATUS_CHECK); |
kenjiArai | 0:5b88d5760320 | 684 | state_machine_run_to_completion(); |
kenjiArai | 0:5b88d5760320 | 685 | } |
kenjiArai | 0:5b88d5760320 | 686 | |
kenjiArai | 0:5b88d5760320 | 687 | void LoRaWANStack::handle_scheduling_failure(void) |
kenjiArai | 0:5b88d5760320 | 688 | { |
kenjiArai | 0:5b88d5760320 | 689 | tr_error("Failed to schedule transmission"); |
kenjiArai | 0:5b88d5760320 | 690 | state_controller(DEVICE_STATE_STATUS_CHECK); |
kenjiArai | 0:5b88d5760320 | 691 | state_machine_run_to_completion(); |
kenjiArai | 0:5b88d5760320 | 692 | } |
kenjiArai | 0:5b88d5760320 | 693 | |
kenjiArai | 0:5b88d5760320 | 694 | |
kenjiArai | 0:5b88d5760320 | 695 | void LoRaWANStack::process_reception(const uint8_t *const payload, uint16_t size, |
kenjiArai | 0:5b88d5760320 | 696 | int16_t rssi, int8_t snr) |
kenjiArai | 0:5b88d5760320 | 697 | { |
kenjiArai | 0:5b88d5760320 | 698 | _device_current_state = DEVICE_STATE_RECEIVING; |
kenjiArai | 0:5b88d5760320 | 699 | |
kenjiArai | 0:5b88d5760320 | 700 | _ctrl_flags &= ~MSG_RECVD_FLAG; |
kenjiArai | 0:5b88d5760320 | 701 | _ctrl_flags &= ~TX_DONE_FLAG; |
kenjiArai | 0:5b88d5760320 | 702 | _ctrl_flags &= ~RETRY_EXHAUSTED_FLAG; |
kenjiArai | 0:5b88d5760320 | 703 | |
kenjiArai | 0:5b88d5760320 | 704 | _loramac.on_radio_rx_done(payload, size, rssi, snr); |
kenjiArai | 0:5b88d5760320 | 705 | |
kenjiArai | 0:5b88d5760320 | 706 | if (_loramac.get_mlme_confirmation()->pending) { |
kenjiArai | 0:5b88d5760320 | 707 | _loramac.post_process_mlme_request(); |
kenjiArai | 0:5b88d5760320 | 708 | mlme_confirm_handler(); |
kenjiArai | 0:5b88d5760320 | 709 | |
kenjiArai | 0:5b88d5760320 | 710 | if (_loramac.get_mlme_confirmation()->req_type == MLME_JOIN) { |
kenjiArai | 0:5b88d5760320 | 711 | core_util_atomic_flag_clear(&_rx_payload_in_use); |
kenjiArai | 0:5b88d5760320 | 712 | return; |
kenjiArai | 0:5b88d5760320 | 713 | } |
kenjiArai | 0:5b88d5760320 | 714 | } |
kenjiArai | 0:5b88d5760320 | 715 | |
kenjiArai | 0:5b88d5760320 | 716 | if (!_loramac.nwk_joined()) { |
kenjiArai | 0:5b88d5760320 | 717 | core_util_atomic_flag_clear(&_rx_payload_in_use); |
kenjiArai | 0:5b88d5760320 | 718 | return; |
kenjiArai | 0:5b88d5760320 | 719 | } |
kenjiArai | 0:5b88d5760320 | 720 | |
kenjiArai | 0:5b88d5760320 | 721 | make_rx_metadata_available(); |
kenjiArai | 0:5b88d5760320 | 722 | |
kenjiArai | 0:5b88d5760320 | 723 | // Post process transmission in response to the reception |
kenjiArai | 0:5b88d5760320 | 724 | post_process_tx_with_reception(); |
kenjiArai | 0:5b88d5760320 | 725 | |
kenjiArai | 0:5b88d5760320 | 726 | // handle any pending MCPS indication |
kenjiArai | 0:5b88d5760320 | 727 | if (_loramac.get_mcps_indication()->pending) { |
kenjiArai | 0:5b88d5760320 | 728 | _loramac.post_process_mcps_ind(); |
kenjiArai | 0:5b88d5760320 | 729 | _ctrl_flags |= MSG_RECVD_FLAG; |
kenjiArai | 0:5b88d5760320 | 730 | state_controller(DEVICE_STATE_STATUS_CHECK); |
kenjiArai | 0:5b88d5760320 | 731 | } |
kenjiArai | 0:5b88d5760320 | 732 | |
kenjiArai | 0:5b88d5760320 | 733 | // complete the cycle only if TX_DONE_FLAG is set |
kenjiArai | 0:5b88d5760320 | 734 | if (_ctrl_flags & TX_DONE_FLAG) { |
kenjiArai | 0:5b88d5760320 | 735 | state_machine_run_to_completion(); |
kenjiArai | 0:5b88d5760320 | 736 | } |
kenjiArai | 0:5b88d5760320 | 737 | |
kenjiArai | 0:5b88d5760320 | 738 | // suppress auto uplink if another auto-uplink is in AWAITING_ACK state |
kenjiArai | 0:5b88d5760320 | 739 | if (_loramac.get_mlme_indication()->pending && !_automatic_uplink_ongoing) { |
kenjiArai | 0:5b88d5760320 | 740 | tr_debug("MLME Indication pending"); |
kenjiArai | 0:5b88d5760320 | 741 | _loramac.post_process_mlme_ind(); |
kenjiArai | 0:5b88d5760320 | 742 | tr_debug("Immediate Uplink requested"); |
kenjiArai | 0:5b88d5760320 | 743 | mlme_indication_handler(); |
kenjiArai | 0:5b88d5760320 | 744 | } |
kenjiArai | 0:5b88d5760320 | 745 | |
kenjiArai | 0:5b88d5760320 | 746 | core_util_atomic_flag_clear(&_rx_payload_in_use); |
kenjiArai | 0:5b88d5760320 | 747 | } |
kenjiArai | 0:5b88d5760320 | 748 | |
kenjiArai | 0:5b88d5760320 | 749 | void LoRaWANStack::process_reception_timeout(bool is_timeout) |
kenjiArai | 0:5b88d5760320 | 750 | { |
kenjiArai | 0:5b88d5760320 | 751 | rx_slot_t slot = _loramac.get_current_slot(); |
kenjiArai | 0:5b88d5760320 | 752 | |
kenjiArai | 0:5b88d5760320 | 753 | // when is_timeout == false, a CRC error took place in the received frame |
kenjiArai | 0:5b88d5760320 | 754 | // we treat that erroneous frame as no frame received at all, hence handle |
kenjiArai | 0:5b88d5760320 | 755 | // it exactly as we would handle timeout |
kenjiArai | 0:5b88d5760320 | 756 | _loramac.on_radio_rx_timeout(is_timeout); |
kenjiArai | 0:5b88d5760320 | 757 | |
kenjiArai | 0:5b88d5760320 | 758 | if (slot == RX_SLOT_WIN_2 && !_loramac.nwk_joined()) { |
kenjiArai | 0:5b88d5760320 | 759 | state_controller(DEVICE_STATE_JOINING); |
kenjiArai | 0:5b88d5760320 | 760 | return; |
kenjiArai | 0:5b88d5760320 | 761 | } |
kenjiArai | 0:5b88d5760320 | 762 | |
kenjiArai | 0:5b88d5760320 | 763 | /** |
kenjiArai | 0:5b88d5760320 | 764 | * LoRaWAN Specification 1.0.2. Section 3.3.6 |
kenjiArai | 0:5b88d5760320 | 765 | * Main point: |
kenjiArai | 0:5b88d5760320 | 766 | * We indicate successful transmission |
kenjiArai | 0:5b88d5760320 | 767 | * of UNCONFIRMED message after RX windows are done with. |
kenjiArai | 0:5b88d5760320 | 768 | * For a CONFIRMED message, it means that we have not received |
kenjiArai | 0:5b88d5760320 | 769 | * ack (actually nothing was received), and we should retransmit if we can. |
kenjiArai | 0:5b88d5760320 | 770 | * |
kenjiArai | 0:5b88d5760320 | 771 | * NOTE: This code block doesn't get hit for Class C as in Class C, RX2 timeout |
kenjiArai | 0:5b88d5760320 | 772 | * never occurs. |
kenjiArai | 0:5b88d5760320 | 773 | */ |
kenjiArai | 0:5b88d5760320 | 774 | if (slot == RX_SLOT_WIN_2) { |
kenjiArai | 0:5b88d5760320 | 775 | post_process_tx_no_reception(); |
kenjiArai | 0:5b88d5760320 | 776 | } |
kenjiArai | 0:5b88d5760320 | 777 | } |
kenjiArai | 0:5b88d5760320 | 778 | |
kenjiArai | 0:5b88d5760320 | 779 | /***************************************************************************** |
kenjiArai | 0:5b88d5760320 | 780 | * Private methods * |
kenjiArai | 0:5b88d5760320 | 781 | ****************************************************************************/ |
kenjiArai | 0:5b88d5760320 | 782 | void LoRaWANStack::make_tx_metadata_available(void) |
kenjiArai | 0:5b88d5760320 | 783 | { |
kenjiArai | 0:5b88d5760320 | 784 | _tx_metadata.stale = false; |
kenjiArai | 0:5b88d5760320 | 785 | _tx_metadata.channel = _loramac.get_mcps_confirmation()->channel; |
kenjiArai | 0:5b88d5760320 | 786 | _tx_metadata.data_rate = _loramac.get_mcps_confirmation()->data_rate; |
kenjiArai | 0:5b88d5760320 | 787 | _tx_metadata.tx_power = _loramac.get_mcps_confirmation()->tx_power; |
kenjiArai | 0:5b88d5760320 | 788 | _tx_metadata.tx_toa = _loramac.get_mcps_confirmation()->tx_toa; |
kenjiArai | 0:5b88d5760320 | 789 | _tx_metadata.nb_retries = _loramac.get_mcps_confirmation()->nb_retries; |
kenjiArai | 0:5b88d5760320 | 790 | } |
kenjiArai | 0:5b88d5760320 | 791 | |
kenjiArai | 0:5b88d5760320 | 792 | void LoRaWANStack::make_rx_metadata_available(void) |
kenjiArai | 0:5b88d5760320 | 793 | { |
kenjiArai | 0:5b88d5760320 | 794 | _rx_metadata.stale = false; |
kenjiArai | 0:5b88d5760320 | 795 | _rx_metadata.rx_datarate = _loramac.get_mcps_indication()->rx_datarate; |
kenjiArai | 0:5b88d5760320 | 796 | _rx_metadata.rssi = _loramac.get_mcps_indication()->rssi; |
kenjiArai | 0:5b88d5760320 | 797 | _rx_metadata.snr = _loramac.get_mcps_indication()->snr; |
kenjiArai | 0:5b88d5760320 | 798 | _rx_metadata.channel = _loramac.get_mcps_indication()->channel; |
kenjiArai | 0:5b88d5760320 | 799 | _rx_metadata.rx_toa = _loramac.get_mcps_indication()->rx_toa; |
kenjiArai | 0:5b88d5760320 | 800 | } |
kenjiArai | 0:5b88d5760320 | 801 | |
kenjiArai | 0:5b88d5760320 | 802 | bool LoRaWANStack::is_port_valid(const uint8_t port, bool allow_port_0) |
kenjiArai | 0:5b88d5760320 | 803 | { |
kenjiArai | 0:5b88d5760320 | 804 | //Application should not use reserved and illegal port numbers. |
kenjiArai | 0:5b88d5760320 | 805 | if (port == 0) { |
kenjiArai | 0:5b88d5760320 | 806 | return allow_port_0; |
kenjiArai | 0:5b88d5760320 | 807 | } else if (port == COMPLIANCE_TESTING_PORT) { |
kenjiArai | 0:5b88d5760320 | 808 | #if !defined(LORAWAN_COMPLIANCE_TEST) |
kenjiArai | 0:5b88d5760320 | 809 | return false; |
kenjiArai | 0:5b88d5760320 | 810 | #endif |
kenjiArai | 0:5b88d5760320 | 811 | } else { |
kenjiArai | 0:5b88d5760320 | 812 | return true; |
kenjiArai | 0:5b88d5760320 | 813 | } |
kenjiArai | 0:5b88d5760320 | 814 | |
kenjiArai | 0:5b88d5760320 | 815 | // fallback for compliance testing port if LORAWAN_COMPLIANCE_TEST |
kenjiArai | 0:5b88d5760320 | 816 | // was defined |
kenjiArai | 0:5b88d5760320 | 817 | return true; |
kenjiArai | 0:5b88d5760320 | 818 | } |
kenjiArai | 0:5b88d5760320 | 819 | |
kenjiArai | 0:5b88d5760320 | 820 | lorawan_status_t LoRaWANStack::set_application_port(const uint8_t port, bool allow_port_0) |
kenjiArai | 0:5b88d5760320 | 821 | { |
kenjiArai | 0:5b88d5760320 | 822 | if (is_port_valid(port, allow_port_0)) { |
kenjiArai | 0:5b88d5760320 | 823 | _app_port = port; |
kenjiArai | 0:5b88d5760320 | 824 | return LORAWAN_STATUS_OK; |
kenjiArai | 0:5b88d5760320 | 825 | } |
kenjiArai | 0:5b88d5760320 | 826 | |
kenjiArai | 0:5b88d5760320 | 827 | return LORAWAN_STATUS_PORT_INVALID; |
kenjiArai | 0:5b88d5760320 | 828 | } |
kenjiArai | 0:5b88d5760320 | 829 | |
kenjiArai | 0:5b88d5760320 | 830 | void LoRaWANStack::state_machine_run_to_completion() |
kenjiArai | 0:5b88d5760320 | 831 | { |
kenjiArai | 0:5b88d5760320 | 832 | if (_loramac.get_device_class() == CLASS_C) { |
kenjiArai | 0:5b88d5760320 | 833 | _device_current_state = DEVICE_STATE_RECEIVING; |
kenjiArai | 0:5b88d5760320 | 834 | return; |
kenjiArai | 0:5b88d5760320 | 835 | } |
kenjiArai | 0:5b88d5760320 | 836 | |
kenjiArai | 0:5b88d5760320 | 837 | _device_current_state = DEVICE_STATE_IDLE; |
kenjiArai | 0:5b88d5760320 | 838 | } |
kenjiArai | 0:5b88d5760320 | 839 | |
kenjiArai | 0:5b88d5760320 | 840 | void LoRaWANStack::send_event_to_application(const lorawan_event_t event) const |
kenjiArai | 0:5b88d5760320 | 841 | { |
kenjiArai | 0:5b88d5760320 | 842 | if (_callbacks.events) { |
kenjiArai | 0:5b88d5760320 | 843 | const int ret = _queue->call(_callbacks.events, event); |
kenjiArai | 0:5b88d5760320 | 844 | MBED_ASSERT(ret != 0); |
kenjiArai | 0:5b88d5760320 | 845 | (void)ret; |
kenjiArai | 0:5b88d5760320 | 846 | } |
kenjiArai | 0:5b88d5760320 | 847 | } |
kenjiArai | 0:5b88d5760320 | 848 | |
kenjiArai | 0:5b88d5760320 | 849 | void LoRaWANStack::send_automatic_uplink_message(const uint8_t port) |
kenjiArai | 0:5b88d5760320 | 850 | { |
kenjiArai | 0:5b88d5760320 | 851 | // we will silently ignore the automatic uplink event if the user is already |
kenjiArai | 0:5b88d5760320 | 852 | // sending something |
kenjiArai | 0:5b88d5760320 | 853 | const int16_t ret = handle_tx(port, NULL, 0, MSG_CONFIRMED_FLAG, true, true); |
kenjiArai | 0:5b88d5760320 | 854 | if (ret == LORAWAN_STATUS_WOULD_BLOCK) { |
kenjiArai | 0:5b88d5760320 | 855 | _automatic_uplink_ongoing = false; |
kenjiArai | 0:5b88d5760320 | 856 | } else if (ret < 0) { |
kenjiArai | 0:5b88d5760320 | 857 | tr_debug("Failed to generate AUTOMATIC UPLINK, error code = %d", ret); |
kenjiArai | 0:5b88d5760320 | 858 | send_event_to_application(AUTOMATIC_UPLINK_ERROR); |
kenjiArai | 0:5b88d5760320 | 859 | } |
kenjiArai | 0:5b88d5760320 | 860 | } |
kenjiArai | 0:5b88d5760320 | 861 | |
kenjiArai | 0:5b88d5760320 | 862 | int LoRaWANStack::convert_to_msg_flag(const mcps_type_t type) |
kenjiArai | 0:5b88d5760320 | 863 | { |
kenjiArai | 0:5b88d5760320 | 864 | int msg_flag = MSG_UNCONFIRMED_FLAG; |
kenjiArai | 0:5b88d5760320 | 865 | switch (type) { |
kenjiArai | 0:5b88d5760320 | 866 | case MCPS_UNCONFIRMED: |
kenjiArai | 0:5b88d5760320 | 867 | msg_flag = MSG_UNCONFIRMED_FLAG; |
kenjiArai | 0:5b88d5760320 | 868 | break; |
kenjiArai | 0:5b88d5760320 | 869 | |
kenjiArai | 0:5b88d5760320 | 870 | case MCPS_CONFIRMED: |
kenjiArai | 0:5b88d5760320 | 871 | msg_flag = MSG_CONFIRMED_FLAG; |
kenjiArai | 0:5b88d5760320 | 872 | break; |
kenjiArai | 0:5b88d5760320 | 873 | |
kenjiArai | 0:5b88d5760320 | 874 | case MCPS_MULTICAST: |
kenjiArai | 0:5b88d5760320 | 875 | msg_flag = MSG_MULTICAST_FLAG; |
kenjiArai | 0:5b88d5760320 | 876 | break; |
kenjiArai | 0:5b88d5760320 | 877 | |
kenjiArai | 0:5b88d5760320 | 878 | case MCPS_PROPRIETARY: |
kenjiArai | 0:5b88d5760320 | 879 | msg_flag = MSG_PROPRIETARY_FLAG; |
kenjiArai | 0:5b88d5760320 | 880 | break; |
kenjiArai | 0:5b88d5760320 | 881 | |
kenjiArai | 0:5b88d5760320 | 882 | default: |
kenjiArai | 0:5b88d5760320 | 883 | tr_error("Unknown message type!"); |
kenjiArai | 0:5b88d5760320 | 884 | MBED_ASSERT(0); |
kenjiArai | 0:5b88d5760320 | 885 | } |
kenjiArai | 0:5b88d5760320 | 886 | |
kenjiArai | 0:5b88d5760320 | 887 | return msg_flag; |
kenjiArai | 0:5b88d5760320 | 888 | } |
kenjiArai | 0:5b88d5760320 | 889 | |
kenjiArai | 0:5b88d5760320 | 890 | lorawan_status_t LoRaWANStack::handle_connect(bool is_otaa) |
kenjiArai | 0:5b88d5760320 | 891 | { |
kenjiArai | 0:5b88d5760320 | 892 | _ctrl_flags |= CONN_IN_PROGRESS_FLAG; |
kenjiArai | 0:5b88d5760320 | 893 | |
kenjiArai | 0:5b88d5760320 | 894 | if (is_otaa) { |
kenjiArai | 0:5b88d5760320 | 895 | tr_debug("Initiating OTAA"); |
kenjiArai | 0:5b88d5760320 | 896 | |
kenjiArai | 0:5b88d5760320 | 897 | // In 1.0.2 spec, counters are always set to zero for new connection. |
kenjiArai | 0:5b88d5760320 | 898 | // This section is common for both normal and |
kenjiArai | 0:5b88d5760320 | 899 | // connection restore at this moment. Will change in future with 1.1 support. |
kenjiArai | 0:5b88d5760320 | 900 | _lw_session.downlink_counter = 0; |
kenjiArai | 0:5b88d5760320 | 901 | _lw_session.uplink_counter = 0; |
kenjiArai | 0:5b88d5760320 | 902 | _ctrl_flags |= USING_OTAA_FLAG; |
kenjiArai | 0:5b88d5760320 | 903 | } else { |
kenjiArai | 0:5b88d5760320 | 904 | // If current state is SHUTDOWN, device may be trying to re-establish |
kenjiArai | 0:5b88d5760320 | 905 | // communication. In case of ABP specification is meddled about frame counters. |
kenjiArai | 0:5b88d5760320 | 906 | // It says to reset counters to zero but there is no mechanism to tell the |
kenjiArai | 0:5b88d5760320 | 907 | // network server that the device was disconnected or restarted. |
kenjiArai | 0:5b88d5760320 | 908 | // At the moment, this implementation does not support a non-volatile |
kenjiArai | 0:5b88d5760320 | 909 | // memory storage. |
kenjiArai | 0:5b88d5760320 | 910 | //_lw_session.downlink_counter; //Get from NVM |
kenjiArai | 0:5b88d5760320 | 911 | //_lw_session.uplink_counter; //Get from NVM |
kenjiArai | 0:5b88d5760320 | 912 | |
kenjiArai | 0:5b88d5760320 | 913 | tr_debug("Initiating ABP"); |
kenjiArai | 0:5b88d5760320 | 914 | tr_debug("Frame Counters. UpCnt=%lu, DownCnt=%lu", |
kenjiArai | 0:5b88d5760320 | 915 | _lw_session.uplink_counter, _lw_session.downlink_counter); |
kenjiArai | 0:5b88d5760320 | 916 | _ctrl_flags &= ~USING_OTAA_FLAG; |
kenjiArai | 0:5b88d5760320 | 917 | } |
kenjiArai | 0:5b88d5760320 | 918 | |
kenjiArai | 0:5b88d5760320 | 919 | return state_controller(DEVICE_STATE_CONNECTING); |
kenjiArai | 0:5b88d5760320 | 920 | } |
kenjiArai | 0:5b88d5760320 | 921 | |
kenjiArai | 0:5b88d5760320 | 922 | void LoRaWANStack::mlme_indication_handler() |
kenjiArai | 0:5b88d5760320 | 923 | { |
kenjiArai | 0:5b88d5760320 | 924 | if (_loramac.get_mlme_indication()->indication_type == MLME_SCHEDULE_UPLINK) { |
kenjiArai | 0:5b88d5760320 | 925 | // The MAC signals that we shall provide an uplink as soon as possible |
kenjiArai | 0:5b88d5760320 | 926 | #if MBED_CONF_LORA_AUTOMATIC_UPLINK_MESSAGE |
kenjiArai | 0:5b88d5760320 | 927 | _automatic_uplink_ongoing = true; |
kenjiArai | 0:5b88d5760320 | 928 | tr_debug("mlme indication: sending empty uplink to port 0 to acknowledge MAC commands..."); |
kenjiArai | 0:5b88d5760320 | 929 | const uint8_t port = 0; |
kenjiArai | 0:5b88d5760320 | 930 | const int ret = _queue->call(this, &LoRaWANStack::send_automatic_uplink_message, port); |
kenjiArai | 0:5b88d5760320 | 931 | MBED_ASSERT(ret != 0); |
kenjiArai | 0:5b88d5760320 | 932 | (void)ret; |
kenjiArai | 0:5b88d5760320 | 933 | #else |
kenjiArai | 0:5b88d5760320 | 934 | send_event_to_application(UPLINK_REQUIRED); |
kenjiArai | 0:5b88d5760320 | 935 | #endif |
kenjiArai | 0:5b88d5760320 | 936 | return; |
kenjiArai | 0:5b88d5760320 | 937 | } |
kenjiArai | 0:5b88d5760320 | 938 | |
kenjiArai | 0:5b88d5760320 | 939 | tr_error("Unknown MLME Indication type."); |
kenjiArai | 0:5b88d5760320 | 940 | } |
kenjiArai | 0:5b88d5760320 | 941 | |
kenjiArai | 0:5b88d5760320 | 942 | void LoRaWANStack::mlme_confirm_handler() |
kenjiArai | 0:5b88d5760320 | 943 | { |
kenjiArai | 0:5b88d5760320 | 944 | if (_loramac.get_mlme_confirmation()->req_type == MLME_LINK_CHECK) { |
kenjiArai | 0:5b88d5760320 | 945 | if (_loramac.get_mlme_confirmation()->status |
kenjiArai | 0:5b88d5760320 | 946 | == LORAMAC_EVENT_INFO_STATUS_OK) { |
kenjiArai | 0:5b88d5760320 | 947 | |
kenjiArai | 0:5b88d5760320 | 948 | if (_callbacks.link_check_resp) { |
kenjiArai | 0:5b88d5760320 | 949 | const int ret = _queue->call( |
kenjiArai | 0:5b88d5760320 | 950 | _callbacks.link_check_resp, |
kenjiArai | 0:5b88d5760320 | 951 | _loramac.get_mlme_confirmation()->demod_margin, |
kenjiArai | 0:5b88d5760320 | 952 | _loramac.get_mlme_confirmation()->nb_gateways); |
kenjiArai | 0:5b88d5760320 | 953 | MBED_ASSERT(ret != 0); |
kenjiArai | 0:5b88d5760320 | 954 | (void) ret; |
kenjiArai | 0:5b88d5760320 | 955 | } |
kenjiArai | 0:5b88d5760320 | 956 | } |
kenjiArai | 0:5b88d5760320 | 957 | } |
kenjiArai | 0:5b88d5760320 | 958 | |
kenjiArai | 0:5b88d5760320 | 959 | if (_loramac.get_mlme_confirmation()->req_type == MLME_JOIN) { |
kenjiArai | 0:5b88d5760320 | 960 | |
kenjiArai | 0:5b88d5760320 | 961 | switch (_loramac.get_mlme_confirmation()->status) { |
kenjiArai | 0:5b88d5760320 | 962 | case LORAMAC_EVENT_INFO_STATUS_OK: |
kenjiArai | 0:5b88d5760320 | 963 | state_controller(DEVICE_STATE_CONNECTED); |
kenjiArai | 0:5b88d5760320 | 964 | break; |
kenjiArai | 0:5b88d5760320 | 965 | |
kenjiArai | 0:5b88d5760320 | 966 | case LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL: |
kenjiArai | 0:5b88d5760320 | 967 | // fatal error |
kenjiArai | 0:5b88d5760320 | 968 | _device_current_state = DEVICE_STATE_IDLE; |
kenjiArai | 0:5b88d5760320 | 969 | tr_error("Joining abandoned: CRYPTO_ERROR"); |
kenjiArai | 0:5b88d5760320 | 970 | send_event_to_application(CRYPTO_ERROR); |
kenjiArai | 0:5b88d5760320 | 971 | break; |
kenjiArai | 0:5b88d5760320 | 972 | |
kenjiArai | 0:5b88d5760320 | 973 | case LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT: |
kenjiArai | 0:5b88d5760320 | 974 | // fatal error |
kenjiArai | 0:5b88d5760320 | 975 | _device_current_state = DEVICE_STATE_IDLE; |
kenjiArai | 0:5b88d5760320 | 976 | tr_error("Joining abandoned: Radio failed to transmit"); |
kenjiArai | 0:5b88d5760320 | 977 | send_event_to_application(TX_TIMEOUT); |
kenjiArai | 0:5b88d5760320 | 978 | break; |
kenjiArai | 0:5b88d5760320 | 979 | |
kenjiArai | 0:5b88d5760320 | 980 | default: |
kenjiArai | 0:5b88d5760320 | 981 | // non-fatal, retry if possible |
kenjiArai | 0:5b88d5760320 | 982 | _device_current_state = DEVICE_STATE_AWAITING_JOIN_ACCEPT; |
kenjiArai | 0:5b88d5760320 | 983 | state_controller(DEVICE_STATE_JOINING); |
kenjiArai | 0:5b88d5760320 | 984 | } |
kenjiArai | 0:5b88d5760320 | 985 | } |
kenjiArai | 0:5b88d5760320 | 986 | } |
kenjiArai | 0:5b88d5760320 | 987 | |
kenjiArai | 0:5b88d5760320 | 988 | void LoRaWANStack::mcps_confirm_handler() |
kenjiArai | 0:5b88d5760320 | 989 | { |
kenjiArai | 0:5b88d5760320 | 990 | switch (_loramac.get_mcps_confirmation()->status) { |
kenjiArai | 0:5b88d5760320 | 991 | |
kenjiArai | 0:5b88d5760320 | 992 | case LORAMAC_EVENT_INFO_STATUS_OK: |
kenjiArai | 0:5b88d5760320 | 993 | _lw_session.uplink_counter = _loramac.get_mcps_confirmation()->ul_frame_counter; |
kenjiArai | 0:5b88d5760320 | 994 | send_event_to_application(TX_DONE); |
kenjiArai | 0:5b88d5760320 | 995 | break; |
kenjiArai | 0:5b88d5760320 | 996 | |
kenjiArai | 0:5b88d5760320 | 997 | case LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT: |
kenjiArai | 0:5b88d5760320 | 998 | tr_error("Fatal Error, Radio failed to transmit"); |
kenjiArai | 0:5b88d5760320 | 999 | send_event_to_application(TX_TIMEOUT); |
kenjiArai | 0:5b88d5760320 | 1000 | break; |
kenjiArai | 0:5b88d5760320 | 1001 | |
kenjiArai | 0:5b88d5760320 | 1002 | case LORAMAC_EVENT_INFO_STATUS_TX_DR_PAYLOAD_SIZE_ERROR: |
kenjiArai | 0:5b88d5760320 | 1003 | send_event_to_application(TX_SCHEDULING_ERROR); |
kenjiArai | 0:5b88d5760320 | 1004 | break; |
kenjiArai | 0:5b88d5760320 | 1005 | |
kenjiArai | 0:5b88d5760320 | 1006 | default: |
kenjiArai | 0:5b88d5760320 | 1007 | // if no ack was received after enough retries, send TX_ERROR |
kenjiArai | 0:5b88d5760320 | 1008 | send_event_to_application(TX_ERROR); |
kenjiArai | 0:5b88d5760320 | 1009 | } |
kenjiArai | 0:5b88d5760320 | 1010 | } |
kenjiArai | 0:5b88d5760320 | 1011 | |
kenjiArai | 0:5b88d5760320 | 1012 | void LoRaWANStack::mcps_indication_handler() |
kenjiArai | 0:5b88d5760320 | 1013 | { |
kenjiArai | 0:5b88d5760320 | 1014 | const loramac_mcps_indication_t *mcps_indication = _loramac.get_mcps_indication(); |
kenjiArai | 0:5b88d5760320 | 1015 | if (mcps_indication->status != LORAMAC_EVENT_INFO_STATUS_OK) { |
kenjiArai | 0:5b88d5760320 | 1016 | tr_error("RX_ERROR: mcps_indication status = %d", mcps_indication->status); |
kenjiArai | 0:5b88d5760320 | 1017 | send_event_to_application(RX_ERROR); |
kenjiArai | 0:5b88d5760320 | 1018 | return; |
kenjiArai | 0:5b88d5760320 | 1019 | } |
kenjiArai | 0:5b88d5760320 | 1020 | |
kenjiArai | 0:5b88d5760320 | 1021 | _lw_session.downlink_counter = mcps_indication->dl_frame_counter; |
kenjiArai | 0:5b88d5760320 | 1022 | |
kenjiArai | 0:5b88d5760320 | 1023 | /** |
kenjiArai | 0:5b88d5760320 | 1024 | * Check port, if it's compliance testing port and the compliance testing is |
kenjiArai | 0:5b88d5760320 | 1025 | * not enabled, give up silently |
kenjiArai | 0:5b88d5760320 | 1026 | */ |
kenjiArai | 0:5b88d5760320 | 1027 | if (mcps_indication->port == COMPLIANCE_TESTING_PORT) { |
kenjiArai | 0:5b88d5760320 | 1028 | #if !defined(LORAWAN_COMPLIANCE_TEST) |
kenjiArai | 0:5b88d5760320 | 1029 | return; |
kenjiArai | 0:5b88d5760320 | 1030 | #endif |
kenjiArai | 0:5b88d5760320 | 1031 | } |
kenjiArai | 0:5b88d5760320 | 1032 | |
kenjiArai | 0:5b88d5760320 | 1033 | if (mcps_indication->is_data_recvd) { |
kenjiArai | 0:5b88d5760320 | 1034 | // Valid message arrived. |
kenjiArai | 0:5b88d5760320 | 1035 | _rx_msg.type = LORAMAC_RX_MCPS_INDICATION; |
kenjiArai | 0:5b88d5760320 | 1036 | _rx_msg.msg.mcps_indication.buffer_size = mcps_indication->buffer_size; |
kenjiArai | 0:5b88d5760320 | 1037 | _rx_msg.msg.mcps_indication.port = mcps_indication->port; |
kenjiArai | 0:5b88d5760320 | 1038 | _rx_msg.msg.mcps_indication.buffer = mcps_indication->buffer; |
kenjiArai | 0:5b88d5760320 | 1039 | _rx_msg.msg.mcps_indication.type = mcps_indication->type; |
kenjiArai | 0:5b88d5760320 | 1040 | |
kenjiArai | 0:5b88d5760320 | 1041 | // Notify application about received frame.. |
kenjiArai | 0:5b88d5760320 | 1042 | tr_debug("Packet Received %d bytes, Port=%d", |
kenjiArai | 0:5b88d5760320 | 1043 | _rx_msg.msg.mcps_indication.buffer_size, |
kenjiArai | 0:5b88d5760320 | 1044 | mcps_indication->port); |
kenjiArai | 0:5b88d5760320 | 1045 | _rx_msg.receive_ready = true; |
kenjiArai | 0:5b88d5760320 | 1046 | send_event_to_application(RX_DONE); |
kenjiArai | 0:5b88d5760320 | 1047 | } |
kenjiArai | 0:5b88d5760320 | 1048 | |
kenjiArai | 0:5b88d5760320 | 1049 | /* |
kenjiArai | 0:5b88d5760320 | 1050 | * If fPending bit is set we try to generate an empty packet |
kenjiArai | 0:5b88d5760320 | 1051 | * with CONFIRMED flag set. We always set a CONFIRMED flag so |
kenjiArai | 0:5b88d5760320 | 1052 | * that we could retry a certain number of times if the uplink |
kenjiArai | 0:5b88d5760320 | 1053 | * failed for some reason |
kenjiArai | 0:5b88d5760320 | 1054 | * or |
kenjiArai | 0:5b88d5760320 | 1055 | * Class C and node received a confirmed message so we need to |
kenjiArai | 0:5b88d5760320 | 1056 | * send an empty packet to acknowledge the message. |
kenjiArai | 0:5b88d5760320 | 1057 | * This scenario is unspecified by LoRaWAN 1.0.2 specification, |
kenjiArai | 0:5b88d5760320 | 1058 | * but version 1.1.0 says that network SHALL not send any new |
kenjiArai | 0:5b88d5760320 | 1059 | * confirmed messages until ack has been sent |
kenjiArai | 0:5b88d5760320 | 1060 | */ |
kenjiArai | 0:5b88d5760320 | 1061 | if ((_loramac.get_device_class() != CLASS_C |
kenjiArai | 0:5b88d5760320 | 1062 | && mcps_indication->fpending_status) |
kenjiArai | 0:5b88d5760320 | 1063 | || (_loramac.get_device_class() == CLASS_C |
kenjiArai | 0:5b88d5760320 | 1064 | && mcps_indication->type == MCPS_CONFIRMED)) { |
kenjiArai | 0:5b88d5760320 | 1065 | #if (MBED_CONF_LORA_AUTOMATIC_UPLINK_MESSAGE) |
kenjiArai | 0:5b88d5760320 | 1066 | // Do not queue an automatic uplink of there is one already outgoing |
kenjiArai | 0:5b88d5760320 | 1067 | // This means we have not received an ack for the previous automatic uplink |
kenjiArai | 0:5b88d5760320 | 1068 | if (!_automatic_uplink_ongoing) { |
kenjiArai | 0:5b88d5760320 | 1069 | tr_debug("Sending empty uplink message..."); |
kenjiArai | 0:5b88d5760320 | 1070 | _automatic_uplink_ongoing = true; |
kenjiArai | 0:5b88d5760320 | 1071 | const int ret = _queue->call(this, &LoRaWANStack::send_automatic_uplink_message, mcps_indication->port); |
kenjiArai | 0:5b88d5760320 | 1072 | MBED_ASSERT(ret != 0); |
kenjiArai | 0:5b88d5760320 | 1073 | (void)ret; |
kenjiArai | 0:5b88d5760320 | 1074 | } |
kenjiArai | 0:5b88d5760320 | 1075 | #else |
kenjiArai | 0:5b88d5760320 | 1076 | send_event_to_application(UPLINK_REQUIRED); |
kenjiArai | 0:5b88d5760320 | 1077 | #endif |
kenjiArai | 0:5b88d5760320 | 1078 | } |
kenjiArai | 0:5b88d5760320 | 1079 | } |
kenjiArai | 0:5b88d5760320 | 1080 | |
kenjiArai | 0:5b88d5760320 | 1081 | |
kenjiArai | 0:5b88d5760320 | 1082 | lorawan_status_t LoRaWANStack::state_controller(device_states_t new_state) |
kenjiArai | 0:5b88d5760320 | 1083 | { |
kenjiArai | 0:5b88d5760320 | 1084 | lorawan_status_t status = LORAWAN_STATUS_OK; |
kenjiArai | 0:5b88d5760320 | 1085 | |
kenjiArai | 0:5b88d5760320 | 1086 | switch (new_state) { |
kenjiArai | 0:5b88d5760320 | 1087 | case DEVICE_STATE_IDLE: |
kenjiArai | 0:5b88d5760320 | 1088 | process_idle_state(status); |
kenjiArai | 0:5b88d5760320 | 1089 | break; |
kenjiArai | 0:5b88d5760320 | 1090 | case DEVICE_STATE_CONNECTING: |
kenjiArai | 0:5b88d5760320 | 1091 | process_connecting_state(status); |
kenjiArai | 0:5b88d5760320 | 1092 | break; |
kenjiArai | 0:5b88d5760320 | 1093 | case DEVICE_STATE_JOINING: |
kenjiArai | 0:5b88d5760320 | 1094 | process_joining_state(status); |
kenjiArai | 0:5b88d5760320 | 1095 | break; |
kenjiArai | 0:5b88d5760320 | 1096 | case DEVICE_STATE_CONNECTED: |
kenjiArai | 0:5b88d5760320 | 1097 | process_connected_state(); |
kenjiArai | 0:5b88d5760320 | 1098 | break; |
kenjiArai | 0:5b88d5760320 | 1099 | case DEVICE_STATE_SCHEDULING: |
kenjiArai | 0:5b88d5760320 | 1100 | process_scheduling_state(status); |
kenjiArai | 0:5b88d5760320 | 1101 | break; |
kenjiArai | 0:5b88d5760320 | 1102 | case DEVICE_STATE_STATUS_CHECK: |
kenjiArai | 0:5b88d5760320 | 1103 | process_status_check_state(); |
kenjiArai | 0:5b88d5760320 | 1104 | break; |
kenjiArai | 0:5b88d5760320 | 1105 | case DEVICE_STATE_SHUTDOWN: |
kenjiArai | 0:5b88d5760320 | 1106 | process_shutdown_state(status); |
kenjiArai | 0:5b88d5760320 | 1107 | break; |
kenjiArai | 0:5b88d5760320 | 1108 | default: |
kenjiArai | 0:5b88d5760320 | 1109 | //Because this is internal function only coding error causes this |
kenjiArai | 0:5b88d5760320 | 1110 | tr_error("Unknown state: %d:", new_state); |
kenjiArai | 0:5b88d5760320 | 1111 | MBED_ASSERT(false); |
kenjiArai | 0:5b88d5760320 | 1112 | } |
kenjiArai | 0:5b88d5760320 | 1113 | |
kenjiArai | 0:5b88d5760320 | 1114 | return status; |
kenjiArai | 0:5b88d5760320 | 1115 | } |
kenjiArai | 0:5b88d5760320 | 1116 | |
kenjiArai | 0:5b88d5760320 | 1117 | void LoRaWANStack::process_shutdown_state(lorawan_status_t &op_status) |
kenjiArai | 0:5b88d5760320 | 1118 | { |
kenjiArai | 0:5b88d5760320 | 1119 | /** |
kenjiArai | 0:5b88d5760320 | 1120 | * Remove channels |
kenjiArai | 0:5b88d5760320 | 1121 | * Radio will be put to sleep by the APIs underneath |
kenjiArai | 0:5b88d5760320 | 1122 | */ |
kenjiArai | 0:5b88d5760320 | 1123 | drop_channel_list(); |
kenjiArai | 0:5b88d5760320 | 1124 | _loramac.disconnect(); |
kenjiArai | 0:5b88d5760320 | 1125 | _lw_session.active = false; |
kenjiArai | 0:5b88d5760320 | 1126 | _device_current_state = DEVICE_STATE_SHUTDOWN; |
kenjiArai | 0:5b88d5760320 | 1127 | op_status = LORAWAN_STATUS_DEVICE_OFF; |
kenjiArai | 0:5b88d5760320 | 1128 | _ctrl_flags = 0; |
kenjiArai | 0:5b88d5760320 | 1129 | send_event_to_application(DISCONNECTED); |
kenjiArai | 0:5b88d5760320 | 1130 | } |
kenjiArai | 0:5b88d5760320 | 1131 | |
kenjiArai | 0:5b88d5760320 | 1132 | void LoRaWANStack::process_status_check_state() |
kenjiArai | 0:5b88d5760320 | 1133 | { |
kenjiArai | 0:5b88d5760320 | 1134 | if (_device_current_state == DEVICE_STATE_SENDING || |
kenjiArai | 0:5b88d5760320 | 1135 | _device_current_state == DEVICE_STATE_AWAITING_ACK) { |
kenjiArai | 0:5b88d5760320 | 1136 | // If there was a successful transmission, this block gets a kick after |
kenjiArai | 0:5b88d5760320 | 1137 | // RX2 slot is exhausted. We may or may not have a successful UNCONFIRMED transmission |
kenjiArai | 0:5b88d5760320 | 1138 | // here. In CONFIRMED case this block is invoked only |
kenjiArai | 0:5b88d5760320 | 1139 | // when the MAX number of retries are exhausted, i.e., only error |
kenjiArai | 0:5b88d5760320 | 1140 | // case will fall here. Moreover, it will happen for Class A only. |
kenjiArai | 0:5b88d5760320 | 1141 | // Another possibility is the case when the stack fails to schedule a |
kenjiArai | 0:5b88d5760320 | 1142 | // deferred transmission and a scheduling failure handler is invoked. |
kenjiArai | 0:5b88d5760320 | 1143 | _ctrl_flags &= ~TX_DONE_FLAG; |
kenjiArai | 0:5b88d5760320 | 1144 | _loramac.set_tx_ongoing(false); |
kenjiArai | 0:5b88d5760320 | 1145 | _loramac.reset_ongoing_tx(); |
kenjiArai | 0:5b88d5760320 | 1146 | mcps_confirm_handler(); |
kenjiArai | 0:5b88d5760320 | 1147 | |
kenjiArai | 0:5b88d5760320 | 1148 | } else if (_device_current_state == DEVICE_STATE_RECEIVING) { |
kenjiArai | 0:5b88d5760320 | 1149 | |
kenjiArai | 0:5b88d5760320 | 1150 | if ((_ctrl_flags & TX_DONE_FLAG) || (_ctrl_flags & RETRY_EXHAUSTED_FLAG)) { |
kenjiArai | 0:5b88d5760320 | 1151 | _ctrl_flags &= ~TX_DONE_FLAG; |
kenjiArai | 0:5b88d5760320 | 1152 | _ctrl_flags &= ~RETRY_EXHAUSTED_FLAG; |
kenjiArai | 0:5b88d5760320 | 1153 | _loramac.set_tx_ongoing(false); |
kenjiArai | 0:5b88d5760320 | 1154 | _loramac.reset_ongoing_tx(); |
kenjiArai | 0:5b88d5760320 | 1155 | // if an automatic uplink is ongoing, we should not send a TX_DONE |
kenjiArai | 0:5b88d5760320 | 1156 | // event to application |
kenjiArai | 0:5b88d5760320 | 1157 | if (_automatic_uplink_ongoing) { |
kenjiArai | 0:5b88d5760320 | 1158 | _automatic_uplink_ongoing = false; |
kenjiArai | 0:5b88d5760320 | 1159 | } else { |
kenjiArai | 0:5b88d5760320 | 1160 | mcps_confirm_handler(); |
kenjiArai | 0:5b88d5760320 | 1161 | } |
kenjiArai | 0:5b88d5760320 | 1162 | } |
kenjiArai | 0:5b88d5760320 | 1163 | |
kenjiArai | 0:5b88d5760320 | 1164 | // handle any received data and send event accordingly |
kenjiArai | 0:5b88d5760320 | 1165 | if (_ctrl_flags & MSG_RECVD_FLAG) { |
kenjiArai | 0:5b88d5760320 | 1166 | _ctrl_flags &= ~MSG_RECVD_FLAG; |
kenjiArai | 0:5b88d5760320 | 1167 | mcps_indication_handler(); |
kenjiArai | 0:5b88d5760320 | 1168 | } |
kenjiArai | 0:5b88d5760320 | 1169 | } |
kenjiArai | 0:5b88d5760320 | 1170 | } |
kenjiArai | 0:5b88d5760320 | 1171 | |
kenjiArai | 0:5b88d5760320 | 1172 | void LoRaWANStack::process_scheduling_state(lorawan_status_t &op_status) |
kenjiArai | 0:5b88d5760320 | 1173 | { |
kenjiArai | 0:5b88d5760320 | 1174 | if (_device_current_state != DEVICE_STATE_IDLE) { |
kenjiArai | 0:5b88d5760320 | 1175 | if (_device_current_state != DEVICE_STATE_RECEIVING |
kenjiArai | 0:5b88d5760320 | 1176 | && _loramac.get_device_class() != CLASS_C) { |
kenjiArai | 0:5b88d5760320 | 1177 | op_status = LORAWAN_STATUS_BUSY; |
kenjiArai | 0:5b88d5760320 | 1178 | return; |
kenjiArai | 0:5b88d5760320 | 1179 | } |
kenjiArai | 0:5b88d5760320 | 1180 | } |
kenjiArai | 0:5b88d5760320 | 1181 | |
kenjiArai | 0:5b88d5760320 | 1182 | op_status = _loramac.send_ongoing_tx(); |
kenjiArai | 0:5b88d5760320 | 1183 | if (op_status == LORAWAN_STATUS_OK) { |
kenjiArai | 0:5b88d5760320 | 1184 | _ctrl_flags &= ~TX_DONE_FLAG; |
kenjiArai | 0:5b88d5760320 | 1185 | _loramac.set_tx_ongoing(true); |
kenjiArai | 0:5b88d5760320 | 1186 | _device_current_state = DEVICE_STATE_SENDING; |
kenjiArai | 0:5b88d5760320 | 1187 | } |
kenjiArai | 0:5b88d5760320 | 1188 | } |
kenjiArai | 0:5b88d5760320 | 1189 | |
kenjiArai | 0:5b88d5760320 | 1190 | void LoRaWANStack::process_joining_state(lorawan_status_t &op_status) |
kenjiArai | 0:5b88d5760320 | 1191 | { |
kenjiArai | 0:5b88d5760320 | 1192 | if (_device_current_state == DEVICE_STATE_CONNECTING) { |
kenjiArai | 0:5b88d5760320 | 1193 | _device_current_state = DEVICE_STATE_JOINING; |
kenjiArai | 0:5b88d5760320 | 1194 | tr_debug("Sending Join Request ..."); |
kenjiArai | 0:5b88d5760320 | 1195 | op_status = _loramac.join(true); |
kenjiArai | 0:5b88d5760320 | 1196 | return; |
kenjiArai | 0:5b88d5760320 | 1197 | } |
kenjiArai | 0:5b88d5760320 | 1198 | |
kenjiArai | 0:5b88d5760320 | 1199 | if (_device_current_state == DEVICE_STATE_AWAITING_JOIN_ACCEPT && |
kenjiArai | 0:5b88d5760320 | 1200 | _loramac.get_current_slot() != RX_SLOT_WIN_1) { |
kenjiArai | 0:5b88d5760320 | 1201 | _device_current_state = DEVICE_STATE_JOINING; |
kenjiArai | 0:5b88d5760320 | 1202 | // retry join |
kenjiArai | 0:5b88d5760320 | 1203 | bool can_continue = _loramac.continue_joining_process(); |
kenjiArai | 0:5b88d5760320 | 1204 | |
kenjiArai | 0:5b88d5760320 | 1205 | if (!can_continue) { |
kenjiArai | 0:5b88d5760320 | 1206 | _ctrl_flags &= ~CONN_IN_PROGRESS_FLAG; |
kenjiArai | 0:5b88d5760320 | 1207 | send_event_to_application(JOIN_FAILURE); |
kenjiArai | 0:5b88d5760320 | 1208 | _device_current_state = DEVICE_STATE_IDLE; |
kenjiArai | 0:5b88d5760320 | 1209 | return; |
kenjiArai | 0:5b88d5760320 | 1210 | } |
kenjiArai | 0:5b88d5760320 | 1211 | } |
kenjiArai | 0:5b88d5760320 | 1212 | } |
kenjiArai | 0:5b88d5760320 | 1213 | |
kenjiArai | 0:5b88d5760320 | 1214 | void LoRaWANStack::process_connected_state() |
kenjiArai | 0:5b88d5760320 | 1215 | { |
kenjiArai | 0:5b88d5760320 | 1216 | _ctrl_flags |= CONNECTED_FLAG; |
kenjiArai | 0:5b88d5760320 | 1217 | _ctrl_flags &= ~CONN_IN_PROGRESS_FLAG; |
kenjiArai | 0:5b88d5760320 | 1218 | |
kenjiArai | 0:5b88d5760320 | 1219 | if (_ctrl_flags & USING_OTAA_FLAG) { |
kenjiArai | 0:5b88d5760320 | 1220 | tr_debug("OTAA Connection OK!"); |
kenjiArai | 0:5b88d5760320 | 1221 | } |
kenjiArai | 0:5b88d5760320 | 1222 | |
kenjiArai | 0:5b88d5760320 | 1223 | _lw_session.active = true; |
kenjiArai | 0:5b88d5760320 | 1224 | send_event_to_application(CONNECTED); |
kenjiArai | 0:5b88d5760320 | 1225 | |
kenjiArai | 0:5b88d5760320 | 1226 | _device_current_state = DEVICE_STATE_IDLE; |
kenjiArai | 0:5b88d5760320 | 1227 | } |
kenjiArai | 0:5b88d5760320 | 1228 | |
kenjiArai | 0:5b88d5760320 | 1229 | void LoRaWANStack::process_connecting_state(lorawan_status_t &op_status) |
kenjiArai | 0:5b88d5760320 | 1230 | { |
kenjiArai | 0:5b88d5760320 | 1231 | MBED_ASSERT(_device_current_state == DEVICE_STATE_IDLE || |
kenjiArai | 0:5b88d5760320 | 1232 | _device_current_state == DEVICE_STATE_SHUTDOWN); |
kenjiArai | 0:5b88d5760320 | 1233 | |
kenjiArai | 0:5b88d5760320 | 1234 | _device_current_state = DEVICE_STATE_CONNECTING; |
kenjiArai | 0:5b88d5760320 | 1235 | |
kenjiArai | 0:5b88d5760320 | 1236 | if (_ctrl_flags & USING_OTAA_FLAG) { |
kenjiArai | 0:5b88d5760320 | 1237 | process_joining_state(op_status); |
kenjiArai | 0:5b88d5760320 | 1238 | return; |
kenjiArai | 0:5b88d5760320 | 1239 | } |
kenjiArai | 0:5b88d5760320 | 1240 | |
kenjiArai | 0:5b88d5760320 | 1241 | op_status = _loramac.join(false); |
kenjiArai | 0:5b88d5760320 | 1242 | tr_debug("ABP connection OK."); |
kenjiArai | 0:5b88d5760320 | 1243 | process_connected_state(); |
kenjiArai | 0:5b88d5760320 | 1244 | } |
kenjiArai | 0:5b88d5760320 | 1245 | |
kenjiArai | 0:5b88d5760320 | 1246 | void LoRaWANStack::process_idle_state(lorawan_status_t &op_status) |
kenjiArai | 0:5b88d5760320 | 1247 | { |
kenjiArai | 0:5b88d5760320 | 1248 | if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) { |
kenjiArai | 0:5b88d5760320 | 1249 | _device_current_state = DEVICE_STATE_IDLE; |
kenjiArai | 0:5b88d5760320 | 1250 | process_uninitialized_state(op_status); |
kenjiArai | 0:5b88d5760320 | 1251 | return; |
kenjiArai | 0:5b88d5760320 | 1252 | } |
kenjiArai | 0:5b88d5760320 | 1253 | |
kenjiArai | 0:5b88d5760320 | 1254 | _device_current_state = DEVICE_STATE_IDLE; |
kenjiArai | 0:5b88d5760320 | 1255 | op_status = LORAWAN_STATUS_OK; |
kenjiArai | 0:5b88d5760320 | 1256 | } |
kenjiArai | 0:5b88d5760320 | 1257 | |
kenjiArai | 0:5b88d5760320 | 1258 | void LoRaWANStack::process_uninitialized_state(lorawan_status_t &op_status) |
kenjiArai | 0:5b88d5760320 | 1259 | { |
kenjiArai | 0:5b88d5760320 | 1260 | op_status = _loramac.initialize(_queue, mbed::callback(this, |
kenjiArai | 0:5b88d5760320 | 1261 | &LoRaWANStack::handle_scheduling_failure)); |
kenjiArai | 0:5b88d5760320 | 1262 | |
kenjiArai | 0:5b88d5760320 | 1263 | if (op_status == LORAWAN_STATUS_OK) { |
kenjiArai | 0:5b88d5760320 | 1264 | _device_current_state = DEVICE_STATE_IDLE; |
kenjiArai | 0:5b88d5760320 | 1265 | } |
kenjiArai | 0:5b88d5760320 | 1266 | } |