BBR 1 Ebene

Committer:
borlanic
Date:
Mon May 14 11:29:06 2018 +0000
Revision:
0:fbdae7e6d805
BBR

Who changed what in which revision?

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