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