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