BA / SerialCom

Fork of OmniWheels by Gustav Atmel

Committer:
gustavatmel
Date:
Tue May 01 15:55:34 2018 +0000
Revision:
2:798925c9e4a8
Parent:
1:9c5af431a1f1
bluetooth

Who changed what in which revision?

UserRevisionLine numberNew contents of line
gustavatmel 1:9c5af431a1f1 1 /**
gustavatmel 1:9c5af431a1f1 2 / _____) _ | |
gustavatmel 1:9c5af431a1f1 3 ( (____ _____ ____ _| |_ _____ ____| |__
gustavatmel 1:9c5af431a1f1 4 \____ \| ___ | (_ _) ___ |/ ___) _ \
gustavatmel 1:9c5af431a1f1 5 _____) ) ____| | | || |_| ____( (___| | | |
gustavatmel 1:9c5af431a1f1 6 (______/|_____)_|_|_| \__)_____)\____)_| |_|
gustavatmel 1:9c5af431a1f1 7 (C)2013 Semtech
gustavatmel 1:9c5af431a1f1 8 ___ _____ _ ___ _ _____ ___ ___ ___ ___
gustavatmel 1:9c5af431a1f1 9 / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
gustavatmel 1:9c5af431a1f1 10 \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
gustavatmel 1:9c5af431a1f1 11 |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
gustavatmel 1:9c5af431a1f1 12 embedded.connectivity.solutions===============
gustavatmel 1:9c5af431a1f1 13
gustavatmel 1:9c5af431a1f1 14 Description: LoRaWAN stack layer that controls both MAC and PHY underneath
gustavatmel 1:9c5af431a1f1 15
gustavatmel 1:9c5af431a1f1 16 License: Revised BSD License, see LICENSE.TXT file include in the project
gustavatmel 1:9c5af431a1f1 17
gustavatmel 1:9c5af431a1f1 18 Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE )
gustavatmel 1:9c5af431a1f1 19
gustavatmel 1:9c5af431a1f1 20
gustavatmel 1:9c5af431a1f1 21 Copyright (c) 2017, Arm Limited and affiliates.
gustavatmel 1:9c5af431a1f1 22
gustavatmel 1:9c5af431a1f1 23 SPDX-License-Identifier: BSD-3-Clause
gustavatmel 1:9c5af431a1f1 24 */
gustavatmel 1:9c5af431a1f1 25
gustavatmel 1:9c5af431a1f1 26 #include <string.h>
gustavatmel 1:9c5af431a1f1 27 #include <stdlib.h>
gustavatmel 1:9c5af431a1f1 28 #include "platform/Callback.h"
gustavatmel 1:9c5af431a1f1 29 #include "events/EventQueue.h"
gustavatmel 1:9c5af431a1f1 30 #include "lorawan/LoRaWANStack.h"
gustavatmel 1:9c5af431a1f1 31 #if defined(FEATURE_COMMON_PAL)
gustavatmel 1:9c5af431a1f1 32 #include "mbed_trace.h"
gustavatmel 1:9c5af431a1f1 33 #define TRACE_GROUP "LSTK"
gustavatmel 1:9c5af431a1f1 34 #else
gustavatmel 1:9c5af431a1f1 35 #define tr_debug(...) (void(0)) //dummies if feature common pal is not added
gustavatmel 1:9c5af431a1f1 36 #define tr_info(...) (void(0)) //dummies if feature common pal is not added
gustavatmel 1:9c5af431a1f1 37 #define tr_error(...) (void(0)) //dummies if feature common pal is not added
gustavatmel 1:9c5af431a1f1 38 #define tr_warn(...) (void(0)) //dummies if feature common pal is not added
gustavatmel 1:9c5af431a1f1 39 #endif //defined(FEATURE_COMMON_PAL)
gustavatmel 1:9c5af431a1f1 40
gustavatmel 1:9c5af431a1f1 41 #define INVALID_PORT 0xFF
gustavatmel 1:9c5af431a1f1 42 #define MAX_CONFIRMED_MSG_RETRIES 255
gustavatmel 1:9c5af431a1f1 43
gustavatmel 1:9c5af431a1f1 44 using namespace mbed;
gustavatmel 1:9c5af431a1f1 45 using namespace events;
gustavatmel 1:9c5af431a1f1 46
gustavatmel 1:9c5af431a1f1 47 #if defined(LORAWAN_COMPLIANCE_TEST)
gustavatmel 1:9c5af431a1f1 48 /**
gustavatmel 1:9c5af431a1f1 49 *
gustavatmel 1:9c5af431a1f1 50 * User application data buffer size if compliance test is used
gustavatmel 1:9c5af431a1f1 51 */
gustavatmel 1:9c5af431a1f1 52 #if (MBED_CONF_LORA_PHY == 0 || MBED_CONF_LORA_PHY == 4 || MBED_CONF_LORA_PHY == 6 || MBED_CONF_LORA_PHY == 7)
gustavatmel 1:9c5af431a1f1 53 #define LORAWAN_COMPLIANCE_TEST_DATA_SIZE 16
gustavatmel 1:9c5af431a1f1 54 #elif (MBED_CONF_LORA_PHY == 1 || MBED_CONF_LORA_PHY == 2 || MBED_CONF_LORA_PHY == 8 || MBED_CONF_LORA_PHY == 9)
gustavatmel 1:9c5af431a1f1 55 #define LORAWAN_COMPLIANCE_TEST_DATA_SIZE 11
gustavatmel 1:9c5af431a1f1 56 #else
gustavatmel 1:9c5af431a1f1 57 #error "Must set LoRa PHY layer parameters."
gustavatmel 1:9c5af431a1f1 58 #endif
gustavatmel 1:9c5af431a1f1 59 #endif
gustavatmel 1:9c5af431a1f1 60
gustavatmel 1:9c5af431a1f1 61 /*****************************************************************************
gustavatmel 1:9c5af431a1f1 62 * Private Member Functions *
gustavatmel 1:9c5af431a1f1 63 ****************************************************************************/
gustavatmel 1:9c5af431a1f1 64 bool LoRaWANStack::is_port_valid(uint8_t port)
gustavatmel 1:9c5af431a1f1 65 {
gustavatmel 1:9c5af431a1f1 66 //Application should not use reserved and illegal port numbers.
gustavatmel 1:9c5af431a1f1 67 if (port >= 224 || port == 0) {
gustavatmel 1:9c5af431a1f1 68 return false;
gustavatmel 1:9c5af431a1f1 69 } else {
gustavatmel 1:9c5af431a1f1 70 return true;
gustavatmel 1:9c5af431a1f1 71 }
gustavatmel 1:9c5af431a1f1 72 }
gustavatmel 1:9c5af431a1f1 73
gustavatmel 1:9c5af431a1f1 74 lorawan_status_t LoRaWANStack::set_application_port(uint8_t port)
gustavatmel 1:9c5af431a1f1 75 {
gustavatmel 1:9c5af431a1f1 76 if (is_port_valid(port)) {
gustavatmel 1:9c5af431a1f1 77 _app_port = port;
gustavatmel 1:9c5af431a1f1 78 return LORAWAN_STATUS_OK;
gustavatmel 1:9c5af431a1f1 79 }
gustavatmel 1:9c5af431a1f1 80
gustavatmel 1:9c5af431a1f1 81 return LORAWAN_STATUS_PORT_INVALID;
gustavatmel 1:9c5af431a1f1 82 }
gustavatmel 1:9c5af431a1f1 83
gustavatmel 1:9c5af431a1f1 84 /*****************************************************************************
gustavatmel 1:9c5af431a1f1 85 * Constructor and destructor *
gustavatmel 1:9c5af431a1f1 86 ****************************************************************************/
gustavatmel 1:9c5af431a1f1 87 LoRaWANStack::LoRaWANStack()
gustavatmel 1:9c5af431a1f1 88 : _loramac(_lora_time), _lora_phy(_lora_time),
gustavatmel 1:9c5af431a1f1 89 _device_current_state(DEVICE_STATE_NOT_INITIALIZED), _mac_handlers(NULL),
gustavatmel 1:9c5af431a1f1 90 _num_retry(1), _app_port(INVALID_PORT), _duty_cycle_on(MBED_CONF_LORA_DUTY_CYCLE_ON),
gustavatmel 1:9c5af431a1f1 91 _queue(NULL)
gustavatmel 1:9c5af431a1f1 92 {
gustavatmel 1:9c5af431a1f1 93 #ifdef MBED_CONF_LORA_APP_PORT
gustavatmel 1:9c5af431a1f1 94 if (is_port_valid(MBED_CONF_LORA_APP_PORT)) {
gustavatmel 1:9c5af431a1f1 95 _app_port = MBED_CONF_LORA_APP_PORT;
gustavatmel 1:9c5af431a1f1 96 } else {
gustavatmel 1:9c5af431a1f1 97 tr_error("User defined port in .json is illegal.");
gustavatmel 1:9c5af431a1f1 98 }
gustavatmel 1:9c5af431a1f1 99 #endif
gustavatmel 1:9c5af431a1f1 100
gustavatmel 1:9c5af431a1f1 101 memset(&_lw_session, 0, sizeof(_lw_session));
gustavatmel 1:9c5af431a1f1 102 memset(&_tx_msg, 0, sizeof(_tx_msg));
gustavatmel 1:9c5af431a1f1 103 memset(&_rx_msg, 0, sizeof(_rx_msg));
gustavatmel 1:9c5af431a1f1 104
gustavatmel 1:9c5af431a1f1 105 LoRaMacPrimitives.mcps_confirm = callback(this, &LoRaWANStack::mcps_confirm_handler);
gustavatmel 1:9c5af431a1f1 106 LoRaMacPrimitives.mcps_indication = callback(this, &LoRaWANStack::mcps_indication_handler);
gustavatmel 1:9c5af431a1f1 107 LoRaMacPrimitives.mlme_confirm = callback(this, &LoRaWANStack::mlme_confirm_handler);
gustavatmel 1:9c5af431a1f1 108 LoRaMacPrimitives.mlme_indication = callback(this, &LoRaWANStack::mlme_indication_handler);
gustavatmel 1:9c5af431a1f1 109 }
gustavatmel 1:9c5af431a1f1 110
gustavatmel 1:9c5af431a1f1 111 LoRaWANStack::~LoRaWANStack()
gustavatmel 1:9c5af431a1f1 112 {
gustavatmel 1:9c5af431a1f1 113 }
gustavatmel 1:9c5af431a1f1 114
gustavatmel 1:9c5af431a1f1 115 /*****************************************************************************
gustavatmel 1:9c5af431a1f1 116 * Public member functions *
gustavatmel 1:9c5af431a1f1 117 ****************************************************************************/
gustavatmel 1:9c5af431a1f1 118 LoRaWANStack& LoRaWANStack::get_lorawan_stack()
gustavatmel 1:9c5af431a1f1 119 {
gustavatmel 1:9c5af431a1f1 120 static LoRaWANStack _lw_stack;
gustavatmel 1:9c5af431a1f1 121 return _lw_stack;
gustavatmel 1:9c5af431a1f1 122 }
gustavatmel 1:9c5af431a1f1 123
gustavatmel 1:9c5af431a1f1 124 radio_events_t *LoRaWANStack::bind_radio_driver(LoRaRadio& radio)
gustavatmel 1:9c5af431a1f1 125 {
gustavatmel 1:9c5af431a1f1 126 // Store pointer to callback routines inside MAC layer (non-IRQ safe)
gustavatmel 1:9c5af431a1f1 127 _mac_handlers = _loramac.get_phy_event_handlers();
gustavatmel 1:9c5af431a1f1 128 // passes the reference to radio driver down to PHY layer
gustavatmel 1:9c5af431a1f1 129 _lora_phy.set_radio_instance(radio);
gustavatmel 1:9c5af431a1f1 130 return _mac_handlers;
gustavatmel 1:9c5af431a1f1 131 }
gustavatmel 1:9c5af431a1f1 132
gustavatmel 1:9c5af431a1f1 133 lorawan_status_t LoRaWANStack::initialize_mac_layer(EventQueue *queue)
gustavatmel 1:9c5af431a1f1 134 {
gustavatmel 1:9c5af431a1f1 135 if (DEVICE_STATE_NOT_INITIALIZED != _device_current_state)
gustavatmel 1:9c5af431a1f1 136 {
gustavatmel 1:9c5af431a1f1 137 tr_debug("Initialized already");
gustavatmel 1:9c5af431a1f1 138 return LORAWAN_STATUS_OK;
gustavatmel 1:9c5af431a1f1 139 }
gustavatmel 1:9c5af431a1f1 140
gustavatmel 1:9c5af431a1f1 141 tr_debug("Initializing MAC layer");
gustavatmel 1:9c5af431a1f1 142
gustavatmel 1:9c5af431a1f1 143 //store a pointer to Event Queue
gustavatmel 1:9c5af431a1f1 144 _queue = queue;
gustavatmel 1:9c5af431a1f1 145
gustavatmel 1:9c5af431a1f1 146 #if defined(LORAWAN_COMPLIANCE_TEST)
gustavatmel 1:9c5af431a1f1 147 _compliance_test.app_data_buffer = compliance_test_buffer;
gustavatmel 1:9c5af431a1f1 148 #endif
gustavatmel 1:9c5af431a1f1 149
gustavatmel 1:9c5af431a1f1 150 _lora_time.activate_timer_subsystem(queue);
gustavatmel 1:9c5af431a1f1 151 _loramac.initialize(&LoRaMacPrimitives, &_lora_phy, queue);
gustavatmel 1:9c5af431a1f1 152
gustavatmel 1:9c5af431a1f1 153 loramac_mib_req_confirm_t mib_req;
gustavatmel 1:9c5af431a1f1 154
gustavatmel 1:9c5af431a1f1 155 mib_req.type = MIB_ADR;
gustavatmel 1:9c5af431a1f1 156 mib_req.param.is_adr_enable = MBED_CONF_LORA_ADR_ON;
gustavatmel 1:9c5af431a1f1 157 mib_set_request(&mib_req);
gustavatmel 1:9c5af431a1f1 158
gustavatmel 1:9c5af431a1f1 159 mib_req.type = MIB_PUBLIC_NETWORK;
gustavatmel 1:9c5af431a1f1 160 mib_req.param.enable_public_nwk = MBED_CONF_LORA_PUBLIC_NETWORK;
gustavatmel 1:9c5af431a1f1 161 mib_set_request(&mib_req);
gustavatmel 1:9c5af431a1f1 162
gustavatmel 1:9c5af431a1f1 163 // Reset counters to zero. Will change in future with 1.1 support.
gustavatmel 1:9c5af431a1f1 164 _lw_session.downlink_counter = 0;
gustavatmel 1:9c5af431a1f1 165 _lw_session.uplink_counter = 0;
gustavatmel 1:9c5af431a1f1 166
gustavatmel 1:9c5af431a1f1 167 // Start loRaWAN state machine.
gustavatmel 1:9c5af431a1f1 168 set_device_state(DEVICE_STATE_INIT);
gustavatmel 1:9c5af431a1f1 169 return lora_state_machine();
gustavatmel 1:9c5af431a1f1 170 }
gustavatmel 1:9c5af431a1f1 171
gustavatmel 1:9c5af431a1f1 172 uint16_t LoRaWANStack::check_possible_tx_size(uint16_t size)
gustavatmel 1:9c5af431a1f1 173 {
gustavatmel 1:9c5af431a1f1 174 loramac_tx_info_t tx_info;
gustavatmel 1:9c5af431a1f1 175 if (_loramac.query_tx_possible(size, &tx_info) == LORAWAN_STATUS_LENGTH_ERROR) {
gustavatmel 1:9c5af431a1f1 176 // Cannot transmit this much. Return how much data can be sent
gustavatmel 1:9c5af431a1f1 177 // at the moment
gustavatmel 1:9c5af431a1f1 178 return tx_info.max_possible_payload_size;
gustavatmel 1:9c5af431a1f1 179 }
gustavatmel 1:9c5af431a1f1 180
gustavatmel 1:9c5af431a1f1 181 return tx_info.current_payload_size;
gustavatmel 1:9c5af431a1f1 182 }
gustavatmel 1:9c5af431a1f1 183
gustavatmel 1:9c5af431a1f1 184 /** Hands over the frame to MAC layer
gustavatmel 1:9c5af431a1f1 185 *
gustavatmel 1:9c5af431a1f1 186 * \return returns the state of the LoRa MAC
gustavatmel 1:9c5af431a1f1 187 */
gustavatmel 1:9c5af431a1f1 188 lorawan_status_t LoRaWANStack::send_frame_to_mac()
gustavatmel 1:9c5af431a1f1 189 {
gustavatmel 1:9c5af431a1f1 190 loramac_mcps_req_t mcps_req;
gustavatmel 1:9c5af431a1f1 191 lorawan_status_t status;
gustavatmel 1:9c5af431a1f1 192 loramac_mib_req_confirm_t mib_get_params;
gustavatmel 1:9c5af431a1f1 193
gustavatmel 1:9c5af431a1f1 194 mcps_req.type = _tx_msg.type;
gustavatmel 1:9c5af431a1f1 195
gustavatmel 1:9c5af431a1f1 196 if (MCPS_UNCONFIRMED == mcps_req.type) {
gustavatmel 1:9c5af431a1f1 197 mcps_req.f_buffer = _tx_msg.f_buffer;
gustavatmel 1:9c5af431a1f1 198 mcps_req.f_buffer_size = _tx_msg.f_buffer_size;
gustavatmel 1:9c5af431a1f1 199
gustavatmel 1:9c5af431a1f1 200 mcps_req.fport = _tx_msg.fport;
gustavatmel 1:9c5af431a1f1 201 mcps_req.nb_trials = 1;
gustavatmel 1:9c5af431a1f1 202 mib_get_params.type = MIB_CHANNELS_DATARATE;
gustavatmel 1:9c5af431a1f1 203 if(mib_get_request(&mib_get_params) != LORAWAN_STATUS_OK) {
gustavatmel 1:9c5af431a1f1 204 tr_debug("Couldn't get MIB parameters: Using default data rate");
gustavatmel 1:9c5af431a1f1 205 mcps_req.data_rate = _lora_phy.get_default_tx_datarate();
gustavatmel 1:9c5af431a1f1 206 } else {
gustavatmel 1:9c5af431a1f1 207 mcps_req.data_rate = mib_get_params.param.channel_data_rate;
gustavatmel 1:9c5af431a1f1 208 }
gustavatmel 1:9c5af431a1f1 209
gustavatmel 1:9c5af431a1f1 210 } else if (mcps_req.type == MCPS_CONFIRMED) {
gustavatmel 1:9c5af431a1f1 211 mcps_req.f_buffer = _tx_msg.f_buffer;
gustavatmel 1:9c5af431a1f1 212 mcps_req.f_buffer_size = _tx_msg.f_buffer_size;
gustavatmel 1:9c5af431a1f1 213 mcps_req.fport = _tx_msg.fport;
gustavatmel 1:9c5af431a1f1 214 mcps_req.nb_trials = _tx_msg.nb_trials;
gustavatmel 1:9c5af431a1f1 215
gustavatmel 1:9c5af431a1f1 216 mib_get_params.type = MIB_CHANNELS_DATARATE;
gustavatmel 1:9c5af431a1f1 217 if(mib_get_request(&mib_get_params) != LORAWAN_STATUS_OK) {
gustavatmel 1:9c5af431a1f1 218 tr_debug("Couldn't get MIB parameters: Using default data rate");
gustavatmel 1:9c5af431a1f1 219 mcps_req.data_rate = _lora_phy.get_default_tx_datarate();
gustavatmel 1:9c5af431a1f1 220 } else {
gustavatmel 1:9c5af431a1f1 221 mcps_req.data_rate = mib_get_params.param.channel_data_rate;
gustavatmel 1:9c5af431a1f1 222 }
gustavatmel 1:9c5af431a1f1 223
gustavatmel 1:9c5af431a1f1 224 } else if ( mcps_req.type == MCPS_PROPRIETARY) {
gustavatmel 1:9c5af431a1f1 225 mcps_req.f_buffer = _tx_msg.f_buffer;
gustavatmel 1:9c5af431a1f1 226 mcps_req.f_buffer_size = _tx_msg.f_buffer_size;
gustavatmel 1:9c5af431a1f1 227 mcps_req.fport = 0;
gustavatmel 1:9c5af431a1f1 228 mcps_req.nb_trials = 1;
gustavatmel 1:9c5af431a1f1 229
gustavatmel 1:9c5af431a1f1 230 mib_get_params.type = MIB_CHANNELS_DATARATE;
gustavatmel 1:9c5af431a1f1 231 if(mib_get_request(&mib_get_params) != LORAWAN_STATUS_OK) {
gustavatmel 1:9c5af431a1f1 232 tr_debug("Couldn't get MIB parameters: Using default data rate");
gustavatmel 1:9c5af431a1f1 233 mcps_req.data_rate = _lora_phy.get_default_tx_datarate();
gustavatmel 1:9c5af431a1f1 234 } else {
gustavatmel 1:9c5af431a1f1 235 mcps_req.data_rate = mib_get_params.param.channel_data_rate;
gustavatmel 1:9c5af431a1f1 236 }
gustavatmel 1:9c5af431a1f1 237
gustavatmel 1:9c5af431a1f1 238 } else {
gustavatmel 1:9c5af431a1f1 239 return LORAWAN_STATUS_SERVICE_UNKNOWN;
gustavatmel 1:9c5af431a1f1 240 }
gustavatmel 1:9c5af431a1f1 241
gustavatmel 1:9c5af431a1f1 242 status = mcps_request_handler(&mcps_req);
gustavatmel 1:9c5af431a1f1 243
gustavatmel 1:9c5af431a1f1 244 return status;
gustavatmel 1:9c5af431a1f1 245 }
gustavatmel 1:9c5af431a1f1 246
gustavatmel 1:9c5af431a1f1 247 lorawan_status_t LoRaWANStack::set_confirmed_msg_retry(uint8_t count)
gustavatmel 1:9c5af431a1f1 248 {
gustavatmel 1:9c5af431a1f1 249 if (count >= MAX_CONFIRMED_MSG_RETRIES) {
gustavatmel 1:9c5af431a1f1 250 return LORAWAN_STATUS_PARAMETER_INVALID;
gustavatmel 1:9c5af431a1f1 251 }
gustavatmel 1:9c5af431a1f1 252
gustavatmel 1:9c5af431a1f1 253 _num_retry = count;
gustavatmel 1:9c5af431a1f1 254
gustavatmel 1:9c5af431a1f1 255 return LORAWAN_STATUS_OK;
gustavatmel 1:9c5af431a1f1 256 }
gustavatmel 1:9c5af431a1f1 257
gustavatmel 1:9c5af431a1f1 258 void LoRaWANStack::set_device_state(device_states_t new_state)
gustavatmel 1:9c5af431a1f1 259 {
gustavatmel 1:9c5af431a1f1 260 _device_current_state = new_state;
gustavatmel 1:9c5af431a1f1 261 }
gustavatmel 1:9c5af431a1f1 262
gustavatmel 1:9c5af431a1f1 263 /*!
gustavatmel 1:9c5af431a1f1 264 * \brief MLME-Indication event function
gustavatmel 1:9c5af431a1f1 265 *
gustavatmel 1:9c5af431a1f1 266 * \param [IN] mlmeIndication - Pointer to the indication structure.
gustavatmel 1:9c5af431a1f1 267 */
gustavatmel 1:9c5af431a1f1 268 void LoRaWANStack::mlme_indication_handler(loramac_mlme_indication_t *mlmeIndication)
gustavatmel 1:9c5af431a1f1 269 {
gustavatmel 1:9c5af431a1f1 270 switch( mlmeIndication->indication_type )
gustavatmel 1:9c5af431a1f1 271 {
gustavatmel 1:9c5af431a1f1 272 case MLME_SCHEDULE_UPLINK:
gustavatmel 1:9c5af431a1f1 273 {// The MAC signals that we shall provide an uplink as soon as possible
gustavatmel 1:9c5af431a1f1 274 // TODO: Sending implementation missing and will be implemented using
gustavatmel 1:9c5af431a1f1 275 // another task.
gustavatmel 1:9c5af431a1f1 276 //OnTxNextPacketTimerEvent( );
gustavatmel 1:9c5af431a1f1 277 break;
gustavatmel 1:9c5af431a1f1 278 }
gustavatmel 1:9c5af431a1f1 279 default:
gustavatmel 1:9c5af431a1f1 280 break;
gustavatmel 1:9c5af431a1f1 281 }
gustavatmel 1:9c5af431a1f1 282 }
gustavatmel 1:9c5af431a1f1 283
gustavatmel 1:9c5af431a1f1 284 void LoRaWANStack::set_lora_callbacks(lorawan_app_callbacks_t *cbs)
gustavatmel 1:9c5af431a1f1 285 {
gustavatmel 1:9c5af431a1f1 286 if (cbs) {
gustavatmel 1:9c5af431a1f1 287 if (cbs->events) {
gustavatmel 1:9c5af431a1f1 288 _callbacks.events = cbs->events;
gustavatmel 1:9c5af431a1f1 289 }
gustavatmel 1:9c5af431a1f1 290
gustavatmel 1:9c5af431a1f1 291 if (cbs->link_check_resp) {
gustavatmel 1:9c5af431a1f1 292 _callbacks.link_check_resp = cbs->link_check_resp;
gustavatmel 1:9c5af431a1f1 293 }
gustavatmel 1:9c5af431a1f1 294
gustavatmel 1:9c5af431a1f1 295 if (cbs->battery_level) {
gustavatmel 1:9c5af431a1f1 296 _callbacks.battery_level = cbs->battery_level;
gustavatmel 1:9c5af431a1f1 297 }
gustavatmel 1:9c5af431a1f1 298 }
gustavatmel 1:9c5af431a1f1 299 }
gustavatmel 1:9c5af431a1f1 300
gustavatmel 1:9c5af431a1f1 301 lorawan_status_t LoRaWANStack::add_channels(const lorawan_channelplan_t &channel_plan)
gustavatmel 1:9c5af431a1f1 302 {
gustavatmel 1:9c5af431a1f1 303 // If device is not initialized, stop right away
gustavatmel 1:9c5af431a1f1 304 if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) {
gustavatmel 1:9c5af431a1f1 305 tr_error("Stack not initialized!");
gustavatmel 1:9c5af431a1f1 306 return LORAWAN_STATUS_NOT_INITIALIZED;
gustavatmel 1:9c5af431a1f1 307 }
gustavatmel 1:9c5af431a1f1 308
gustavatmel 1:9c5af431a1f1 309 return _loramac.add_channel_plan(channel_plan);
gustavatmel 1:9c5af431a1f1 310 }
gustavatmel 1:9c5af431a1f1 311
gustavatmel 1:9c5af431a1f1 312 lorawan_status_t LoRaWANStack::drop_channel_list()
gustavatmel 1:9c5af431a1f1 313 {
gustavatmel 1:9c5af431a1f1 314 if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) {
gustavatmel 1:9c5af431a1f1 315 tr_error("Stack not initialized!");
gustavatmel 1:9c5af431a1f1 316 return LORAWAN_STATUS_NOT_INITIALIZED;
gustavatmel 1:9c5af431a1f1 317 }
gustavatmel 1:9c5af431a1f1 318
gustavatmel 1:9c5af431a1f1 319 return _loramac.remove_channel_plan();
gustavatmel 1:9c5af431a1f1 320 }
gustavatmel 1:9c5af431a1f1 321
gustavatmel 1:9c5af431a1f1 322 lorawan_status_t LoRaWANStack::remove_a_channel(uint8_t channel_id)
gustavatmel 1:9c5af431a1f1 323 {
gustavatmel 1:9c5af431a1f1 324 if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED )
gustavatmel 1:9c5af431a1f1 325 {
gustavatmel 1:9c5af431a1f1 326 tr_error("Stack not initialized!");
gustavatmel 1:9c5af431a1f1 327 return LORAWAN_STATUS_NOT_INITIALIZED;
gustavatmel 1:9c5af431a1f1 328 }
gustavatmel 1:9c5af431a1f1 329
gustavatmel 1:9c5af431a1f1 330 return _loramac.remove_single_channel(channel_id);
gustavatmel 1:9c5af431a1f1 331 }
gustavatmel 1:9c5af431a1f1 332
gustavatmel 1:9c5af431a1f1 333 lorawan_status_t LoRaWANStack::get_enabled_channels(lorawan_channelplan_t& channel_plan)
gustavatmel 1:9c5af431a1f1 334 {
gustavatmel 1:9c5af431a1f1 335 if (_device_current_state == DEVICE_STATE_JOINING
gustavatmel 1:9c5af431a1f1 336 || _device_current_state == DEVICE_STATE_NOT_INITIALIZED
gustavatmel 1:9c5af431a1f1 337 || _device_current_state == DEVICE_STATE_INIT)
gustavatmel 1:9c5af431a1f1 338 {
gustavatmel 1:9c5af431a1f1 339 tr_error("Cannot get channel plan until Joined!");
gustavatmel 1:9c5af431a1f1 340 return LORAWAN_STATUS_BUSY;
gustavatmel 1:9c5af431a1f1 341 }
gustavatmel 1:9c5af431a1f1 342
gustavatmel 1:9c5af431a1f1 343 return _loramac.get_channel_plan(channel_plan);
gustavatmel 1:9c5af431a1f1 344 }
gustavatmel 1:9c5af431a1f1 345
gustavatmel 1:9c5af431a1f1 346 lorawan_status_t LoRaWANStack::enable_adaptive_datarate(bool adr_enabled)
gustavatmel 1:9c5af431a1f1 347 {
gustavatmel 1:9c5af431a1f1 348 if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state)
gustavatmel 1:9c5af431a1f1 349 {
gustavatmel 1:9c5af431a1f1 350 tr_error("Stack not initialized!");
gustavatmel 1:9c5af431a1f1 351 return LORAWAN_STATUS_NOT_INITIALIZED;
gustavatmel 1:9c5af431a1f1 352 }
gustavatmel 1:9c5af431a1f1 353
gustavatmel 1:9c5af431a1f1 354 loramac_mib_req_confirm_t adr_mib_params;
gustavatmel 1:9c5af431a1f1 355
gustavatmel 1:9c5af431a1f1 356 adr_mib_params.type = MIB_ADR;
gustavatmel 1:9c5af431a1f1 357 adr_mib_params.param.is_adr_enable = adr_enabled;
gustavatmel 1:9c5af431a1f1 358
gustavatmel 1:9c5af431a1f1 359 return mib_set_request(&adr_mib_params);
gustavatmel 1:9c5af431a1f1 360 }
gustavatmel 1:9c5af431a1f1 361
gustavatmel 1:9c5af431a1f1 362 lorawan_status_t LoRaWANStack::set_channel_data_rate(uint8_t data_rate)
gustavatmel 1:9c5af431a1f1 363 {
gustavatmel 1:9c5af431a1f1 364 if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state)
gustavatmel 1:9c5af431a1f1 365 {
gustavatmel 1:9c5af431a1f1 366 tr_error("Stack not initialized!");
gustavatmel 1:9c5af431a1f1 367 return LORAWAN_STATUS_NOT_INITIALIZED;
gustavatmel 1:9c5af431a1f1 368 }
gustavatmel 1:9c5af431a1f1 369
gustavatmel 1:9c5af431a1f1 370 loramac_mib_req_confirm_t mib_params;
gustavatmel 1:9c5af431a1f1 371 mib_params.type = MIB_ADR;
gustavatmel 1:9c5af431a1f1 372 if (mib_get_request(&mib_params) != LORAWAN_STATUS_OK) {
gustavatmel 1:9c5af431a1f1 373 tr_error("Cannot set data rate. Please turn off ADR first.");
gustavatmel 1:9c5af431a1f1 374 return LORAWAN_STATUS_PARAMETER_INVALID;
gustavatmel 1:9c5af431a1f1 375 }
gustavatmel 1:9c5af431a1f1 376
gustavatmel 1:9c5af431a1f1 377 mib_params.type = MIB_CHANNELS_DATARATE;
gustavatmel 1:9c5af431a1f1 378 mib_params.param.channel_data_rate = data_rate;
gustavatmel 1:9c5af431a1f1 379
gustavatmel 1:9c5af431a1f1 380 return mib_set_request(&mib_params);
gustavatmel 1:9c5af431a1f1 381 }
gustavatmel 1:9c5af431a1f1 382
gustavatmel 1:9c5af431a1f1 383 void LoRaWANStack::commission_device(const lorawan_dev_commission_t &commission_data)
gustavatmel 1:9c5af431a1f1 384 {
gustavatmel 1:9c5af431a1f1 385 _lw_session.connection.connect_type = commission_data.connection.connect_type;
gustavatmel 1:9c5af431a1f1 386 _lw_session.downlink_counter = commission_data.downlink_counter;
gustavatmel 1:9c5af431a1f1 387 _lw_session.uplink_counter = commission_data.uplink_counter;
gustavatmel 1:9c5af431a1f1 388
gustavatmel 1:9c5af431a1f1 389 if (commission_data.connection.connect_type == LORAWAN_CONNECTION_OTAA) {
gustavatmel 1:9c5af431a1f1 390 _lw_session.connection.connection_u.otaa.app_eui =
gustavatmel 1:9c5af431a1f1 391 commission_data.connection.connection_u.otaa.app_eui;
gustavatmel 1:9c5af431a1f1 392 _lw_session.connection.connection_u.otaa.app_key =
gustavatmel 1:9c5af431a1f1 393 commission_data.connection.connection_u.otaa.app_key;
gustavatmel 1:9c5af431a1f1 394 _lw_session.connection.connection_u.otaa.dev_eui =
gustavatmel 1:9c5af431a1f1 395 commission_data.connection.connection_u.otaa.dev_eui;
gustavatmel 1:9c5af431a1f1 396 _lw_session.connection.connection_u.otaa.nb_trials =
gustavatmel 1:9c5af431a1f1 397 commission_data.connection.connection_u.otaa.nb_trials;
gustavatmel 1:9c5af431a1f1 398 } else {
gustavatmel 1:9c5af431a1f1 399 _lw_session.connection.connection_u.abp.dev_addr =
gustavatmel 1:9c5af431a1f1 400 commission_data.connection.connection_u.abp.dev_addr;
gustavatmel 1:9c5af431a1f1 401 _lw_session.connection.connection_u.abp.nwk_skey =
gustavatmel 1:9c5af431a1f1 402 commission_data.connection.connection_u.abp.nwk_skey;
gustavatmel 1:9c5af431a1f1 403 _lw_session.connection.connection_u.abp.app_skey =
gustavatmel 1:9c5af431a1f1 404 commission_data.connection.connection_u.abp.app_skey;
gustavatmel 1:9c5af431a1f1 405 }
gustavatmel 1:9c5af431a1f1 406 }
gustavatmel 1:9c5af431a1f1 407
gustavatmel 1:9c5af431a1f1 408 /**
gustavatmel 1:9c5af431a1f1 409 *
gustavatmel 1:9c5af431a1f1 410 * Join OTAA
gustavatmel 1:9c5af431a1f1 411 */
gustavatmel 1:9c5af431a1f1 412 lorawan_status_t LoRaWANStack::join_request_by_otaa(const lorawan_connect_t &params)
gustavatmel 1:9c5af431a1f1 413 {
gustavatmel 1:9c5af431a1f1 414 lorawan_dev_commission_t commission;
gustavatmel 1:9c5af431a1f1 415
gustavatmel 1:9c5af431a1f1 416 if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state)
gustavatmel 1:9c5af431a1f1 417 {
gustavatmel 1:9c5af431a1f1 418 tr_error("Stack not initialized!");
gustavatmel 1:9c5af431a1f1 419 return LORAWAN_STATUS_NOT_INITIALIZED;
gustavatmel 1:9c5af431a1f1 420 }
gustavatmel 1:9c5af431a1f1 421
gustavatmel 1:9c5af431a1f1 422 tr_debug("Initiating OTAA");
gustavatmel 1:9c5af431a1f1 423
gustavatmel 1:9c5af431a1f1 424 commission.connection.connect_type = LORAWAN_CONNECTION_OTAA;
gustavatmel 1:9c5af431a1f1 425 commission.connection.connection_u.otaa.dev_eui = params.connection_u.otaa.dev_eui;
gustavatmel 1:9c5af431a1f1 426 commission.connection.connection_u.otaa.app_eui = params.connection_u.otaa.app_eui;
gustavatmel 1:9c5af431a1f1 427 commission.connection.connection_u.otaa.app_key = params.connection_u.otaa.app_key;
gustavatmel 1:9c5af431a1f1 428 commission.connection.connection_u.otaa.nb_trials = params.connection_u.otaa.nb_trials;
gustavatmel 1:9c5af431a1f1 429
gustavatmel 1:9c5af431a1f1 430 // As mentioned in the comment above, in 1.0.2 spec, counters are always set
gustavatmel 1:9c5af431a1f1 431 // to zero for new connection. This section is common for both normal and
gustavatmel 1:9c5af431a1f1 432 // connection restore at this moment. Will change in future with 1.1 support.
gustavatmel 1:9c5af431a1f1 433 commission.downlink_counter = 0;
gustavatmel 1:9c5af431a1f1 434 commission.uplink_counter = 0;
gustavatmel 1:9c5af431a1f1 435
gustavatmel 1:9c5af431a1f1 436 commission_device(commission);
gustavatmel 1:9c5af431a1f1 437 set_device_state(DEVICE_STATE_JOINING);
gustavatmel 1:9c5af431a1f1 438 return lora_state_machine();
gustavatmel 1:9c5af431a1f1 439 }
gustavatmel 1:9c5af431a1f1 440
gustavatmel 1:9c5af431a1f1 441 /**
gustavatmel 1:9c5af431a1f1 442 *
gustavatmel 1:9c5af431a1f1 443 * Connect ABP
gustavatmel 1:9c5af431a1f1 444 */
gustavatmel 1:9c5af431a1f1 445 lorawan_status_t LoRaWANStack::activation_by_personalization(const lorawan_connect_t &params)
gustavatmel 1:9c5af431a1f1 446 {
gustavatmel 1:9c5af431a1f1 447 lorawan_status_t status;
gustavatmel 1:9c5af431a1f1 448 lorawan_dev_commission_t commission;
gustavatmel 1:9c5af431a1f1 449
gustavatmel 1:9c5af431a1f1 450 if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) {
gustavatmel 1:9c5af431a1f1 451 tr_error("Stack not initialized!");
gustavatmel 1:9c5af431a1f1 452 return LORAWAN_STATUS_NOT_INITIALIZED;
gustavatmel 1:9c5af431a1f1 453 }
gustavatmel 1:9c5af431a1f1 454
gustavatmel 1:9c5af431a1f1 455 tr_debug("Initiating ABP");
gustavatmel 1:9c5af431a1f1 456
gustavatmel 1:9c5af431a1f1 457 commission.connection.connect_type = LORAWAN_CONNECTION_ABP;
gustavatmel 1:9c5af431a1f1 458 commission.connection.connection_u.abp.dev_addr = params.connection_u.abp.dev_addr;
gustavatmel 1:9c5af431a1f1 459 commission.connection.connection_u.abp.nwk_skey = params.connection_u.abp.nwk_skey;
gustavatmel 1:9c5af431a1f1 460 commission.connection.connection_u.abp.app_skey = params.connection_u.abp.app_skey;
gustavatmel 1:9c5af431a1f1 461
gustavatmel 1:9c5af431a1f1 462 // If current state is SHUTDOWN, device may be trying to re-establish
gustavatmel 1:9c5af431a1f1 463 // communication. In case of ABP specification is meddled about frame counters.
gustavatmel 1:9c5af431a1f1 464 // It says to reset counters to zero but there is no mechanism to tell the
gustavatmel 1:9c5af431a1f1 465 // network server that the device was disconnected or restarted.
gustavatmel 1:9c5af431a1f1 466 // At the moment, this implementation does not support a non-volatile
gustavatmel 1:9c5af431a1f1 467 // memory storage, so we try a last ditch effort here to restore correct
gustavatmel 1:9c5af431a1f1 468 // frame counters. If that doesn't work, user must manually reset frame
gustavatmel 1:9c5af431a1f1 469 // counters on their network server.
gustavatmel 1:9c5af431a1f1 470 commission.downlink_counter = _lw_session.downlink_counter;
gustavatmel 1:9c5af431a1f1 471 commission.uplink_counter = _lw_session.uplink_counter;
gustavatmel 1:9c5af431a1f1 472
gustavatmel 1:9c5af431a1f1 473 tr_debug("Frame Counters. UpCnt=%lu, DownCnt=%lu",
gustavatmel 1:9c5af431a1f1 474 commission.uplink_counter, commission.downlink_counter);
gustavatmel 1:9c5af431a1f1 475
gustavatmel 1:9c5af431a1f1 476 commission_device(commission);
gustavatmel 1:9c5af431a1f1 477
gustavatmel 1:9c5af431a1f1 478 set_device_state(DEVICE_STATE_ABP_CONNECTING);
gustavatmel 1:9c5af431a1f1 479 status = lora_state_machine();
gustavatmel 1:9c5af431a1f1 480
gustavatmel 1:9c5af431a1f1 481 return status;
gustavatmel 1:9c5af431a1f1 482 }
gustavatmel 1:9c5af431a1f1 483
gustavatmel 1:9c5af431a1f1 484 int16_t LoRaWANStack::handle_tx(uint8_t port, const uint8_t* data,
gustavatmel 1:9c5af431a1f1 485 uint16_t length, uint8_t flags)
gustavatmel 1:9c5af431a1f1 486 {
gustavatmel 1:9c5af431a1f1 487 if (!_lw_session.active) {
gustavatmel 1:9c5af431a1f1 488 return LORAWAN_STATUS_NO_ACTIVE_SESSIONS;
gustavatmel 1:9c5af431a1f1 489 }
gustavatmel 1:9c5af431a1f1 490
gustavatmel 1:9c5af431a1f1 491 if (_tx_msg.tx_ongoing) {
gustavatmel 1:9c5af431a1f1 492 return LORAWAN_STATUS_WOULD_BLOCK;
gustavatmel 1:9c5af431a1f1 493 }
gustavatmel 1:9c5af431a1f1 494
gustavatmel 1:9c5af431a1f1 495 if (!data && length > 0) {
gustavatmel 1:9c5af431a1f1 496 return LORAWAN_STATUS_PARAMETER_INVALID;
gustavatmel 1:9c5af431a1f1 497 }
gustavatmel 1:9c5af431a1f1 498
gustavatmel 1:9c5af431a1f1 499 #if defined(LORAWAN_COMPLIANCE_TEST)
gustavatmel 1:9c5af431a1f1 500 if (_compliance_test.running) {
gustavatmel 1:9c5af431a1f1 501 return LORAWAN_STATUS_COMPLIANCE_TEST_ON;
gustavatmel 1:9c5af431a1f1 502 }
gustavatmel 1:9c5af431a1f1 503 #endif
gustavatmel 1:9c5af431a1f1 504
gustavatmel 1:9c5af431a1f1 505 loramac_mib_req_confirm_t mib_req;
gustavatmel 1:9c5af431a1f1 506 lorawan_status_t status;
gustavatmel 1:9c5af431a1f1 507 mib_req.type = MIB_NETWORK_JOINED;
gustavatmel 1:9c5af431a1f1 508 status = mib_get_request(&mib_req);
gustavatmel 1:9c5af431a1f1 509
gustavatmel 1:9c5af431a1f1 510 if (status == LORAWAN_STATUS_OK) {
gustavatmel 1:9c5af431a1f1 511 if (mib_req.param.is_nwk_joined == false) {
gustavatmel 1:9c5af431a1f1 512 return LORAWAN_STATUS_NO_NETWORK_JOINED;
gustavatmel 1:9c5af431a1f1 513 }
gustavatmel 1:9c5af431a1f1 514 }
gustavatmel 1:9c5af431a1f1 515
gustavatmel 1:9c5af431a1f1 516 status = set_application_port(port);
gustavatmel 1:9c5af431a1f1 517
gustavatmel 1:9c5af431a1f1 518 if (status != LORAWAN_STATUS_OK) {
gustavatmel 1:9c5af431a1f1 519 tr_error("Illegal application port definition.");
gustavatmel 1:9c5af431a1f1 520 return status;
gustavatmel 1:9c5af431a1f1 521 }
gustavatmel 1:9c5af431a1f1 522
gustavatmel 1:9c5af431a1f1 523 if (flags == 0
gustavatmel 1:9c5af431a1f1 524 || (flags & MSG_FLAG_MASK) == (MSG_CONFIRMED_FLAG|MSG_UNCONFIRMED_FLAG)) {
gustavatmel 1:9c5af431a1f1 525 tr_error("CONFIRMED and UNCONFIRMED are mutually exclusive for send()");
gustavatmel 1:9c5af431a1f1 526 return LORAWAN_STATUS_PARAMETER_INVALID;
gustavatmel 1:9c5af431a1f1 527 }
gustavatmel 1:9c5af431a1f1 528
gustavatmel 1:9c5af431a1f1 529 _tx_msg.port = port;
gustavatmel 1:9c5af431a1f1 530
gustavatmel 1:9c5af431a1f1 531 uint16_t max_possible_size = check_possible_tx_size(length);
gustavatmel 1:9c5af431a1f1 532
gustavatmel 1:9c5af431a1f1 533 if (max_possible_size > MBED_CONF_LORA_TX_MAX_SIZE) {
gustavatmel 1:9c5af431a1f1 534 // LORAWAN_APP_DATA_MAX_SIZE should at least be
gustavatmel 1:9c5af431a1f1 535 // either equal to or bigger than maximum possible
gustavatmel 1:9c5af431a1f1 536 // tx size because our tx message buffer takes its
gustavatmel 1:9c5af431a1f1 537 // length from that macro. Force maximum possible tx unit
gustavatmel 1:9c5af431a1f1 538 // to be equal to the buffer size user chose.
gustavatmel 1:9c5af431a1f1 539 max_possible_size = MBED_CONF_LORA_TX_MAX_SIZE;
gustavatmel 1:9c5af431a1f1 540 }
gustavatmel 1:9c5af431a1f1 541
gustavatmel 1:9c5af431a1f1 542 if (max_possible_size < length) {
gustavatmel 1:9c5af431a1f1 543 tr_info("Cannot transmit %d bytes. Possible TX Size is %d bytes",
gustavatmel 1:9c5af431a1f1 544 length, max_possible_size);
gustavatmel 1:9c5af431a1f1 545
gustavatmel 1:9c5af431a1f1 546 _tx_msg.pending_size = length - max_possible_size;
gustavatmel 1:9c5af431a1f1 547 _tx_msg.f_buffer_size = max_possible_size;
gustavatmel 1:9c5af431a1f1 548 // copy user buffer upto the max_possible_size
gustavatmel 1:9c5af431a1f1 549 memcpy(_tx_msg.f_buffer, data, _tx_msg.f_buffer_size);
gustavatmel 1:9c5af431a1f1 550 } else {
gustavatmel 1:9c5af431a1f1 551 // Whole message can be sent at one time
gustavatmel 1:9c5af431a1f1 552 _tx_msg.f_buffer_size = length;
gustavatmel 1:9c5af431a1f1 553 _tx_msg.pending_size = 0;
gustavatmel 1:9c5af431a1f1 554 // copy user buffer upto the max_possible_size
gustavatmel 1:9c5af431a1f1 555 if (length > 0) {
gustavatmel 1:9c5af431a1f1 556 memcpy(_tx_msg.f_buffer, data, length);
gustavatmel 1:9c5af431a1f1 557 }
gustavatmel 1:9c5af431a1f1 558 }
gustavatmel 1:9c5af431a1f1 559
gustavatmel 1:9c5af431a1f1 560 // Handles all unconfirmed messages, including proprietary and multicast
gustavatmel 1:9c5af431a1f1 561 if ((flags & MSG_FLAG_MASK) == MSG_UNCONFIRMED_FLAG
gustavatmel 1:9c5af431a1f1 562 || (flags & MSG_FLAG_MASK) == MSG_UNCONFIRMED_MULTICAST
gustavatmel 1:9c5af431a1f1 563 || (flags & MSG_FLAG_MASK) == MSG_UNCONFIRMED_PROPRIETARY) {
gustavatmel 1:9c5af431a1f1 564
gustavatmel 1:9c5af431a1f1 565 _tx_msg.type = MCPS_UNCONFIRMED;
gustavatmel 1:9c5af431a1f1 566 _tx_msg.fport = _app_port;
gustavatmel 1:9c5af431a1f1 567 }
gustavatmel 1:9c5af431a1f1 568
gustavatmel 1:9c5af431a1f1 569 // Handles all confirmed messages, including proprietary and multicast
gustavatmel 1:9c5af431a1f1 570 if ((flags & MSG_FLAG_MASK) == MSG_CONFIRMED_FLAG
gustavatmel 1:9c5af431a1f1 571 || (flags & MSG_FLAG_MASK) == MSG_CONFIRMED_MULTICAST
gustavatmel 1:9c5af431a1f1 572 || (flags & MSG_FLAG_MASK) == MSG_CONFIRMED_PROPRIETARY) {
gustavatmel 1:9c5af431a1f1 573
gustavatmel 1:9c5af431a1f1 574 _tx_msg.type = MCPS_CONFIRMED;
gustavatmel 1:9c5af431a1f1 575 _tx_msg.fport = _app_port;
gustavatmel 1:9c5af431a1f1 576 _tx_msg.nb_trials = _num_retry;
gustavatmel 1:9c5af431a1f1 577 }
gustavatmel 1:9c5af431a1f1 578
gustavatmel 1:9c5af431a1f1 579 tr_info("RTS = %u bytes, PEND = %u", _tx_msg.f_buffer_size, _tx_msg.pending_size);
gustavatmel 1:9c5af431a1f1 580 set_device_state(DEVICE_STATE_SEND);
gustavatmel 1:9c5af431a1f1 581 status = lora_state_machine();
gustavatmel 1:9c5af431a1f1 582
gustavatmel 1:9c5af431a1f1 583 // send user the length of data which is scheduled now.
gustavatmel 1:9c5af431a1f1 584 // user should take care of the pending data.
gustavatmel 1:9c5af431a1f1 585 return (status == LORAWAN_STATUS_OK) ? _tx_msg.f_buffer_size : (int16_t) status;
gustavatmel 1:9c5af431a1f1 586 }
gustavatmel 1:9c5af431a1f1 587
gustavatmel 1:9c5af431a1f1 588 int16_t LoRaWANStack::handle_rx(const uint8_t port, uint8_t* data,
gustavatmel 1:9c5af431a1f1 589 uint16_t length, uint8_t flags)
gustavatmel 1:9c5af431a1f1 590 {
gustavatmel 1:9c5af431a1f1 591 if (!_lw_session.active) {
gustavatmel 1:9c5af431a1f1 592 return LORAWAN_STATUS_NO_ACTIVE_SESSIONS;
gustavatmel 1:9c5af431a1f1 593 }
gustavatmel 1:9c5af431a1f1 594
gustavatmel 1:9c5af431a1f1 595 // No messages to read.
gustavatmel 1:9c5af431a1f1 596 if (!_rx_msg.receive_ready) {
gustavatmel 1:9c5af431a1f1 597 return LORAWAN_STATUS_WOULD_BLOCK;
gustavatmel 1:9c5af431a1f1 598 }
gustavatmel 1:9c5af431a1f1 599
gustavatmel 1:9c5af431a1f1 600 #if defined(LORAWAN_COMPLIANCE_TEST)
gustavatmel 1:9c5af431a1f1 601 if (_compliance_test.running) {
gustavatmel 1:9c5af431a1f1 602 return LORAWAN_STATUS_COMPLIANCE_TEST_ON;
gustavatmel 1:9c5af431a1f1 603 }
gustavatmel 1:9c5af431a1f1 604 #endif
gustavatmel 1:9c5af431a1f1 605
gustavatmel 1:9c5af431a1f1 606 if (data == NULL) {
gustavatmel 1:9c5af431a1f1 607 return LORAWAN_STATUS_PARAMETER_INVALID;
gustavatmel 1:9c5af431a1f1 608 }
gustavatmel 1:9c5af431a1f1 609
gustavatmel 1:9c5af431a1f1 610 uint8_t *base_ptr = _rx_msg.msg.mcps_indication.buffer;
gustavatmel 1:9c5af431a1f1 611 uint16_t base_size = _rx_msg.msg.mcps_indication.buffer_size;
gustavatmel 1:9c5af431a1f1 612 bool read_complete = false;
gustavatmel 1:9c5af431a1f1 613
gustavatmel 1:9c5af431a1f1 614 if (_rx_msg.msg.mcps_indication.port != port) {
gustavatmel 1:9c5af431a1f1 615 // Nothing yet received for this particular port
gustavatmel 1:9c5af431a1f1 616 return LORAWAN_STATUS_WOULD_BLOCK;
gustavatmel 1:9c5af431a1f1 617 }
gustavatmel 1:9c5af431a1f1 618
gustavatmel 1:9c5af431a1f1 619 // check if message received is a Confirmed message and user subscribed to it or not
gustavatmel 1:9c5af431a1f1 620 if (_rx_msg.msg.mcps_indication.type == MCPS_CONFIRMED
gustavatmel 1:9c5af431a1f1 621 && ((flags & MSG_FLAG_MASK) == MSG_CONFIRMED_FLAG
gustavatmel 1:9c5af431a1f1 622 || (flags & MSG_FLAG_MASK) == MSG_CONFIRMED_MULTICAST
gustavatmel 1:9c5af431a1f1 623 || (flags & MSG_FLAG_MASK) == MSG_CONFIRMED_PROPRIETARY)) {
gustavatmel 1:9c5af431a1f1 624
gustavatmel 1:9c5af431a1f1 625 tr_debug("RX - Confirmed Message, flags=%d", flags);
gustavatmel 1:9c5af431a1f1 626 }
gustavatmel 1:9c5af431a1f1 627
gustavatmel 1:9c5af431a1f1 628 // check if message received is a Unconfirmed message and user subscribed to it or not
gustavatmel 1:9c5af431a1f1 629 if (_rx_msg.msg.mcps_indication.type == MCPS_UNCONFIRMED
gustavatmel 1:9c5af431a1f1 630 && ((flags & MSG_FLAG_MASK) == MSG_UNCONFIRMED_FLAG
gustavatmel 1:9c5af431a1f1 631 || (flags & MSG_FLAG_MASK) == MSG_UNCONFIRMED_MULTICAST
gustavatmel 1:9c5af431a1f1 632 || (flags & MSG_FLAG_MASK) == MSG_UNCONFIRMED_PROPRIETARY)) {
gustavatmel 1:9c5af431a1f1 633 tr_debug("RX - Unconfirmed Message - flags=%d", flags);
gustavatmel 1:9c5af431a1f1 634 }
gustavatmel 1:9c5af431a1f1 635
gustavatmel 1:9c5af431a1f1 636 // check the length of received message whether we can fit into user
gustavatmel 1:9c5af431a1f1 637 // buffer completely or not
gustavatmel 1:9c5af431a1f1 638 if (_rx_msg.msg.mcps_indication.buffer_size > length &&
gustavatmel 1:9c5af431a1f1 639 _rx_msg.prev_read_size == 0) {
gustavatmel 1:9c5af431a1f1 640 // we can't fit into user buffer. Invoke counter measures
gustavatmel 1:9c5af431a1f1 641 _rx_msg.pending_size = _rx_msg.msg.mcps_indication.buffer_size - length;
gustavatmel 1:9c5af431a1f1 642 base_size = length;
gustavatmel 1:9c5af431a1f1 643 _rx_msg.prev_read_size = base_size;
gustavatmel 1:9c5af431a1f1 644 memcpy(data, base_ptr, base_size);
gustavatmel 1:9c5af431a1f1 645 } else if (_rx_msg.prev_read_size == 0) {
gustavatmel 1:9c5af431a1f1 646 _rx_msg.pending_size = 0;
gustavatmel 1:9c5af431a1f1 647 _rx_msg.prev_read_size = 0;
gustavatmel 1:9c5af431a1f1 648 memcpy(data, base_ptr, base_size);
gustavatmel 1:9c5af431a1f1 649 read_complete = true;
gustavatmel 1:9c5af431a1f1 650 }
gustavatmel 1:9c5af431a1f1 651
gustavatmel 1:9c5af431a1f1 652 // If its the pending read then we should copy only the remaining part of
gustavatmel 1:9c5af431a1f1 653 // the buffer. Due to checks above, in case of a pending read, this block
gustavatmel 1:9c5af431a1f1 654 // will be the only one to get invoked
gustavatmel 1:9c5af431a1f1 655 if (_rx_msg.pending_size > 0 && _rx_msg.prev_read_size > 0) {
gustavatmel 1:9c5af431a1f1 656 memcpy(data, base_ptr+_rx_msg.prev_read_size, base_size);
gustavatmel 1:9c5af431a1f1 657 }
gustavatmel 1:9c5af431a1f1 658
gustavatmel 1:9c5af431a1f1 659 // we are done handing over received buffer to user. check if there is
gustavatmel 1:9c5af431a1f1 660 // anything pending. If not, memset the buffer to zero and indicate
gustavatmel 1:9c5af431a1f1 661 // that no read is in progress
gustavatmel 1:9c5af431a1f1 662 if (read_complete) {
gustavatmel 1:9c5af431a1f1 663 memset(_rx_msg.msg.mcps_indication.buffer, 0, LORAMAC_PHY_MAXPAYLOAD);
gustavatmel 1:9c5af431a1f1 664 _rx_msg.receive_ready = false;
gustavatmel 1:9c5af431a1f1 665 }
gustavatmel 1:9c5af431a1f1 666
gustavatmel 1:9c5af431a1f1 667 return base_size;
gustavatmel 1:9c5af431a1f1 668 }
gustavatmel 1:9c5af431a1f1 669
gustavatmel 1:9c5af431a1f1 670 lorawan_status_t LoRaWANStack::mlme_request_handler(loramac_mlme_req_t *mlme_request)
gustavatmel 1:9c5af431a1f1 671 {
gustavatmel 1:9c5af431a1f1 672 if (mlme_request == NULL) {
gustavatmel 1:9c5af431a1f1 673 return LORAWAN_STATUS_PARAMETER_INVALID;
gustavatmel 1:9c5af431a1f1 674 }
gustavatmel 1:9c5af431a1f1 675
gustavatmel 1:9c5af431a1f1 676 return _loramac.mlme_request(mlme_request);
gustavatmel 1:9c5af431a1f1 677 }
gustavatmel 1:9c5af431a1f1 678
gustavatmel 1:9c5af431a1f1 679 /** MLME-Confirm event function
gustavatmel 1:9c5af431a1f1 680 *
gustavatmel 1:9c5af431a1f1 681 * \param mlme_confirm Pointer to the confirm structure,
gustavatmel 1:9c5af431a1f1 682 * containing confirm attributes.
gustavatmel 1:9c5af431a1f1 683 */
gustavatmel 1:9c5af431a1f1 684 void LoRaWANStack::mlme_confirm_handler(loramac_mlme_confirm_t *mlme_confirm)
gustavatmel 1:9c5af431a1f1 685 {
gustavatmel 1:9c5af431a1f1 686 if (NULL == mlme_confirm) {
gustavatmel 1:9c5af431a1f1 687 tr_error("mlme_confirm: struct [in] is null!");
gustavatmel 1:9c5af431a1f1 688 MBED_ASSERT(0);
gustavatmel 1:9c5af431a1f1 689 return;
gustavatmel 1:9c5af431a1f1 690 }
gustavatmel 1:9c5af431a1f1 691
gustavatmel 1:9c5af431a1f1 692 switch (mlme_confirm->req_type) {
gustavatmel 1:9c5af431a1f1 693 case MLME_JOIN:
gustavatmel 1:9c5af431a1f1 694 if (mlme_confirm->status == LORAMAC_EVENT_INFO_STATUS_OK) {
gustavatmel 1:9c5af431a1f1 695 // Status is OK, node has joined the network
gustavatmel 1:9c5af431a1f1 696 set_device_state(DEVICE_STATE_JOINED);
gustavatmel 1:9c5af431a1f1 697 if (lora_state_machine() != LORAWAN_STATUS_OK) {
gustavatmel 1:9c5af431a1f1 698 tr_error("Lora state machine did not return LORAWAN_STATUS_OK");
gustavatmel 1:9c5af431a1f1 699 }
gustavatmel 1:9c5af431a1f1 700 } else {
gustavatmel 1:9c5af431a1f1 701 // Join attempt failed.
gustavatmel 1:9c5af431a1f1 702 set_device_state(DEVICE_STATE_IDLE);
gustavatmel 1:9c5af431a1f1 703 if (lora_state_machine() != LORAWAN_STATUS_IDLE) {
gustavatmel 1:9c5af431a1f1 704 tr_error("Lora state machine did not return DEVICE_STATE_IDLE !");
gustavatmel 1:9c5af431a1f1 705 }
gustavatmel 1:9c5af431a1f1 706
gustavatmel 1:9c5af431a1f1 707 if (_callbacks.events) {
gustavatmel 1:9c5af431a1f1 708 const int ret = _queue->call(_callbacks.events, JOIN_FAILURE);
gustavatmel 1:9c5af431a1f1 709 MBED_ASSERT(ret != 0);
gustavatmel 1:9c5af431a1f1 710 (void)ret;
gustavatmel 1:9c5af431a1f1 711 }
gustavatmel 1:9c5af431a1f1 712 }
gustavatmel 1:9c5af431a1f1 713 break;
gustavatmel 1:9c5af431a1f1 714 case MLME_LINK_CHECK:
gustavatmel 1:9c5af431a1f1 715 if (mlme_confirm->status == LORAMAC_EVENT_INFO_STATUS_OK) {
gustavatmel 1:9c5af431a1f1 716 // Check DemodMargin
gustavatmel 1:9c5af431a1f1 717 // Check NbGateways
gustavatmel 1:9c5af431a1f1 718 #if defined(LORAWAN_COMPLIANCE_TEST)
gustavatmel 1:9c5af431a1f1 719 if (_compliance_test.running == true) {
gustavatmel 1:9c5af431a1f1 720 _compliance_test.link_check = true;
gustavatmel 1:9c5af431a1f1 721 _compliance_test.demod_margin = mlme_confirm->demod_margin;
gustavatmel 1:9c5af431a1f1 722 _compliance_test.nb_gateways = mlme_confirm->nb_gateways;
gustavatmel 1:9c5af431a1f1 723 } else
gustavatmel 1:9c5af431a1f1 724 #endif
gustavatmel 1:9c5af431a1f1 725 {
gustavatmel 1:9c5af431a1f1 726 // normal operation as oppose to compliance testing
gustavatmel 1:9c5af431a1f1 727 if (_callbacks.link_check_resp) {
gustavatmel 1:9c5af431a1f1 728 const int ret = _queue->call(_callbacks.link_check_resp,
gustavatmel 1:9c5af431a1f1 729 mlme_confirm->demod_margin,
gustavatmel 1:9c5af431a1f1 730 mlme_confirm->nb_gateways);
gustavatmel 1:9c5af431a1f1 731 MBED_ASSERT(ret != 0);
gustavatmel 1:9c5af431a1f1 732 (void)ret;
gustavatmel 1:9c5af431a1f1 733 }
gustavatmel 1:9c5af431a1f1 734 }
gustavatmel 1:9c5af431a1f1 735 }
gustavatmel 1:9c5af431a1f1 736 break;
gustavatmel 1:9c5af431a1f1 737 default:
gustavatmel 1:9c5af431a1f1 738 break;
gustavatmel 1:9c5af431a1f1 739 }
gustavatmel 1:9c5af431a1f1 740 }
gustavatmel 1:9c5af431a1f1 741
gustavatmel 1:9c5af431a1f1 742 lorawan_status_t LoRaWANStack::mcps_request_handler(loramac_mcps_req_t *mcps_request)
gustavatmel 1:9c5af431a1f1 743 {
gustavatmel 1:9c5af431a1f1 744 if (mcps_request == NULL) {
gustavatmel 1:9c5af431a1f1 745 return LORAWAN_STATUS_PARAMETER_INVALID;
gustavatmel 1:9c5af431a1f1 746 }
gustavatmel 1:9c5af431a1f1 747
gustavatmel 1:9c5af431a1f1 748 return _loramac.mcps_request(mcps_request);
gustavatmel 1:9c5af431a1f1 749 }
gustavatmel 1:9c5af431a1f1 750
gustavatmel 1:9c5af431a1f1 751 /** MCPS-Confirm event function
gustavatmel 1:9c5af431a1f1 752 *
gustavatmel 1:9c5af431a1f1 753 * \param mcps_confirm Pointer to the confirm structure,
gustavatmel 1:9c5af431a1f1 754 * containing confirm attributes.
gustavatmel 1:9c5af431a1f1 755 */
gustavatmel 1:9c5af431a1f1 756 void LoRaWANStack::mcps_confirm_handler(loramac_mcps_confirm_t *mcps_confirm)
gustavatmel 1:9c5af431a1f1 757 {
gustavatmel 1:9c5af431a1f1 758 if (mcps_confirm == NULL) {
gustavatmel 1:9c5af431a1f1 759 tr_error("mcps_confirm: struct [in] is null!");
gustavatmel 1:9c5af431a1f1 760 MBED_ASSERT(0);
gustavatmel 1:9c5af431a1f1 761 return;
gustavatmel 1:9c5af431a1f1 762 }
gustavatmel 1:9c5af431a1f1 763
gustavatmel 1:9c5af431a1f1 764 if (mcps_confirm->status != LORAMAC_EVENT_INFO_STATUS_OK) {
gustavatmel 1:9c5af431a1f1 765 // Couldn't schedule packet, ack not recieved in CONFIRMED case
gustavatmel 1:9c5af431a1f1 766 // or some other error happened. Discard buffer, unset the tx-ongoing
gustavatmel 1:9c5af431a1f1 767 // flag and let the application know
gustavatmel 1:9c5af431a1f1 768 _tx_msg.tx_ongoing = false;
gustavatmel 1:9c5af431a1f1 769 memset(_tx_msg.f_buffer, 0, MBED_CONF_LORA_TX_MAX_SIZE);
gustavatmel 1:9c5af431a1f1 770 _tx_msg.f_buffer_size = MBED_CONF_LORA_TX_MAX_SIZE;
gustavatmel 1:9c5af431a1f1 771
gustavatmel 1:9c5af431a1f1 772 tr_error("mcps_confirm_handler: Error code = %d", mcps_confirm->status);
gustavatmel 1:9c5af431a1f1 773
gustavatmel 1:9c5af431a1f1 774 // If sending timed out, we have a special event for that
gustavatmel 1:9c5af431a1f1 775 if (mcps_confirm->status == LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT) {
gustavatmel 1:9c5af431a1f1 776 if (_callbacks.events) {
gustavatmel 1:9c5af431a1f1 777 const int ret = _queue->call(_callbacks.events, TX_TIMEOUT);
gustavatmel 1:9c5af431a1f1 778 MBED_ASSERT(ret != 0);
gustavatmel 1:9c5af431a1f1 779 (void)ret;
gustavatmel 1:9c5af431a1f1 780 }
gustavatmel 1:9c5af431a1f1 781 return;
gustavatmel 1:9c5af431a1f1 782 } if (mcps_confirm->status == LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT) {
gustavatmel 1:9c5af431a1f1 783 tr_debug("Did not receive Ack");
gustavatmel 1:9c5af431a1f1 784 }
gustavatmel 1:9c5af431a1f1 785
gustavatmel 1:9c5af431a1f1 786 // Otherwise send a general TX_ERROR event
gustavatmel 1:9c5af431a1f1 787 if (_callbacks.events) {
gustavatmel 1:9c5af431a1f1 788 const int ret = _queue->call(_callbacks.events, TX_ERROR);
gustavatmel 1:9c5af431a1f1 789 MBED_ASSERT(ret != 0);
gustavatmel 1:9c5af431a1f1 790 (void)ret;
gustavatmel 1:9c5af431a1f1 791 }
gustavatmel 1:9c5af431a1f1 792 return;
gustavatmel 1:9c5af431a1f1 793 }
gustavatmel 1:9c5af431a1f1 794
gustavatmel 1:9c5af431a1f1 795 // If No errors encountered, let's proceed with the status.
gustavatmel 1:9c5af431a1f1 796 // CONFIRMED needs special handling because of acks
gustavatmel 1:9c5af431a1f1 797 if (mcps_confirm->req_type == MCPS_CONFIRMED) {
gustavatmel 1:9c5af431a1f1 798 // In confirmed case, we need to check if we have received the Ack or not.
gustavatmel 1:9c5af431a1f1 799 // This is actually just being paranoid about ack because LoRaMac.cpp doesn't
gustavatmel 1:9c5af431a1f1 800 // call this callback until an ack is received.
gustavatmel 1:9c5af431a1f1 801 if (mcps_confirm->ack_received) {
gustavatmel 1:9c5af431a1f1 802 tr_debug("Ack received.");
gustavatmel 1:9c5af431a1f1 803 }
gustavatmel 1:9c5af431a1f1 804 }
gustavatmel 1:9c5af431a1f1 805
gustavatmel 1:9c5af431a1f1 806 // This part is common to both CONFIRMED and UNCONFIRMED.
gustavatmel 1:9c5af431a1f1 807 // Tell the application about successful transmission and store
gustavatmel 1:9c5af431a1f1 808 // data rate plus frame counter.
gustavatmel 1:9c5af431a1f1 809 _lw_session.uplink_counter = mcps_confirm->ul_frame_counter;
gustavatmel 1:9c5af431a1f1 810 _tx_msg.tx_ongoing = false;
gustavatmel 1:9c5af431a1f1 811 if (_callbacks.events) {
gustavatmel 1:9c5af431a1f1 812 const int ret = _queue->call(_callbacks.events, TX_DONE);
gustavatmel 1:9c5af431a1f1 813 MBED_ASSERT(ret != 0);
gustavatmel 1:9c5af431a1f1 814 (void)ret;
gustavatmel 1:9c5af431a1f1 815 }
gustavatmel 1:9c5af431a1f1 816 }
gustavatmel 1:9c5af431a1f1 817
gustavatmel 1:9c5af431a1f1 818 /** MCPS-Indication event function
gustavatmel 1:9c5af431a1f1 819 *
gustavatmel 1:9c5af431a1f1 820 * \param mcps_indication Pointer to the indication structure,
gustavatmel 1:9c5af431a1f1 821 * containing indication attributes.
gustavatmel 1:9c5af431a1f1 822 */
gustavatmel 1:9c5af431a1f1 823 void LoRaWANStack::mcps_indication_handler(loramac_mcps_indication_t *mcps_indication)
gustavatmel 1:9c5af431a1f1 824 {
gustavatmel 1:9c5af431a1f1 825 if (mcps_indication == NULL) {
gustavatmel 1:9c5af431a1f1 826 tr_error("mcps_indication: struct [in] is null.");
gustavatmel 1:9c5af431a1f1 827 return;
gustavatmel 1:9c5af431a1f1 828 }
gustavatmel 1:9c5af431a1f1 829
gustavatmel 1:9c5af431a1f1 830 if (mcps_indication->status != LORAMAC_EVENT_INFO_STATUS_OK) {
gustavatmel 1:9c5af431a1f1 831 if (_callbacks.events) {
gustavatmel 1:9c5af431a1f1 832 const int ret = _queue->call(_callbacks.events, RX_ERROR);
gustavatmel 1:9c5af431a1f1 833 MBED_ASSERT(ret != 0);
gustavatmel 1:9c5af431a1f1 834 (void)ret;
gustavatmel 1:9c5af431a1f1 835 }
gustavatmel 1:9c5af431a1f1 836 return;
gustavatmel 1:9c5af431a1f1 837 }
gustavatmel 1:9c5af431a1f1 838
gustavatmel 1:9c5af431a1f1 839 switch (mcps_indication->type) {
gustavatmel 1:9c5af431a1f1 840 case MCPS_UNCONFIRMED:
gustavatmel 1:9c5af431a1f1 841 break;
gustavatmel 1:9c5af431a1f1 842 case MCPS_CONFIRMED:
gustavatmel 1:9c5af431a1f1 843 break;
gustavatmel 1:9c5af431a1f1 844 case MCPS_PROPRIETARY:
gustavatmel 1:9c5af431a1f1 845 break;
gustavatmel 1:9c5af431a1f1 846 case MCPS_MULTICAST:
gustavatmel 1:9c5af431a1f1 847 break;
gustavatmel 1:9c5af431a1f1 848 default:
gustavatmel 1:9c5af431a1f1 849 break;
gustavatmel 1:9c5af431a1f1 850 }
gustavatmel 1:9c5af431a1f1 851
gustavatmel 1:9c5af431a1f1 852 // Check Multicast
gustavatmel 1:9c5af431a1f1 853 // Check Port
gustavatmel 1:9c5af431a1f1 854 // Check Datarate
gustavatmel 1:9c5af431a1f1 855 // Check FramePending
gustavatmel 1:9c5af431a1f1 856 // Check Buffer
gustavatmel 1:9c5af431a1f1 857 // Check BufferSize
gustavatmel 1:9c5af431a1f1 858 // Check Rssi
gustavatmel 1:9c5af431a1f1 859 // Check Snr
gustavatmel 1:9c5af431a1f1 860 // Check RxSlot
gustavatmel 1:9c5af431a1f1 861
gustavatmel 1:9c5af431a1f1 862 _lw_session.downlink_counter++;
gustavatmel 1:9c5af431a1f1 863
gustavatmel 1:9c5af431a1f1 864 #if defined(LORAWAN_COMPLIANCE_TEST)
gustavatmel 1:9c5af431a1f1 865 if (_compliance_test.running == true) {
gustavatmel 1:9c5af431a1f1 866 _compliance_test.downlink_counter++;
gustavatmel 1:9c5af431a1f1 867 }
gustavatmel 1:9c5af431a1f1 868 #endif
gustavatmel 1:9c5af431a1f1 869
gustavatmel 1:9c5af431a1f1 870 if (mcps_indication->is_data_recvd == true) {
gustavatmel 1:9c5af431a1f1 871 switch (mcps_indication->port) {
gustavatmel 1:9c5af431a1f1 872 case 224:
gustavatmel 1:9c5af431a1f1 873 #if defined(LORAWAN_COMPLIANCE_TEST)
gustavatmel 1:9c5af431a1f1 874 tr_debug("Compliance test command received.");
gustavatmel 1:9c5af431a1f1 875 compliance_test_handler(mcps_indication);
gustavatmel 1:9c5af431a1f1 876 #else
gustavatmel 1:9c5af431a1f1 877 tr_debug("Compliance test disabled.");
gustavatmel 1:9c5af431a1f1 878 #endif
gustavatmel 1:9c5af431a1f1 879 break;
gustavatmel 1:9c5af431a1f1 880 default:
gustavatmel 1:9c5af431a1f1 881 if (is_port_valid(mcps_indication->port) == true ||
gustavatmel 1:9c5af431a1f1 882 mcps_indication->type == MCPS_PROPRIETARY) {
gustavatmel 1:9c5af431a1f1 883
gustavatmel 1:9c5af431a1f1 884 // Valid message arrived.
gustavatmel 1:9c5af431a1f1 885 _rx_msg.type = LORAMAC_RX_MCPS_INDICATION;
gustavatmel 1:9c5af431a1f1 886 _rx_msg.msg.mcps_indication.buffer_size = mcps_indication->buffer_size;
gustavatmel 1:9c5af431a1f1 887 _rx_msg.msg.mcps_indication.port = mcps_indication->port;
gustavatmel 1:9c5af431a1f1 888
gustavatmel 1:9c5af431a1f1 889 // no copy, just set the pointer for the user
gustavatmel 1:9c5af431a1f1 890 _rx_msg.msg.mcps_indication.buffer =
gustavatmel 1:9c5af431a1f1 891 mcps_indication->buffer;
gustavatmel 1:9c5af431a1f1 892
gustavatmel 1:9c5af431a1f1 893 // Notify application about received frame..
gustavatmel 1:9c5af431a1f1 894 tr_debug("Received %d bytes", _rx_msg.msg.mcps_indication.buffer_size);
gustavatmel 1:9c5af431a1f1 895 _rx_msg.receive_ready = true;
gustavatmel 1:9c5af431a1f1 896
gustavatmel 1:9c5af431a1f1 897 if (_callbacks.events) {
gustavatmel 1:9c5af431a1f1 898 const int ret = _queue->call(_callbacks.events, RX_DONE);
gustavatmel 1:9c5af431a1f1 899 MBED_ASSERT(ret != 0);
gustavatmel 1:9c5af431a1f1 900 (void)ret;
gustavatmel 1:9c5af431a1f1 901 }
gustavatmel 1:9c5af431a1f1 902
gustavatmel 1:9c5af431a1f1 903 // If fPending bit is set we try to generate an empty packet
gustavatmel 1:9c5af431a1f1 904 // with CONFIRMED flag set. We always set a CONFIRMED flag so
gustavatmel 1:9c5af431a1f1 905 // that we could retry a certain number of times if the uplink
gustavatmel 1:9c5af431a1f1 906 // failed for some reason
gustavatmel 1:9c5af431a1f1 907 if (mcps_indication->fpending_status) {
gustavatmel 1:9c5af431a1f1 908 handle_tx(mcps_indication->port, NULL, 0, MSG_CONFIRMED_FLAG);
gustavatmel 1:9c5af431a1f1 909 }
gustavatmel 1:9c5af431a1f1 910 } else {
gustavatmel 1:9c5af431a1f1 911 // Invalid port, ports 0, 224 and 225-255 are reserved.
gustavatmel 1:9c5af431a1f1 912 }
gustavatmel 1:9c5af431a1f1 913 break;
gustavatmel 1:9c5af431a1f1 914 }
gustavatmel 1:9c5af431a1f1 915 }
gustavatmel 1:9c5af431a1f1 916 }
gustavatmel 1:9c5af431a1f1 917
gustavatmel 1:9c5af431a1f1 918 #if defined(LORAWAN_COMPLIANCE_TEST)
gustavatmel 1:9c5af431a1f1 919 /** Compliance testing function
gustavatmel 1:9c5af431a1f1 920 *
gustavatmel 1:9c5af431a1f1 921 * \param mcps_indication Pointer to the indication structure,
gustavatmel 1:9c5af431a1f1 922 * containing indication attributes.
gustavatmel 1:9c5af431a1f1 923 */
gustavatmel 1:9c5af431a1f1 924 void LoRaWANStack::compliance_test_handler(loramac_mcps_indication_t *mcps_indication)
gustavatmel 1:9c5af431a1f1 925 {
gustavatmel 1:9c5af431a1f1 926 if (_compliance_test.running == false) {
gustavatmel 1:9c5af431a1f1 927 // Check compliance test enable command (i)
gustavatmel 1:9c5af431a1f1 928 if ((mcps_indication->buffer_size == 4) &&
gustavatmel 1:9c5af431a1f1 929 (mcps_indication->buffer[0] == 0x01) &&
gustavatmel 1:9c5af431a1f1 930 (mcps_indication->buffer[1] == 0x01) &&
gustavatmel 1:9c5af431a1f1 931 (mcps_indication->buffer[2] == 0x01) &&
gustavatmel 1:9c5af431a1f1 932 (mcps_indication->buffer[3] == 0x01)) {
gustavatmel 1:9c5af431a1f1 933 _compliance_test.is_tx_confirmed = false;
gustavatmel 1:9c5af431a1f1 934 _compliance_test.app_port = 224;
gustavatmel 1:9c5af431a1f1 935 _compliance_test.app_data_size = 2;
gustavatmel 1:9c5af431a1f1 936 _compliance_test.downlink_counter = 0;
gustavatmel 1:9c5af431a1f1 937 _compliance_test.link_check = false;
gustavatmel 1:9c5af431a1f1 938 _compliance_test.demod_margin = 0;
gustavatmel 1:9c5af431a1f1 939 _compliance_test.nb_gateways = 0;
gustavatmel 1:9c5af431a1f1 940 _compliance_test.running = true;
gustavatmel 1:9c5af431a1f1 941 _compliance_test.state = 1;
gustavatmel 1:9c5af431a1f1 942
gustavatmel 1:9c5af431a1f1 943 loramac_mib_req_confirm_t mib_req;
gustavatmel 1:9c5af431a1f1 944 mib_req.type = MIB_ADR;
gustavatmel 1:9c5af431a1f1 945 mib_req.param.is_adr_enable = true;
gustavatmel 1:9c5af431a1f1 946 mib_set_request(&mib_req);
gustavatmel 1:9c5af431a1f1 947
gustavatmel 1:9c5af431a1f1 948 #if MBED_CONF_LORA_PHY == 0
gustavatmel 1:9c5af431a1f1 949 _loramac.LoRaMacTestSetDutyCycleOn(false);
gustavatmel 1:9c5af431a1f1 950 #endif
gustavatmel 1:9c5af431a1f1 951 //5000ms
gustavatmel 1:9c5af431a1f1 952 _loramac.LoRaMacSetTxTimer(5000);
gustavatmel 1:9c5af431a1f1 953 set_device_state(DEVICE_STATE_COMPLIANCE_TEST);
gustavatmel 1:9c5af431a1f1 954 tr_debug("Compliance test activated.");
gustavatmel 1:9c5af431a1f1 955 }
gustavatmel 1:9c5af431a1f1 956 } else {
gustavatmel 1:9c5af431a1f1 957 _compliance_test.state = mcps_indication->buffer[0];
gustavatmel 1:9c5af431a1f1 958 switch (_compliance_test.state) {
gustavatmel 1:9c5af431a1f1 959 case 0: // Check compliance test disable command (ii)
gustavatmel 1:9c5af431a1f1 960 _compliance_test.is_tx_confirmed = true;
gustavatmel 1:9c5af431a1f1 961 _compliance_test.app_port = MBED_CONF_LORA_APP_PORT;
gustavatmel 1:9c5af431a1f1 962 _compliance_test.app_data_size = LORAWAN_COMPLIANCE_TEST_DATA_SIZE;
gustavatmel 1:9c5af431a1f1 963 _compliance_test.downlink_counter = 0;
gustavatmel 1:9c5af431a1f1 964 _compliance_test.running = false;
gustavatmel 1:9c5af431a1f1 965
gustavatmel 1:9c5af431a1f1 966 loramac_mib_req_confirm_t mib_req;
gustavatmel 1:9c5af431a1f1 967 mib_req.type = MIB_ADR;
gustavatmel 1:9c5af431a1f1 968 mib_req.param.is_adr_enable = MBED_CONF_LORA_ADR_ON;
gustavatmel 1:9c5af431a1f1 969 mib_set_request(&mib_req);
gustavatmel 1:9c5af431a1f1 970 #if MBED_CONF_LORA_PHY == 0
gustavatmel 1:9c5af431a1f1 971 _loramac.LoRaMacTestSetDutyCycleOn(MBED_CONF_LORA_DUTY_CYCLE_ON);
gustavatmel 1:9c5af431a1f1 972 #endif
gustavatmel 1:9c5af431a1f1 973 // Go to idle state after compliance test mode.
gustavatmel 1:9c5af431a1f1 974 tr_debug("Compliance test disabled.");
gustavatmel 1:9c5af431a1f1 975 _loramac.LoRaMacStopTxTimer();
gustavatmel 1:9c5af431a1f1 976
gustavatmel 1:9c5af431a1f1 977 // Clear any compliance test message stuff before going back to normal operation.
gustavatmel 1:9c5af431a1f1 978 memset(&_tx_msg, 0, sizeof(_tx_msg));
gustavatmel 1:9c5af431a1f1 979 set_device_state(DEVICE_STATE_IDLE);
gustavatmel 1:9c5af431a1f1 980 lora_state_machine();
gustavatmel 1:9c5af431a1f1 981 break;
gustavatmel 1:9c5af431a1f1 982 case 1: // (iii, iv)
gustavatmel 1:9c5af431a1f1 983 _compliance_test.app_data_size = 2;
gustavatmel 1:9c5af431a1f1 984 break;
gustavatmel 1:9c5af431a1f1 985 case 2: // Enable confirmed messages (v)
gustavatmel 1:9c5af431a1f1 986 _compliance_test.is_tx_confirmed = true;
gustavatmel 1:9c5af431a1f1 987 _compliance_test.state = 1;
gustavatmel 1:9c5af431a1f1 988 break;
gustavatmel 1:9c5af431a1f1 989 case 3: // Disable confirmed messages (vi)
gustavatmel 1:9c5af431a1f1 990 _compliance_test.is_tx_confirmed = false;
gustavatmel 1:9c5af431a1f1 991 _compliance_test.state = 1;
gustavatmel 1:9c5af431a1f1 992 break;
gustavatmel 1:9c5af431a1f1 993 case 4: // (vii)
gustavatmel 1:9c5af431a1f1 994 _compliance_test.app_data_size = mcps_indication->buffer_size;
gustavatmel 1:9c5af431a1f1 995
gustavatmel 1:9c5af431a1f1 996 _compliance_test.app_data_buffer[0] = 4;
gustavatmel 1:9c5af431a1f1 997 for(uint8_t i = 1; i < MIN(_compliance_test.app_data_size, LORAMAC_PHY_MAXPAYLOAD); ++i) {
gustavatmel 1:9c5af431a1f1 998 _compliance_test.app_data_buffer[i] = mcps_indication->buffer[i] + 1;
gustavatmel 1:9c5af431a1f1 999 }
gustavatmel 1:9c5af431a1f1 1000
gustavatmel 1:9c5af431a1f1 1001 send_compliance_test_frame_to_mac();
gustavatmel 1:9c5af431a1f1 1002 break;
gustavatmel 1:9c5af431a1f1 1003 case 5: // (viii)
gustavatmel 1:9c5af431a1f1 1004 loramac_mlme_req_t mlme_req;
gustavatmel 1:9c5af431a1f1 1005 mlme_req.type = MLME_LINK_CHECK;
gustavatmel 1:9c5af431a1f1 1006 mlme_request_handler(&mlme_req);
gustavatmel 1:9c5af431a1f1 1007 break;
gustavatmel 1:9c5af431a1f1 1008 case 6: // (ix)
gustavatmel 1:9c5af431a1f1 1009 loramac_mlme_req_t mlme_request;
gustavatmel 1:9c5af431a1f1 1010 loramac_mib_req_confirm_t mib_request;
gustavatmel 1:9c5af431a1f1 1011
gustavatmel 1:9c5af431a1f1 1012 // Disable TestMode and revert back to normal operation
gustavatmel 1:9c5af431a1f1 1013 _compliance_test.is_tx_confirmed = true;
gustavatmel 1:9c5af431a1f1 1014 _compliance_test.app_port = MBED_CONF_LORA_APP_PORT;
gustavatmel 1:9c5af431a1f1 1015 _compliance_test.app_data_size = LORAWAN_COMPLIANCE_TEST_DATA_SIZE;
gustavatmel 1:9c5af431a1f1 1016 _compliance_test.downlink_counter = 0;
gustavatmel 1:9c5af431a1f1 1017 _compliance_test.running = false;
gustavatmel 1:9c5af431a1f1 1018
gustavatmel 1:9c5af431a1f1 1019 mib_request.type = MIB_ADR;
gustavatmel 1:9c5af431a1f1 1020 mib_request.param.is_adr_enable = MBED_CONF_LORA_ADR_ON;
gustavatmel 1:9c5af431a1f1 1021 mib_set_request(&mib_request);
gustavatmel 1:9c5af431a1f1 1022 #if MBED_CONF_LORA_PHY == 0
gustavatmel 1:9c5af431a1f1 1023 _loramac.LoRaMacTestSetDutyCycleOn(MBED_CONF_LORA_DUTY_CYCLE_ON);
gustavatmel 1:9c5af431a1f1 1024 #endif
gustavatmel 1:9c5af431a1f1 1025 mlme_request.type = MLME_JOIN;
gustavatmel 1:9c5af431a1f1 1026 mlme_request.req.join.dev_eui = _lw_session.connection.connection_u.otaa.dev_eui;
gustavatmel 1:9c5af431a1f1 1027 mlme_request.req.join.app_eui = _lw_session.connection.connection_u.otaa.app_eui;
gustavatmel 1:9c5af431a1f1 1028 mlme_request.req.join.app_key = _lw_session.connection.connection_u.otaa.app_key;
gustavatmel 1:9c5af431a1f1 1029 mlme_request.req.join.nb_trials = _lw_session.connection.connection_u.otaa.nb_trials;
gustavatmel 1:9c5af431a1f1 1030 mlme_request_handler(&mlme_request);
gustavatmel 1:9c5af431a1f1 1031 break;
gustavatmel 1:9c5af431a1f1 1032 case 7: // (x)
gustavatmel 1:9c5af431a1f1 1033 if (mcps_indication->buffer_size == 3) {
gustavatmel 1:9c5af431a1f1 1034 loramac_mlme_req_t mlme_req;
gustavatmel 1:9c5af431a1f1 1035 mlme_req.type = MLME_TXCW;
gustavatmel 1:9c5af431a1f1 1036 mlme_req.req.cw_tx_mode.timeout = (uint16_t)((mcps_indication->buffer[1] << 8) | mcps_indication->buffer[2]);
gustavatmel 1:9c5af431a1f1 1037 mlme_request_handler(&mlme_req);
gustavatmel 1:9c5af431a1f1 1038 } else if (mcps_indication->buffer_size == 7) {
gustavatmel 1:9c5af431a1f1 1039 loramac_mlme_req_t mlme_req;
gustavatmel 1:9c5af431a1f1 1040 mlme_req.type = MLME_TXCW_1;
gustavatmel 1:9c5af431a1f1 1041 mlme_req.req.cw_tx_mode.timeout = (uint16_t)((mcps_indication->buffer[1] << 8) | mcps_indication->buffer[2]);
gustavatmel 1:9c5af431a1f1 1042 mlme_req.req.cw_tx_mode.frequency = (uint32_t)((mcps_indication->buffer[3] << 16) | (mcps_indication->buffer[4] << 8)
gustavatmel 1:9c5af431a1f1 1043 | mcps_indication->buffer[5]) * 100;
gustavatmel 1:9c5af431a1f1 1044 mlme_req.req.cw_tx_mode.power = mcps_indication->buffer[6];
gustavatmel 1:9c5af431a1f1 1045 mlme_request_handler(&mlme_req);
gustavatmel 1:9c5af431a1f1 1046 }
gustavatmel 1:9c5af431a1f1 1047 _compliance_test.state = 1;
gustavatmel 1:9c5af431a1f1 1048 break;
gustavatmel 1:9c5af431a1f1 1049 }
gustavatmel 1:9c5af431a1f1 1050 }
gustavatmel 1:9c5af431a1f1 1051 }
gustavatmel 1:9c5af431a1f1 1052 #endif
gustavatmel 1:9c5af431a1f1 1053
gustavatmel 1:9c5af431a1f1 1054 lorawan_status_t LoRaWANStack::mib_set_request(loramac_mib_req_confirm_t *mib_set_params)
gustavatmel 1:9c5af431a1f1 1055 {
gustavatmel 1:9c5af431a1f1 1056 if (NULL == mib_set_params) {
gustavatmel 1:9c5af431a1f1 1057 return LORAWAN_STATUS_PARAMETER_INVALID;
gustavatmel 1:9c5af431a1f1 1058 }
gustavatmel 1:9c5af431a1f1 1059 return _loramac.mib_set_request_confirm(mib_set_params);
gustavatmel 1:9c5af431a1f1 1060 }
gustavatmel 1:9c5af431a1f1 1061
gustavatmel 1:9c5af431a1f1 1062 lorawan_status_t LoRaWANStack::mib_get_request(loramac_mib_req_confirm_t *mib_get_params)
gustavatmel 1:9c5af431a1f1 1063 {
gustavatmel 1:9c5af431a1f1 1064 if(NULL == mib_get_params) {
gustavatmel 1:9c5af431a1f1 1065 return LORAWAN_STATUS_PARAMETER_INVALID;
gustavatmel 1:9c5af431a1f1 1066 }
gustavatmel 1:9c5af431a1f1 1067 return _loramac.mib_get_request_confirm(mib_get_params);
gustavatmel 1:9c5af431a1f1 1068 }
gustavatmel 1:9c5af431a1f1 1069
gustavatmel 1:9c5af431a1f1 1070 lorawan_status_t LoRaWANStack::set_link_check_request()
gustavatmel 1:9c5af431a1f1 1071 {
gustavatmel 1:9c5af431a1f1 1072 if (!_callbacks.link_check_resp) {
gustavatmel 1:9c5af431a1f1 1073 tr_error("Must assign a callback function for link check request. ");
gustavatmel 1:9c5af431a1f1 1074 return LORAWAN_STATUS_PARAMETER_INVALID;
gustavatmel 1:9c5af431a1f1 1075 }
gustavatmel 1:9c5af431a1f1 1076
gustavatmel 1:9c5af431a1f1 1077 loramac_mlme_req_t mlme_req;
gustavatmel 1:9c5af431a1f1 1078
gustavatmel 1:9c5af431a1f1 1079 mlme_req.type = MLME_LINK_CHECK;
gustavatmel 1:9c5af431a1f1 1080 return mlme_request_handler(&mlme_req);
gustavatmel 1:9c5af431a1f1 1081 }
gustavatmel 1:9c5af431a1f1 1082
gustavatmel 1:9c5af431a1f1 1083 lorawan_status_t LoRaWANStack::shutdown()
gustavatmel 1:9c5af431a1f1 1084 {
gustavatmel 1:9c5af431a1f1 1085 set_device_state(DEVICE_STATE_SHUTDOWN);
gustavatmel 1:9c5af431a1f1 1086 return lora_state_machine();
gustavatmel 1:9c5af431a1f1 1087 }
gustavatmel 1:9c5af431a1f1 1088
gustavatmel 1:9c5af431a1f1 1089 lorawan_status_t LoRaWANStack::lora_state_machine()
gustavatmel 1:9c5af431a1f1 1090 {
gustavatmel 1:9c5af431a1f1 1091 loramac_mib_req_confirm_t mib_req;
gustavatmel 1:9c5af431a1f1 1092 lorawan_status_t status = LORAWAN_STATUS_DEVICE_OFF;
gustavatmel 1:9c5af431a1f1 1093
gustavatmel 1:9c5af431a1f1 1094 switch (_device_current_state) {
gustavatmel 1:9c5af431a1f1 1095 case DEVICE_STATE_SHUTDOWN:
gustavatmel 1:9c5af431a1f1 1096 /*
gustavatmel 1:9c5af431a1f1 1097 * Remove channels
gustavatmel 1:9c5af431a1f1 1098 * Radio will be put to sleep by the APIs underneath
gustavatmel 1:9c5af431a1f1 1099 */
gustavatmel 1:9c5af431a1f1 1100 drop_channel_list();
gustavatmel 1:9c5af431a1f1 1101
gustavatmel 1:9c5af431a1f1 1102 // Shutdown LoRaMac
gustavatmel 1:9c5af431a1f1 1103 _loramac.disconnect();
gustavatmel 1:9c5af431a1f1 1104
gustavatmel 1:9c5af431a1f1 1105 // Stop sending messages and set joined status to false.
gustavatmel 1:9c5af431a1f1 1106 #if defined(LORAWAN_COMPLIANCE_TEST)
gustavatmel 1:9c5af431a1f1 1107 _loramac.LoRaMacStopTxTimer();
gustavatmel 1:9c5af431a1f1 1108 #endif
gustavatmel 1:9c5af431a1f1 1109 mib_req.type = MIB_NETWORK_JOINED;
gustavatmel 1:9c5af431a1f1 1110 mib_req.param.is_nwk_joined = false;
gustavatmel 1:9c5af431a1f1 1111 mib_set_request(&mib_req);
gustavatmel 1:9c5af431a1f1 1112
gustavatmel 1:9c5af431a1f1 1113 // reset buffers to original state
gustavatmel 1:9c5af431a1f1 1114 memset(_tx_msg.f_buffer, 0, MBED_CONF_LORA_TX_MAX_SIZE);
gustavatmel 1:9c5af431a1f1 1115 _tx_msg.pending_size = 0;
gustavatmel 1:9c5af431a1f1 1116 _tx_msg.f_buffer_size = 0;
gustavatmel 1:9c5af431a1f1 1117 _tx_msg.tx_ongoing = false;
gustavatmel 1:9c5af431a1f1 1118 _rx_msg.msg.mcps_indication.buffer = NULL;
gustavatmel 1:9c5af431a1f1 1119 _rx_msg.receive_ready = false;
gustavatmel 1:9c5af431a1f1 1120 _rx_msg.prev_read_size = 0;
gustavatmel 1:9c5af431a1f1 1121 _rx_msg.msg.mcps_indication.buffer_size = 0;
gustavatmel 1:9c5af431a1f1 1122
gustavatmel 1:9c5af431a1f1 1123 // disable the session
gustavatmel 1:9c5af431a1f1 1124 _lw_session.active = false;
gustavatmel 1:9c5af431a1f1 1125
gustavatmel 1:9c5af431a1f1 1126 tr_debug("LoRaWAN protocol has been shut down.");
gustavatmel 1:9c5af431a1f1 1127 if (_callbacks.events) {
gustavatmel 1:9c5af431a1f1 1128 const int ret = _queue->call(_callbacks.events, DISCONNECTED);
gustavatmel 1:9c5af431a1f1 1129 MBED_ASSERT(ret != 0);
gustavatmel 1:9c5af431a1f1 1130 (void)ret;
gustavatmel 1:9c5af431a1f1 1131 }
gustavatmel 1:9c5af431a1f1 1132 status = LORAWAN_STATUS_DEVICE_OFF;
gustavatmel 1:9c5af431a1f1 1133 break;
gustavatmel 1:9c5af431a1f1 1134 case DEVICE_STATE_NOT_INITIALIZED:
gustavatmel 1:9c5af431a1f1 1135 // Device is disconnected.
gustavatmel 1:9c5af431a1f1 1136 status = LORAWAN_STATUS_DEVICE_OFF;
gustavatmel 1:9c5af431a1f1 1137 break;
gustavatmel 1:9c5af431a1f1 1138 case DEVICE_STATE_INIT:
gustavatmel 1:9c5af431a1f1 1139 status = LORAWAN_STATUS_OK;
gustavatmel 1:9c5af431a1f1 1140 break;
gustavatmel 1:9c5af431a1f1 1141 case DEVICE_STATE_JOINING:
gustavatmel 1:9c5af431a1f1 1142 if (_lw_session.connection.connect_type == LORAWAN_CONNECTION_OTAA) {
gustavatmel 1:9c5af431a1f1 1143 /*
gustavatmel 1:9c5af431a1f1 1144 * OTAA join
gustavatmel 1:9c5af431a1f1 1145 */
gustavatmel 1:9c5af431a1f1 1146 tr_debug("Send Join-request..");
gustavatmel 1:9c5af431a1f1 1147 loramac_mlme_req_t mlme_req;
gustavatmel 1:9c5af431a1f1 1148 mlme_req.type = MLME_JOIN;
gustavatmel 1:9c5af431a1f1 1149
gustavatmel 1:9c5af431a1f1 1150 mlme_req.req.join.dev_eui = _lw_session.connection.connection_u.otaa.dev_eui;
gustavatmel 1:9c5af431a1f1 1151 mlme_req.req.join.app_eui = _lw_session.connection.connection_u.otaa.app_eui;
gustavatmel 1:9c5af431a1f1 1152 mlme_req.req.join.app_key = _lw_session.connection.connection_u.otaa.app_key;
gustavatmel 1:9c5af431a1f1 1153 mlme_req.req.join.nb_trials = _lw_session.connection.connection_u.otaa.nb_trials;
gustavatmel 1:9c5af431a1f1 1154
gustavatmel 1:9c5af431a1f1 1155 // Send join request to server.
gustavatmel 1:9c5af431a1f1 1156 status = mlme_request_handler(&mlme_req);
gustavatmel 1:9c5af431a1f1 1157 if (status != LORAWAN_STATUS_OK) {
gustavatmel 1:9c5af431a1f1 1158 return status;
gustavatmel 1:9c5af431a1f1 1159 }
gustavatmel 1:9c5af431a1f1 1160 // Otherwise request was successful and OTAA connect is in
gustavatmel 1:9c5af431a1f1 1161 //progress
gustavatmel 1:9c5af431a1f1 1162 return LORAWAN_STATUS_CONNECT_IN_PROGRESS;
gustavatmel 1:9c5af431a1f1 1163 } else {
gustavatmel 1:9c5af431a1f1 1164 status = LORAWAN_STATUS_PARAMETER_INVALID;
gustavatmel 1:9c5af431a1f1 1165 }
gustavatmel 1:9c5af431a1f1 1166 break;
gustavatmel 1:9c5af431a1f1 1167 case DEVICE_STATE_JOINED:
gustavatmel 1:9c5af431a1f1 1168 tr_debug("Join OK!");
gustavatmel 1:9c5af431a1f1 1169 // Session is now active
gustavatmel 1:9c5af431a1f1 1170 _lw_session.active = true;
gustavatmel 1:9c5af431a1f1 1171 // Tell the application that we are connected
gustavatmel 1:9c5af431a1f1 1172 if (_callbacks.events) {
gustavatmel 1:9c5af431a1f1 1173 const int ret = _queue->call(_callbacks.events, CONNECTED);
gustavatmel 1:9c5af431a1f1 1174 MBED_ASSERT(ret != 0);
gustavatmel 1:9c5af431a1f1 1175 (void)ret;
gustavatmel 1:9c5af431a1f1 1176 }
gustavatmel 1:9c5af431a1f1 1177 status = LORAWAN_STATUS_OK;
gustavatmel 1:9c5af431a1f1 1178 break;
gustavatmel 1:9c5af431a1f1 1179 case DEVICE_STATE_ABP_CONNECTING:
gustavatmel 1:9c5af431a1f1 1180 /*
gustavatmel 1:9c5af431a1f1 1181 * ABP connection
gustavatmel 1:9c5af431a1f1 1182 */
gustavatmel 1:9c5af431a1f1 1183 mib_req.type = MIB_NET_ID;
gustavatmel 1:9c5af431a1f1 1184 mib_req.param.net_id = _lw_session.connection.connection_u.abp.nwk_id;
gustavatmel 1:9c5af431a1f1 1185 mib_set_request(&mib_req);
gustavatmel 1:9c5af431a1f1 1186
gustavatmel 1:9c5af431a1f1 1187 mib_req.type = MIB_DEV_ADDR;
gustavatmel 1:9c5af431a1f1 1188 mib_req.param.dev_addr = _lw_session.connection.connection_u.abp.dev_addr;
gustavatmel 1:9c5af431a1f1 1189 mib_set_request(&mib_req);
gustavatmel 1:9c5af431a1f1 1190
gustavatmel 1:9c5af431a1f1 1191 mib_req.type = MIB_NWK_SKEY;
gustavatmel 1:9c5af431a1f1 1192 mib_req.param.nwk_skey = _lw_session.connection.connection_u.abp.nwk_skey;
gustavatmel 1:9c5af431a1f1 1193 mib_set_request(&mib_req);
gustavatmel 1:9c5af431a1f1 1194
gustavatmel 1:9c5af431a1f1 1195 mib_req.type = MIB_APP_SKEY;
gustavatmel 1:9c5af431a1f1 1196 mib_req.param.app_skey = _lw_session.connection.connection_u.abp.app_skey;
gustavatmel 1:9c5af431a1f1 1197 mib_set_request(&mib_req);
gustavatmel 1:9c5af431a1f1 1198
gustavatmel 1:9c5af431a1f1 1199 mib_req.type = MIB_NETWORK_JOINED;
gustavatmel 1:9c5af431a1f1 1200 mib_req.param.is_nwk_joined = true;
gustavatmel 1:9c5af431a1f1 1201 mib_set_request(&mib_req);
gustavatmel 1:9c5af431a1f1 1202 tr_debug("ABP Connection OK!");
gustavatmel 1:9c5af431a1f1 1203 // tell the application we are okay
gustavatmel 1:9c5af431a1f1 1204 // if users provide wrong keys, it's their responsibility
gustavatmel 1:9c5af431a1f1 1205 // there is no way to test ABP authentication success
gustavatmel 1:9c5af431a1f1 1206 status = LORAWAN_STATUS_OK;
gustavatmel 1:9c5af431a1f1 1207 // Session is now active
gustavatmel 1:9c5af431a1f1 1208 _lw_session.active = true;
gustavatmel 1:9c5af431a1f1 1209 if (_callbacks.events) {
gustavatmel 1:9c5af431a1f1 1210 const int ret = _queue->call(_callbacks.events, CONNECTED);
gustavatmel 1:9c5af431a1f1 1211 MBED_ASSERT(ret != 0);
gustavatmel 1:9c5af431a1f1 1212 (void)ret;
gustavatmel 1:9c5af431a1f1 1213 }
gustavatmel 1:9c5af431a1f1 1214 break;
gustavatmel 1:9c5af431a1f1 1215 case DEVICE_STATE_SEND:
gustavatmel 1:9c5af431a1f1 1216 // If a transmission is ongoing, don't interrupt
gustavatmel 1:9c5af431a1f1 1217 if (_tx_msg.tx_ongoing) {
gustavatmel 1:9c5af431a1f1 1218 status = LORAWAN_STATUS_OK;
gustavatmel 1:9c5af431a1f1 1219 } else {
gustavatmel 1:9c5af431a1f1 1220 _tx_msg.tx_ongoing = true;
gustavatmel 1:9c5af431a1f1 1221 status = send_frame_to_mac();
gustavatmel 1:9c5af431a1f1 1222
gustavatmel 1:9c5af431a1f1 1223 switch (status) {
gustavatmel 1:9c5af431a1f1 1224 case LORAWAN_STATUS_OK:
gustavatmel 1:9c5af431a1f1 1225 tr_debug("Frame scheduled to TX..");
gustavatmel 1:9c5af431a1f1 1226 break;
gustavatmel 1:9c5af431a1f1 1227 case LORAWAN_STATUS_CRYPTO_FAIL:
gustavatmel 1:9c5af431a1f1 1228 tr_error("Crypto failed. Clearing TX buffers");
gustavatmel 1:9c5af431a1f1 1229 if (_callbacks.events) {
gustavatmel 1:9c5af431a1f1 1230 const int ret = _queue->call(_callbacks.events, TX_CRYPTO_ERROR);
gustavatmel 1:9c5af431a1f1 1231 MBED_ASSERT(ret != 0);
gustavatmel 1:9c5af431a1f1 1232 (void)ret;
gustavatmel 1:9c5af431a1f1 1233 }
gustavatmel 1:9c5af431a1f1 1234 break;
gustavatmel 1:9c5af431a1f1 1235 default:
gustavatmel 1:9c5af431a1f1 1236 tr_error("Failure to schedule TX!");
gustavatmel 1:9c5af431a1f1 1237 if (_callbacks.events) {
gustavatmel 1:9c5af431a1f1 1238 const int ret = _queue->call(_callbacks.events, TX_SCHEDULING_ERROR);
gustavatmel 1:9c5af431a1f1 1239 MBED_ASSERT(ret != 0);
gustavatmel 1:9c5af431a1f1 1240 (void)ret;
gustavatmel 1:9c5af431a1f1 1241 }
gustavatmel 1:9c5af431a1f1 1242 break;
gustavatmel 1:9c5af431a1f1 1243 }
gustavatmel 1:9c5af431a1f1 1244 }
gustavatmel 1:9c5af431a1f1 1245 // otherwise all done, put device in idle state
gustavatmel 1:9c5af431a1f1 1246 set_device_state(DEVICE_STATE_IDLE);
gustavatmel 1:9c5af431a1f1 1247 break;
gustavatmel 1:9c5af431a1f1 1248 case DEVICE_STATE_IDLE:
gustavatmel 1:9c5af431a1f1 1249 //Do nothing
gustavatmel 1:9c5af431a1f1 1250 status = LORAWAN_STATUS_IDLE;
gustavatmel 1:9c5af431a1f1 1251 break;
gustavatmel 1:9c5af431a1f1 1252 #if defined(LORAWAN_COMPLIANCE_TEST)
gustavatmel 1:9c5af431a1f1 1253 case DEVICE_STATE_COMPLIANCE_TEST:
gustavatmel 1:9c5af431a1f1 1254 //Device is in compliance test mode
gustavatmel 1:9c5af431a1f1 1255 tr_debug("Device is in compliance test mode.");
gustavatmel 1:9c5af431a1f1 1256
gustavatmel 1:9c5af431a1f1 1257 //5000ms
gustavatmel 1:9c5af431a1f1 1258 _loramac.LoRaMacSetTxTimer(5000);
gustavatmel 1:9c5af431a1f1 1259 if (_compliance_test.running == true) {
gustavatmel 1:9c5af431a1f1 1260 send_compliance_test_frame_to_mac();
gustavatmel 1:9c5af431a1f1 1261 }
gustavatmel 1:9c5af431a1f1 1262 status = LORAWAN_STATUS_COMPLIANCE_TEST_ON;
gustavatmel 1:9c5af431a1f1 1263 break;
gustavatmel 1:9c5af431a1f1 1264 #endif
gustavatmel 1:9c5af431a1f1 1265 default:
gustavatmel 1:9c5af431a1f1 1266 status = LORAWAN_STATUS_SERVICE_UNKNOWN;
gustavatmel 1:9c5af431a1f1 1267 break;
gustavatmel 1:9c5af431a1f1 1268 }
gustavatmel 1:9c5af431a1f1 1269
gustavatmel 1:9c5af431a1f1 1270 return status;
gustavatmel 1:9c5af431a1f1 1271 }
gustavatmel 1:9c5af431a1f1 1272
gustavatmel 1:9c5af431a1f1 1273 #if defined(LORAWAN_COMPLIANCE_TEST)
gustavatmel 1:9c5af431a1f1 1274 /**
gustavatmel 1:9c5af431a1f1 1275 *
gustavatmel 1:9c5af431a1f1 1276 * Prepares the upload message to reserved ports
gustavatmel 1:9c5af431a1f1 1277 *
gustavatmel 1:9c5af431a1f1 1278 * \param port Application port
gustavatmel 1:9c5af431a1f1 1279 */
gustavatmel 1:9c5af431a1f1 1280 void LoRaWANStack::prepare_special_tx_frame(uint8_t port)
gustavatmel 1:9c5af431a1f1 1281 {
gustavatmel 1:9c5af431a1f1 1282 if (port == 224) {
gustavatmel 1:9c5af431a1f1 1283 // Clear any normal message stuff before compliance test.
gustavatmel 1:9c5af431a1f1 1284 memset(&_tx_msg, 0, sizeof(_tx_msg));
gustavatmel 1:9c5af431a1f1 1285
gustavatmel 1:9c5af431a1f1 1286 if (_compliance_test.link_check == true) {
gustavatmel 1:9c5af431a1f1 1287 _compliance_test.link_check = false;
gustavatmel 1:9c5af431a1f1 1288 _compliance_test.state = 1;
gustavatmel 1:9c5af431a1f1 1289 _tx_msg.f_buffer_size = 3;
gustavatmel 1:9c5af431a1f1 1290 _tx_msg.f_buffer[0] = 5;
gustavatmel 1:9c5af431a1f1 1291 _tx_msg.f_buffer[1] = _compliance_test.demod_margin;
gustavatmel 1:9c5af431a1f1 1292 _tx_msg.f_buffer[2] = _compliance_test.nb_gateways;
gustavatmel 1:9c5af431a1f1 1293 } else {
gustavatmel 1:9c5af431a1f1 1294 switch (_compliance_test.state) {
gustavatmel 1:9c5af431a1f1 1295 case 4:
gustavatmel 1:9c5af431a1f1 1296 _compliance_test.state = 1;
gustavatmel 1:9c5af431a1f1 1297 _tx_msg.f_buffer_size = _compliance_test.app_data_size;
gustavatmel 1:9c5af431a1f1 1298
gustavatmel 1:9c5af431a1f1 1299 _tx_msg.f_buffer[0] = _compliance_test.app_data_buffer[0];
gustavatmel 1:9c5af431a1f1 1300 for(uint8_t i = 1; i < MIN(_compliance_test.app_data_size, MBED_CONF_LORA_TX_MAX_SIZE); ++i) {
gustavatmel 1:9c5af431a1f1 1301 _tx_msg.f_buffer[i] = _compliance_test.app_data_buffer[i];
gustavatmel 1:9c5af431a1f1 1302 }
gustavatmel 1:9c5af431a1f1 1303 break;
gustavatmel 1:9c5af431a1f1 1304 case 1:
gustavatmel 1:9c5af431a1f1 1305 _tx_msg.f_buffer_size = 2;
gustavatmel 1:9c5af431a1f1 1306 _tx_msg.f_buffer[0] = _compliance_test.downlink_counter >> 8;
gustavatmel 1:9c5af431a1f1 1307 _tx_msg.f_buffer[1] = _compliance_test.downlink_counter;
gustavatmel 1:9c5af431a1f1 1308 break;
gustavatmel 1:9c5af431a1f1 1309 }
gustavatmel 1:9c5af431a1f1 1310 }
gustavatmel 1:9c5af431a1f1 1311 }
gustavatmel 1:9c5af431a1f1 1312 }
gustavatmel 1:9c5af431a1f1 1313
gustavatmel 1:9c5af431a1f1 1314 /** Hands over the compliance test frame to MAC layer
gustavatmel 1:9c5af431a1f1 1315 *
gustavatmel 1:9c5af431a1f1 1316 * \return returns the state of the LoRa MAC
gustavatmel 1:9c5af431a1f1 1317 */
gustavatmel 1:9c5af431a1f1 1318 lorawan_status_t LoRaWANStack::send_compliance_test_frame_to_mac()
gustavatmel 1:9c5af431a1f1 1319 {
gustavatmel 1:9c5af431a1f1 1320 loramac_mcps_req_t mcps_req;
gustavatmel 1:9c5af431a1f1 1321
gustavatmel 1:9c5af431a1f1 1322 prepare_special_tx_frame(_compliance_test.app_port);
gustavatmel 1:9c5af431a1f1 1323
gustavatmel 1:9c5af431a1f1 1324 if (!_compliance_test.is_tx_confirmed) {
gustavatmel 1:9c5af431a1f1 1325 mcps_req.type = MCPS_UNCONFIRMED;
gustavatmel 1:9c5af431a1f1 1326 mcps_req.f_buffer = _tx_msg.f_buffer;
gustavatmel 1:9c5af431a1f1 1327 mcps_req.f_buffer_size = _tx_msg.f_buffer_size;
gustavatmel 1:9c5af431a1f1 1328 mcps_req.fport = _compliance_test.app_port;
gustavatmel 1:9c5af431a1f1 1329 mcps_req.nb_trials = 1;
gustavatmel 1:9c5af431a1f1 1330 mcps_req.data_rate = _lora_phy.get_default_tx_datarate();
gustavatmel 1:9c5af431a1f1 1331
gustavatmel 1:9c5af431a1f1 1332 tr_info("Transmit unconfirmed compliance test frame %d bytes.", mcps_req.f_buffer_size);
gustavatmel 1:9c5af431a1f1 1333
gustavatmel 1:9c5af431a1f1 1334 for (uint8_t i = 0; i < mcps_req.f_buffer_size; ++i) {
gustavatmel 1:9c5af431a1f1 1335 tr_info("Byte %d, data is 0x%x", i+1, ((uint8_t*)mcps_req.f_buffer)[i]);
gustavatmel 1:9c5af431a1f1 1336 }
gustavatmel 1:9c5af431a1f1 1337 } else if (_compliance_test.is_tx_confirmed) {
gustavatmel 1:9c5af431a1f1 1338 mcps_req.type = MCPS_CONFIRMED;
gustavatmel 1:9c5af431a1f1 1339 mcps_req.f_buffer = _tx_msg.f_buffer;
gustavatmel 1:9c5af431a1f1 1340 mcps_req.f_buffer_size = _tx_msg.f_buffer_size;
gustavatmel 1:9c5af431a1f1 1341 mcps_req.fport = _compliance_test.app_port;
gustavatmel 1:9c5af431a1f1 1342 mcps_req.nb_trials = _num_retry;
gustavatmel 1:9c5af431a1f1 1343 mcps_req.data_rate = _lora_phy.get_default_tx_datarate();
gustavatmel 1:9c5af431a1f1 1344
gustavatmel 1:9c5af431a1f1 1345 tr_info("Transmit confirmed compliance test frame %d bytes.", mcps_req.f_buffer_size);
gustavatmel 1:9c5af431a1f1 1346
gustavatmel 1:9c5af431a1f1 1347 for (uint8_t i = 0; i < mcps_req.f_buffer_size; ++i) {
gustavatmel 1:9c5af431a1f1 1348 tr_info("Byte %d, data is 0x%x", i+1, ((uint8_t*)mcps_req.f_buffer)[i]);
gustavatmel 1:9c5af431a1f1 1349 }
gustavatmel 1:9c5af431a1f1 1350 } else {
gustavatmel 1:9c5af431a1f1 1351 return LORAWAN_STATUS_SERVICE_UNKNOWN;
gustavatmel 1:9c5af431a1f1 1352 }
gustavatmel 1:9c5af431a1f1 1353
gustavatmel 1:9c5af431a1f1 1354 return mcps_request_handler(&mcps_req);
gustavatmel 1:9c5af431a1f1 1355 }
gustavatmel 1:9c5af431a1f1 1356 #endif
gustavatmel 1:9c5af431a1f1 1357