takashi kadono / Mbed OS Nucleo_446

Dependencies:   ssd1331

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers LoRaWANStack.cpp Source File

LoRaWANStack.cpp

00001 /**
00002  / _____)             _              | |
00003 ( (____  _____ ____ _| |_ _____  ____| |__
00004  \____ \| ___ |    (_   _) ___ |/ ___)  _ \
00005  _____) ) ____| | | || |_| ____( (___| | | |
00006 (______/|_____)_|_|_| \__)_____)\____)_| |_|
00007     (C)2013 Semtech
00008  ___ _____ _   ___ _  _____ ___  ___  ___ ___
00009 / __|_   _/_\ / __| |/ / __/ _ \| _ \/ __| __|
00010 \__ \ | |/ _ \ (__| ' <| _| (_) |   / (__| _|
00011 |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
00012 embedded.connectivity.solutions===============
00013 
00014 Description: LoRaWAN stack layer that controls both MAC and PHY underneath
00015 
00016 License: Revised BSD License, see LICENSE.TXT file include in the project
00017 
00018 Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE )
00019 
00020 
00021 Copyright (c) 2017, Arm Limited and affiliates.
00022 
00023 SPDX-License-Identifier: BSD-3-Clause
00024 */
00025 
00026 #include <string.h>
00027 #include <stdlib.h>
00028 #include "platform/Callback.h"
00029 #include "events/EventQueue.h"
00030 
00031 #include "LoRaWANStack.h"
00032 
00033 #include "mbed-trace/mbed_trace.h"
00034 #define TRACE_GROUP "LSTK"
00035 
00036 #define INVALID_PORT                0xFF
00037 #define MAX_CONFIRMED_MSG_RETRIES   255
00038 #define COMPLIANCE_TESTING_PORT     224
00039 /**
00040  * Control flags for transient states
00041  */
00042 #define IDLE_FLAG                   0x00000000
00043 #define TX_ONGOING_FLAG             0x00000001
00044 #define MSG_RECVD_FLAG              0x00000002
00045 #define CONNECTED_FLAG              0x00000004
00046 #define USING_OTAA_FLAG             0x00000008
00047 #define TX_DONE_FLAG                0x00000010
00048 #define CONN_IN_PROGRESS_FLAG       0x00000020
00049 
00050 using namespace mbed;
00051 using namespace events;
00052 
00053 /**
00054  * Bit mask for message flags
00055  */
00056 
00057 #define MSG_FLAG_MASK                         0x0F
00058 
00059 /*****************************************************************************
00060  * Constructor                                                               *
00061  ****************************************************************************/
00062 LoRaWANStack::LoRaWANStack()
00063     : _loramac(),
00064       _device_current_state(DEVICE_STATE_NOT_INITIALIZED),
00065       _lw_session(),
00066       _tx_msg(),
00067       _rx_msg(),
00068       _tx_metadata(),
00069       _rx_metadata(),
00070       _num_retry(1),
00071       _ctrl_flags(IDLE_FLAG),
00072       _app_port(INVALID_PORT),
00073       _link_check_requested(false),
00074       _automatic_uplink_ongoing(false),
00075       _ready_for_rx(true),
00076       _queue(NULL)
00077 {
00078     _tx_metadata.stale = true;
00079     _rx_metadata.stale = true;
00080 
00081 #ifdef MBED_CONF_LORA_APP_PORT
00082     if (is_port_valid(MBED_CONF_LORA_APP_PORT)) {
00083         _app_port = MBED_CONF_LORA_APP_PORT;
00084     } else {
00085         tr_error("User defined port in .json is illegal.");
00086     }
00087 #endif
00088 }
00089 
00090 /*****************************************************************************
00091  * Public Methods                                                            *
00092  ****************************************************************************/
00093 void LoRaWANStack::bind_phy_and_radio_driver(LoRaRadio &radio, LoRaPHY &phy)
00094 {
00095     radio_events.tx_done = mbed::callback(this, &LoRaWANStack::tx_interrupt_handler);
00096     radio_events.rx_done = mbed::callback(this, &LoRaWANStack::rx_interrupt_handler);
00097     radio_events.rx_error = mbed::callback(this, &LoRaWANStack::rx_error_interrupt_handler);
00098     radio_events.tx_timeout = mbed::callback(this, &LoRaWANStack::tx_timeout_interrupt_handler);
00099     radio_events.rx_timeout = mbed::callback(this, &LoRaWANStack::rx_timeout_interrupt_handler);
00100 
00101     phy.set_radio_instance(radio);
00102     _loramac.bind_phy(phy);
00103 
00104     radio.lock();
00105     radio.init_radio(&radio_events);
00106     radio.unlock();
00107 }
00108 
00109 lorawan_status_t LoRaWANStack::initialize_mac_layer(EventQueue *queue)
00110 {
00111     if (!queue) {
00112         return LORAWAN_STATUS_PARAMETER_INVALID;
00113     }
00114 
00115     tr_debug("Initializing MAC layer");
00116     _queue = queue;
00117 
00118     return state_controller(DEVICE_STATE_IDLE);
00119 }
00120 
00121 lorawan_status_t LoRaWANStack::set_lora_callbacks(const lorawan_app_callbacks_t *callbacks)
00122 {
00123     if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) {
00124         return LORAWAN_STATUS_NOT_INITIALIZED;
00125     }
00126 
00127     if (!callbacks || !callbacks->events) {
00128         return LORAWAN_STATUS_PARAMETER_INVALID;
00129     }
00130 
00131     _callbacks.events = callbacks->events;
00132 
00133     if (callbacks->link_check_resp) {
00134         _callbacks.link_check_resp = callbacks->link_check_resp;
00135     }
00136 
00137     if (callbacks->battery_level) {
00138         _callbacks.battery_level = callbacks->battery_level;
00139         _loramac.set_batterylevel_callback(callbacks->battery_level);
00140     }
00141 
00142     return LORAWAN_STATUS_OK;
00143 }
00144 
00145 lorawan_status_t LoRaWANStack::connect()
00146 {
00147     if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) {
00148         return LORAWAN_STATUS_NOT_INITIALIZED;
00149     }
00150 
00151     if (_ctrl_flags & CONN_IN_PROGRESS_FLAG) {
00152         return LORAWAN_STATUS_BUSY;
00153     }
00154 
00155     if (_ctrl_flags & CONNECTED_FLAG) {
00156         return LORAWAN_STATUS_ALREADY_CONNECTED;
00157     }
00158 
00159     lorawan_status_t status = _loramac.prepare_join(NULL, MBED_CONF_LORA_OVER_THE_AIR_ACTIVATION);
00160 
00161     if (LORAWAN_STATUS_OK != status) {
00162         return status;
00163     }
00164 
00165     return handle_connect(MBED_CONF_LORA_OVER_THE_AIR_ACTIVATION);
00166 }
00167 
00168 lorawan_status_t LoRaWANStack::connect(const lorawan_connect_t &connect)
00169 {
00170     if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) {
00171         return LORAWAN_STATUS_NOT_INITIALIZED;
00172     }
00173 
00174     if (_ctrl_flags & CONN_IN_PROGRESS_FLAG) {
00175         return LORAWAN_STATUS_BUSY;
00176     }
00177 
00178     if (_ctrl_flags & CONNECTED_FLAG) {
00179         return LORAWAN_STATUS_ALREADY_CONNECTED;
00180     }
00181 
00182     if (!(connect.connect_type == LORAWAN_CONNECTION_OTAA)
00183             && !(connect.connect_type == LORAWAN_CONNECTION_ABP)) {
00184         return LORAWAN_STATUS_PARAMETER_INVALID;
00185     }
00186 
00187     bool is_otaa = (connect.connect_type == LORAWAN_CONNECTION_OTAA);
00188 
00189     lorawan_status_t status = _loramac.prepare_join(&connect, is_otaa);
00190 
00191     if (LORAWAN_STATUS_OK != status) {
00192         return status;
00193     }
00194 
00195     return handle_connect(is_otaa);
00196 }
00197 
00198 lorawan_status_t LoRaWANStack::add_channels(const lorawan_channelplan_t &channel_plan)
00199 {
00200     if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) {
00201         return LORAWAN_STATUS_NOT_INITIALIZED;
00202     }
00203 
00204     return _loramac.add_channel_plan(channel_plan);
00205 }
00206 
00207 lorawan_status_t LoRaWANStack::remove_a_channel(uint8_t channel_id)
00208 {
00209     if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) {
00210         return LORAWAN_STATUS_NOT_INITIALIZED;
00211     }
00212 
00213     return _loramac.remove_single_channel(channel_id);
00214 }
00215 
00216 lorawan_status_t LoRaWANStack::drop_channel_list()
00217 {
00218     if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) {
00219         return LORAWAN_STATUS_NOT_INITIALIZED;
00220     }
00221 
00222     return _loramac.remove_channel_plan();
00223 }
00224 
00225 lorawan_status_t LoRaWANStack::get_enabled_channels(lorawan_channelplan_t &channel_plan)
00226 {
00227     if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) {
00228         return LORAWAN_STATUS_NOT_INITIALIZED;
00229     }
00230 
00231     return _loramac.get_channel_plan(channel_plan);
00232 }
00233 
00234 lorawan_status_t LoRaWANStack::set_confirmed_msg_retry(uint8_t count)
00235 {
00236     if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) {
00237         return LORAWAN_STATUS_NOT_INITIALIZED;
00238     }
00239 
00240     if (count >= MAX_CONFIRMED_MSG_RETRIES) {
00241         return LORAWAN_STATUS_PARAMETER_INVALID;
00242     }
00243 
00244     _num_retry = count;
00245 
00246     return LORAWAN_STATUS_OK;
00247 }
00248 
00249 lorawan_status_t LoRaWANStack::set_channel_data_rate(uint8_t data_rate)
00250 {
00251     if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) {
00252         return LORAWAN_STATUS_NOT_INITIALIZED;
00253     }
00254 
00255     return _loramac.set_channel_data_rate(data_rate);
00256 }
00257 
00258 
00259 lorawan_status_t LoRaWANStack::enable_adaptive_datarate(bool adr_enabled)
00260 {
00261     if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) {
00262         return LORAWAN_STATUS_NOT_INITIALIZED;
00263     }
00264 
00265     _loramac.enable_adaptive_datarate(adr_enabled);
00266     return LORAWAN_STATUS_OK;
00267 }
00268 
00269 lorawan_status_t LoRaWANStack::stop_sending(void)
00270 {
00271     if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) {
00272         return LORAWAN_STATUS_NOT_INITIALIZED;
00273     }
00274 
00275     if (_loramac.clear_tx_pipe() == LORAWAN_STATUS_OK) {
00276         _ctrl_flags &= ~TX_DONE_FLAG;
00277         _ctrl_flags &= ~TX_ONGOING_FLAG;
00278         _loramac.set_tx_ongoing(false);
00279         _device_current_state = DEVICE_STATE_IDLE;
00280         return LORAWAN_STATUS_OK;
00281     }
00282 
00283     return LORAWAN_STATUS_BUSY;
00284 }
00285 
00286 int16_t LoRaWANStack::handle_tx(const uint8_t port, const uint8_t *data,
00287                                 uint16_t length, uint8_t flags,
00288                                 bool null_allowed, bool allow_port_0)
00289 {
00290     if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) {
00291         return LORAWAN_STATUS_NOT_INITIALIZED;
00292     }
00293 
00294     if (!null_allowed && !data) {
00295         return LORAWAN_STATUS_PARAMETER_INVALID;
00296     }
00297     // add a link check request with normal data, until the application
00298     // explicitly removes it.
00299     if (_link_check_requested) {
00300         _loramac.setup_link_check_request();
00301     }
00302 
00303     if (!_lw_session.active) {
00304         return LORAWAN_STATUS_NO_ACTIVE_SESSIONS;
00305     }
00306 
00307     if (_loramac.tx_ongoing()) {
00308         return LORAWAN_STATUS_WOULD_BLOCK;
00309     }
00310 
00311     lorawan_status_t status;
00312 
00313     if (_loramac.nwk_joined() == false) {
00314         return LORAWAN_STATUS_NO_NETWORK_JOINED;
00315     }
00316 
00317     status = set_application_port(port, allow_port_0);
00318 
00319     if (status != LORAWAN_STATUS_OK) {
00320         tr_error("Illegal application port definition.");
00321         return status;
00322     }
00323 
00324     // All the flags are mutually exclusive. In addition to that MSG_MULTICAST_FLAG cannot be
00325     // used for uplink.
00326     switch (flags & MSG_FLAG_MASK) {
00327         case MSG_UNCONFIRMED_FLAG:
00328         case MSG_CONFIRMED_FLAG:
00329         case MSG_PROPRIETARY_FLAG:
00330             break;
00331 
00332         default:
00333             tr_error("Invalid send flags");
00334             return LORAWAN_STATUS_PARAMETER_INVALID;
00335     }
00336 
00337     int16_t len = _loramac.prepare_ongoing_tx(port, data, length, flags, _num_retry);
00338 
00339     status = state_controller(DEVICE_STATE_SCHEDULING);
00340 
00341     // send user the length of data which is scheduled now.
00342     // user should take care of the pending data.
00343     return (status == LORAWAN_STATUS_OK) ? len : (int16_t) status;
00344 }
00345 
00346 int16_t LoRaWANStack::handle_rx(uint8_t *data, uint16_t length, uint8_t &port, int &flags, bool validate_params)
00347 {
00348     if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) {
00349         return LORAWAN_STATUS_NOT_INITIALIZED;
00350     }
00351 
00352     if (!_lw_session.active) {
00353         return LORAWAN_STATUS_NO_ACTIVE_SESSIONS;
00354     }
00355 
00356     // No messages to read.
00357     if (!_rx_msg.receive_ready) {
00358         return LORAWAN_STATUS_WOULD_BLOCK;
00359     }
00360 
00361     if (data == NULL || length == 0) {
00362         return LORAWAN_STATUS_PARAMETER_INVALID;
00363     }
00364 
00365     int received_flags = convert_to_msg_flag(_rx_msg.msg.mcps_indication.type);
00366     if (validate_params) {
00367         // Check received message port and flags match with the ones requested by user
00368         received_flags &= MSG_FLAG_MASK;
00369 
00370         if (_rx_msg.msg.mcps_indication.port != port || !(flags & received_flags)) {
00371             return LORAWAN_STATUS_WOULD_BLOCK;
00372         }
00373     }
00374 
00375     // Report values back to user
00376     port = _rx_msg.msg.mcps_indication.port;
00377     flags = received_flags;
00378 
00379     const uint8_t *base_ptr = _rx_msg.msg.mcps_indication.buffer;
00380     uint16_t base_size = _rx_msg.msg.mcps_indication.buffer_size;
00381     bool read_complete = false;
00382 
00383     if (_rx_msg.pending_size == 0) {
00384         _rx_msg.pending_size = _rx_msg.msg.mcps_indication.buffer_size;
00385         _rx_msg.prev_read_size = 0;
00386     }
00387 
00388     // check the length of received message whether we can fit into user
00389     // buffer completely or not
00390     if (_rx_msg.prev_read_size == 0 && _rx_msg.msg.mcps_indication.buffer_size <= length) {
00391         memcpy(data, base_ptr, base_size);
00392         read_complete = true;
00393     } else if (_rx_msg.pending_size > length) {
00394         _rx_msg.pending_size = _rx_msg.pending_size - length;
00395         base_size = length;
00396         memcpy(data, base_ptr + _rx_msg.prev_read_size, base_size);
00397         _rx_msg.prev_read_size += base_size;
00398     } else {
00399         base_size = _rx_msg.pending_size;
00400         memcpy(data, base_ptr + _rx_msg.prev_read_size, base_size);
00401         read_complete = true;
00402     }
00403 
00404     if (read_complete) {
00405         _rx_msg.msg.mcps_indication.buffer = NULL;
00406         _rx_msg.msg.mcps_indication.buffer_size = 0;
00407         _rx_msg.pending_size = 0;
00408         _rx_msg.receive_ready = false;
00409     }
00410 
00411     return base_size;
00412 }
00413 
00414 lorawan_status_t LoRaWANStack::set_link_check_request()
00415 {
00416     if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) {
00417         return LORAWAN_STATUS_NOT_INITIALIZED;
00418     }
00419 
00420     if (!_callbacks.link_check_resp) {
00421         tr_error("Must assign a callback function for link check request. ");
00422         return LORAWAN_STATUS_PARAMETER_INVALID;
00423     }
00424 
00425     _link_check_requested = true;
00426     return LORAWAN_STATUS_OK;
00427 }
00428 
00429 void LoRaWANStack::remove_link_check_request()
00430 {
00431     _link_check_requested = false;
00432 }
00433 
00434 lorawan_status_t LoRaWANStack::shutdown()
00435 {
00436     if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) {
00437         return LORAWAN_STATUS_NOT_INITIALIZED;
00438     }
00439 
00440     return state_controller(DEVICE_STATE_SHUTDOWN);
00441 }
00442 
00443 lorawan_status_t LoRaWANStack::set_device_class(const device_class_t &device_class)
00444 {
00445     if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) {
00446         return LORAWAN_STATUS_NOT_INITIALIZED;
00447     }
00448 
00449     if (device_class == CLASS_B) {
00450         return LORAWAN_STATUS_UNSUPPORTED;
00451     }
00452     _loramac.set_device_class(device_class, mbed::callback(this, &LoRaWANStack::handle_ack_expiry_for_class_c));
00453     return LORAWAN_STATUS_OK;
00454 }
00455 
00456 lorawan_status_t  LoRaWANStack::acquire_tx_metadata(lorawan_tx_metadata &tx_metadata)
00457 {
00458     if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) {
00459         return LORAWAN_STATUS_NOT_INITIALIZED;
00460     }
00461 
00462     if (!_tx_metadata.stale) {
00463         tx_metadata = _tx_metadata;
00464         _tx_metadata.stale = true;
00465         return LORAWAN_STATUS_OK;
00466     }
00467 
00468     return LORAWAN_STATUS_METADATA_NOT_AVAILABLE;
00469 }
00470 
00471 lorawan_status_t LoRaWANStack::acquire_rx_metadata(lorawan_rx_metadata &metadata)
00472 {
00473     if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) {
00474         return LORAWAN_STATUS_NOT_INITIALIZED;
00475     }
00476 
00477     if (!_rx_metadata.stale) {
00478         metadata = _rx_metadata;
00479         _rx_metadata.stale = true;
00480         return LORAWAN_STATUS_OK;
00481     }
00482 
00483     return LORAWAN_STATUS_METADATA_NOT_AVAILABLE;
00484 }
00485 
00486 lorawan_status_t LoRaWANStack::acquire_backoff_metadata(int &backoff)
00487 {
00488     if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) {
00489         return LORAWAN_STATUS_NOT_INITIALIZED;
00490     }
00491 
00492     int id = _loramac.get_backoff_timer_event_id();
00493 
00494     if (_loramac.get_backoff_timer_event_id() > 0) {
00495         backoff = _queue->time_left(id);
00496         return LORAWAN_STATUS_OK;
00497     }
00498 
00499     backoff = -1;
00500     return LORAWAN_STATUS_METADATA_NOT_AVAILABLE;
00501 }
00502 
00503 /*****************************************************************************
00504  * Interrupt handlers                                                        *
00505  ****************************************************************************/
00506 void LoRaWANStack::tx_interrupt_handler(void)
00507 {
00508     _tx_timestamp = _loramac.get_current_time();
00509     const int ret = _queue->call(this, &LoRaWANStack::process_transmission);
00510     MBED_ASSERT(ret != 0);
00511     (void)ret;
00512 }
00513 
00514 void LoRaWANStack::rx_interrupt_handler(const uint8_t *payload, uint16_t size,
00515                                         int16_t rssi, int8_t snr)
00516 {
00517     if (!_ready_for_rx || size > sizeof _rx_payload) {
00518         return;
00519     }
00520 
00521     _ready_for_rx = false;
00522     memcpy(_rx_payload, payload, size);
00523 
00524     const uint8_t *ptr = _rx_payload;
00525     const int ret = _queue->call(this, &LoRaWANStack::process_reception,
00526                                  ptr, size, rssi, snr);
00527     MBED_ASSERT(ret != 0);
00528     (void)ret;
00529 }
00530 
00531 void LoRaWANStack::rx_error_interrupt_handler(void)
00532 {
00533     const int ret = _queue->call(this, &LoRaWANStack::process_reception_timeout,
00534                                  false);
00535     MBED_ASSERT(ret != 0);
00536     (void)ret;
00537 }
00538 
00539 void LoRaWANStack::tx_timeout_interrupt_handler(void)
00540 {
00541     const int ret = _queue->call(this, &LoRaWANStack::process_transmission_timeout);
00542     MBED_ASSERT(ret != 0);
00543     (void)ret;
00544 }
00545 
00546 void LoRaWANStack::rx_timeout_interrupt_handler(void)
00547 {
00548     const int ret = _queue->call(this, &LoRaWANStack::process_reception_timeout,
00549                                  true);
00550     MBED_ASSERT(ret != 0);
00551     (void)ret;
00552 }
00553 
00554 /*****************************************************************************
00555  * Processors for deferred interrupts                                        *
00556  ****************************************************************************/
00557 void LoRaWANStack::process_transmission_timeout()
00558 {
00559     // this is a fatal error and should not happen
00560     tr_debug("TX Timeout");
00561     _loramac.on_radio_tx_timeout();
00562     _ctrl_flags &= ~TX_ONGOING_FLAG;
00563     _ctrl_flags &= ~TX_DONE_FLAG;
00564     if (_device_current_state == DEVICE_STATE_JOINING) {
00565         mlme_confirm_handler();
00566     } else {
00567         state_controller(DEVICE_STATE_STATUS_CHECK);
00568     }
00569 
00570     state_machine_run_to_completion();
00571 }
00572 
00573 void LoRaWANStack::process_transmission(void)
00574 {
00575     tr_debug("Transmission completed");
00576     _loramac.on_radio_tx_done(_tx_timestamp);
00577 
00578     make_tx_metadata_available();
00579 
00580     if (_device_current_state == DEVICE_STATE_JOINING) {
00581         _device_current_state = DEVICE_STATE_AWAITING_JOIN_ACCEPT;
00582     }
00583 
00584     if (_device_current_state == DEVICE_STATE_SENDING) {
00585         if (_loramac.get_mcps_confirmation()->req_type == MCPS_CONFIRMED ) {
00586             _ctrl_flags |= TX_ONGOING_FLAG;
00587             _ctrl_flags &= ~TX_DONE_FLAG;
00588             tr_debug("Awaiting ACK");
00589             _device_current_state = DEVICE_STATE_AWAITING_ACK;
00590         } else if (_loramac.get_device_class() == CLASS_A) {
00591             // Class A unconfirmed message sent, TX_DONE event will be sent to
00592             // application when RX2 windows is elapsed, i.e., in process_reception_timeout()
00593             _ctrl_flags &= ~TX_ONGOING_FLAG;
00594             _ctrl_flags |= TX_DONE_FLAG;
00595         } else if (_loramac.get_device_class() == CLASS_C) {
00596             // In Class C, reception timeout never happens, so we handle the state
00597              // progression for TX_DONE in UNCONFIRMED case here
00598             _loramac.post_process_mcps_req();
00599             state_controller(DEVICE_STATE_STATUS_CHECK);
00600             state_machine_run_to_completion();
00601         }
00602     }
00603 }
00604 
00605 void LoRaWANStack::handle_ack_expiry_for_class_c(void)
00606 {
00607     _ctrl_flags &= ~TX_DONE_FLAG;
00608     _ctrl_flags |= TX_ONGOING_FLAG;
00609     tr_error("Retries exhausted for Class C device");
00610     state_controller(DEVICE_STATE_STATUS_CHECK);
00611 }
00612 
00613 void LoRaWANStack::handle_scheduling_failure(void)
00614 {
00615     tr_error("Failed to schedule transmission");
00616     state_controller(DEVICE_STATE_STATUS_CHECK);
00617     state_machine_run_to_completion();
00618 }
00619 
00620 void LoRaWANStack::process_reception(const uint8_t *const payload, uint16_t size,
00621                                      int16_t rssi, int8_t snr)
00622 {
00623     _device_current_state = DEVICE_STATE_RECEIVING;
00624     _ctrl_flags &= ~MSG_RECVD_FLAG;
00625 
00626     _loramac.on_radio_rx_done(payload, size, rssi, snr);
00627 
00628     make_rx_metadata_available();
00629 
00630     if (_loramac.get_mlme_confirmation()->pending) {
00631         _loramac.post_process_mlme_request();
00632         mlme_confirm_handler();
00633 
00634         if (_loramac.get_mlme_confirmation()->req_type == MLME_JOIN ) {
00635             _ready_for_rx = true;
00636             return;
00637         }
00638     }
00639 
00640     if (!_loramac.nwk_joined()) {
00641         _ready_for_rx = true;
00642         return;
00643     }
00644 
00645     // if the outgoing message was of CONFIRMED type
00646     if (_loramac.get_mcps_confirmation()->req_type == MCPS_CONFIRMED ) {
00647         // if ack was not received, we will try retransmission after
00648         // ACK_TIMEOUT. handle_data_frame() already disables ACK_TIMEOUT timer
00649         // if ack was received. Otherwise, following method will be called in
00650         // LoRaMac.cpp, on_ack_timeout_timer_event().
00651         if (_loramac.get_mcps_indication()->is_ack_recvd) {
00652             tr_debug("Ack=OK, NbTrials=%d",
00653                      _loramac.get_mcps_confirmation()->nb_retries);
00654             _loramac.post_process_mcps_req();
00655             _ctrl_flags |= TX_DONE_FLAG;
00656             _ctrl_flags &= ~TX_ONGOING_FLAG;
00657             state_controller(DEVICE_STATE_STATUS_CHECK);
00658         } else {
00659             if (!_loramac.continue_sending_process() &&
00660                 _loramac.get_current_slot() != RX_SLOT_WIN_1 ) {
00661                 tr_error("Retries exhausted for Class A device");
00662                 _ctrl_flags &= ~TX_DONE_FLAG;
00663                 _ctrl_flags |= TX_ONGOING_FLAG;
00664                 state_controller(DEVICE_STATE_STATUS_CHECK);
00665             }
00666         }
00667     } else if (_loramac.get_device_class() == CLASS_A) {
00668         // handle UNCONFIRMED case here, RX slots were turned off due to
00669         // valid packet reception. For Class C, an outgoing UNCONFIRMED message
00670         // gets its handling in process_transmission.
00671         _loramac.post_process_mcps_req();
00672         _ctrl_flags |= TX_DONE_FLAG;
00673         state_controller(DEVICE_STATE_STATUS_CHECK);
00674     }
00675 
00676     // handle any pending MCPS indication
00677     if (_loramac.get_mcps_indication()->pending) {
00678         _loramac.post_process_mcps_ind();
00679         _ctrl_flags |= MSG_RECVD_FLAG;
00680         state_controller(DEVICE_STATE_STATUS_CHECK);
00681     }
00682 
00683     // change the state only if a TX cycle completes for Class A
00684     // For class C it's not needed as it will already be in receiving
00685     // state, no matter if the TX cycle completed or not.
00686     if (!(_ctrl_flags & TX_ONGOING_FLAG)) {
00687         // we are done here, update the state
00688         state_machine_run_to_completion();
00689     }
00690 
00691     if (_loramac.get_mlme_indication()->pending) {
00692         tr_debug("MLME Indication pending");
00693         _loramac.post_process_mlme_ind();
00694         tr_debug("Immediate Uplink requested");
00695         mlme_indication_handler();
00696     }
00697 
00698     _ready_for_rx = true;
00699 }
00700 
00701 void LoRaWANStack::process_reception_timeout(bool is_timeout)
00702 {
00703     rx_slot_t  slot = _loramac.get_current_slot();
00704 
00705     // when is_timeout == false, a CRC error took place in the received frame
00706     // we treat that erroneous frame as no frame received at all, hence handle
00707     // it exactly as we would handle timeout
00708     _loramac.on_radio_rx_timeout(is_timeout);
00709 
00710     if (slot == RX_SLOT_WIN_2  && !_loramac.nwk_joined()) {
00711         state_controller(DEVICE_STATE_JOINING);
00712         return;
00713     }
00714 
00715     /**
00716      * LoRaWAN Specification 1.0.2. Section 3.3.6
00717      * Main point:
00718      *     We indicate successful transmission
00719      * of UNCONFIRMED message after RX windows are done with.
00720      *     For a CONFIRMED message, it means that we have not received
00721      * ack (actually nothing was received), and we should retransmit if we can.
00722      *
00723      * NOTE: This code block doesn't get hit for Class C as in Class C, RX2 timeout
00724      * never occurs.
00725      */
00726     if (slot == RX_SLOT_WIN_2 ) {
00727         _loramac.post_process_mcps_req();
00728 
00729         if (_loramac.get_mcps_confirmation()->req_type == MCPS_CONFIRMED ) {
00730             if (_loramac.continue_sending_process()) {
00731                 return;
00732             } else {
00733                 tr_error("Retries exhausted for Class A device");
00734             }
00735         }
00736 
00737         state_controller(DEVICE_STATE_STATUS_CHECK);
00738         state_machine_run_to_completion();
00739     }
00740 }
00741 
00742 /*****************************************************************************
00743  * Private methods                                                           *
00744  ****************************************************************************/
00745 void LoRaWANStack::make_tx_metadata_available(void)
00746 {
00747     _tx_metadata.stale = false;
00748     _tx_metadata.channel = _loramac.get_mcps_confirmation()->channel;
00749     _tx_metadata.data_rate = _loramac.get_mcps_confirmation()->data_rate;
00750     _tx_metadata.tx_power = _loramac.get_mcps_confirmation()->tx_power;
00751     _tx_metadata.tx_toa = _loramac.get_mcps_confirmation()->tx_toa;
00752     _tx_metadata.nb_retries = _loramac.get_mcps_confirmation()->nb_retries;
00753 }
00754 
00755 void LoRaWANStack::make_rx_metadata_available(void)
00756 {
00757     _rx_metadata.stale = false;
00758     _rx_metadata.rx_datarate = _loramac.get_mcps_indication()->rx_datarate;
00759     _rx_metadata.rssi = _loramac.get_mcps_indication()->rssi;
00760     _rx_metadata.snr = _loramac.get_mcps_indication()->snr;
00761 }
00762 
00763 bool LoRaWANStack::is_port_valid(const uint8_t port, bool allow_port_0)
00764 {
00765     //Application should not use reserved and illegal port numbers.
00766     if (port == 0) {
00767         return allow_port_0;
00768     } else if (port == COMPLIANCE_TESTING_PORT){
00769 #if !defined(LORAWAN_COMPLIANCE_TEST)
00770         return false;
00771 #endif
00772     } else {
00773         return true;
00774     }
00775 
00776     // fallback for compliance testing port if LORAWAN_COMPLIANCE_TEST
00777     // was defined
00778     return true;
00779 }
00780 
00781 lorawan_status_t LoRaWANStack::set_application_port(const uint8_t port, bool allow_port_0)
00782 {
00783     if (is_port_valid(port, allow_port_0)) {
00784         _app_port = port;
00785         return LORAWAN_STATUS_OK;
00786     }
00787 
00788     return LORAWAN_STATUS_PORT_INVALID;
00789 }
00790 
00791 void LoRaWANStack::state_machine_run_to_completion()
00792 {
00793     if (_loramac.get_device_class() == CLASS_C) {
00794         _device_current_state = DEVICE_STATE_RECEIVING;
00795         return;
00796     }
00797 
00798     _device_current_state = DEVICE_STATE_IDLE;
00799 }
00800 
00801 void LoRaWANStack::send_event_to_application(const lorawan_event_t event) const
00802 {
00803     if (_callbacks.events) {
00804         const int ret = _queue->call(_callbacks.events, event);
00805         MBED_ASSERT(ret != 0);
00806         (void)ret;
00807     }
00808 }
00809 
00810 void LoRaWANStack::send_automatic_uplink_message(const uint8_t port)
00811 {
00812     // we will silently ignore the automatic uplink event if the user is already
00813     // sending something
00814     const int16_t ret = handle_tx(port, NULL, 0, MSG_CONFIRMED_FLAG, true, true);
00815     if (ret == LORAWAN_STATUS_WOULD_BLOCK) {
00816         _automatic_uplink_ongoing = false;
00817     } else if (ret < 0) {
00818         tr_debug("Failed to generate AUTOMATIC UPLINK, error code = %d", ret);
00819         send_event_to_application(AUTOMATIC_UPLINK_ERROR);
00820     }
00821 }
00822 
00823 int LoRaWANStack::convert_to_msg_flag(const mcps_type_t type)
00824 {
00825     int msg_flag = MSG_UNCONFIRMED_FLAG;
00826     switch (type) {
00827         case MCPS_UNCONFIRMED :
00828             msg_flag = MSG_UNCONFIRMED_FLAG;
00829             break;
00830 
00831         case MCPS_CONFIRMED :
00832             msg_flag = MSG_CONFIRMED_FLAG;
00833             break;
00834 
00835         case MCPS_MULTICAST :
00836             msg_flag = MSG_MULTICAST_FLAG;
00837             break;
00838 
00839         case MCPS_PROPRIETARY :
00840             msg_flag = MSG_PROPRIETARY_FLAG;
00841             break;
00842 
00843         default:
00844             tr_error("Unknown message type!");
00845             MBED_ASSERT(0);
00846     }
00847 
00848     return msg_flag;
00849 }
00850 
00851 lorawan_status_t LoRaWANStack::handle_connect(bool is_otaa)
00852 {
00853     _ctrl_flags |= CONN_IN_PROGRESS_FLAG;
00854 
00855     if (is_otaa) {
00856         tr_debug("Initiating OTAA");
00857 
00858         // In 1.0.2 spec, counters are always set to zero for new connection.
00859         // This section is common for both normal and
00860         // connection restore at this moment. Will change in future with 1.1 support.
00861         _lw_session.downlink_counter = 0;
00862         _lw_session.uplink_counter = 0;
00863         _ctrl_flags |= USING_OTAA_FLAG;
00864     } else {
00865         // If current state is SHUTDOWN, device may be trying to re-establish
00866         // communication. In case of ABP specification is meddled about frame counters.
00867         // It says to reset counters to zero but there is no mechanism to tell the
00868         // network server that the device was disconnected or restarted.
00869         // At the moment, this implementation does not support a non-volatile
00870         // memory storage.
00871         //_lw_session.downlink_counter; //Get from NVM
00872         //_lw_session.uplink_counter; //Get from NVM
00873 
00874         tr_debug("Initiating ABP");
00875         tr_debug("Frame Counters. UpCnt=%lu, DownCnt=%lu",
00876                  _lw_session.uplink_counter, _lw_session.downlink_counter);
00877         _ctrl_flags &= ~USING_OTAA_FLAG;
00878     }
00879 
00880     return state_controller(DEVICE_STATE_CONNECTING);
00881 }
00882 
00883 void LoRaWANStack::mlme_indication_handler()
00884 {
00885     if (_loramac.get_mlme_indication()->indication_type == MLME_SCHEDULE_UPLINK ) {
00886         // The MAC signals that we shall provide an uplink as soon as possible
00887 #if MBED_CONF_LORA_AUTOMATIC_UPLINK_MESSAGE
00888         _automatic_uplink_ongoing = true;
00889         tr_debug("mlme indication: sending empty uplink to port 0 to acknowledge MAC commands...");
00890         const uint8_t port = 0;
00891         const int ret = _queue->call(this, &LoRaWANStack::send_automatic_uplink_message, port);
00892         MBED_ASSERT(ret != 0);
00893         (void)ret;
00894 #else
00895         send_event_to_application(UPLINK_REQUIRED);
00896 #endif
00897         return;
00898     }
00899 
00900     tr_error("Unknown MLME Indication type.");
00901 }
00902 
00903 void LoRaWANStack::mlme_confirm_handler()
00904 {
00905     if (_loramac.get_mlme_confirmation()->req_type == MLME_LINK_CHECK ) {
00906         if (_loramac.get_mlme_confirmation()->status
00907                 == LORAMAC_EVENT_INFO_STATUS_OK ) {
00908 
00909             if (_callbacks.link_check_resp) {
00910                 const int ret = _queue->call(
00911                         _callbacks.link_check_resp,
00912                         _loramac.get_mlme_confirmation()->demod_margin,
00913                         _loramac.get_mlme_confirmation()->nb_gateways);
00914                 MBED_ASSERT(ret != 0);
00915                 (void) ret;
00916             }
00917         }
00918     }
00919 
00920     if (_loramac.get_mlme_confirmation()->req_type == MLME_JOIN ) {
00921 
00922         switch (_loramac.get_mlme_confirmation()->status) {
00923             case LORAMAC_EVENT_INFO_STATUS_OK :
00924                 state_controller(DEVICE_STATE_CONNECTED);
00925                 break;
00926 
00927             case LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL :
00928                 // fatal error
00929                 _device_current_state = DEVICE_STATE_IDLE;
00930                 tr_error("Joining abandoned: CRYPTO_ERROR");
00931                 send_event_to_application(CRYPTO_ERROR);
00932                 break;
00933 
00934             case LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT :
00935                 // fatal error
00936                 _device_current_state = DEVICE_STATE_IDLE;
00937                 tr_error("Joining abandoned: Radio failed to transmit");
00938                 send_event_to_application(TX_TIMEOUT);
00939                 break;
00940 
00941             default:
00942                 // non-fatal, retry if possible
00943                 _device_current_state = DEVICE_STATE_AWAITING_JOIN_ACCEPT;
00944                 state_controller(DEVICE_STATE_JOINING);
00945         }
00946     }
00947 }
00948 
00949 void LoRaWANStack::mcps_confirm_handler()
00950 {
00951     switch (_loramac.get_mcps_confirmation()->status) {
00952 
00953         case LORAMAC_EVENT_INFO_STATUS_OK :
00954             _lw_session.uplink_counter = _loramac.get_mcps_confirmation()->ul_frame_counter;
00955             send_event_to_application(TX_DONE);
00956             break;
00957 
00958         case LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT :
00959             tr_error("Fatal Error, Radio failed to transmit");
00960             send_event_to_application(TX_TIMEOUT);
00961             break;
00962 
00963         case LORAMAC_EVENT_INFO_STATUS_TX_DR_PAYLOAD_SIZE_ERROR :
00964             send_event_to_application(TX_SCHEDULING_ERROR);
00965             break;
00966 
00967         default:
00968             // if no ack was received after enough retries, send TX_ERROR
00969             send_event_to_application(TX_ERROR);
00970     }
00971 }
00972 
00973 void LoRaWANStack::mcps_indication_handler()
00974 {
00975     const loramac_mcps_indication_t  *mcps_indication = _loramac.get_mcps_indication();
00976     if (mcps_indication->status  != LORAMAC_EVENT_INFO_STATUS_OK ) {
00977         tr_error("RX_ERROR: mcps_indication status = %d", mcps_indication->status );
00978         send_event_to_application(RX_ERROR);
00979         return;
00980     }
00981 
00982     _lw_session.downlink_counter = mcps_indication->dl_frame_counter ;
00983 
00984     /**
00985      * Check port, if it's compliance testing port and the compliance testing is
00986      * not enabled, give up silently
00987      */
00988     if (mcps_indication->port  == COMPLIANCE_TESTING_PORT) {
00989 #if !defined(LORAWAN_COMPLIANCE_TEST)
00990         return;
00991 #endif
00992     }
00993 
00994     if (mcps_indication->is_data_recvd ) {
00995         // Valid message arrived.
00996         _rx_msg.type = LORAMAC_RX_MCPS_INDICATION;
00997         _rx_msg.msg.mcps_indication.buffer_size = mcps_indication->buffer_size ;
00998         _rx_msg.msg.mcps_indication.port = mcps_indication->port ;
00999         _rx_msg.msg.mcps_indication.buffer = mcps_indication->buffer ;
01000         _rx_msg.msg.mcps_indication.type = mcps_indication->type ;
01001 
01002         // Notify application about received frame..
01003         tr_debug("Packet Received %d bytes, Port=%d",
01004                  _rx_msg.msg.mcps_indication.buffer_size,
01005                  mcps_indication->port );
01006         _rx_msg.receive_ready = true;
01007         send_event_to_application(RX_DONE);
01008     }
01009 
01010     /*
01011      * If fPending bit is set we try to generate an empty packet
01012      * with CONFIRMED flag set. We always set a CONFIRMED flag so
01013      * that we could retry a certain number of times if the uplink
01014      * failed for some reason
01015      * or
01016      * Class C and node received a confirmed message so we need to
01017      * send an empty packet to acknowledge the message.
01018      * This scenario is unspecified by LoRaWAN 1.0.2 specification,
01019      * but version 1.1.0 says that network SHALL not send any new
01020      * confirmed messages until ack has been sent
01021      */
01022     if ((_loramac.get_device_class() != CLASS_C
01023             && mcps_indication->fpending_status )
01024             || (_loramac.get_device_class() == CLASS_C
01025                     && mcps_indication->type  == MCPS_CONFIRMED )) {
01026 #if (MBED_CONF_LORA_AUTOMATIC_UPLINK_MESSAGE)
01027         tr_debug("Sending empty uplink message...");
01028         _automatic_uplink_ongoing = true;
01029         const int ret = _queue->call(this, &LoRaWANStack::send_automatic_uplink_message, mcps_indication->port );
01030         MBED_ASSERT(ret != 0);
01031         (void)ret;
01032 #else
01033         send_event_to_application(UPLINK_REQUIRED);
01034 #endif
01035     }
01036 }
01037 
01038 
01039 lorawan_status_t LoRaWANStack::state_controller(device_states_t new_state)
01040 {
01041     lorawan_status_t status = LORAWAN_STATUS_OK;
01042 
01043     switch (new_state) {
01044         case DEVICE_STATE_IDLE:
01045             process_idle_state(status);
01046             break;
01047         case DEVICE_STATE_CONNECTING:
01048             process_connecting_state(status);
01049             break;
01050         case DEVICE_STATE_JOINING:
01051             process_joining_state(status);
01052             break;
01053         case DEVICE_STATE_CONNECTED:
01054             process_connected_state();
01055             break;
01056         case DEVICE_STATE_SCHEDULING:
01057             process_scheduling_state(status);
01058             break;
01059         case DEVICE_STATE_STATUS_CHECK:
01060             process_status_check_state();
01061             break;
01062         case DEVICE_STATE_SHUTDOWN:
01063             process_shutdown_state(status);
01064             break;
01065         default:
01066             //Because this is internal function only coding error causes this
01067             tr_error("Unknown state: %d:", new_state);
01068             MBED_ASSERT(false);
01069     }
01070 
01071     return status;
01072 }
01073 
01074 void LoRaWANStack::process_shutdown_state(lorawan_status_t &op_status)
01075 {
01076     /**
01077      * Remove channels
01078      * Radio will be put to sleep by the APIs underneath
01079      */
01080     drop_channel_list();
01081     _loramac.disconnect();
01082     _lw_session.active = false;
01083     _device_current_state = DEVICE_STATE_SHUTDOWN;
01084     op_status = LORAWAN_STATUS_DEVICE_OFF;
01085     _ctrl_flags &= ~CONNECTED_FLAG;
01086     _ctrl_flags &= ~CONN_IN_PROGRESS_FLAG;
01087     send_event_to_application(DISCONNECTED);
01088 }
01089 
01090 void LoRaWANStack::process_status_check_state()
01091 {
01092     if (_device_current_state == DEVICE_STATE_SENDING ||
01093             _device_current_state == DEVICE_STATE_AWAITING_ACK) {
01094         // If there was a successful transmission, this block gets a kick after
01095         // RX2 slot is exhausted. We may or may not have a successful UNCONFIRMED transmission
01096         // here. In CONFIRMED case this block is invoked only
01097         // when the MAX number of retries are exhausted, i.e., only error
01098         // case will fall here. Moreover, it will happen for Class A only.
01099         // Another possibility is the case when the stack fails to schedule a
01100         // deferred transmission and a scheduling failure handler is invoked.
01101         _ctrl_flags &= ~TX_DONE_FLAG;
01102         _ctrl_flags &= ~TX_ONGOING_FLAG;
01103         _loramac.set_tx_ongoing(false);
01104         _loramac.reset_ongoing_tx();
01105         mcps_confirm_handler();
01106 
01107     } else if (_device_current_state == DEVICE_STATE_RECEIVING) {
01108 
01109         if ((_ctrl_flags & TX_DONE_FLAG) || (_ctrl_flags & TX_ONGOING_FLAG)) {
01110             // for CONFIRMED case, ack validity is already checked
01111             // If it was a successful transmission, TX_ONGOING_FLAG will not be set.
01112             // If it was indeed set, that means the device was in Class C mode and
01113             // CONFIRMED transmission was in place and the ack retries maxed out.
01114             _ctrl_flags &= ~TX_DONE_FLAG;
01115             _ctrl_flags &= ~TX_ONGOING_FLAG;
01116             _loramac.set_tx_ongoing(false);
01117             _loramac.reset_ongoing_tx();
01118             // if an automatic uplink is ongoing, we should not send a TX_DONE
01119             // event to application
01120             if (_automatic_uplink_ongoing) {
01121                 _automatic_uplink_ongoing = false;
01122             } else {
01123                 mcps_confirm_handler();
01124             }
01125         }
01126 
01127         // handle any received data and send event accordingly
01128         if (_ctrl_flags & MSG_RECVD_FLAG) {
01129             _ctrl_flags &= ~MSG_RECVD_FLAG;
01130             mcps_indication_handler();
01131         }
01132     }
01133 }
01134 
01135 void LoRaWANStack::process_scheduling_state(lorawan_status_t &op_status)
01136 {
01137     if (_device_current_state != DEVICE_STATE_IDLE) {
01138         if (_device_current_state != DEVICE_STATE_RECEIVING
01139                 && _loramac.get_device_class() != CLASS_C) {
01140             op_status = LORAWAN_STATUS_BUSY;
01141             return;
01142         }
01143     }
01144 
01145     op_status = _loramac.send_ongoing_tx();
01146     if (op_status == LORAWAN_STATUS_OK) {
01147         _ctrl_flags |= TX_ONGOING_FLAG;
01148         _ctrl_flags &= ~TX_DONE_FLAG;
01149         _loramac.set_tx_ongoing(true);
01150         _device_current_state = DEVICE_STATE_SENDING;
01151     }
01152 }
01153 
01154 void LoRaWANStack::process_joining_state(lorawan_status_t &op_status)
01155 {
01156     if (_device_current_state == DEVICE_STATE_CONNECTING) {
01157         _device_current_state = DEVICE_STATE_JOINING;
01158         tr_debug("Sending Join Request ...");
01159         op_status = _loramac.join(true);
01160         return;
01161     }
01162 
01163     if (_device_current_state == DEVICE_STATE_AWAITING_JOIN_ACCEPT &&
01164         _loramac.get_current_slot() != RX_SLOT_WIN_1 ) {
01165         _device_current_state = DEVICE_STATE_JOINING;
01166         // retry join
01167         bool can_continue = _loramac.continue_joining_process();
01168 
01169         if (!can_continue) {
01170             _ctrl_flags &= ~CONN_IN_PROGRESS_FLAG;
01171             send_event_to_application(JOIN_FAILURE);
01172             _device_current_state = DEVICE_STATE_IDLE;
01173             return;
01174         }
01175     }
01176 }
01177 
01178 void LoRaWANStack::process_connected_state()
01179 {
01180     _ctrl_flags |= CONNECTED_FLAG;
01181     _ctrl_flags &= ~CONN_IN_PROGRESS_FLAG;
01182 
01183     if (_ctrl_flags & USING_OTAA_FLAG) {
01184         tr_debug("OTAA Connection OK!");
01185     }
01186 
01187     _lw_session.active = true;
01188     send_event_to_application(CONNECTED);
01189 
01190     _device_current_state = DEVICE_STATE_IDLE;
01191 }
01192 
01193 void LoRaWANStack::process_connecting_state(lorawan_status_t &op_status)
01194 {
01195     MBED_ASSERT(_device_current_state == DEVICE_STATE_IDLE ||
01196                 _device_current_state == DEVICE_STATE_SHUTDOWN);
01197 
01198     _device_current_state = DEVICE_STATE_CONNECTING;
01199 
01200     if (_ctrl_flags & USING_OTAA_FLAG) {
01201         process_joining_state(op_status);
01202         return;
01203     }
01204 
01205     op_status = _loramac.join(false);
01206     tr_debug("ABP connection OK.");
01207     process_connected_state();
01208 }
01209 
01210 void LoRaWANStack::process_idle_state(lorawan_status_t &op_status)
01211 {
01212     if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) {
01213         _device_current_state = DEVICE_STATE_IDLE;
01214         process_uninitialized_state(op_status);
01215         return;
01216     }
01217 
01218     _device_current_state = DEVICE_STATE_IDLE;
01219     op_status = LORAWAN_STATUS_OK;
01220 }
01221 
01222 void LoRaWANStack::process_uninitialized_state(lorawan_status_t &op_status)
01223 {
01224     op_status = _loramac.initialize(_queue, mbed::callback(this,
01225                                                            &LoRaWANStack::handle_scheduling_failure));
01226 
01227     if (op_status == LORAWAN_STATUS_OK) {
01228         _device_current_state = DEVICE_STATE_IDLE;
01229     }
01230 }