Knight KE / Mbed OS Game_Master
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers LoRaWANStack.cpp Source File

LoRaWANStack.cpp

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