Denislam Valeev / Mbed OS Nucleo_rtos_basic
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 #include "lorawan/LoRaWANStack.h"
00031 #if defined(FEATURE_COMMON_PAL)
00032 #include "mbed_trace.h"
00033 #define TRACE_GROUP "LSTK"
00034 #else
00035 #define tr_debug(...) (void(0)) //dummies if feature common pal is not added
00036 #define tr_info(...)  (void(0)) //dummies if feature common pal is not added
00037 #define tr_error(...) (void(0)) //dummies if feature common pal is not added
00038 #define tr_warn(...) (void(0)) //dummies if feature common pal is not added
00039 #endif //defined(FEATURE_COMMON_PAL)
00040 
00041 #define INVALID_PORT                0xFF
00042 #define MAX_CONFIRMED_MSG_RETRIES   255
00043 
00044 using namespace mbed;
00045 using namespace events;
00046 
00047 #if defined(LORAWAN_COMPLIANCE_TEST)
00048     /**
00049      *
00050      * User application data buffer size if compliance test is used
00051      */
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
00060 
00061 /*****************************************************************************
00062  * Private Member Functions                                                  *
00063  ****************************************************************************/
00064 bool LoRaWANStack::is_port_valid(uint8_t port)
00065 {
00066     //Application should not use reserved and illegal port numbers.
00067     if (port >= 224 || port == 0) {
00068         return false;
00069     } else {
00070         return true;
00071     }
00072 }
00073 
00074 lorawan_status_t LoRaWANStack::set_application_port(uint8_t port)
00075 {
00076     if (is_port_valid(port)) {
00077         _app_port = port;
00078         return LORAWAN_STATUS_OK;
00079     }
00080 
00081     return LORAWAN_STATUS_PORT_INVALID;
00082 }
00083 
00084 /*****************************************************************************
00085  * Constructor and destructor                                                *
00086  ****************************************************************************/
00087 LoRaWANStack::LoRaWANStack()
00088 : _loramac(_lora_time), _lora_phy(_lora_time),
00089   _device_current_state(DEVICE_STATE_NOT_INITIALIZED), _mac_handlers(NULL),
00090   _num_retry(1), _queue(NULL), _duty_cycle_on(MBED_CONF_LORA_DUTY_CYCLE_ON)
00091 {
00092 #ifdef MBED_CONF_LORA_APP_PORT
00093     // is_port_valid() is not virtual, so we can call it in constructor
00094     if (is_port_valid(MBED_CONF_LORA_APP_PORT)) {
00095         _app_port = MBED_CONF_LORA_APP_PORT;
00096     } else {
00097         tr_error("User defined port in .json is illegal.");
00098         _app_port = INVALID_PORT;
00099     }
00100 
00101 #else
00102     // initialize it to INVALID_PORT (255) an illegal port number.
00103     // user should set the port
00104      _app_port = INVALID_PORT;
00105 #endif
00106 
00107      memset(&_lw_session, 0, sizeof(_lw_session));
00108      memset(&_tx_msg, 0, sizeof(_tx_msg));
00109      memset(&_rx_msg, 0, sizeof(_rx_msg));
00110 
00111      LoRaMacPrimitives.mcps_confirm     = callback(this, &LoRaWANStack::mcps_confirm_handler);
00112      LoRaMacPrimitives.mcps_indication  = callback(this, &LoRaWANStack::mcps_indication_handler);
00113      LoRaMacPrimitives.mlme_confirm     = callback(this, &LoRaWANStack::mlme_confirm_handler);
00114      LoRaMacPrimitives.mlme_indication  = callback(this, &LoRaWANStack::mlme_indication_handler);
00115 }
00116 
00117 LoRaWANStack::~LoRaWANStack()
00118 {
00119 }
00120 
00121 /*****************************************************************************
00122  * Public member functions                                                   *
00123  ****************************************************************************/
00124 LoRaWANStack& LoRaWANStack::get_lorawan_stack()
00125 {
00126     static LoRaWANStack _lw_stack;
00127     return _lw_stack;
00128 }
00129 
00130 radio_events_t *LoRaWANStack::bind_radio_driver(LoRaRadio& radio)
00131 {
00132     // Store pointer to callback routines inside MAC layer (non-IRQ safe)
00133     _mac_handlers = _loramac.get_phy_event_handlers();
00134     //  passes the reference to radio driver down to PHY layer
00135     _lora_phy.set_radio_instance(radio);
00136     return _mac_handlers;
00137 }
00138 
00139 lorawan_status_t LoRaWANStack::initialize_mac_layer(EventQueue *queue)
00140 {
00141     if (DEVICE_STATE_NOT_INITIALIZED != _device_current_state)
00142     {
00143         tr_debug("Initialized already");
00144         return LORAWAN_STATUS_OK;
00145     }
00146 
00147     tr_debug("Initializing MAC layer");
00148 
00149     //store a pointer to Event Queue
00150     _queue = queue;
00151 
00152 #if defined(LORAWAN_COMPLIANCE_TEST)
00153     _compliance_test.app_data_buffer = compliance_test_buffer;
00154 #endif
00155 
00156     _lora_time.activate_timer_subsystem(queue);
00157     _loramac.initialize(&LoRaMacPrimitives, &_lora_phy, queue);
00158 
00159     loramac_mib_req_confirm_t  mib_req;
00160 
00161     mib_req.type  = MIB_ADR ;
00162     mib_req.param .is_adr_enable  = MBED_CONF_LORA_ADR_ON;
00163     mib_set_request(&mib_req);
00164 
00165     mib_req.type  = MIB_PUBLIC_NETWORK ;
00166     mib_req.param .enable_public_nwk  = MBED_CONF_LORA_PUBLIC_NETWORK;
00167     mib_set_request(&mib_req);
00168 
00169     // Reset counters to zero. Will change in future with 1.1 support.
00170     _lw_session.downlink_counter = 0;
00171     _lw_session.uplink_counter = 0;
00172 
00173     // Start loRaWAN state machine.
00174     set_device_state(DEVICE_STATE_INIT);
00175     return lora_state_machine();
00176 }
00177 
00178 #if defined(LORAWAN_COMPLIANCE_TEST)
00179 /**
00180  *
00181  * Prepares the upload message to reserved ports
00182  *
00183  * \param port              Application port
00184  */
00185 void LoRaWANStack::prepare_special_tx_frame(uint8_t port)
00186 {
00187     if (port == 224) {
00188         // Clear any normal message stuff before compliance test.
00189         memset(&_tx_msg, 0, sizeof(_tx_msg));
00190 
00191         if (_compliance_test.link_check == true) {
00192             _compliance_test.link_check = false;
00193             _compliance_test.state = 1;
00194             _tx_msg.f_buffer_size = 3;
00195             _tx_msg.f_buffer[0] = 5;
00196             _tx_msg.f_buffer[1] = _compliance_test.demod_margin;
00197             _tx_msg.f_buffer[2] = _compliance_test.nb_gateways;
00198         } else {
00199             switch (_compliance_test.state) {
00200             case 4:
00201                 _compliance_test.state = 1;
00202                 _tx_msg.f_buffer_size = _compliance_test.app_data_size;
00203 
00204                 _tx_msg.f_buffer[0] = _compliance_test.app_data_buffer[0];
00205                 for(uint8_t i = 1; i < MIN(_compliance_test.app_data_size, MBED_CONF_LORA_TX_MAX_SIZE); ++i) {
00206                     _tx_msg.f_buffer[i] = _compliance_test.app_data_buffer[i];
00207                 }
00208                 break;
00209             case 1:
00210                 _tx_msg.f_buffer_size = 2;
00211                 _tx_msg.f_buffer[0] = _compliance_test.downlink_counter >> 8;
00212                 _tx_msg.f_buffer[1] = _compliance_test.downlink_counter;
00213                 break;
00214             }
00215         }
00216     }
00217 }
00218 
00219 /** Hands over the compliance test frame to MAC layer
00220  *
00221  * \return          returns the state of the LoRa MAC
00222  */
00223 lorawan_status_t LoRaWANStack::send_compliance_test_frame_to_mac()
00224 {
00225     loramac_mcps_req_t  mcps_req;
00226 
00227     get_phy_params_t phy_params;
00228     phy_param_t  default_datarate;
00229     phy_params.attribute = PHY_DEF_TX_DR ;
00230     default_datarate = _lora_phy.get_phy_params(&phy_params);
00231 
00232     prepare_special_tx_frame(_compliance_test.app_port);
00233 
00234     if (!_compliance_test.is_tx_confirmed) {
00235         mcps_req.type  = MCPS_UNCONFIRMED ;
00236         mcps_req.req.unconfirmed .fport  = _compliance_test.app_port;
00237         mcps_req.f_buffer = _tx_msg.f_buffer;
00238         mcps_req.f_buffer_size = _tx_msg.f_buffer_size;
00239         mcps_req.req.unconfirmed .data_rate  = default_datarate.value ;
00240 
00241         tr_info("Transmit unconfirmed compliance test frame %d bytes.", mcps_req.f_buffer_size);
00242 
00243         for (uint8_t i = 0; i < mcps_req.f_buffer_size; ++i) {
00244             tr_info("Byte %d, data is 0x%x", i+1, ((uint8_t*)mcps_req.f_buffer)[i]);
00245         }
00246     } else if (_compliance_test.is_tx_confirmed) {
00247         mcps_req.type  = MCPS_CONFIRMED ;
00248         mcps_req.req.confirmed .fport  = _compliance_test.app_port;
00249         mcps_req.f_buffer = _tx_msg.f_buffer;
00250         mcps_req.f_buffer_size = _tx_msg.f_buffer_size;
00251         mcps_req.req.confirmed .nb_trials  = _num_retry;
00252         mcps_req.req.confirmed .data_rate  = default_datarate.value ;
00253 
00254         tr_info("Transmit confirmed compliance test frame %d bytes.", mcps_req.f_buffer_size);
00255 
00256         for (uint8_t i = 0; i < mcps_req.f_buffer_size; ++i) {
00257             tr_info("Byte %d, data is 0x%x", i+1, ((uint8_t*)mcps_req.f_buffer)[i]);
00258         }
00259     } else {
00260         return LORAWAN_STATUS_SERVICE_UNKNOWN;
00261     }
00262 
00263     return mcps_request_handler(&mcps_req);
00264 }
00265 #endif
00266 
00267 uint16_t LoRaWANStack::check_possible_tx_size(uint16_t size)
00268 {
00269     loramac_tx_info_t  tx_info;
00270     if (_loramac.query_tx_possible(size, &tx_info) == LORAWAN_STATUS_LENGTH_ERROR) {
00271         // Cannot transmit this much. Return how much data can be sent
00272         // at the moment
00273         return tx_info.max_possible_payload_size ;
00274     }
00275 
00276     return tx_info.current_payload_size ;
00277 }
00278 
00279 /** Hands over the frame to MAC layer
00280  *
00281  * \return          returns the state of the LoRa MAC
00282  */
00283 lorawan_status_t LoRaWANStack::send_frame_to_mac()
00284 {
00285     loramac_mcps_req_t  mcps_req;
00286     lorawan_status_t status;
00287     loramac_mib_req_confirm_t  mib_get_params;
00288 
00289     get_phy_params_t phy_params;
00290     phy_param_t  default_datarate;
00291     phy_params.attribute = PHY_DEF_TX_DR ;
00292     default_datarate = _lora_phy.get_phy_params(&phy_params);
00293 
00294     mcps_req.type  = _tx_msg.type;
00295 
00296     if (MCPS_UNCONFIRMED  == mcps_req.type ) {
00297         mcps_req.req.unconfirmed .fport  = _tx_msg.message_u.unconfirmed.fport;
00298         mcps_req.f_buffer = _tx_msg.f_buffer;
00299 
00300         mcps_req.f_buffer_size = _tx_msg.f_buffer_size;
00301 
00302         mib_get_params.type  = MIB_CHANNELS_DATARATE ;
00303         if(mib_get_request(&mib_get_params) != LORAWAN_STATUS_OK) {
00304             tr_debug("Couldn't get MIB parameters: Using default data rate");
00305             mcps_req.req.unconfirmed .data_rate  = default_datarate.value ;
00306         } else {
00307             mcps_req.req.unconfirmed .data_rate  = mib_get_params.param .channel_data_rate ;
00308         }
00309 
00310     } else if (mcps_req.type  == MCPS_CONFIRMED ) {
00311         mcps_req.req.confirmed .fport  = _tx_msg.message_u.confirmed.fport;
00312         mcps_req.f_buffer = _tx_msg.f_buffer;
00313         mcps_req.f_buffer_size = _tx_msg.f_buffer_size;
00314         mcps_req.req.confirmed .nb_trials  = _tx_msg.message_u.confirmed.nb_trials;
00315 
00316         mib_get_params.type  = MIB_CHANNELS_DATARATE ;
00317         if(mib_get_request(&mib_get_params) != LORAWAN_STATUS_OK) {
00318             tr_debug("Couldn't get MIB parameters: Using default data rate");
00319             mcps_req.req.confirmed .data_rate  = default_datarate.value ;
00320         } else {
00321             mcps_req.req.confirmed .data_rate  = mib_get_params.param .channel_data_rate ;
00322         }
00323 
00324     } else if ( mcps_req.type  == MCPS_PROPRIETARY ) {
00325         mcps_req.f_buffer = _tx_msg.f_buffer;
00326         mcps_req.f_buffer_size = _tx_msg.f_buffer_size;
00327 
00328         mib_get_params.type  = MIB_CHANNELS_DATARATE ;
00329         if(mib_get_request(&mib_get_params) != LORAWAN_STATUS_OK) {
00330             tr_debug("Couldn't get MIB parameters: Using default data rate");
00331             mcps_req.req.proprietary .data_rate  = default_datarate.value ;
00332         } else {
00333             mcps_req.req.proprietary .data_rate  = mib_get_params.param .channel_data_rate ;
00334         }
00335 
00336     } else {
00337         return LORAWAN_STATUS_SERVICE_UNKNOWN;
00338     }
00339 
00340     status = mcps_request_handler(&mcps_req);
00341 
00342     return status;
00343 }
00344 
00345 lorawan_status_t LoRaWANStack::set_confirmed_msg_retry(uint8_t count)
00346 {
00347     if (count >= MAX_CONFIRMED_MSG_RETRIES) {
00348         return LORAWAN_STATUS_PARAMETER_INVALID;
00349     }
00350 
00351     _num_retry = count;
00352 
00353     return LORAWAN_STATUS_OK;
00354 }
00355 
00356 void LoRaWANStack::set_device_state(device_states_t new_state)
00357 {
00358     _device_current_state = new_state;
00359 }
00360 
00361 /*!
00362  * \brief   MLME-Indication event function
00363  *
00364  * \param   [IN] mlmeIndication - Pointer to the indication structure.
00365  */
00366 void LoRaWANStack::mlme_indication_handler(loramac_mlme_indication_t  *mlmeIndication)
00367 {
00368     switch( mlmeIndication->indication_type  )
00369     {
00370         case MLME_SCHEDULE_UPLINK :
00371         {// The MAC signals that we shall provide an uplink as soon as possible
00372             // TODO: Sending implementation missing and will be implemented using
00373             //       another task.
00374             //OnTxNextPacketTimerEvent( );
00375             break;
00376         }
00377         default:
00378             break;
00379     }
00380 }
00381 
00382 void LoRaWANStack::set_lora_callbacks(lorawan_app_callbacks_t *cbs)
00383 {
00384     if (cbs) {
00385         if (cbs->events) {
00386             _callbacks.events = cbs->events;
00387         }
00388 
00389         if (cbs->link_check_resp) {
00390             _callbacks.link_check_resp = cbs->link_check_resp;
00391         }
00392 
00393         if (cbs->battery_level) {
00394             _callbacks.battery_level = cbs->battery_level;
00395         }
00396     }
00397 }
00398 
00399 lorawan_status_t LoRaWANStack::add_channels(const lorawan_channelplan_t &channel_plan)
00400 {
00401     // If device is not initialized, stop right away
00402     if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) {
00403         tr_error("Stack not initialized!");
00404         return LORAWAN_STATUS_NOT_INITIALIZED;
00405     }
00406 
00407     return _loramac.add_channel_plan(channel_plan);
00408 }
00409 
00410 lorawan_status_t LoRaWANStack::drop_channel_list()
00411 {
00412     if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) {
00413         tr_error("Stack not initialized!");
00414         return LORAWAN_STATUS_NOT_INITIALIZED;
00415     }
00416 
00417     return _loramac.remove_channel_plan();
00418 }
00419 
00420 lorawan_status_t LoRaWANStack::remove_a_channel(uint8_t channel_id)
00421 {
00422     if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED )
00423     {
00424         tr_error("Stack not initialized!");
00425         return LORAWAN_STATUS_NOT_INITIALIZED;
00426     }
00427 
00428     return _loramac.remove_single_channel(channel_id);
00429 }
00430 
00431 lorawan_status_t LoRaWANStack::get_enabled_channels(lorawan_channelplan_t& channel_plan)
00432 {
00433     if (_device_current_state == DEVICE_STATE_JOINING
00434             || _device_current_state == DEVICE_STATE_NOT_INITIALIZED
00435             || _device_current_state == DEVICE_STATE_INIT)
00436     {
00437         tr_error("Cannot get channel plan until Joined!");
00438         return LORAWAN_STATUS_BUSY;
00439     }
00440 
00441   return _loramac.get_channel_plan(channel_plan);
00442 }
00443 
00444 lorawan_status_t LoRaWANStack::enable_adaptive_datarate(bool adr_enabled)
00445 {
00446     if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state)
00447     {
00448         tr_error("Stack not initialized!");
00449         return LORAWAN_STATUS_NOT_INITIALIZED;
00450     }
00451 
00452     loramac_mib_req_confirm_t  adr_mib_params;
00453 
00454     adr_mib_params.type  = MIB_ADR ;
00455     adr_mib_params.param .is_adr_enable  = adr_enabled;
00456 
00457     return mib_set_request(&adr_mib_params);
00458 }
00459 
00460 lorawan_status_t LoRaWANStack::set_channel_data_rate(uint8_t data_rate)
00461 {
00462     if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state)
00463     {
00464         tr_error("Stack not initialized!");
00465         return LORAWAN_STATUS_NOT_INITIALIZED;
00466     }
00467 
00468     loramac_mib_req_confirm_t  mib_params;
00469     mib_params.type  = MIB_ADR ;
00470     if (mib_get_request(&mib_params) != LORAWAN_STATUS_OK) {
00471         tr_error("Cannot set data rate. Please turn off ADR first.");
00472         return LORAWAN_STATUS_PARAMETER_INVALID;
00473     }
00474 
00475     mib_params.type  = MIB_CHANNELS_DATARATE ;
00476     mib_params.param .channel_data_rate  = data_rate;
00477 
00478     return mib_set_request(&mib_params);
00479 }
00480 
00481 void LoRaWANStack::commission_device(const lorawan_dev_commission_t &commission_data)
00482 {
00483     _lw_session.connection.connect_type = commission_data.connection.connect_type ;
00484     _lw_session.downlink_counter = commission_data.downlink_counter;
00485     _lw_session.uplink_counter = commission_data.uplink_counter;
00486 
00487     if (commission_data.connection.connect_type  == LORAWAN_CONNECTION_OTAA) {
00488         _lw_session.connection.connection_u.otaa.app_eui =
00489                 commission_data.connection.connection_u.otaa .app_eui;
00490         _lw_session.connection.connection_u.otaa.app_key =
00491                 commission_data.connection.connection_u.otaa .app_key;
00492         _lw_session.connection.connection_u.otaa.dev_eui =
00493                 commission_data.connection.connection_u.otaa .dev_eui;
00494         _lw_session.connection.connection_u.otaa.nb_trials =
00495                 commission_data.connection.connection_u.otaa .nb_trials;
00496     } else {
00497         _lw_session.connection.connection_u.abp.dev_addr =
00498                 commission_data.connection.connection_u.abp .dev_addr;
00499         _lw_session.connection.connection_u.abp.nwk_skey =
00500                 commission_data.connection.connection_u.abp .nwk_skey;
00501         _lw_session.connection.connection_u.abp.app_skey =
00502                 commission_data.connection.connection_u.abp .app_skey;
00503     }
00504 }
00505 
00506 /**
00507  *
00508  * Join OTAA
00509  */
00510 lorawan_status_t LoRaWANStack::join_request_by_otaa(const lorawan_connect_t &params)
00511 {
00512     lorawan_dev_commission_t commission;
00513 
00514     if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state)
00515     {
00516         tr_error("Stack not initialized!");
00517         return LORAWAN_STATUS_NOT_INITIALIZED;
00518     }
00519 
00520     tr_debug("Initiating OTAA");
00521 
00522     commission.connection.connect_type  = LORAWAN_CONNECTION_OTAA;
00523     commission.connection.connection_u.otaa .dev_eui = params.connection_u.otaa .dev_eui;
00524     commission.connection.connection_u.otaa .app_eui = params.connection_u.otaa .app_eui;
00525     commission.connection.connection_u.otaa .app_key = params.connection_u.otaa .app_key;
00526     commission.connection.connection_u.otaa .nb_trials = params.connection_u.otaa .nb_trials;
00527 
00528     // As mentioned in the comment above, in 1.0.2 spec, counters are always set
00529     // to zero for new connection. This section is common for both normal and
00530     // connection restore at this moment. Will change in future with 1.1 support.
00531     commission.downlink_counter = 0;
00532     commission.uplink_counter = 0;
00533 
00534     commission_device(commission);
00535     set_device_state(DEVICE_STATE_JOINING);
00536     return lora_state_machine();
00537 }
00538 
00539 /**
00540  *
00541  * Connect ABP
00542  */
00543 lorawan_status_t LoRaWANStack::activation_by_personalization(const lorawan_connect_t &params)
00544 {
00545     lorawan_status_t status;
00546     lorawan_dev_commission_t commission;
00547 
00548     if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) {
00549         tr_error("Stack not initialized!");
00550         return LORAWAN_STATUS_NOT_INITIALIZED;
00551     }
00552 
00553     tr_debug("Initiating ABP");
00554 
00555     commission.connection.connect_type  = LORAWAN_CONNECTION_ABP;
00556     commission.connection.connection_u.abp .dev_addr = params.connection_u.abp .dev_addr;
00557     commission.connection.connection_u.abp .nwk_skey = params.connection_u.abp .nwk_skey;
00558     commission.connection.connection_u.abp .app_skey = params.connection_u.abp .app_skey;
00559 
00560     // If current state is SHUTDOWN, device may be trying to re-establish
00561     // communication. In case of ABP specification is meddled about frame counters.
00562     // It says to reset counters to zero but there is no mechanism to tell the
00563     // network server that the device was disconnected or restarted.
00564     // At the moment, this implementation does not support a non-volatile
00565     // memory storage, so we try a last ditch effort here to restore correct
00566     // frame counters. If that doesn't work, user must manually reset frame
00567     // counters on their network server.
00568     commission.downlink_counter = _lw_session.downlink_counter;
00569     commission.uplink_counter = _lw_session.uplink_counter;
00570 
00571     tr_debug("Frame Counters. UpCnt=%lu, DownCnt=%lu",
00572              commission.uplink_counter, commission.downlink_counter);
00573 
00574     commission_device(commission);
00575 
00576     set_device_state(DEVICE_STATE_ABP_CONNECTING);
00577     status = lora_state_machine();
00578 
00579     return status;
00580 }
00581 
00582 int16_t LoRaWANStack::handle_tx(uint8_t port, const uint8_t* data,
00583                                 uint16_t length, uint8_t flags)
00584 {
00585     if (!_lw_session.active) {
00586         return LORAWAN_STATUS_NO_ACTIVE_SESSIONS;
00587     }
00588 
00589     if (_tx_msg.tx_ongoing) {
00590         return LORAWAN_STATUS_WOULD_BLOCK;
00591     }
00592 
00593     if (!data && length > 0) {
00594         return LORAWAN_STATUS_PARAMETER_INVALID;
00595     }
00596 
00597 #if defined(LORAWAN_COMPLIANCE_TEST)
00598     if (_compliance_test.running) {
00599         return LORAWAN_STATUS_COMPLIANCE_TEST_ON;
00600     }
00601 #endif
00602 
00603     loramac_mib_req_confirm_t  mib_req;
00604     lorawan_status_t status;
00605     mib_req.type  = MIB_NETWORK_JOINED ;
00606     status = mib_get_request(&mib_req);
00607 
00608     if (status == LORAWAN_STATUS_OK) {
00609         if (mib_req.param .is_nwk_joined  == false) {
00610             return LORAWAN_STATUS_NO_NETWORK_JOINED;
00611         }
00612     }
00613 
00614     status = set_application_port(port);
00615 
00616     if (status != LORAWAN_STATUS_OK) {
00617         tr_error("Illegal application port definition.");
00618         return status;
00619     }
00620 
00621     if (flags == 0
00622             || (flags & MSG_FLAG_MASK) == (MSG_CONFIRMED_FLAG|MSG_UNCONFIRMED_FLAG)) {
00623         tr_error("CONFIRMED and UNCONFIRMED are mutually exclusive for send()");
00624         return LORAWAN_STATUS_PARAMETER_INVALID;
00625     }
00626 
00627     _tx_msg.port = port;
00628 
00629     uint16_t max_possible_size = check_possible_tx_size(length);
00630 
00631     if (max_possible_size > MBED_CONF_LORA_TX_MAX_SIZE) {
00632         // LORAWAN_APP_DATA_MAX_SIZE should at least be
00633         // either equal to or bigger than maximum possible
00634         // tx size because our tx message buffer takes its
00635         // length from that macro. Force maximum possible tx unit
00636         // to be equal to the buffer size user chose.
00637         max_possible_size = MBED_CONF_LORA_TX_MAX_SIZE;
00638     }
00639 
00640     if (max_possible_size < length) {
00641         tr_info("Cannot transmit %d bytes. Possible TX Size is %d bytes",
00642                 length, max_possible_size);
00643 
00644         _tx_msg.pending_size = length - max_possible_size;
00645         _tx_msg.f_buffer_size = max_possible_size;
00646         // copy user buffer upto the max_possible_size
00647         memcpy(_tx_msg.f_buffer, data, _tx_msg.f_buffer_size);
00648     } else {
00649         // Whole message can be sent at one time
00650         _tx_msg.f_buffer_size = length;
00651         _tx_msg.pending_size = 0;
00652         // copy user buffer upto the max_possible_size
00653         if (length > 0) {
00654             memcpy(_tx_msg.f_buffer, data, length);
00655         }
00656     }
00657 
00658     // Handles all unconfirmed messages, including proprietary and multicast
00659     if ((flags & MSG_FLAG_MASK) == MSG_UNCONFIRMED_FLAG
00660             || (flags & MSG_FLAG_MASK) == MSG_UNCONFIRMED_MULTICAST
00661             || (flags & MSG_FLAG_MASK) == MSG_UNCONFIRMED_PROPRIETARY) {
00662 
00663          _tx_msg.type = MCPS_UNCONFIRMED ;
00664          _tx_msg.message_u.unconfirmed.fport = _app_port;
00665     }
00666 
00667     // Handles all confirmed messages, including proprietary and multicast
00668     if ((flags & MSG_FLAG_MASK) == MSG_CONFIRMED_FLAG
00669             || (flags & MSG_FLAG_MASK) == MSG_CONFIRMED_MULTICAST
00670             || (flags & MSG_FLAG_MASK) == MSG_CONFIRMED_PROPRIETARY) {
00671 
00672         _tx_msg.type = MCPS_CONFIRMED ;
00673         _tx_msg.message_u.confirmed.fport = _app_port;
00674         _tx_msg.message_u.confirmed.nb_trials = _num_retry;
00675     }
00676 
00677     tr_info("RTS = %u bytes, PEND = %u", _tx_msg.f_buffer_size, _tx_msg.pending_size);
00678     set_device_state(DEVICE_STATE_SEND);
00679     status = lora_state_machine();
00680 
00681     // send user the length of data which is scheduled now.
00682     // user should take care of the pending data.
00683     return (status == LORAWAN_STATUS_OK) ? _tx_msg.f_buffer_size : (int16_t) status;
00684 }
00685 
00686 int16_t LoRaWANStack::handle_rx(const uint8_t port, uint8_t* data,
00687                                 uint16_t length, uint8_t flags)
00688 {
00689     if (!_lw_session.active) {
00690         return LORAWAN_STATUS_NO_ACTIVE_SESSIONS;
00691     }
00692 
00693     // No messages to read.
00694     if (!_rx_msg.receive_ready) {
00695         return LORAWAN_STATUS_WOULD_BLOCK;
00696     }
00697 
00698 #if defined(LORAWAN_COMPLIANCE_TEST)
00699     if (_compliance_test.running) {
00700         return LORAWAN_STATUS_COMPLIANCE_TEST_ON;
00701     }
00702 #endif
00703 
00704     if (data == NULL) {
00705         return LORAWAN_STATUS_PARAMETER_INVALID;
00706     }
00707 
00708     uint8_t *base_ptr = _rx_msg.msg.mcps_indication.buffer;
00709     uint16_t base_size = _rx_msg.msg.mcps_indication.buffer_size;
00710     bool read_complete = false;
00711 
00712     if (_rx_msg.msg.mcps_indication.port != port) {
00713         // Nothing yet received for this particular port
00714         return LORAWAN_STATUS_WOULD_BLOCK;
00715     }
00716 
00717     // check if message received is a Confirmed message and user subscribed to it or not
00718     if (_rx_msg.msg.mcps_indication.type == MCPS_CONFIRMED 
00719             && ((flags & MSG_FLAG_MASK) == MSG_CONFIRMED_FLAG
00720                     || (flags & MSG_FLAG_MASK) == MSG_CONFIRMED_MULTICAST
00721                     || (flags & MSG_FLAG_MASK) == MSG_CONFIRMED_PROPRIETARY)) {
00722 
00723         tr_debug("RX - Confirmed Message, flags=%d", flags);
00724     }
00725 
00726     // check if message received is a Unconfirmed message and user subscribed to it or not
00727     if (_rx_msg.msg.mcps_indication.type == MCPS_UNCONFIRMED 
00728             && ((flags & MSG_FLAG_MASK) == MSG_UNCONFIRMED_FLAG
00729                     || (flags & MSG_FLAG_MASK) == MSG_UNCONFIRMED_MULTICAST
00730                     || (flags & MSG_FLAG_MASK) == MSG_UNCONFIRMED_PROPRIETARY)) {
00731         tr_debug("RX - Unconfirmed Message - flags=%d", flags);
00732     }
00733 
00734     // check the length of received message whether we can fit into user
00735     // buffer completely or not
00736     if (_rx_msg.msg.mcps_indication.buffer_size > length &&
00737             _rx_msg.prev_read_size == 0) {
00738         // we can't fit into user buffer. Invoke counter measures
00739         _rx_msg.pending_size = _rx_msg.msg.mcps_indication.buffer_size - length;
00740         base_size = length;
00741         _rx_msg.prev_read_size = base_size;
00742         memcpy(data, base_ptr, base_size);
00743     } else if (_rx_msg.prev_read_size == 0) {
00744         _rx_msg.pending_size = 0;
00745         _rx_msg.prev_read_size = 0;
00746         memcpy(data, base_ptr, base_size);
00747         read_complete = true;
00748     }
00749 
00750     // If its the pending read then we should copy only the remaining part of
00751     // the buffer. Due to checks above, in case of a pending read, this block
00752     // will be the only one to get invoked
00753     if (_rx_msg.pending_size > 0 && _rx_msg.prev_read_size > 0) {
00754         memcpy(data, base_ptr+_rx_msg.prev_read_size, base_size);
00755     }
00756 
00757     // we are done handing over received buffer to user. check if there is
00758     // anything pending. If not, memset the buffer to zero and indicate
00759     // that no read is in progress
00760     if (read_complete) {
00761         memset(_rx_msg.msg.mcps_indication.buffer, 0, LORAMAC_PHY_MAXPAYLOAD);
00762         _rx_msg.receive_ready = false;
00763     }
00764 
00765     return base_size;
00766 }
00767 
00768 lorawan_status_t LoRaWANStack::mlme_request_handler(loramac_mlme_req_t  *mlme_request)
00769 {
00770     if (mlme_request == NULL) {
00771         return LORAWAN_STATUS_PARAMETER_INVALID;
00772     }
00773 
00774     return _loramac.mlme_request(mlme_request);
00775 }
00776 
00777 /** MLME-Confirm event function
00778  *
00779  * \param mlme_confirm      Pointer to the confirm structure,
00780  *                          containing confirm attributes.
00781  */
00782 void LoRaWANStack::mlme_confirm_handler(loramac_mlme_confirm_t  *mlme_confirm)
00783 {
00784     if (NULL == mlme_confirm) {
00785         tr_error("mlme_confirm: struct [in] is null!");
00786         MBED_ASSERT(0);
00787         return;
00788     }
00789 
00790     switch (mlme_confirm->req_type ) {
00791         case MLME_JOIN :
00792             if (mlme_confirm->status  == LORAMAC_EVENT_INFO_STATUS_OK ) {
00793                 // Status is OK, node has joined the network
00794                 set_device_state(DEVICE_STATE_JOINED);
00795                 if (lora_state_machine() != LORAWAN_STATUS_OK) {
00796                     tr_error("Lora state machine did not return LORAWAN_STATUS_OK");
00797                 }
00798             } else {
00799                 // Join attempt failed.
00800                 set_device_state(DEVICE_STATE_IDLE);
00801                 if (lora_state_machine() != LORAWAN_STATUS_IDLE) {
00802                     tr_error("Lora state machine did not return DEVICE_STATE_IDLE !");
00803                 }
00804 
00805                 if (_callbacks.events) {
00806                     const int ret = _queue->call(_callbacks.events, JOIN_FAILURE);
00807                     MBED_ASSERT(ret != 0);
00808                     (void)ret;
00809                 }
00810             }
00811             break;
00812         case MLME_LINK_CHECK :
00813             if (mlme_confirm->status  == LORAMAC_EVENT_INFO_STATUS_OK ) {
00814                 // Check DemodMargin
00815                 // Check NbGateways
00816 #if defined(LORAWAN_COMPLIANCE_TEST)
00817                 if (_compliance_test.running == true) {
00818                     _compliance_test.link_check = true;
00819                     _compliance_test.demod_margin = mlme_confirm->demod_margin ;
00820                     _compliance_test.nb_gateways = mlme_confirm->nb_gateways ;
00821                 } else
00822 #endif
00823                 {
00824                     // normal operation as oppose to compliance testing
00825                     if (_callbacks.link_check_resp) {
00826                         const int ret = _queue->call(_callbacks.link_check_resp,
00827                                                      mlme_confirm->demod_margin ,
00828                                                      mlme_confirm->nb_gateways );
00829                         MBED_ASSERT(ret != 0);
00830                         (void)ret;
00831                     }
00832                 }
00833             }
00834             break;
00835         default:
00836             break;
00837     }
00838 }
00839 
00840 lorawan_status_t LoRaWANStack::mcps_request_handler(loramac_mcps_req_t  *mcps_request)
00841 {
00842     if (mcps_request == NULL) {
00843         return LORAWAN_STATUS_PARAMETER_INVALID;
00844     }
00845 
00846     return _loramac.mcps_request(mcps_request);
00847 }
00848 
00849 /** MCPS-Confirm event function
00850  *
00851  * \param mcps_confirm      Pointer to the confirm structure,
00852  *                          containing confirm attributes.
00853  */
00854 void LoRaWANStack::mcps_confirm_handler(loramac_mcps_confirm_t  *mcps_confirm)
00855 {
00856     if (mcps_confirm == NULL) {
00857         tr_error("mcps_confirm: struct [in] is null!");
00858         MBED_ASSERT(0);
00859         return;
00860     }
00861 
00862     if (mcps_confirm->status  != LORAMAC_EVENT_INFO_STATUS_OK ) {
00863         // Couldn't schedule packet, ack not recieved in CONFIRMED case
00864         // or some other error happened. Discard buffer, unset the tx-ongoing
00865         // flag and let the application know
00866         _tx_msg.tx_ongoing = false;
00867         memset(_tx_msg.f_buffer, 0, MBED_CONF_LORA_TX_MAX_SIZE);
00868         _tx_msg.f_buffer_size = MBED_CONF_LORA_TX_MAX_SIZE;
00869 
00870         tr_error("mcps_confirm_handler: Error code = %d", mcps_confirm->status );
00871 
00872         // If sending timed out, we have a special event for that
00873         if (mcps_confirm->status  == LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT ) {
00874             if (_callbacks.events) {
00875                 const int ret = _queue->call(_callbacks.events, TX_TIMEOUT);
00876                 MBED_ASSERT(ret != 0);
00877                 (void)ret;
00878             }
00879             return;
00880         } if (mcps_confirm->status  == LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT ) {
00881             tr_debug("Did not receive Ack");
00882         }
00883 
00884         // Otherwise send a general TX_ERROR event
00885         if (_callbacks.events) {
00886             const int ret = _queue->call(_callbacks.events, TX_ERROR);
00887             MBED_ASSERT(ret != 0);
00888             (void)ret;
00889         }
00890         return;
00891     }
00892 
00893     // If No errors encountered, let's proceed with the status.
00894     // CONFIRMED needs special handling because of acks
00895     if (mcps_confirm->req_type  == MCPS_CONFIRMED ) {
00896         // In confirmed case, we need to check if we have received the Ack or not.
00897         // This is actually just being paranoid about ack because LoRaMac.cpp doesn't
00898         // call this callback until an ack is received.
00899         if (mcps_confirm->ack_received ) {
00900             tr_debug("Ack received.");
00901         }
00902     }
00903 
00904     // This part is common to both CONFIRMED and UNCONFIRMED.
00905     // Tell the application about successful transmission and store
00906     // data rate plus frame counter.
00907     _lw_session.uplink_counter = mcps_confirm->ul_frame_counter ;
00908     _tx_msg.tx_ongoing = false;
00909      if (_callbacks.events) {
00910          const int ret = _queue->call(_callbacks.events, TX_DONE);
00911          MBED_ASSERT(ret != 0);
00912          (void)ret;
00913      }
00914 }
00915 
00916 /** MCPS-Indication event function
00917  *
00918  * \param mcps_indication   Pointer to the indication structure,
00919  *                          containing indication attributes.
00920  */
00921 void LoRaWANStack::mcps_indication_handler(loramac_mcps_indication_t  *mcps_indication)
00922 {
00923     if (mcps_indication == NULL) {
00924         tr_error("mcps_indication: struct [in] is null.");
00925         return;
00926     }
00927 
00928     if (mcps_indication->status  != LORAMAC_EVENT_INFO_STATUS_OK ) {
00929         if (_callbacks.events) {
00930             const int ret = _queue->call(_callbacks.events, RX_ERROR);
00931             MBED_ASSERT(ret != 0);
00932             (void)ret;
00933         }
00934         return;
00935     }
00936 
00937     switch (mcps_indication->type ) {
00938         case MCPS_UNCONFIRMED :
00939             break;
00940         case MCPS_CONFIRMED :
00941             break;
00942         case MCPS_PROPRIETARY :
00943             break;
00944         case MCPS_MULTICAST :
00945             break;
00946         default:
00947             break;
00948     }
00949 
00950     // Check Multicast
00951     // Check Port
00952     // Check Datarate
00953     // Check FramePending
00954     // Check Buffer
00955     // Check BufferSize
00956     // Check Rssi
00957     // Check Snr
00958     // Check RxSlot
00959 
00960     _lw_session.downlink_counter++;
00961 
00962 #if defined(LORAWAN_COMPLIANCE_TEST)
00963     if (_compliance_test.running == true) {
00964         _compliance_test.downlink_counter++;
00965     }
00966 #endif
00967 
00968     if (mcps_indication->is_data_recvd  == true) {
00969         switch (mcps_indication->port ) {
00970         case 224:
00971 #if defined(LORAWAN_COMPLIANCE_TEST)
00972             tr_debug("Compliance test command received.");
00973             compliance_test_handler(mcps_indication);
00974 #else
00975             tr_debug("Compliance test disabled.");
00976 #endif
00977             break;
00978         default:
00979             if (is_port_valid(mcps_indication->port ) == true ||
00980                 mcps_indication->type  == MCPS_PROPRIETARY ) {
00981 
00982                 // Valid message arrived.
00983                 _rx_msg.type = LORAMAC_RX_MCPS_INDICATION;
00984                 _rx_msg.msg.mcps_indication.buffer_size = mcps_indication->buffer_size ;
00985                 _rx_msg.msg.mcps_indication.port = mcps_indication->port ;
00986 
00987                 // no copy, just set the pointer for the user
00988                 _rx_msg.msg.mcps_indication.buffer =
00989                 mcps_indication->buffer ;
00990 
00991                 // Notify application about received frame..
00992                 tr_debug("Received %d bytes", _rx_msg.msg.mcps_indication.buffer_size);
00993                 _rx_msg.receive_ready = true;
00994 
00995                 if (_callbacks.events) {
00996                     const int ret = _queue->call(_callbacks.events, RX_DONE);
00997                     MBED_ASSERT(ret != 0);
00998                     (void)ret;
00999                 }
01000 
01001                 // If fPending bit is set we try to generate an empty packet
01002                 // with CONFIRMED flag set. We always set a CONFIRMED flag so
01003                 // that we could retry a certain number of times if the uplink
01004                 // failed for some reason
01005                 if (mcps_indication->fpending_status ) {
01006                     handle_tx(mcps_indication->port , NULL, 0, MSG_CONFIRMED_FLAG);
01007                 }
01008             } else {
01009                 // Invalid port, ports 0, 224 and 225-255 are reserved.
01010             }
01011             break;
01012         }
01013     }
01014 }
01015 
01016 #if defined(LORAWAN_COMPLIANCE_TEST)
01017 /** Compliance testing function
01018  *
01019  * \param mcps_indication   Pointer to the indication structure,
01020  *                          containing indication attributes.
01021  */
01022 void LoRaWANStack::compliance_test_handler(loramac_mcps_indication_t  *mcps_indication)
01023 {
01024     if (_compliance_test.running == false) {
01025         // Check compliance test enable command (i)
01026         if ((mcps_indication->buffer_size  == 4) &&
01027             (mcps_indication->buffer [0] == 0x01) &&
01028             (mcps_indication->buffer [1] == 0x01) &&
01029             (mcps_indication->buffer [2] == 0x01) &&
01030             (mcps_indication->buffer [3] == 0x01)) {
01031             _compliance_test.is_tx_confirmed = false;
01032             _compliance_test.app_port = 224;
01033             _compliance_test.app_data_size = 2;
01034             _compliance_test.downlink_counter = 0;
01035             _compliance_test.link_check = false;
01036             _compliance_test.demod_margin = 0;
01037             _compliance_test.nb_gateways = 0;
01038             _compliance_test.running = true;
01039             _compliance_test.state = 1;
01040 
01041             loramac_mib_req_confirm_t  mib_req;
01042             mib_req.type  = MIB_ADR ;
01043             mib_req.param .is_adr_enable  = true;
01044             mib_set_request(&mib_req);
01045 
01046 #if MBED_CONF_LORA_PHY      == 0
01047             _loramac.LoRaMacTestSetDutyCycleOn(false);
01048 #endif
01049             //5000ms
01050             _loramac.LoRaMacSetTxTimer(5000);
01051             set_device_state(DEVICE_STATE_COMPLIANCE_TEST);
01052             tr_debug("Compliance test activated.");
01053         }
01054     } else {
01055         _compliance_test.state = mcps_indication->buffer [0];
01056         switch (_compliance_test.state) {
01057         case 0: // Check compliance test disable command (ii)
01058             _compliance_test.is_tx_confirmed = true;
01059             _compliance_test.app_port = MBED_CONF_LORA_APP_PORT;
01060             _compliance_test.app_data_size = LORAWAN_COMPLIANCE_TEST_DATA_SIZE;
01061             _compliance_test.downlink_counter = 0;
01062             _compliance_test.running = false;
01063 
01064             loramac_mib_req_confirm_t  mib_req;
01065             mib_req.type  = MIB_ADR ;
01066             mib_req.param .is_adr_enable  = MBED_CONF_LORA_ADR_ON;
01067             mib_set_request(&mib_req);
01068 #if MBED_CONF_LORA_PHY      == 0
01069             _loramac.LoRaMacTestSetDutyCycleOn(MBED_CONF_LORA_DUTY_CYCLE_ON);
01070 #endif
01071             // Go to idle state after compliance test mode.
01072             tr_debug("Compliance test disabled.");
01073             _loramac.LoRaMacStopTxTimer();
01074 
01075             // Clear any compliance test message stuff before going back to normal operation.
01076             memset(&_tx_msg, 0, sizeof(_tx_msg));
01077             set_device_state(DEVICE_STATE_IDLE);
01078             lora_state_machine();
01079             break;
01080         case 1: // (iii, iv)
01081             _compliance_test.app_data_size = 2;
01082             break;
01083         case 2: // Enable confirmed messages (v)
01084             _compliance_test.is_tx_confirmed = true;
01085             _compliance_test.state = 1;
01086             break;
01087         case 3:  // Disable confirmed messages (vi)
01088             _compliance_test.is_tx_confirmed = false;
01089             _compliance_test.state = 1;
01090             break;
01091         case 4: // (vii)
01092             _compliance_test.app_data_size = mcps_indication->buffer_size ;
01093 
01094             _compliance_test.app_data_buffer[0] = 4;
01095             for(uint8_t i = 1; i < MIN(_compliance_test.app_data_size, LORAMAC_PHY_MAXPAYLOAD); ++i) {
01096                 _compliance_test.app_data_buffer[i] = mcps_indication->buffer [i] + 1;
01097             }
01098 
01099             send_compliance_test_frame_to_mac();
01100             break;
01101         case 5: // (viii)
01102             loramac_mlme_req_t  mlme_req;
01103             mlme_req.type  = MLME_LINK_CHECK ;
01104             mlme_request_handler(&mlme_req);
01105             break;
01106         case 6: // (ix)
01107             loramac_mlme_req_t  mlme_request;
01108             loramac_mib_req_confirm_t  mib_request;
01109 
01110             // Disable TestMode and revert back to normal operation
01111             _compliance_test.is_tx_confirmed = true;
01112             _compliance_test.app_port = MBED_CONF_LORA_APP_PORT;
01113             _compliance_test.app_data_size = LORAWAN_COMPLIANCE_TEST_DATA_SIZE;
01114             _compliance_test.downlink_counter = 0;
01115             _compliance_test.running = false;
01116 
01117             mib_request.type  = MIB_ADR ;
01118             mib_request.param .is_adr_enable  = MBED_CONF_LORA_ADR_ON;
01119             mib_set_request(&mib_request);
01120 #if MBED_CONF_LORA_PHY      == 0
01121             _loramac.LoRaMacTestSetDutyCycleOn(MBED_CONF_LORA_DUTY_CYCLE_ON);
01122 #endif
01123             mlme_request.type  = MLME_JOIN ;
01124             mlme_request.req.join .dev_eui  = _lw_session.connection.connection_u.otaa.dev_eui;
01125             mlme_request.req.join .app_eui  = _lw_session.connection.connection_u.otaa.app_eui;
01126             mlme_request.req.join .app_key  = _lw_session.connection.connection_u.otaa.app_key;
01127             mlme_request.req.join .nb_trials  = _lw_session.connection.connection_u.otaa.nb_trials;
01128             mlme_request_handler(&mlme_request);
01129             break;
01130         case 7: // (x)
01131             if (mcps_indication->buffer_size  == 3) {
01132                 loramac_mlme_req_t  mlme_req;
01133                 mlme_req.type  = MLME_TXCW ;
01134                 mlme_req.req.cw_tx_mode .timeout  = (uint16_t)((mcps_indication->buffer [1] << 8) | mcps_indication->buffer [2]);
01135                 mlme_request_handler(&mlme_req);
01136             } else if (mcps_indication->buffer_size  == 7) {
01137                 loramac_mlme_req_t  mlme_req;
01138                 mlme_req.type  = MLME_TXCW_1 ;
01139                 mlme_req.req.cw_tx_mode .timeout  = (uint16_t)((mcps_indication->buffer [1] << 8) | mcps_indication->buffer [2]);
01140                 mlme_req.req.cw_tx_mode .frequency  = (uint32_t)((mcps_indication->buffer [3] << 16) | (mcps_indication->buffer [4] << 8)
01141                         | mcps_indication->buffer [5]) * 100;
01142                 mlme_req.req.cw_tx_mode .power  = mcps_indication->buffer [6];
01143                 mlme_request_handler(&mlme_req);
01144             }
01145             _compliance_test.state = 1;
01146             break;
01147         }
01148     }
01149 }
01150 #endif
01151 
01152 lorawan_status_t LoRaWANStack::mib_set_request(loramac_mib_req_confirm_t  *mib_set_params)
01153 {
01154     if (NULL == mib_set_params) {
01155         return LORAWAN_STATUS_PARAMETER_INVALID;
01156     }
01157     return _loramac.mib_set_request_confirm(mib_set_params);
01158 }
01159 
01160 lorawan_status_t LoRaWANStack::mib_get_request(loramac_mib_req_confirm_t  *mib_get_params)
01161 {
01162     if(NULL == mib_get_params) {
01163         return LORAWAN_STATUS_PARAMETER_INVALID;
01164     }
01165     return _loramac.mib_get_request_confirm(mib_get_params);
01166 }
01167 
01168 lorawan_status_t LoRaWANStack::set_link_check_request()
01169 {
01170     if (!_callbacks.link_check_resp) {
01171         tr_error("Must assign a callback function for link check request. ");
01172         return LORAWAN_STATUS_PARAMETER_INVALID;
01173     }
01174 
01175     loramac_mlme_req_t  mlme_req;
01176 
01177     mlme_req.type  = MLME_LINK_CHECK ;
01178     return mlme_request_handler(&mlme_req);
01179 }
01180 
01181 lorawan_status_t LoRaWANStack::shutdown()
01182 {
01183     set_device_state(DEVICE_STATE_SHUTDOWN);
01184     return lora_state_machine();
01185 }
01186 
01187 lorawan_status_t LoRaWANStack::lora_state_machine()
01188 {
01189     loramac_mib_req_confirm_t  mib_req;
01190     lorawan_status_t status = LORAWAN_STATUS_DEVICE_OFF;
01191 
01192     switch (_device_current_state) {
01193         case DEVICE_STATE_SHUTDOWN:
01194             /*
01195              * Remove channels
01196              * Radio will be put to sleep by the APIs underneath
01197              */
01198             drop_channel_list();
01199 
01200             // Shutdown LoRaMac
01201             _loramac.disconnect();
01202 
01203             // Stop sending messages and set joined status to false.
01204 #if defined(LORAWAN_COMPLIANCE_TEST)
01205             _loramac.LoRaMacStopTxTimer();
01206 #endif
01207             mib_req.type  = MIB_NETWORK_JOINED ;
01208             mib_req.param .is_nwk_joined  = false;
01209             mib_set_request(&mib_req);
01210 
01211             // reset buffers to original state
01212             memset(_tx_msg.f_buffer, 0, MBED_CONF_LORA_TX_MAX_SIZE);
01213             _tx_msg.pending_size = 0;
01214             _tx_msg.f_buffer_size = 0;
01215             _tx_msg.tx_ongoing = false;
01216             _rx_msg.msg.mcps_indication.buffer = NULL;
01217             _rx_msg.receive_ready = false;
01218             _rx_msg.prev_read_size = 0;
01219             _rx_msg.msg.mcps_indication.buffer_size = 0;
01220 
01221             // disable the session
01222             _lw_session.active = false;
01223 
01224             tr_debug("LoRaWAN protocol has been shut down.");
01225             if (_callbacks.events) {
01226                 const int ret = _queue->call(_callbacks.events, DISCONNECTED);
01227                 MBED_ASSERT(ret != 0);
01228                 (void)ret;
01229             }
01230             status = LORAWAN_STATUS_DEVICE_OFF;
01231             break;
01232         case DEVICE_STATE_NOT_INITIALIZED:
01233             // Device is disconnected.
01234             status = LORAWAN_STATUS_DEVICE_OFF;
01235             break;
01236         case DEVICE_STATE_INIT:
01237             status = LORAWAN_STATUS_OK;
01238             break;
01239         case DEVICE_STATE_JOINING:
01240             if (_lw_session.connection.connect_type == LORAWAN_CONNECTION_OTAA) {
01241                 /*
01242                  * OTAA join
01243                  */
01244                 tr_debug("Send Join-request..");
01245                 loramac_mlme_req_t  mlme_req;
01246                 mlme_req.type  = MLME_JOIN ;
01247 
01248                 mlme_req.req.join .dev_eui  = _lw_session.connection.connection_u.otaa.dev_eui;
01249                 mlme_req.req.join .app_eui  = _lw_session.connection.connection_u.otaa.app_eui;
01250                 mlme_req.req.join .app_key  = _lw_session.connection.connection_u.otaa.app_key;
01251                 mlme_req.req.join .nb_trials  = _lw_session.connection.connection_u.otaa.nb_trials;
01252 
01253                 // Send join request to server.
01254                 status = mlme_request_handler(&mlme_req);
01255                 if (status != LORAWAN_STATUS_OK) {
01256                     return status;
01257                 }
01258                 // Otherwise request was successful and OTAA connect is in
01259                 //progress
01260                 return LORAWAN_STATUS_CONNECT_IN_PROGRESS;
01261             } else {
01262                 status = LORAWAN_STATUS_PARAMETER_INVALID;
01263             }
01264             break;
01265         case DEVICE_STATE_JOINED:
01266             tr_debug("Join OK!");
01267             // Session is now active
01268             _lw_session.active = true;
01269             // Tell the application that we are connected
01270             if (_callbacks.events) {
01271                 const int ret = _queue->call(_callbacks.events, CONNECTED);
01272                 MBED_ASSERT(ret != 0);
01273                 (void)ret;
01274             }
01275             status = LORAWAN_STATUS_OK;
01276             break;
01277         case DEVICE_STATE_ABP_CONNECTING:
01278             /*
01279              * ABP connection
01280              */
01281             mib_req.type  = MIB_NET_ID ;
01282             mib_req.param .net_id  = _lw_session.connection.connection_u.abp.nwk_id;
01283             mib_set_request(&mib_req);
01284 
01285             mib_req.type  = MIB_DEV_ADDR ;
01286             mib_req.param .dev_addr  = _lw_session.connection.connection_u.abp.dev_addr;
01287             mib_set_request(&mib_req);
01288 
01289             mib_req.type  = MIB_NWK_SKEY ;
01290             mib_req.param .nwk_skey  = _lw_session.connection.connection_u.abp.nwk_skey;
01291             mib_set_request(&mib_req);
01292 
01293             mib_req.type  = MIB_APP_SKEY ;
01294             mib_req.param .app_skey  = _lw_session.connection.connection_u.abp.app_skey;
01295             mib_set_request(&mib_req);
01296 
01297             mib_req.type  = MIB_NETWORK_JOINED ;
01298             mib_req.param .is_nwk_joined  = true;
01299             mib_set_request(&mib_req);
01300             tr_debug("ABP Connection OK!");
01301             // tell the application we are okay
01302             // if users provide wrong keys, it's their responsibility
01303             // there is no way to test ABP authentication success
01304             status = LORAWAN_STATUS_OK;
01305             // Session is now active
01306             _lw_session.active = true;
01307             if (_callbacks.events) {
01308                 const int ret = _queue->call(_callbacks.events, CONNECTED);
01309                 MBED_ASSERT(ret != 0);
01310                 (void)ret;
01311             }
01312             break;
01313         case DEVICE_STATE_SEND:
01314             // If a transmission is ongoing, don't interrupt
01315             if (_tx_msg.tx_ongoing) {
01316                 status = LORAWAN_STATUS_OK;
01317             } else {
01318                 _tx_msg.tx_ongoing = true;
01319                 status = send_frame_to_mac();
01320 
01321                 switch (status) {
01322                     case LORAWAN_STATUS_OK:
01323                         tr_debug("Frame scheduled to TX..");
01324                         break;
01325                     case LORAWAN_STATUS_CRYPTO_FAIL:
01326                         tr_error("Crypto failed. Clearing TX buffers");
01327                         if (_callbacks.events) {
01328                             const int ret = _queue->call(_callbacks.events, TX_CRYPTO_ERROR);
01329                             MBED_ASSERT(ret != 0);
01330                             (void)ret;
01331                         }
01332                         break;
01333                     default:
01334                         tr_error("Failure to schedule TX!");
01335                         if (_callbacks.events) {
01336                             const int ret = _queue->call(_callbacks.events, TX_SCHEDULING_ERROR);
01337                             MBED_ASSERT(ret != 0);
01338                             (void)ret;
01339                         }
01340                         break;
01341                 }
01342             }
01343             // otherwise all done, put device in idle state
01344             set_device_state(DEVICE_STATE_IDLE);
01345             break;
01346         case DEVICE_STATE_IDLE:
01347             //Do nothing
01348             status = LORAWAN_STATUS_IDLE;
01349             break;
01350 #if defined(LORAWAN_COMPLIANCE_TEST)
01351         case DEVICE_STATE_COMPLIANCE_TEST:
01352             //Device is in compliance test mode
01353             tr_debug("Device is in compliance test mode.");
01354 
01355             //5000ms
01356             _loramac.LoRaMacSetTxTimer(5000);
01357             if (_compliance_test.running == true) {
01358                 send_compliance_test_frame_to_mac();
01359             }
01360             status = LORAWAN_STATUS_COMPLIANCE_TEST_ON;
01361             break;
01362 #endif
01363         default:
01364             status = LORAWAN_STATUS_SERVICE_UNKNOWN;
01365             break;
01366     }
01367 
01368     return status;
01369 }