BA / Mbed OS BaBoRo_test2
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 using namespace mbed;
00046 using namespace events;
00047 
00048 #if defined(LORAWAN_COMPLIANCE_TEST)
00049     #if (MBED_CONF_LORA_PHY == 0 || MBED_CONF_LORA_PHY == 4 || MBED_CONF_LORA_PHY == 6 || MBED_CONF_LORA_PHY == 7)
00050         #define LORAWAN_COMPLIANCE_TEST_DATA_SIZE                  16
00051     #elif (MBED_CONF_LORA_PHY == 1 || MBED_CONF_LORA_PHY == 2 || MBED_CONF_LORA_PHY == 8 || MBED_CONF_LORA_PHY == 9)
00052         #define LORAWAN_COMPLIANCE_TEST_DATA_SIZE                  11
00053     #else
00054         #error "Must set LoRa PHY layer parameters."
00055     #endif
00056 #endif
00057 
00058 /*****************************************************************************
00059  * Private Member Functions                                                  *
00060  ****************************************************************************/
00061 bool LoRaWANStack::is_port_valid(uint8_t port)
00062 {
00063     //Application should not use reserved and illegal port numbers.
00064     if (port >= 224 || port == 0) {
00065         return false;
00066     } else {
00067         return true;
00068     }
00069 }
00070 
00071 lorawan_status_t LoRaWANStack::set_application_port(uint8_t port)
00072 {
00073     if (is_port_valid(port)) {
00074         _app_port = port;
00075         return LORAWAN_STATUS_OK;
00076     }
00077 
00078     return LORAWAN_STATUS_PORT_INVALID;
00079 }
00080 
00081 /*****************************************************************************
00082  * Constructor and destructor                                                *
00083  ****************************************************************************/
00084 LoRaWANStack::LoRaWANStack()
00085 : _loramac(),
00086   _device_current_state(DEVICE_STATE_NOT_INITIALIZED), _num_retry(1),
00087   _app_port(INVALID_PORT), _link_check_requested(false), _queue(NULL)
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      memset(&_lw_session, 0, sizeof(_lw_session));
00098      memset(&_rx_msg, 0, sizeof(_rx_msg));
00099 
00100      LoRaMacPrimitives.mcps_confirm     = callback(this, &LoRaWANStack::mcps_confirm_handler);
00101      LoRaMacPrimitives.mcps_indication  = callback(this, &LoRaWANStack::mcps_indication_handler);
00102      LoRaMacPrimitives.mlme_confirm     = callback(this, &LoRaWANStack::mlme_confirm_handler);
00103      LoRaMacPrimitives.mlme_indication  = callback(this, &LoRaWANStack::mlme_indication_handler);
00104 }
00105 
00106 LoRaWANStack::~LoRaWANStack()
00107 {
00108 }
00109 
00110 /*****************************************************************************
00111  * Public member functions                                                   *
00112  ****************************************************************************/
00113 LoRaWANStack& LoRaWANStack::get_lorawan_stack()
00114 {
00115     static LoRaWANStack _lw_stack;
00116     return _lw_stack;
00117 }
00118 
00119 void LoRaWANStack::bind_radio_driver(LoRaRadio& radio)
00120 {
00121     _loramac.bind_radio_driver(radio);
00122 }
00123 
00124 lorawan_status_t LoRaWANStack::connect()
00125 {
00126     if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) {
00127         tr_error("Stack not initialized!");
00128         return LORAWAN_STATUS_NOT_INITIALIZED;
00129     }
00130 
00131     lorawan_status_t status = _loramac.prepare_join(NULL, MBED_CONF_LORA_OVER_THE_AIR_ACTIVATION);
00132 
00133     if (LORAWAN_STATUS_OK != status) {
00134         return status;
00135     }
00136 
00137     return handle_connect(MBED_CONF_LORA_OVER_THE_AIR_ACTIVATION);
00138 }
00139 
00140 lorawan_status_t LoRaWANStack::connect(const lorawan_connect_t &connect)
00141 {
00142     if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) {
00143         tr_error("Stack not initialized!");
00144         return LORAWAN_STATUS_NOT_INITIALIZED;
00145     }
00146 
00147     if (!(connect.connect_type  == LORAWAN_CONNECTION_OTAA) &&
00148         !(connect.connect_type  == LORAWAN_CONNECTION_ABP)) {
00149         return LORAWAN_STATUS_PARAMETER_INVALID;
00150     }
00151     bool is_otaa = (connect.connect_type  == LORAWAN_CONNECTION_OTAA);
00152 
00153     lorawan_status_t status = _loramac.prepare_join(&connect, is_otaa);
00154 
00155     if (LORAWAN_STATUS_OK != status) {
00156         return status;
00157     }
00158 
00159     return handle_connect(is_otaa);
00160 }
00161 
00162 lorawan_status_t LoRaWANStack::handle_connect(bool is_otaa)
00163 {
00164     device_states_t new_state;
00165 
00166     if (is_otaa) {
00167         tr_debug("Initiating OTAA");
00168 
00169         // As mentioned in the comment above, in 1.0.2 spec, counters are always set
00170         // to zero for new connection. This section is common for both normal and
00171         // connection restore at this moment. Will change in future with 1.1 support.
00172         _lw_session.downlink_counter = 0;
00173         _lw_session.uplink_counter = 0;
00174         new_state = DEVICE_STATE_JOINING;
00175     } else {
00176         // If current state is SHUTDOWN, device may be trying to re-establish
00177         // communication. In case of ABP specification is meddled about frame counters.
00178         // It says to reset counters to zero but there is no mechanism to tell the
00179         // network server that the device was disconnected or restarted.
00180         // At the moment, this implementation does not support a non-volatile
00181         // memory storage.
00182         //_lw_session.downlink_counter; //Get from NVM
00183         //_lw_session.uplink_counter; //Get from NVM
00184 
00185         tr_debug("Initiating ABP");
00186         tr_debug("Frame Counters. UpCnt=%lu, DownCnt=%lu",
00187                  _lw_session.uplink_counter, _lw_session.downlink_counter);
00188         new_state = DEVICE_STATE_ABP_CONNECTING;
00189     }
00190 
00191     return lora_state_machine(new_state);
00192 }
00193 
00194 lorawan_status_t LoRaWANStack::initialize_mac_layer(EventQueue *queue)
00195 {
00196     if(!queue) {
00197         return LORAWAN_STATUS_PARAMETER_INVALID;
00198     }
00199 
00200     if (DEVICE_STATE_NOT_INITIALIZED != _device_current_state)
00201     {
00202         tr_debug("Initialized already");
00203         return LORAWAN_STATUS_OK;
00204     }
00205 
00206     tr_debug("Initializing MAC layer");
00207     _queue = queue;
00208 
00209     _loramac.initialize(&LoRaMacPrimitives, queue);
00210 
00211     // Reset counters to zero. Will change in future with 1.1 support.
00212     _lw_session.downlink_counter = 0;
00213     _lw_session.uplink_counter = 0;
00214 
00215     return lora_state_machine(DEVICE_STATE_INIT);
00216 }
00217 
00218 lorawan_status_t LoRaWANStack::set_confirmed_msg_retry(uint8_t count)
00219 {
00220     if (count >= MAX_CONFIRMED_MSG_RETRIES) {
00221         return LORAWAN_STATUS_PARAMETER_INVALID;
00222     }
00223 
00224     _num_retry = count;
00225 
00226     return LORAWAN_STATUS_OK;
00227 }
00228 
00229 /*!
00230  * \brief   MLME-Indication event function
00231  *
00232  * \param   [IN] mlmeIndication - Pointer to the indication structure.
00233  */
00234 void LoRaWANStack::mlme_indication_handler(loramac_mlme_indication_t  *mlmeIndication)
00235 {
00236     switch( mlmeIndication->indication_type  )
00237     {
00238         case MLME_SCHEDULE_UPLINK :
00239         {// The MAC signals that we shall provide an uplink as soon as possible
00240             // TODO: Sending implementation missing and will be implemented using
00241             //       another task.
00242             //OnTxNextPacketTimerEvent( );
00243             break;
00244         }
00245         default:
00246             break;
00247     }
00248 }
00249 
00250 lorawan_status_t LoRaWANStack::set_lora_callbacks(lorawan_app_callbacks_t *cbs)
00251 {
00252     if (!cbs || !cbs->events) {
00253         return LORAWAN_STATUS_PARAMETER_INVALID;
00254     }
00255 
00256     _callbacks.events = cbs->events;
00257 
00258     if (cbs->link_check_resp) {
00259         _callbacks.link_check_resp = cbs->link_check_resp;
00260     }
00261 
00262     if (cbs->battery_level) {
00263         _callbacks.battery_level = cbs->battery_level;
00264     }
00265 
00266     return LORAWAN_STATUS_OK;
00267 }
00268 
00269 lorawan_status_t LoRaWANStack::add_channels(const lorawan_channelplan_t &channel_plan)
00270 {
00271     if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) {
00272         tr_error("Stack not initialized!");
00273         return LORAWAN_STATUS_NOT_INITIALIZED;
00274     }
00275 
00276     return _loramac.add_channel_plan(channel_plan);
00277 }
00278 
00279 lorawan_status_t LoRaWANStack::drop_channel_list()
00280 {
00281     if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) {
00282         tr_error("Stack not initialized!");
00283         return LORAWAN_STATUS_NOT_INITIALIZED;
00284     }
00285 
00286     return _loramac.remove_channel_plan();
00287 }
00288 
00289 lorawan_status_t LoRaWANStack::remove_a_channel(uint8_t channel_id)
00290 {
00291     if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED )
00292     {
00293         tr_error("Stack not initialized!");
00294         return LORAWAN_STATUS_NOT_INITIALIZED;
00295     }
00296 
00297     return _loramac.remove_single_channel(channel_id);
00298 }
00299 
00300 lorawan_status_t LoRaWANStack::get_enabled_channels(lorawan_channelplan_t& channel_plan)
00301 {
00302     if (_device_current_state == DEVICE_STATE_JOINING
00303             || _device_current_state == DEVICE_STATE_NOT_INITIALIZED
00304             || _device_current_state == DEVICE_STATE_INIT)
00305     {
00306         tr_error("Cannot get channel plan until Joined!");
00307         return LORAWAN_STATUS_BUSY;
00308     }
00309 
00310   return _loramac.get_channel_plan(channel_plan);
00311 }
00312 
00313 lorawan_status_t LoRaWANStack::enable_adaptive_datarate(bool adr_enabled)
00314 {
00315     if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state)
00316     {
00317         tr_error("Stack not initialized!");
00318         return LORAWAN_STATUS_NOT_INITIALIZED;
00319     }
00320     _loramac.enable_adaptive_datarate(adr_enabled);
00321     return LORAWAN_STATUS_OK;
00322 }
00323 
00324 lorawan_status_t LoRaWANStack::set_channel_data_rate(uint8_t data_rate)
00325 {
00326     if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state)
00327     {
00328         tr_error("Stack not initialized!");
00329         return LORAWAN_STATUS_NOT_INITIALIZED;
00330     }
00331 
00332     return _loramac.set_channel_data_rate(data_rate);
00333 }
00334 
00335 int16_t LoRaWANStack::handle_tx(uint8_t port, const uint8_t* data,
00336                                 uint16_t length, uint8_t flags, bool null_allowed)
00337 {
00338     if (!null_allowed && !data) {
00339         return LORAWAN_STATUS_PARAMETER_INVALID;
00340     }
00341     // add a link check request with normal data, until the application
00342     // explicitly removes it.
00343     if (_link_check_requested) {
00344         set_link_check_request();
00345     }
00346 
00347     if (!_lw_session.active) {
00348         return LORAWAN_STATUS_NO_ACTIVE_SESSIONS;
00349     }
00350 
00351     if(_loramac.tx_ongoing()) {
00352         return LORAWAN_STATUS_WOULD_BLOCK;
00353     }
00354 
00355 #if defined(LORAWAN_COMPLIANCE_TEST)
00356     if (_compliance_test.running) {
00357         return LORAWAN_STATUS_COMPLIANCE_TEST_ON;
00358     }
00359 #endif
00360 
00361     lorawan_status_t status;
00362 
00363     if (_loramac.nwk_joined() == false) {
00364         return LORAWAN_STATUS_NO_NETWORK_JOINED;
00365     }
00366 
00367     status = set_application_port(port);
00368 
00369     if (status != LORAWAN_STATUS_OK) {
00370         tr_error("Illegal application port definition.");
00371         return status;
00372     }
00373 
00374     if (flags == 0 ||
00375            (flags & MSG_FLAG_MASK) == (MSG_CONFIRMED_FLAG|MSG_UNCONFIRMED_FLAG)) {
00376         tr_error("CONFIRMED and UNCONFIRMED are mutually exclusive for send()");
00377         return LORAWAN_STATUS_PARAMETER_INVALID;
00378     }
00379 
00380     int16_t len = _loramac.prepare_ongoing_tx(port, data, length, flags, _num_retry);
00381 
00382 
00383     status = lora_state_machine(DEVICE_STATE_SEND);
00384 
00385     // send user the length of data which is scheduled now.
00386     // user should take care of the pending data.
00387     return (status == LORAWAN_STATUS_OK) ? len : (int16_t) status;
00388 }
00389 
00390 int convert_to_msg_flag(const mcps_type_t type)
00391 {
00392     int msg_flag = MSG_UNCONFIRMED_FLAG;
00393     switch (type) {
00394         case MCPS_UNCONFIRMED :
00395             msg_flag = MSG_UNCONFIRMED_FLAG;
00396             break;
00397 
00398         case MCPS_CONFIRMED :
00399             msg_flag = MSG_CONFIRMED_FLAG;
00400             break;
00401 
00402         case MCPS_MULTICAST :
00403             msg_flag = MSG_MULTICAST_FLAG;
00404             break;
00405 
00406         case MCPS_PROPRIETARY :
00407             msg_flag = MSG_PROPRIETARY_FLAG;
00408             break;
00409 
00410         default:
00411             tr_error("Unknown message type!");
00412             MBED_ASSERT(0);
00413     }
00414 
00415     return msg_flag;
00416 }
00417 
00418 int16_t LoRaWANStack::handle_rx(uint8_t* data, uint16_t length, uint8_t& port, int& flags, bool validate_params)
00419 {
00420     if (!_lw_session.active) {
00421         return LORAWAN_STATUS_NO_ACTIVE_SESSIONS;
00422     }
00423 
00424     // No messages to read.
00425     if (!_rx_msg.receive_ready) {
00426         return LORAWAN_STATUS_WOULD_BLOCK;
00427     }
00428 
00429 #if defined(LORAWAN_COMPLIANCE_TEST)
00430     if (_compliance_test.running) {
00431         return LORAWAN_STATUS_COMPLIANCE_TEST_ON;
00432     }
00433 #endif
00434 
00435     if (data == NULL || length == 0) {
00436         return LORAWAN_STATUS_PARAMETER_INVALID;
00437     }
00438 
00439     int received_flags = convert_to_msg_flag(_rx_msg.msg.mcps_indication.type);
00440     if (validate_params) {
00441         // Check received message port and flags match with the ones requested by user
00442         received_flags &= MSG_FLAG_MASK;
00443 
00444         if (_rx_msg.msg.mcps_indication.port != port || !(flags & received_flags)) {
00445             return LORAWAN_STATUS_WOULD_BLOCK;
00446         }
00447     }
00448 
00449     // Report values back to user
00450     port = _rx_msg.msg.mcps_indication.port;
00451     flags = received_flags;
00452 
00453     const uint8_t *base_ptr = _rx_msg.msg.mcps_indication.buffer;
00454     uint16_t base_size = _rx_msg.msg.mcps_indication.buffer_size;
00455     bool read_complete = false;
00456 
00457     // check the length of received message whether we can fit into user
00458     // buffer completely or not
00459     if (_rx_msg.msg.mcps_indication.buffer_size > length &&
00460         _rx_msg.prev_read_size == 0) {
00461         // we can't fit into user buffer. Invoke counter measures
00462         _rx_msg.pending_size = _rx_msg.msg.mcps_indication.buffer_size - length;
00463         base_size = length;
00464         _rx_msg.prev_read_size = base_size;
00465         memcpy(data, base_ptr, base_size);
00466     } else if (_rx_msg.prev_read_size == 0) {
00467         _rx_msg.pending_size = 0;
00468         _rx_msg.prev_read_size = 0;
00469         memcpy(data, base_ptr, base_size);
00470         read_complete = true;
00471     }
00472 
00473     // If its the pending read then we should copy only the remaining part of
00474     // the buffer. Due to checks above, in case of a pending read, this block
00475     // will be the only one to get invoked
00476     if (_rx_msg.pending_size > 0 && _rx_msg.prev_read_size > 0) {
00477         memcpy(data, base_ptr+_rx_msg.prev_read_size, base_size);
00478     }
00479 
00480     // we are done handing over received buffer to user. check if there is
00481     // anything pending. If not, memset the buffer to zero and indicate
00482     // that no read is in progress
00483     if (read_complete) {
00484         memset(_rx_msg.msg.mcps_indication.buffer, 0, LORAMAC_PHY_MAXPAYLOAD);
00485         _rx_msg.receive_ready = false;
00486     }
00487 
00488     return base_size;
00489 }
00490 
00491 void LoRaWANStack::mlme_confirm_handler(loramac_mlme_confirm_t  *mlme_confirm)
00492 {
00493     switch (mlme_confirm->req_type ) {
00494         case MLME_JOIN :
00495             if (mlme_confirm->status  == LORAMAC_EVENT_INFO_STATUS_OK ) {
00496                 if (lora_state_machine(DEVICE_STATE_JOINED) != LORAWAN_STATUS_OK) {
00497                     tr_error("Lora state machine did not return LORAWAN_STATUS_OK");
00498                 }
00499             } else {
00500                 if (lora_state_machine(DEVICE_STATE_IDLE) != LORAWAN_STATUS_IDLE) {
00501                     tr_error("Lora state machine did not return DEVICE_STATE_IDLE !");
00502                 }
00503 
00504                 if (_callbacks.events) {
00505                     const int ret = _queue->call(_callbacks.events, JOIN_FAILURE);
00506                     MBED_ASSERT(ret != 0);
00507                     (void)ret;
00508                 }
00509             }
00510             break;
00511         case MLME_LINK_CHECK :
00512             if (mlme_confirm->status  == LORAMAC_EVENT_INFO_STATUS_OK ) {
00513 #if defined(LORAWAN_COMPLIANCE_TEST)
00514                 if (_compliance_test.running == true) {
00515                     _compliance_test.link_check = true;
00516                     _compliance_test.demod_margin = mlme_confirm->demod_margin ;
00517                     _compliance_test.nb_gateways = mlme_confirm->nb_gateways ;
00518                 } else
00519 #endif
00520                 {
00521                     if (_callbacks.link_check_resp) {
00522                         const int ret = _queue->call(_callbacks.link_check_resp,
00523                                                      mlme_confirm->demod_margin ,
00524                                                      mlme_confirm->nb_gateways );
00525                         MBED_ASSERT(ret != 0);
00526                         (void)ret;
00527                     }
00528                 }
00529             }
00530             break;
00531         default:
00532             break;
00533     }
00534 }
00535 
00536 void LoRaWANStack::mcps_confirm_handler(loramac_mcps_confirm_t  *mcps_confirm)
00537 {
00538     if (mcps_confirm->status  != LORAMAC_EVENT_INFO_STATUS_OK ) {
00539         _loramac.reset_ongoing_tx();
00540 
00541         tr_error("mcps_confirm_handler: Error code = %d", mcps_confirm->status );
00542 
00543         if (mcps_confirm->status  == LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT ) {
00544             if (_callbacks.events) {
00545                 const int ret = _queue->call(_callbacks.events, TX_TIMEOUT);
00546                 MBED_ASSERT(ret != 0);
00547                 (void)ret;
00548             }
00549             return;
00550         } else if (mcps_confirm->status  == LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT ) {
00551             tr_debug("Did not receive Ack");
00552         }
00553 
00554         if (_callbacks.events) {
00555             const int ret = _queue->call(_callbacks.events, TX_ERROR);
00556             MBED_ASSERT(ret != 0);
00557             (void)ret;
00558         }
00559         return;
00560     }
00561 
00562     if (mcps_confirm->req_type  == MCPS_CONFIRMED  &&
00563         mcps_confirm->ack_received ) {
00564             tr_debug("Ack received.");
00565     }
00566 
00567     _lw_session.uplink_counter = mcps_confirm->ul_frame_counter ;
00568     _loramac.set_tx_ongoing(false);
00569      if (_callbacks.events) {
00570          const int ret = _queue->call(_callbacks.events, TX_DONE);
00571          MBED_ASSERT(ret != 0);
00572          (void)ret;
00573      }
00574 }
00575 
00576 void LoRaWANStack::mcps_indication_handler(loramac_mcps_indication_t  *mcps_indication)
00577 {
00578     if (mcps_indication->status  != LORAMAC_EVENT_INFO_STATUS_OK ) {
00579         if (_callbacks.events) {
00580             tr_error("RX_ERROR: mcps_indication status = %d", mcps_indication->status );
00581             const int ret = _queue->call(_callbacks.events, RX_ERROR);
00582             MBED_ASSERT(ret != 0);
00583             (void)ret;
00584         }
00585         return;
00586     }
00587 
00588     switch (mcps_indication->type ) {
00589         case MCPS_UNCONFIRMED :
00590             break;
00591         case MCPS_CONFIRMED :
00592             break;
00593         case MCPS_PROPRIETARY :
00594             break;
00595         case MCPS_MULTICAST :
00596             break;
00597         default:
00598             break;
00599     }
00600 
00601     //TODO:
00602     // Check Multicast
00603     // Check Port
00604     // Check Datarate
00605     // Check FramePending
00606     // Check Buffer
00607     // Check BufferSize
00608     // Check Rssi
00609     // Check Snr
00610     // Check RxSlot
00611 
00612     _lw_session.downlink_counter++;
00613 
00614 #if defined(LORAWAN_COMPLIANCE_TEST)
00615     if (_compliance_test.running == true) {
00616         _compliance_test.downlink_counter++;
00617     }
00618 #endif
00619 
00620     if (!mcps_indication->is_data_recvd ) {
00621         return;
00622     }
00623 
00624     switch (mcps_indication->port ) {
00625         case 224: {
00626 #if defined(LORAWAN_COMPLIANCE_TEST)
00627             tr_debug("Compliance test command received.");
00628             compliance_test_handler(mcps_indication);
00629 #else
00630             tr_info("Compliance test disabled.");
00631 #endif
00632             break;
00633         }
00634         default: {
00635             if (is_port_valid(mcps_indication->port ) == true ||
00636                     mcps_indication->type  == MCPS_PROPRIETARY ) {
00637                 // Valid message arrived.
00638                 _rx_msg.type = LORAMAC_RX_MCPS_INDICATION;
00639                 _rx_msg.msg.mcps_indication.buffer_size = mcps_indication->buffer_size ;
00640                 _rx_msg.msg.mcps_indication.port = mcps_indication->port ;
00641                 _rx_msg.msg.mcps_indication.buffer = mcps_indication->buffer ;
00642                 _rx_msg.msg.mcps_indication.type = mcps_indication->type ;
00643 
00644                 // Notify application about received frame..
00645                 tr_debug("Received %d bytes", _rx_msg.msg.mcps_indication.buffer_size);
00646                 _rx_msg.receive_ready = true;
00647 
00648                 if (_callbacks.events) {
00649                     const int ret = _queue->call(_callbacks.events, RX_DONE);
00650                     MBED_ASSERT(ret != 0);
00651                     (void)ret;
00652                 }
00653 
00654                 //TODO: below if clauses can be combined,
00655                 //      because those are calling same function with same parameters
00656 
00657                 // If fPending bit is set we try to generate an empty packet
00658                 // with CONFIRMED flag set. We always set a CONFIRMED flag so
00659                 // that we could retry a certain number of times if the uplink
00660                 // failed for some reason
00661                 if (_loramac.get_device_class() != CLASS_C  && mcps_indication->fpending_status ) {
00662                     tr_debug("Pending bit set. Sending empty message to receive pending data...");
00663                     handle_tx(mcps_indication->port , NULL, 0, MSG_CONFIRMED_FLAG, true);
00664                 }
00665 
00666                 // Class C and node received a confirmed message so we need to
00667                 // send an empty packet to acknowledge the message.
00668                 // This scenario is unspecified by LoRaWAN 1.0.2 specification,
00669                 // but version 1.1.0 says that network SHALL not send any new
00670                 // confirmed messages until ack has been sent
00671                 if (_loramac.get_device_class() == CLASS_C  && mcps_indication->type  == MCPS_CONFIRMED ) {
00672                     tr_debug("Acknowledging confirmed message (class C)...");
00673                     handle_tx(mcps_indication->port , NULL, 0, MSG_CONFIRMED_FLAG, true);
00674                 }
00675             } else {
00676                 // Invalid port, ports 0, 224 and 225-255 are reserved.
00677             }
00678             break;
00679         }
00680     }
00681 }
00682 
00683 lorawan_status_t LoRaWANStack::set_link_check_request()
00684 {
00685     _link_check_requested = true;
00686     if (!_callbacks.link_check_resp) {
00687         tr_error("Must assign a callback function for link check request. ");
00688         return LORAWAN_STATUS_PARAMETER_INVALID;
00689     }
00690 
00691     _loramac.setup_link_check_request();
00692     return LORAWAN_STATUS_OK;
00693 }
00694 
00695 void LoRaWANStack::remove_link_check_request()
00696 {
00697     _link_check_requested = false;
00698 }
00699 
00700 lorawan_status_t LoRaWANStack::shutdown()
00701 {
00702     return lora_state_machine(DEVICE_STATE_SHUTDOWN);
00703 }
00704 
00705 lorawan_status_t LoRaWANStack::set_device_class(const device_class_t & device_class)
00706 {
00707     if (device_class == CLASS_B ) {
00708         return LORAWAN_STATUS_UNSUPPORTED;
00709     }
00710     _loramac.set_device_class(device_class);
00711     return LORAWAN_STATUS_OK;
00712 }
00713 
00714 lorawan_status_t LoRaWANStack::lora_state_machine(device_states_t new_state)
00715 {
00716     lorawan_status_t status = LORAWAN_STATUS_DEVICE_OFF;
00717 
00718     _device_current_state = new_state;
00719 
00720     switch (_device_current_state) {
00721         case DEVICE_STATE_SHUTDOWN:
00722             /*
00723              * Remove channels
00724              * Radio will be put to sleep by the APIs underneath
00725              */
00726             drop_channel_list();
00727             _loramac.disconnect();
00728 
00729 #if defined(LORAWAN_COMPLIANCE_TEST)
00730             _loramac.LoRaMacStopTxTimer();
00731 #endif
00732             _loramac.set_nwk_joined(false);
00733 
00734             _loramac.reset_ongoing_tx(true);
00735 
00736             _rx_msg.msg.mcps_indication.buffer = NULL;
00737             _rx_msg.receive_ready = false;
00738             _rx_msg.prev_read_size = 0;
00739             _rx_msg.msg.mcps_indication.buffer_size = 0;
00740 
00741             _lw_session.active = false;
00742 
00743             tr_debug("LoRaWAN protocol has been shut down.");
00744             if (_callbacks.events) {
00745                 const int ret = _queue->call(_callbacks.events, DISCONNECTED);
00746                 MBED_ASSERT(ret != 0);
00747                 (void)ret;
00748             }
00749             status = LORAWAN_STATUS_DEVICE_OFF;
00750             break;
00751         case DEVICE_STATE_NOT_INITIALIZED:
00752             status = LORAWAN_STATUS_DEVICE_OFF;
00753             break;
00754         case DEVICE_STATE_INIT:
00755             status = LORAWAN_STATUS_OK;
00756             break;
00757         case DEVICE_STATE_JOINING:
00758             if (_lw_session.connect_type == LORAWAN_CONNECTION_OTAA) {
00759                 tr_debug("Send Join-request..");
00760 
00761                 status = _loramac.join(true);
00762                 if (status != LORAWAN_STATUS_OK) {
00763                     return status;
00764                 }
00765 
00766                 return LORAWAN_STATUS_CONNECT_IN_PROGRESS;
00767             } else {
00768                 status = LORAWAN_STATUS_PARAMETER_INVALID;
00769             }
00770             break;
00771         case DEVICE_STATE_JOINED:
00772             tr_debug("Join OK!");
00773 
00774             _lw_session.active = true;
00775 
00776             if (_callbacks.events) {
00777                 const int ret = _queue->call(_callbacks.events, CONNECTED);
00778                 MBED_ASSERT(ret != 0);
00779                 (void)ret;
00780             }
00781             status = LORAWAN_STATUS_OK;
00782             break;
00783         case DEVICE_STATE_ABP_CONNECTING:
00784 
00785             _loramac.join(false);
00786 
00787             tr_debug("ABP Connection OK!");
00788 
00789             status = LORAWAN_STATUS_OK;
00790 
00791             _lw_session.active = true;
00792             if (_callbacks.events) {
00793                 const int ret = _queue->call(_callbacks.events, CONNECTED);
00794                 MBED_ASSERT(ret != 0);
00795                 (void)ret;
00796             }
00797             break;
00798         case DEVICE_STATE_SEND:
00799             if (_loramac.tx_ongoing()) {
00800                 status = LORAWAN_STATUS_OK;
00801             } else {
00802                 _loramac.set_tx_ongoing(true);
00803                 status = _loramac.send_ongoing_tx();
00804 
00805                 switch (status) {
00806                     case LORAWAN_STATUS_OK:
00807                         tr_debug("Frame scheduled to TX..");
00808                         break;
00809                     case LORAWAN_STATUS_CRYPTO_FAIL:
00810                         tr_error("Crypto failed. Clearing TX buffers");
00811                         if (_callbacks.events) {
00812                             const int ret = _queue->call(_callbacks.events, TX_CRYPTO_ERROR);
00813                             MBED_ASSERT(ret != 0);
00814                             (void)ret;
00815                         }
00816                         break;
00817                     default:
00818                         tr_error("Failure to schedule TX!");
00819                         if (_callbacks.events) {
00820                             const int ret = _queue->call(_callbacks.events, TX_SCHEDULING_ERROR);
00821                             MBED_ASSERT(ret != 0);
00822                             (void)ret;
00823                         }
00824                         break;
00825                 }
00826             }
00827 
00828             _device_current_state = DEVICE_STATE_IDLE;
00829             break;
00830         case DEVICE_STATE_IDLE:
00831             status = LORAWAN_STATUS_IDLE;
00832             break;
00833 #if defined(LORAWAN_COMPLIANCE_TEST)
00834         case DEVICE_STATE_COMPLIANCE_TEST:
00835             tr_debug("Device is in compliance test mode.");
00836 
00837             _loramac.LoRaMacSetTxTimer(5000); //ms
00838             if (_compliance_test.running == true) {
00839                 send_compliance_test_frame_to_mac();
00840             }
00841             status = LORAWAN_STATUS_COMPLIANCE_TEST_ON;
00842             break;
00843 #endif
00844         default:
00845             status = LORAWAN_STATUS_SERVICE_UNKNOWN;
00846             break;
00847     }
00848 
00849     return status;
00850 }
00851 
00852 #if defined(LORAWAN_COMPLIANCE_TEST)
00853 
00854 lorawan_status_t LoRaWANStack::send_compliance_test_frame_to_mac()
00855 {
00856     loramac_compliance_test_req_t test_req;
00857 
00858     //TODO: What if the port is not 224 ???
00859     if (_compliance_test.app_port == 224) {
00860         // Clear any normal message stuff before compliance test.
00861         memset(&test_req, 0, sizeof(test_req));
00862 
00863         if (_compliance_test.link_check == true) {
00864             _compliance_test.link_check = false;
00865             _compliance_test.state = 1;
00866             test_req.f_buffer_size = 3;
00867             test_req.f_buffer[0] = 5;
00868             test_req.f_buffer[1] = _compliance_test.demod_margin;
00869             test_req.f_buffer[2] = _compliance_test.nb_gateways;
00870         } else {
00871             switch (_compliance_test.state) {
00872             case 4:
00873                 _compliance_test.state = 1;
00874                 test_req.f_buffer_size = _compliance_test.app_data_size;
00875                 test_req.f_buffer[0] = _compliance_test.app_data_buffer[0];
00876                 for(uint8_t i = 1; i < MIN(_compliance_test.app_data_size, MBED_CONF_LORA_TX_MAX_SIZE); ++i) {
00877                     test_req.f_buffer[i] = _compliance_test.app_data_buffer[i];
00878                 }
00879                 break;
00880             case 1:
00881                 test_req.f_buffer_size = 2;
00882                 test_req.f_buffer[0] = _compliance_test.downlink_counter >> 8;
00883                 test_req.f_buffer[1] = _compliance_test.downlink_counter;
00884                 break;
00885             }
00886         }
00887     }
00888 
00889     //TODO: If port is not 224, this might not work!
00890     //Is there a test case where same _tx_msg's buffer would be used, when port is not 224???
00891     if (!_compliance_test.is_tx_confirmed) {
00892         test_req.type = MCPS_UNCONFIRMED ;
00893         test_req.fport = _compliance_test.app_port;
00894         test_req.nb_trials = 1;
00895         test_req.data_rate = _loramac.get_default_tx_datarate();
00896 
00897         tr_info("Transmit unconfirmed compliance test frame %d bytes.", test_req.f_buffer_size);
00898 
00899         for (uint8_t i = 0; i < test_req.f_buffer_size; ++i) {
00900             tr_info("Byte %d, data is 0x%x", i+1, ((uint8_t*)test_req.f_buffer)[i]);
00901         }
00902     } else if (_compliance_test.is_tx_confirmed) {
00903         test_req.type = MCPS_CONFIRMED ;
00904         test_req.fport = _compliance_test.app_port;
00905         test_req.nb_trials = _num_retry;
00906         test_req.data_rate = _loramac.get_default_tx_datarate();
00907 
00908         tr_info("Transmit confirmed compliance test frame %d bytes.", test_req.f_buffer_size);
00909 
00910         for (uint8_t i = 0; i < test_req.f_buffer_size; ++i) {
00911             tr_info("Byte %d, data is 0x%x", i+1, ((uint8_t*)test_req.f_buffer)[i]);
00912         }
00913     } else {
00914         return LORAWAN_STATUS_SERVICE_UNKNOWN;
00915     }
00916 
00917     return _loramac.test_request(&test_req);
00918 }
00919 
00920 void LoRaWANStack::compliance_test_handler(loramac_mcps_indication_t  *mcps_indication)
00921 {
00922     if (_compliance_test.running == false) {
00923         // Check compliance test enable command (i)
00924         if ((mcps_indication->buffer_size  == 4) &&
00925             (mcps_indication->buffer [0] == 0x01) &&
00926             (mcps_indication->buffer [1] == 0x01) &&
00927             (mcps_indication->buffer [2] == 0x01) &&
00928             (mcps_indication->buffer [3] == 0x01)) {
00929             _compliance_test.is_tx_confirmed = false;
00930             _compliance_test.app_port = 224;
00931             _compliance_test.app_data_size = 2;
00932             _compliance_test.downlink_counter = 0;
00933             _compliance_test.link_check = false;
00934             _compliance_test.demod_margin = 0;
00935             _compliance_test.nb_gateways = 0;
00936             _compliance_test.running = true;
00937             _compliance_test.state = 1;
00938 
00939             _loramac.enable_adaptive_datarate(true);
00940 
00941 #if MBED_CONF_LORA_PHY      == 0
00942             _loramac.LoRaMacTestSetDutyCycleOn(false);
00943 #endif
00944             //5000ms
00945             _loramac.LoRaMacSetTxTimer(5000);
00946 
00947             //TODO: Should we call lora_state_machine here instead of just setting the state?
00948             _device_current_state = DEVICE_STATE_COMPLIANCE_TEST;
00949 //            lora_state_machine(DEVICE_STATE_COMPLIANCE_TEST);
00950             tr_debug("Compliance test activated.");
00951         }
00952     } else {
00953         _compliance_test.state = mcps_indication->buffer [0];
00954         switch (_compliance_test.state) {
00955         case 0: // Check compliance test disable command (ii)
00956             _compliance_test.is_tx_confirmed = true;
00957             _compliance_test.app_port = MBED_CONF_LORA_APP_PORT;
00958             _compliance_test.app_data_size = LORAWAN_COMPLIANCE_TEST_DATA_SIZE;
00959             _compliance_test.downlink_counter = 0;
00960             _compliance_test.running = false;
00961 
00962             _loramac.enable_adaptive_datarate(MBED_CONF_LORA_ADR_ON);
00963 
00964 #if MBED_CONF_LORA_PHY      == 0
00965             _loramac.LoRaMacTestSetDutyCycleOn(MBED_CONF_LORA_DUTY_CYCLE_ON);
00966 #endif
00967             // Go to idle state after compliance test mode.
00968             tr_debug("Compliance test disabled.");
00969             _loramac.LoRaMacStopTxTimer();
00970 
00971             // Clear any compliance test message stuff before going back to normal operation.
00972             _loramac.reset_ongoing_tx();
00973             lora_state_machine(DEVICE_STATE_IDLE);
00974             break;
00975         case 1: // (iii, iv)
00976             _compliance_test.app_data_size = 2;
00977             break;
00978         case 2: // Enable confirmed messages (v)
00979             _compliance_test.is_tx_confirmed = true;
00980             _compliance_test.state = 1;
00981             break;
00982         case 3:  // Disable confirmed messages (vi)
00983             _compliance_test.is_tx_confirmed = false;
00984             _compliance_test.state = 1;
00985             break;
00986         case 4: // (vii)
00987             _compliance_test.app_data_size = mcps_indication->buffer_size ;
00988 
00989             _compliance_test.app_data_buffer[0] = 4;
00990             for(uint8_t i = 1; i < MIN(_compliance_test.app_data_size, LORAMAC_PHY_MAXPAYLOAD); ++i) {
00991                 _compliance_test.app_data_buffer[i] = mcps_indication->buffer [i] + 1;
00992             }
00993 
00994             send_compliance_test_frame_to_mac();
00995             break;
00996         case 5: // (viii)
00997             _loramac.setup_link_check_request();
00998             break;
00999         case 6: // (ix)
01000             // Disable TestMode and revert back to normal operation
01001             _compliance_test.is_tx_confirmed = true;
01002             _compliance_test.app_port = MBED_CONF_LORA_APP_PORT;
01003             _compliance_test.app_data_size = LORAWAN_COMPLIANCE_TEST_DATA_SIZE;
01004             _compliance_test.downlink_counter = 0;
01005             _compliance_test.running = false;
01006 
01007             _loramac.enable_adaptive_datarate(MBED_CONF_LORA_ADR_ON);
01008 
01009 #if MBED_CONF_LORA_PHY      == 0
01010             _loramac.LoRaMacTestSetDutyCycleOn(MBED_CONF_LORA_DUTY_CYCLE_ON);
01011 #endif
01012             _loramac.join(true);
01013             break;
01014         case 7: // (x)
01015             if (mcps_indication->buffer_size  == 3) {
01016                 loramac_mlme_req_t mlme_req;
01017                 mlme_req.type = MLME_TXCW ;
01018                 mlme_req.cw_tx_mode.timeout = (uint16_t)((mcps_indication->buffer [1] << 8) | mcps_indication->buffer [2]);
01019                 _loramac.mlme_request(&mlme_req);
01020             } else if (mcps_indication->buffer_size  == 7) {
01021                 loramac_mlme_req_t mlme_req;
01022                 mlme_req.type = MLME_TXCW_1 ;
01023                 mlme_req.cw_tx_mode.timeout = (uint16_t)((mcps_indication->buffer [1] << 8) | mcps_indication->buffer [2]);
01024                 mlme_req.cw_tx_mode.frequency = (uint32_t)((mcps_indication->buffer [3] << 16) | (mcps_indication->buffer [4] << 8)
01025                         | mcps_indication->buffer [5]) * 100;
01026                 mlme_req.cw_tx_mode.power = mcps_indication->buffer [6];
01027                 _loramac.mlme_request(&mlme_req);
01028             }
01029             _compliance_test.state = 1;
01030             break;
01031         }
01032     }
01033 }
01034 #endif
01035