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