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