Nicolas Borla
/
BBR_1Ebene
BBR 1 Ebene
mbed-os/features/lorawan/LoRaWANStack.cpp@0:fbdae7e6d805, 2018-05-14 (annotated)
- Committer:
- borlanic
- Date:
- Mon May 14 11:29:06 2018 +0000
- Revision:
- 0:fbdae7e6d805
BBR
Who changed what in which revision?
User | Revision | Line number | New 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 |