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