Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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 ¶ms) 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 ¶ms) 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
Generated on Tue Jul 12 2022 12:21:59 by
