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