Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

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?

UserRevisionLine numberNew 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 }