takashi kadono / Mbed OS Nucleo_446

Dependencies:   ssd1331

Committer:
kadonotakashi
Date:
Wed Oct 10 00:33:53 2018 +0000
Revision:
0:8fdf9a60065b
how to make mbed librry

Who changed what in which revision?

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