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 00033 #include "mbed-trace/mbed_trace.h" 00034 #define TRACE_GROUP "LSTK" 00035 00036 #define INVALID_PORT 0xFF 00037 #define MAX_CONFIRMED_MSG_RETRIES 255 00038 /** 00039 * Control flags for transient states 00040 */ 00041 #define IDLE_FLAG 0x00000000 00042 #define TX_ONGOING_FLAG 0x00000001 00043 #define MSG_RECVD_FLAG 0x00000002 00044 #define CONNECTED_FLAG 0x00000004 00045 #define USING_OTAA_FLAG 0x00000008 00046 #define TX_DONE_FLAG 0x00000010 00047 00048 using namespace mbed; 00049 using namespace events; 00050 00051 #if defined(LORAWAN_COMPLIANCE_TEST) 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 //defined(LORAWAN_COMPLIANCE_TEST) 00060 00061 /** 00062 * Bit mask for message flags 00063 */ 00064 00065 #define MSG_FLAG_MASK 0x0F 00066 00067 /***************************************************************************** 00068 * Constructor * 00069 ****************************************************************************/ 00070 LoRaWANStack::LoRaWANStack() 00071 : _loramac(), 00072 _device_current_state(DEVICE_STATE_NOT_INITIALIZED), 00073 _lw_session(), 00074 _tx_msg(), 00075 _rx_msg(), 00076 _tx_metadata(), 00077 _rx_metadata(), 00078 _num_retry(1), 00079 _ctrl_flags(IDLE_FLAG), 00080 _app_port(INVALID_PORT), 00081 _link_check_requested(false), 00082 _automatic_uplink_ongoing(false), 00083 _ready_for_rx(true), 00084 _queue(NULL) 00085 { 00086 _tx_metadata.stale = true; 00087 _rx_metadata.stale = true; 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 00098 /***************************************************************************** 00099 * Public Methods * 00100 ****************************************************************************/ 00101 void LoRaWANStack::bind_radio_driver(LoRaRadio &radio) 00102 { 00103 radio_events.tx_done = mbed::callback(this, &LoRaWANStack::tx_interrupt_handler); 00104 radio_events.rx_done = mbed::callback(this, &LoRaWANStack::rx_interrupt_handler); 00105 radio_events.rx_error = mbed::callback(this, &LoRaWANStack::rx_error_interrupt_handler); 00106 radio_events.tx_timeout = mbed::callback(this, &LoRaWANStack::tx_timeout_interrupt_handler); 00107 radio_events.rx_timeout = mbed::callback(this, &LoRaWANStack::rx_timeout_interrupt_handler); 00108 00109 _loramac.bind_radio_driver(radio); 00110 00111 radio.lock(); 00112 radio.init_radio(&radio_events); 00113 radio.unlock(); 00114 } 00115 00116 lorawan_status_t LoRaWANStack::initialize_mac_layer(EventQueue *queue) 00117 { 00118 if (!queue) { 00119 return LORAWAN_STATUS_PARAMETER_INVALID; 00120 } 00121 00122 tr_debug("Initializing MAC layer"); 00123 _queue = queue; 00124 00125 return state_controller(DEVICE_STATE_IDLE); 00126 } 00127 00128 lorawan_status_t LoRaWANStack::set_lora_callbacks(const lorawan_app_callbacks_t *callbacks) 00129 { 00130 if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { 00131 return LORAWAN_STATUS_NOT_INITIALIZED; 00132 } 00133 00134 if (!callbacks || !callbacks->events) { 00135 return LORAWAN_STATUS_PARAMETER_INVALID; 00136 } 00137 00138 _callbacks.events = callbacks->events; 00139 00140 if (callbacks->link_check_resp) { 00141 _callbacks.link_check_resp = callbacks->link_check_resp; 00142 } 00143 00144 if (callbacks->battery_level) { 00145 _callbacks.battery_level = callbacks->battery_level; 00146 _loramac.set_batterylevel_callback(callbacks->battery_level); 00147 } 00148 00149 return LORAWAN_STATUS_OK; 00150 } 00151 00152 lorawan_status_t LoRaWANStack::connect() 00153 { 00154 if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { 00155 return LORAWAN_STATUS_NOT_INITIALIZED; 00156 } 00157 00158 lorawan_status_t status = _loramac.prepare_join(NULL, MBED_CONF_LORA_OVER_THE_AIR_ACTIVATION); 00159 00160 if (LORAWAN_STATUS_OK != status) { 00161 return status; 00162 } 00163 00164 return handle_connect(MBED_CONF_LORA_OVER_THE_AIR_ACTIVATION); 00165 } 00166 00167 lorawan_status_t LoRaWANStack::connect(const lorawan_connect_t &connect) 00168 { 00169 if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { 00170 return LORAWAN_STATUS_NOT_INITIALIZED; 00171 } 00172 00173 if (!(connect.connect_type == LORAWAN_CONNECTION_OTAA) 00174 && !(connect.connect_type == LORAWAN_CONNECTION_ABP)) { 00175 return LORAWAN_STATUS_PARAMETER_INVALID; 00176 } 00177 00178 bool is_otaa = (connect.connect_type == LORAWAN_CONNECTION_OTAA); 00179 00180 lorawan_status_t status = _loramac.prepare_join(&connect, is_otaa); 00181 00182 if (LORAWAN_STATUS_OK != status) { 00183 return status; 00184 } 00185 00186 return handle_connect(is_otaa); 00187 } 00188 00189 lorawan_status_t LoRaWANStack::add_channels(const lorawan_channelplan_t &channel_plan) 00190 { 00191 if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) { 00192 return LORAWAN_STATUS_NOT_INITIALIZED; 00193 } 00194 00195 return _loramac.add_channel_plan(channel_plan); 00196 } 00197 00198 lorawan_status_t LoRaWANStack::remove_a_channel(uint8_t channel_id) 00199 { 00200 if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) { 00201 return LORAWAN_STATUS_NOT_INITIALIZED; 00202 } 00203 00204 return _loramac.remove_single_channel(channel_id); 00205 } 00206 00207 lorawan_status_t LoRaWANStack::drop_channel_list() 00208 { 00209 if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) { 00210 return LORAWAN_STATUS_NOT_INITIALIZED; 00211 } 00212 00213 return _loramac.remove_channel_plan(); 00214 } 00215 00216 lorawan_status_t LoRaWANStack::get_enabled_channels(lorawan_channelplan_t &channel_plan) 00217 { 00218 if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) { 00219 return LORAWAN_STATUS_NOT_INITIALIZED; 00220 } 00221 00222 return _loramac.get_channel_plan(channel_plan); 00223 } 00224 00225 lorawan_status_t LoRaWANStack::set_confirmed_msg_retry(uint8_t count) 00226 { 00227 if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) { 00228 return LORAWAN_STATUS_NOT_INITIALIZED; 00229 } 00230 00231 if (count >= MAX_CONFIRMED_MSG_RETRIES) { 00232 return LORAWAN_STATUS_PARAMETER_INVALID; 00233 } 00234 00235 _num_retry = count; 00236 00237 return LORAWAN_STATUS_OK; 00238 } 00239 00240 lorawan_status_t LoRaWANStack::set_channel_data_rate(uint8_t data_rate) 00241 { 00242 if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { 00243 return LORAWAN_STATUS_NOT_INITIALIZED; 00244 } 00245 00246 return _loramac.set_channel_data_rate(data_rate); 00247 } 00248 00249 00250 lorawan_status_t LoRaWANStack::enable_adaptive_datarate(bool adr_enabled) 00251 { 00252 if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) { 00253 return LORAWAN_STATUS_NOT_INITIALIZED; 00254 } 00255 00256 _loramac.enable_adaptive_datarate(adr_enabled); 00257 return LORAWAN_STATUS_OK; 00258 } 00259 00260 lorawan_status_t LoRaWANStack::stop_sending(void) 00261 { 00262 if (_loramac.clear_tx_pipe() == LORAWAN_STATUS_OK) { 00263 if (_device_current_state == DEVICE_STATE_SENDING) { 00264 _ctrl_flags &= ~TX_DONE_FLAG; 00265 _ctrl_flags &= ~TX_ONGOING_FLAG; 00266 _loramac.set_tx_ongoing(false); 00267 _device_current_state = DEVICE_STATE_IDLE; 00268 return LORAWAN_STATUS_OK; 00269 } 00270 } 00271 00272 return LORAWAN_STATUS_BUSY; 00273 } 00274 00275 int16_t LoRaWANStack::handle_tx(const uint8_t port, const uint8_t *data, 00276 uint16_t length, uint8_t flags, 00277 bool null_allowed, bool allow_port_0) 00278 { 00279 if (!null_allowed && !data) { 00280 return LORAWAN_STATUS_PARAMETER_INVALID; 00281 } 00282 // add a link check request with normal data, until the application 00283 // explicitly removes it. 00284 if (_link_check_requested) { 00285 set_link_check_request(); 00286 } 00287 00288 if (!_lw_session.active) { 00289 return LORAWAN_STATUS_NO_ACTIVE_SESSIONS; 00290 } 00291 00292 if (_loramac.tx_ongoing()) { 00293 return LORAWAN_STATUS_WOULD_BLOCK; 00294 } 00295 00296 #if defined(LORAWAN_COMPLIANCE_TEST) 00297 if (_compliance_test.running) { 00298 return LORAWAN_STATUS_COMPLIANCE_TEST_ON; 00299 } 00300 #endif 00301 00302 lorawan_status_t status; 00303 00304 if (_loramac.nwk_joined() == false) { 00305 return LORAWAN_STATUS_NO_NETWORK_JOINED; 00306 } 00307 00308 status = set_application_port(port, allow_port_0); 00309 00310 if (status != LORAWAN_STATUS_OK) { 00311 tr_error("Illegal application port definition."); 00312 return status; 00313 } 00314 00315 // All the flags mutually exclusive. In addition to that MSG_MULTICAST_FLAG cannot be 00316 // used for uplink. 00317 switch (flags & MSG_FLAG_MASK) { 00318 case MSG_UNCONFIRMED_FLAG: 00319 case MSG_CONFIRMED_FLAG: 00320 case MSG_PROPRIETARY_FLAG: 00321 break; 00322 00323 default: 00324 tr_error("Invalid send flags"); 00325 return LORAWAN_STATUS_PARAMETER_INVALID; 00326 } 00327 00328 int16_t len = _loramac.prepare_ongoing_tx(port, data, length, flags, _num_retry); 00329 00330 status = state_controller(DEVICE_STATE_SCHEDULING); 00331 00332 // send user the length of data which is scheduled now. 00333 // user should take care of the pending data. 00334 return (status == LORAWAN_STATUS_OK) ? len : (int16_t) status; 00335 } 00336 00337 int16_t LoRaWANStack::handle_rx(uint8_t *data, uint16_t length, uint8_t &port, int &flags, bool validate_params) 00338 { 00339 if (!_lw_session.active) { 00340 return LORAWAN_STATUS_NO_ACTIVE_SESSIONS; 00341 } 00342 00343 // No messages to read. 00344 if (!_rx_msg.receive_ready) { 00345 return LORAWAN_STATUS_WOULD_BLOCK; 00346 } 00347 00348 #if defined(LORAWAN_COMPLIANCE_TEST) 00349 if (_compliance_test.running) { 00350 return LORAWAN_STATUS_COMPLIANCE_TEST_ON; 00351 } 00352 #endif 00353 00354 if (data == NULL || length == 0) { 00355 return LORAWAN_STATUS_PARAMETER_INVALID; 00356 } 00357 00358 int received_flags = convert_to_msg_flag(_rx_msg.msg.mcps_indication.type); 00359 if (validate_params) { 00360 // Check received message port and flags match with the ones requested by user 00361 received_flags &= MSG_FLAG_MASK; 00362 00363 if (_rx_msg.msg.mcps_indication.port != port || !(flags & received_flags)) { 00364 return LORAWAN_STATUS_WOULD_BLOCK; 00365 } 00366 } 00367 00368 // Report values back to user 00369 port = _rx_msg.msg.mcps_indication.port; 00370 flags = received_flags; 00371 00372 const uint8_t *base_ptr = _rx_msg.msg.mcps_indication.buffer; 00373 uint16_t base_size = _rx_msg.msg.mcps_indication.buffer_size; 00374 bool read_complete = false; 00375 00376 // check the length of received message whether we can fit into user 00377 // buffer completely or not 00378 if (_rx_msg.msg.mcps_indication.buffer_size > length 00379 && _rx_msg.prev_read_size == 0) { 00380 // we can't fit into user buffer. Invoke counter measures 00381 _rx_msg.pending_size = _rx_msg.msg.mcps_indication.buffer_size - length; 00382 base_size = length; 00383 _rx_msg.prev_read_size = base_size; 00384 memcpy(data, base_ptr, base_size); 00385 } else if (_rx_msg.prev_read_size == 0) { 00386 _rx_msg.pending_size = 0; 00387 _rx_msg.prev_read_size = 0; 00388 memcpy(data, base_ptr, base_size); 00389 read_complete = true; 00390 } 00391 00392 // If its the pending read then we should copy only the remaining part of 00393 // the buffer. Due to checks above, in case of a pending read, this block 00394 // will be the only one to get invoked 00395 if (_rx_msg.pending_size > 0 && _rx_msg.prev_read_size > 0) { 00396 memcpy(data, base_ptr + _rx_msg.prev_read_size, base_size); 00397 } 00398 00399 // we are done handing over received buffer to user. check if there is 00400 // anything pending. If not, memset the buffer to zero and indicate 00401 // that no read is in progress 00402 if (read_complete) { 00403 _rx_msg.msg.mcps_indication.buffer = NULL; 00404 _rx_msg.msg.mcps_indication.buffer_size = 0; 00405 _rx_msg.receive_ready = false; 00406 } 00407 00408 return base_size; 00409 } 00410 00411 lorawan_status_t LoRaWANStack::set_link_check_request() 00412 { 00413 if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { 00414 return LORAWAN_STATUS_NOT_INITIALIZED; 00415 } 00416 00417 _link_check_requested = true; 00418 if (!_callbacks.link_check_resp) { 00419 tr_error("Must assign a callback function for link check request. "); 00420 return LORAWAN_STATUS_PARAMETER_INVALID; 00421 } 00422 00423 _loramac.setup_link_check_request(); 00424 return LORAWAN_STATUS_OK; 00425 } 00426 00427 void LoRaWANStack::remove_link_check_request() 00428 { 00429 _link_check_requested = false; 00430 } 00431 00432 lorawan_status_t LoRaWANStack::shutdown() 00433 { 00434 if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { 00435 return LORAWAN_STATUS_NOT_INITIALIZED; 00436 } 00437 00438 return state_controller(DEVICE_STATE_SHUTDOWN); 00439 } 00440 00441 lorawan_status_t LoRaWANStack::set_device_class(const device_class_t &device_class) 00442 { 00443 if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { 00444 return LORAWAN_STATUS_NOT_INITIALIZED; 00445 } 00446 00447 if (device_class == CLASS_B) { 00448 return LORAWAN_STATUS_UNSUPPORTED; 00449 } 00450 _loramac.set_device_class(device_class, mbed::callback(this, &LoRaWANStack::handle_ack_expiry_for_class_c)); 00451 return LORAWAN_STATUS_OK; 00452 } 00453 00454 lorawan_status_t LoRaWANStack::acquire_tx_metadata(lorawan_tx_metadata &tx_metadata) 00455 { 00456 if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { 00457 return LORAWAN_STATUS_NOT_INITIALIZED; 00458 } 00459 00460 if (!_tx_metadata.stale) { 00461 tx_metadata = _tx_metadata; 00462 _tx_metadata.stale = true; 00463 return LORAWAN_STATUS_OK; 00464 } 00465 00466 return LORAWAN_STATUS_METADATA_NOT_AVAILABLE; 00467 } 00468 00469 lorawan_status_t LoRaWANStack::acquire_rx_metadata(lorawan_rx_metadata &metadata) 00470 { 00471 if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { 00472 return LORAWAN_STATUS_NOT_INITIALIZED; 00473 } 00474 00475 if (!_rx_metadata.stale) { 00476 metadata = _rx_metadata; 00477 _rx_metadata.stale = true; 00478 return LORAWAN_STATUS_OK; 00479 } 00480 00481 return LORAWAN_STATUS_METADATA_NOT_AVAILABLE; 00482 } 00483 00484 lorawan_status_t LoRaWANStack::acquire_backoff_metadata(int &backoff) 00485 { 00486 if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { 00487 return LORAWAN_STATUS_NOT_INITIALIZED; 00488 } 00489 00490 int id = _loramac.get_backoff_timer_event_id(); 00491 00492 if (_loramac.get_backoff_timer_event_id() > 0) { 00493 backoff = _queue->time_left(id); 00494 return LORAWAN_STATUS_OK; 00495 } 00496 00497 backoff = -1; 00498 return LORAWAN_STATUS_METADATA_NOT_AVAILABLE; 00499 } 00500 00501 /***************************************************************************** 00502 * Interrupt handlers * 00503 ****************************************************************************/ 00504 void LoRaWANStack::tx_interrupt_handler(void) 00505 { 00506 _tx_timestamp = _loramac.get_current_time(); 00507 const int ret = _queue->call(this, &LoRaWANStack::process_transmission); 00508 MBED_ASSERT(ret != 0); 00509 (void)ret; 00510 } 00511 00512 void LoRaWANStack::rx_interrupt_handler(const uint8_t *payload, uint16_t size, 00513 int16_t rssi, int8_t snr) 00514 { 00515 if (!_ready_for_rx || size > sizeof _rx_payload) { 00516 return; 00517 } 00518 00519 _ready_for_rx = false; 00520 memcpy(_rx_payload, payload, size); 00521 00522 const uint8_t *ptr = _rx_payload; 00523 const int ret = _queue->call(this, &LoRaWANStack::process_reception, 00524 ptr, size, rssi, snr); 00525 MBED_ASSERT(ret != 0); 00526 (void)ret; 00527 } 00528 00529 void LoRaWANStack::rx_error_interrupt_handler(void) 00530 { 00531 const int ret = _queue->call(this, &LoRaWANStack::process_reception_timeout, 00532 false); 00533 MBED_ASSERT(ret != 0); 00534 (void)ret; 00535 } 00536 00537 void LoRaWANStack::tx_timeout_interrupt_handler(void) 00538 { 00539 const int ret = _queue->call(this, &LoRaWANStack::process_transmission_timeout); 00540 MBED_ASSERT(ret != 0); 00541 (void)ret; 00542 } 00543 00544 void LoRaWANStack::rx_timeout_interrupt_handler(void) 00545 { 00546 const int ret = _queue->call(this, &LoRaWANStack::process_reception_timeout, 00547 true); 00548 MBED_ASSERT(ret != 0); 00549 (void)ret; 00550 } 00551 00552 /***************************************************************************** 00553 * Processors for deferred interrupts * 00554 ****************************************************************************/ 00555 void LoRaWANStack::process_transmission_timeout() 00556 { 00557 // this is a fatal error and should not happen 00558 tr_debug("TX Timeout"); 00559 _loramac.on_radio_tx_timeout(); 00560 _ctrl_flags |= TX_ONGOING_FLAG; 00561 _ctrl_flags &= ~TX_DONE_FLAG; 00562 state_controller(DEVICE_STATE_STATUS_CHECK); 00563 state_machine_run_to_completion(); 00564 } 00565 00566 void LoRaWANStack::process_transmission(void) 00567 { 00568 tr_debug("Transmission completed"); 00569 _loramac.on_radio_tx_done(_tx_timestamp); 00570 00571 make_tx_metadata_available(); 00572 00573 if (_device_current_state == DEVICE_STATE_JOINING) { 00574 _device_current_state = DEVICE_STATE_AWAITING_JOIN_ACCEPT; 00575 } 00576 00577 if (_device_current_state == DEVICE_STATE_SENDING) { 00578 if (_loramac.get_mcps_confirmation()->req_type == MCPS_CONFIRMED ) { 00579 _ctrl_flags |= TX_ONGOING_FLAG; 00580 _ctrl_flags &= ~TX_DONE_FLAG; 00581 tr_debug("Awaiting ACK"); 00582 _device_current_state = DEVICE_STATE_AWAITING_ACK; 00583 return; 00584 } 00585 00586 // Class A unconfirmed message sent, TX_DONE event will be sent to 00587 // application when RX2 windows is elapsed, i.e., in process_reception_timeout() 00588 _ctrl_flags &= ~TX_ONGOING_FLAG; 00589 _ctrl_flags |= TX_DONE_FLAG; 00590 00591 // In Class C, reception timeout never happens, so we handle the state 00592 // progression for TX_DONE in UNCONFIRMED case here 00593 if (_loramac.get_device_class() == CLASS_C) { 00594 _loramac.post_process_mcps_req(); 00595 state_controller(DEVICE_STATE_STATUS_CHECK); 00596 state_machine_run_to_completion(); 00597 } 00598 } 00599 } 00600 00601 void LoRaWANStack::handle_ack_expiry_for_class_c(void) 00602 { 00603 _ctrl_flags &= ~TX_DONE_FLAG; 00604 _ctrl_flags |= TX_ONGOING_FLAG; 00605 tr_error("Retries exhausted for Class C device"); 00606 state_controller(DEVICE_STATE_STATUS_CHECK); 00607 } 00608 00609 void LoRaWANStack::process_reception(const uint8_t *const payload, uint16_t size, 00610 int16_t rssi, int8_t snr) 00611 { 00612 _device_current_state = DEVICE_STATE_RECEIVING; 00613 _ctrl_flags &= ~MSG_RECVD_FLAG; 00614 00615 _loramac.on_radio_rx_done(payload, size, rssi, snr); 00616 00617 make_rx_metadata_available(); 00618 00619 if (_loramac.get_mlme_confirmation()->pending) { 00620 _loramac.post_process_mlme_request(); 00621 mlme_confirm_handler(); 00622 } 00623 00624 if (!_loramac.nwk_joined()) { 00625 return; 00626 } 00627 00628 // if the outgoing message was of CONFIRMED type 00629 if (_loramac.get_mcps_confirmation()->req_type == MCPS_CONFIRMED ) { 00630 // if ack was not received, we will try retransmission after 00631 // ACK_TIMEOUT. handle_data_frame() already disables ACK_TIMEOUT timer 00632 // if ack was received. Otherwise, following method will be called in 00633 // LoRaMac.cpp, on_ack_timeout_timer_event(). 00634 if (_loramac.get_mcps_indication()->is_ack_recvd) { 00635 tr_debug("Ack=OK, NbTrials=%d", 00636 _loramac.get_mcps_confirmation()->nb_retries); 00637 _loramac.post_process_mcps_req(); 00638 _ctrl_flags |= TX_DONE_FLAG; 00639 _ctrl_flags &= ~TX_ONGOING_FLAG; 00640 state_controller(DEVICE_STATE_STATUS_CHECK); 00641 } else { 00642 if (!_loramac.continue_sending_process()) { 00643 tr_error("Retries exhausted for Class A device"); 00644 _ctrl_flags &= ~TX_DONE_FLAG; 00645 _ctrl_flags |= TX_ONGOING_FLAG; 00646 state_controller(DEVICE_STATE_STATUS_CHECK); 00647 } 00648 } 00649 } else { 00650 // handle UNCONFIRMED case here, RX slots were turned off due to 00651 // valid packet reception 00652 _loramac.post_process_mcps_req(); 00653 _ctrl_flags |= TX_DONE_FLAG; 00654 state_controller(DEVICE_STATE_STATUS_CHECK); 00655 } 00656 00657 // handle any pending MCPS indication 00658 if (_loramac.get_mcps_indication()->pending) { 00659 _loramac.post_process_mcps_ind(); 00660 _ctrl_flags |= MSG_RECVD_FLAG; 00661 state_controller(DEVICE_STATE_STATUS_CHECK); 00662 } 00663 00664 // change the state only if a TX cycle completes for Class A 00665 // For class C it's not needed as it will already be in receiving 00666 // state, no matter if the TX cycle completed or not. 00667 if (!(_ctrl_flags & TX_ONGOING_FLAG)) { 00668 // we are done here, update the state 00669 state_machine_run_to_completion(); 00670 } 00671 00672 if (_loramac.get_mlme_indication()->pending) { 00673 tr_debug("MLME Indication pending"); 00674 _loramac.post_process_mlme_ind(); 00675 tr_debug("Immediate Uplink requested"); 00676 mlme_indication_handler(); 00677 } 00678 00679 _ready_for_rx = true; 00680 } 00681 00682 void LoRaWANStack::process_reception_timeout(bool is_timeout) 00683 { 00684 rx_slot_t slot = _loramac.get_current_slot(); 00685 00686 // when is_timeout == false, a CRC error took place in the received frame 00687 // we treat that erroneous frame as no frame received at all, hence handle 00688 // it exactly as we would handle timeout 00689 _loramac.on_radio_rx_timeout(is_timeout); 00690 00691 if (slot == RX_SLOT_WIN_2 && !_loramac.nwk_joined()) { 00692 state_controller(DEVICE_STATE_JOINING); 00693 return; 00694 } 00695 00696 /** 00697 * LoRaWAN Specification 1.0.2. Section 3.3.6 00698 * Main point: 00699 * We indicate successful transmission 00700 * of UNCONFIRMED message after RX windows are done with. 00701 * For a CONFIRMED message, it means that we have not received 00702 * ack (actually nothing was received), and we should retransmit if we can. 00703 * 00704 * NOTE: This code block doesn't get hit for Class C as in Class C, RX2 timeout 00705 * never occurs. 00706 */ 00707 if (slot == RX_SLOT_WIN_2 ) { 00708 _loramac.post_process_mcps_req(); 00709 00710 if (_loramac.get_mcps_confirmation()->req_type == MCPS_CONFIRMED ) { 00711 if (_loramac.continue_sending_process()) { 00712 return; 00713 } else { 00714 tr_error("Retries exhausted for Class A device"); 00715 } 00716 } 00717 00718 state_controller(DEVICE_STATE_STATUS_CHECK); 00719 state_machine_run_to_completion(); 00720 } 00721 } 00722 00723 /***************************************************************************** 00724 * Private methods * 00725 ****************************************************************************/ 00726 void LoRaWANStack::make_tx_metadata_available(void) 00727 { 00728 _tx_metadata.stale = false; 00729 _tx_metadata.channel = _loramac.get_mcps_confirmation()->channel; 00730 _tx_metadata.data_rate = _loramac.get_mcps_confirmation()->data_rate; 00731 _tx_metadata.tx_power = _loramac.get_mcps_confirmation()->tx_power; 00732 _tx_metadata.tx_toa = _loramac.get_mcps_confirmation()->tx_toa; 00733 _tx_metadata.nb_retries = _loramac.get_mcps_confirmation()->nb_retries; 00734 } 00735 00736 void LoRaWANStack::make_rx_metadata_available(void) 00737 { 00738 _rx_metadata.stale = false; 00739 _rx_metadata.rx_datarate = _loramac.get_mcps_indication()->rx_datarate; 00740 _rx_metadata.rssi = _loramac.get_mcps_indication()->rssi; 00741 _rx_metadata.snr = _loramac.get_mcps_indication()->snr; 00742 } 00743 00744 bool LoRaWANStack::is_port_valid(const uint8_t port, bool allow_port_0) 00745 { 00746 //Application should not use reserved and illegal port numbers. 00747 if (port == 0) { 00748 return allow_port_0; 00749 } else { 00750 return true; 00751 } 00752 } 00753 00754 lorawan_status_t LoRaWANStack::set_application_port(const uint8_t port, bool allow_port_0) 00755 { 00756 if (is_port_valid(port, allow_port_0)) { 00757 _app_port = port; 00758 return LORAWAN_STATUS_OK; 00759 } 00760 00761 return LORAWAN_STATUS_PORT_INVALID; 00762 } 00763 00764 void LoRaWANStack::state_machine_run_to_completion() 00765 { 00766 if (_loramac.get_device_class() == CLASS_C) { 00767 _device_current_state = DEVICE_STATE_RECEIVING; 00768 return; 00769 } 00770 00771 _device_current_state = DEVICE_STATE_IDLE; 00772 } 00773 00774 void LoRaWANStack::send_event_to_application(const lorawan_event_t event) const 00775 { 00776 if (_callbacks.events) { 00777 const int ret = _queue->call(_callbacks.events, event); 00778 MBED_ASSERT(ret != 0); 00779 (void)ret; 00780 } 00781 } 00782 00783 void LoRaWANStack::send_automatic_uplink_message(const uint8_t port) 00784 { 00785 const int16_t ret = handle_tx(port, NULL, 0, MSG_CONFIRMED_FLAG, true, true); 00786 if (ret < 0) { 00787 tr_debug("Failed to generate AUTOMATIC UPLINK, error code = %d", ret); 00788 send_event_to_application(AUTOMATIC_UPLINK_ERROR); 00789 } 00790 } 00791 00792 int LoRaWANStack::convert_to_msg_flag(const mcps_type_t type) 00793 { 00794 int msg_flag = MSG_UNCONFIRMED_FLAG; 00795 switch (type) { 00796 case MCPS_UNCONFIRMED : 00797 msg_flag = MSG_UNCONFIRMED_FLAG; 00798 break; 00799 00800 case MCPS_CONFIRMED : 00801 msg_flag = MSG_CONFIRMED_FLAG; 00802 break; 00803 00804 case MCPS_MULTICAST : 00805 msg_flag = MSG_MULTICAST_FLAG; 00806 break; 00807 00808 case MCPS_PROPRIETARY : 00809 msg_flag = MSG_PROPRIETARY_FLAG; 00810 break; 00811 00812 default: 00813 tr_error("Unknown message type!"); 00814 MBED_ASSERT(0); 00815 } 00816 00817 return msg_flag; 00818 } 00819 00820 lorawan_status_t LoRaWANStack::handle_connect(bool is_otaa) 00821 { 00822 if (is_otaa) { 00823 tr_debug("Initiating OTAA"); 00824 00825 // In 1.0.2 spec, counters are always set to zero for new connection. 00826 // This section is common for both normal and 00827 // connection restore at this moment. Will change in future with 1.1 support. 00828 _lw_session.downlink_counter = 0; 00829 _lw_session.uplink_counter = 0; 00830 _ctrl_flags |= USING_OTAA_FLAG; 00831 } else { 00832 // If current state is SHUTDOWN, device may be trying to re-establish 00833 // communication. In case of ABP specification is meddled about frame counters. 00834 // It says to reset counters to zero but there is no mechanism to tell the 00835 // network server that the device was disconnected or restarted. 00836 // At the moment, this implementation does not support a non-volatile 00837 // memory storage. 00838 //_lw_session.downlink_counter; //Get from NVM 00839 //_lw_session.uplink_counter; //Get from NVM 00840 00841 tr_debug("Initiating ABP"); 00842 tr_debug("Frame Counters. UpCnt=%lu, DownCnt=%lu", 00843 _lw_session.uplink_counter, _lw_session.downlink_counter); 00844 _ctrl_flags &= ~USING_OTAA_FLAG; 00845 } 00846 00847 return state_controller(DEVICE_STATE_CONNECTING); 00848 } 00849 00850 void LoRaWANStack::mlme_indication_handler() 00851 { 00852 if (_loramac.get_mlme_indication()->indication_type == MLME_SCHEDULE_UPLINK ) { 00853 // The MAC signals that we shall provide an uplink as soon as possible 00854 #if MBED_CONF_LORA_AUTOMATIC_UPLINK_MESSAGE 00855 _automatic_uplink_ongoing = true; 00856 tr_debug("mlme indication: sending empty uplink to port 0 to acknowledge MAC commands..."); 00857 const uint8_t port = 0; 00858 const int ret = _queue->call(this, &LoRaWANStack::send_automatic_uplink_message, port); 00859 MBED_ASSERT(ret != 0); 00860 (void)ret; 00861 #else 00862 send_event_to_application(UPLINK_REQUIRED); 00863 #endif 00864 return; 00865 } 00866 00867 tr_error("Unknown MLME Indication type."); 00868 } 00869 00870 void LoRaWANStack::mlme_confirm_handler() 00871 { 00872 if (_loramac.get_mlme_confirmation()->req_type == MLME_LINK_CHECK ) { 00873 if (_loramac.get_mlme_confirmation()->status == LORAMAC_EVENT_INFO_STATUS_OK ) { 00874 #if defined(LORAWAN_COMPLIANCE_TEST) 00875 if (_compliance_test.running == true) { 00876 _compliance_test.link_check = true; 00877 _compliance_test.demod_margin = _loramac.get_mlme_confirmation()->demod_margin; 00878 _compliance_test.nb_gateways = _loramac.get_mlme_confirmation()->nb_gateways; 00879 } else 00880 #endif 00881 { 00882 if (_callbacks.link_check_resp) { 00883 const int ret = _queue->call(_callbacks.link_check_resp, 00884 _loramac.get_mlme_confirmation()->demod_margin, 00885 _loramac.get_mlme_confirmation()->nb_gateways); 00886 MBED_ASSERT(ret != 0); 00887 (void)ret; 00888 } 00889 } 00890 } 00891 } else if (_loramac.get_mlme_confirmation()->req_type == MLME_JOIN ) { 00892 if (_loramac.get_mlme_confirmation()->status == LORAMAC_EVENT_INFO_STATUS_OK ) { 00893 state_controller(DEVICE_STATE_CONNECTED); 00894 } else { 00895 tr_error("Joining error: %d", _loramac.get_mlme_confirmation()->status); 00896 if (_loramac.get_mlme_confirmation()->status == LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL ) { 00897 // fatal error 00898 _device_current_state = DEVICE_STATE_IDLE; 00899 send_event_to_application(CRYPTO_ERROR); 00900 } else { 00901 // non-fatal, retry if possible 00902 _device_current_state = DEVICE_STATE_AWAITING_JOIN_ACCEPT; 00903 state_controller(DEVICE_STATE_JOINING); 00904 } 00905 00906 } 00907 } 00908 } 00909 00910 void LoRaWANStack::mcps_confirm_handler() 00911 { 00912 // success case 00913 if (_loramac.get_mcps_confirmation()->status == LORAMAC_EVENT_INFO_STATUS_OK ) { 00914 _lw_session.uplink_counter = _loramac.get_mcps_confirmation()->ul_frame_counter; 00915 send_event_to_application(TX_DONE); 00916 return; 00917 } 00918 00919 // failure case 00920 tr_error("mcps_confirmation: Error code = %d", _loramac.get_mcps_confirmation()->status); 00921 00922 if (_loramac.get_mcps_confirmation()->status == LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT ) { 00923 send_event_to_application(TX_TIMEOUT); 00924 return; 00925 } 00926 00927 // if no ack was received, send TX_ERROR 00928 send_event_to_application(TX_ERROR); 00929 } 00930 00931 void LoRaWANStack::mcps_indication_handler() 00932 { 00933 const loramac_mcps_indication_t *mcps_indication = _loramac.get_mcps_indication(); 00934 if (mcps_indication->status != LORAMAC_EVENT_INFO_STATUS_OK ) { 00935 tr_error("RX_ERROR: mcps_indication status = %d", mcps_indication->status ); 00936 send_event_to_application(RX_ERROR); 00937 return; 00938 } 00939 00940 _lw_session.downlink_counter = mcps_indication->dl_frame_counter ; 00941 00942 #if defined(LORAWAN_COMPLIANCE_TEST) 00943 if (_compliance_test.running == true) { 00944 _compliance_test.downlink_counter++; 00945 } 00946 #endif 00947 00948 if (mcps_indication->port == 224) { 00949 #if defined(LORAWAN_COMPLIANCE_TEST) 00950 tr_debug("Compliance test command received."); 00951 compliance_test_handler(mcps_indication); 00952 #else 00953 tr_info("Compliance test disabled."); 00954 #endif 00955 } else { 00956 if (mcps_indication->is_data_recvd ) { 00957 // Valid message arrived. 00958 _rx_msg.type = LORAMAC_RX_MCPS_INDICATION; 00959 _rx_msg.msg.mcps_indication.buffer_size = mcps_indication->buffer_size ; 00960 _rx_msg.msg.mcps_indication.port = mcps_indication->port ; 00961 _rx_msg.msg.mcps_indication.buffer = mcps_indication->buffer ; 00962 _rx_msg.msg.mcps_indication.type = mcps_indication->type ; 00963 00964 // Notify application about received frame.. 00965 tr_debug("Packet Received %d bytes, Port=%d", 00966 _rx_msg.msg.mcps_indication.buffer_size, 00967 mcps_indication->port ); 00968 _rx_msg.receive_ready = true; 00969 send_event_to_application(RX_DONE); 00970 } 00971 00972 /* 00973 * If fPending bit is set we try to generate an empty packet 00974 * with CONFIRMED flag set. We always set a CONFIRMED flag so 00975 * that we could retry a certain number of times if the uplink 00976 * failed for some reason 00977 * or 00978 * Class C and node received a confirmed message so we need to 00979 * send an empty packet to acknowledge the message. 00980 * This scenario is unspecified by LoRaWAN 1.0.2 specification, 00981 * but version 1.1.0 says that network SHALL not send any new 00982 * confirmed messages until ack has been sent 00983 */ 00984 if ((_loramac.get_device_class() != CLASS_C && mcps_indication->fpending_status ) 00985 || 00986 (_loramac.get_device_class() == CLASS_C && mcps_indication->type == MCPS_CONFIRMED )) { 00987 #if (MBED_CONF_LORA_AUTOMATIC_UPLINK_MESSAGE) 00988 tr_debug("Sending empty uplink message..."); 00989 _automatic_uplink_ongoing = true; 00990 const int ret = _queue->call(this, &LoRaWANStack::send_automatic_uplink_message, mcps_indication->port ); 00991 MBED_ASSERT(ret != 0); 00992 (void)ret; 00993 #else 00994 send_event_to_application(UPLINK_REQUIRED); 00995 #endif 00996 } 00997 } 00998 } 00999 01000 lorawan_status_t LoRaWANStack::state_controller(device_states_t new_state) 01001 { 01002 lorawan_status_t status = LORAWAN_STATUS_OK; 01003 01004 switch (new_state) { 01005 case DEVICE_STATE_IDLE: 01006 process_idle_state(status); 01007 break; 01008 case DEVICE_STATE_CONNECTING: 01009 process_connecting_state(status); 01010 break; 01011 case DEVICE_STATE_JOINING: 01012 process_joining_state(status); 01013 break; 01014 case DEVICE_STATE_CONNECTED: 01015 process_connected_state(); 01016 break; 01017 case DEVICE_STATE_SCHEDULING: 01018 process_scheduling_state(status); 01019 break; 01020 case DEVICE_STATE_STATUS_CHECK: 01021 process_status_check_state(); 01022 break; 01023 case DEVICE_STATE_SHUTDOWN: 01024 process_shutdown_state(status); 01025 break; 01026 default: 01027 tr_debug("state_controller: Unknown state!"); 01028 status = LORAWAN_STATUS_SERVICE_UNKNOWN; 01029 break; 01030 } 01031 01032 return status; 01033 } 01034 01035 void LoRaWANStack::process_shutdown_state(lorawan_status_t &op_status) 01036 { 01037 /** 01038 * Remove channels 01039 * Radio will be put to sleep by the APIs underneath 01040 */ 01041 drop_channel_list(); 01042 _loramac.disconnect(); 01043 _lw_session.active = false; 01044 _device_current_state = DEVICE_STATE_SHUTDOWN; 01045 op_status = LORAWAN_STATUS_DEVICE_OFF; 01046 _ctrl_flags &= ~CONNECTED_FLAG; 01047 send_event_to_application(DISCONNECTED); 01048 } 01049 01050 void LoRaWANStack::process_status_check_state() 01051 { 01052 if (_device_current_state == DEVICE_STATE_SENDING || 01053 _device_current_state == DEVICE_STATE_AWAITING_ACK) { 01054 // this happens after RX2 slot is exhausted 01055 // we may or may not have a successful UNCONFIRMED transmission 01056 // here. In CONFIRMED case this block is invoked only 01057 // when the MAX number of retries are exhausted, i.e., only error 01058 // case will fall here. Moreover, it will happen for Class A only. 01059 _ctrl_flags &= ~TX_DONE_FLAG; 01060 _ctrl_flags &= ~TX_ONGOING_FLAG; 01061 _loramac.set_tx_ongoing(false); 01062 _loramac.reset_ongoing_tx(); 01063 mcps_confirm_handler(); 01064 01065 } else if (_device_current_state == DEVICE_STATE_RECEIVING) { 01066 01067 if ((_ctrl_flags & TX_DONE_FLAG) || (_ctrl_flags & TX_ONGOING_FLAG)) { 01068 // for CONFIRMED case, ack validity is already checked 01069 // If it was a successful transmission, TX_ONGOING_FLAG will not be set. 01070 // If it was indeed set, that means the device was in Class C mode and 01071 // CONFIRMED transmission was in place and the ack retries maxed out. 01072 _ctrl_flags &= ~TX_DONE_FLAG; 01073 _ctrl_flags &= ~TX_ONGOING_FLAG; 01074 _loramac.set_tx_ongoing(false); 01075 _loramac.reset_ongoing_tx(); 01076 // if an automatic uplink is ongoing, we should not send a TX_DONE 01077 // event to application 01078 if (_automatic_uplink_ongoing) { 01079 _automatic_uplink_ongoing = false; 01080 } else { 01081 mcps_confirm_handler(); 01082 } 01083 } 01084 01085 // handle any received data and send event accordingly 01086 if (_ctrl_flags & MSG_RECVD_FLAG) { 01087 _ctrl_flags &= ~MSG_RECVD_FLAG; 01088 mcps_indication_handler(); 01089 } 01090 } 01091 } 01092 01093 void LoRaWANStack::process_scheduling_state(lorawan_status_t &op_status) 01094 { 01095 if (_device_current_state != DEVICE_STATE_IDLE) { 01096 if (_device_current_state != DEVICE_STATE_RECEIVING 01097 && _loramac.get_device_class() != CLASS_C) { 01098 op_status = LORAWAN_STATUS_BUSY; 01099 return; 01100 } 01101 } 01102 01103 op_status = _loramac.send_ongoing_tx(); 01104 if (op_status == LORAWAN_STATUS_OK) { 01105 _ctrl_flags |= TX_ONGOING_FLAG; 01106 _ctrl_flags &= ~TX_DONE_FLAG; 01107 _loramac.set_tx_ongoing(true); 01108 _device_current_state = DEVICE_STATE_SENDING; 01109 } 01110 } 01111 01112 void LoRaWANStack::process_joining_state(lorawan_status_t &op_status) 01113 { 01114 if (_device_current_state == DEVICE_STATE_CONNECTING) { 01115 _device_current_state = DEVICE_STATE_JOINING; 01116 tr_debug("Sending Join Request ..."); 01117 op_status = _loramac.join(true); 01118 return; 01119 } 01120 01121 if (_device_current_state == DEVICE_STATE_AWAITING_JOIN_ACCEPT) { 01122 _device_current_state = DEVICE_STATE_JOINING; 01123 // retry join 01124 bool can_continue = _loramac.continue_joining_process(); 01125 01126 if (!can_continue) { 01127 send_event_to_application(JOIN_FAILURE); 01128 _device_current_state = DEVICE_STATE_IDLE; 01129 return; 01130 } 01131 } 01132 } 01133 01134 void LoRaWANStack::process_connected_state() 01135 { 01136 if (_ctrl_flags & USING_OTAA_FLAG) { 01137 tr_debug("OTAA Connection OK!"); 01138 } 01139 01140 _lw_session.active = true; 01141 send_event_to_application(CONNECTED); 01142 _ctrl_flags |= CONNECTED_FLAG; 01143 01144 _device_current_state = DEVICE_STATE_IDLE; 01145 } 01146 01147 void LoRaWANStack::process_connecting_state(lorawan_status_t &op_status) 01148 { 01149 if (_device_current_state != DEVICE_STATE_IDLE 01150 && _device_current_state != DEVICE_STATE_SHUTDOWN) { 01151 op_status = LORAWAN_STATUS_BUSY; 01152 return; 01153 } 01154 01155 if (_ctrl_flags & CONNECTED_FLAG) { 01156 tr_debug("Already connected"); 01157 op_status = LORAWAN_STATUS_OK; 01158 return; 01159 } 01160 01161 _device_current_state = DEVICE_STATE_CONNECTING; 01162 01163 if (_ctrl_flags & USING_OTAA_FLAG) { 01164 process_joining_state(op_status); 01165 return; 01166 } 01167 01168 op_status = _loramac.join(false); 01169 tr_debug("ABP connection OK."); 01170 process_connected_state(); 01171 } 01172 01173 void LoRaWANStack::process_idle_state(lorawan_status_t &op_status) 01174 { 01175 if (_device_current_state == DEVICE_STATE_NOT_INITIALIZED) { 01176 _device_current_state = DEVICE_STATE_IDLE; 01177 process_uninitialized_state(op_status); 01178 return; 01179 } 01180 01181 _device_current_state = DEVICE_STATE_IDLE; 01182 op_status = LORAWAN_STATUS_OK; 01183 } 01184 01185 void LoRaWANStack::process_uninitialized_state(lorawan_status_t &op_status) 01186 { 01187 op_status = _loramac.initialize(_queue); 01188 01189 if (op_status == LORAWAN_STATUS_OK) { 01190 _device_current_state = DEVICE_STATE_IDLE; 01191 } 01192 } 01193 01194 #if defined(LORAWAN_COMPLIANCE_TEST) 01195 01196 lorawan_status_t LoRaWANStack::send_compliance_test_frame_to_mac() 01197 { 01198 loramac_compliance_test_req_t test_req; 01199 01200 //TODO: What if the port is not 224 ??? 01201 if (_compliance_test.app_port == 224) { 01202 // Clear any normal message stuff before compliance test. 01203 memset(&test_req, 0, sizeof(test_req)); 01204 01205 if (_compliance_test.link_check == true) { 01206 _compliance_test.link_check = false; 01207 _compliance_test.state = 1; 01208 test_req.f_buffer_size = 3; 01209 test_req.f_buffer[0] = 5; 01210 test_req.f_buffer[1] = _compliance_test.demod_margin; 01211 test_req.f_buffer[2] = _compliance_test.nb_gateways; 01212 } else { 01213 switch (_compliance_test.state) { 01214 case 4: 01215 _compliance_test.state = 1; 01216 test_req.f_buffer_size = _compliance_test.app_data_size; 01217 test_req.f_buffer[0] = _compliance_test.app_data_buffer[0]; 01218 for (uint8_t i = 1; i < MIN(_compliance_test.app_data_size, MBED_CONF_LORA_TX_MAX_SIZE); ++i) { 01219 test_req.f_buffer[i] = _compliance_test.app_data_buffer[i]; 01220 } 01221 break; 01222 case 1: 01223 test_req.f_buffer_size = 2; 01224 test_req.f_buffer[0] = _compliance_test.downlink_counter >> 8; 01225 test_req.f_buffer[1] = _compliance_test.downlink_counter; 01226 break; 01227 } 01228 } 01229 } 01230 01231 //TODO: If port is not 224, this might not work! 01232 //Is there a test case where same _tx_msg's buffer would be used, when port is not 224??? 01233 if (!_compliance_test.is_tx_confirmed) { 01234 test_req.type = MCPS_UNCONFIRMED ; 01235 test_req.fport = _compliance_test.app_port; 01236 test_req.nb_trials = 1; 01237 test_req.data_rate = _loramac.get_default_tx_datarate(); 01238 01239 tr_info("Transmit unconfirmed compliance test frame %d bytes.", test_req.f_buffer_size); 01240 01241 for (uint8_t i = 0; i < test_req.f_buffer_size; ++i) { 01242 tr_info("Byte %d, data is 0x%x", i + 1, ((uint8_t *)test_req.f_buffer)[i]); 01243 } 01244 } else if (_compliance_test.is_tx_confirmed) { 01245 test_req.type = MCPS_CONFIRMED ; 01246 test_req.fport = _compliance_test.app_port; 01247 test_req.nb_trials = _num_retry; 01248 test_req.data_rate = _loramac.get_default_tx_datarate(); 01249 01250 tr_info("Transmit confirmed compliance test frame %d bytes.", test_req.f_buffer_size); 01251 01252 for (uint8_t i = 0; i < test_req.f_buffer_size; ++i) { 01253 tr_info("Byte %d, data is 0x%x", i + 1, ((uint8_t *)test_req.f_buffer)[i]); 01254 } 01255 } else { 01256 return LORAWAN_STATUS_SERVICE_UNKNOWN; 01257 } 01258 01259 return _loramac.test_request(&test_req); 01260 } 01261 01262 void LoRaWANStack::compliance_test_handler(loramac_mcps_indication_t *mcps_indication) 01263 { 01264 if (_compliance_test.running == false) { 01265 // Check compliance test enable command (i) 01266 if ((mcps_indication->buffer_size == 4) && 01267 (mcps_indication->buffer [0] == 0x01) && 01268 (mcps_indication->buffer [1] == 0x01) && 01269 (mcps_indication->buffer [2] == 0x01) && 01270 (mcps_indication->buffer [3] == 0x01)) { 01271 _compliance_test.is_tx_confirmed = false; 01272 _compliance_test.app_port = 224; 01273 _compliance_test.app_data_size = 2; 01274 _compliance_test.downlink_counter = 0; 01275 _compliance_test.link_check = false; 01276 _compliance_test.demod_margin = 0; 01277 _compliance_test.nb_gateways = 0; 01278 _compliance_test.running = true; 01279 _compliance_test.state = 1; 01280 01281 _loramac.enable_adaptive_datarate(true); 01282 01283 #if MBED_CONF_LORA_PHY == 0 01284 _loramac.LoRaMacTestSetDutyCycleOn(false); 01285 #endif 01286 //5000ms 01287 _loramac.LoRaMacSetTxTimer(5000); 01288 01289 //TODO: Should we call lora_state_machine here instead of just setting the state? 01290 _device_current_state = DEVICE_STATE_COMPLIANCE_TEST; 01291 // lora_state_machine(DEVICE_STATE_COMPLIANCE_TEST); 01292 tr_debug("Compliance test activated."); 01293 } 01294 } else { 01295 _compliance_test.state = mcps_indication->buffer [0]; 01296 switch (_compliance_test.state) { 01297 case 0: // Check compliance test disable command (ii) 01298 _compliance_test.is_tx_confirmed = true; 01299 _compliance_test.app_port = MBED_CONF_LORA_APP_PORT; 01300 _compliance_test.app_data_size = LORAWAN_COMPLIANCE_TEST_DATA_SIZE; 01301 _compliance_test.downlink_counter = 0; 01302 _compliance_test.running = false; 01303 01304 _loramac.enable_adaptive_datarate(MBED_CONF_LORA_ADR_ON); 01305 01306 #if MBED_CONF_LORA_PHY == 0 01307 _loramac.LoRaMacTestSetDutyCycleOn(MBED_CONF_LORA_DUTY_CYCLE_ON); 01308 #endif 01309 // Go to idle state after compliance test mode. 01310 tr_debug("Compliance test disabled."); 01311 _loramac.LoRaMacStopTxTimer(); 01312 01313 // Clear any compliance test message stuff before going back to normal operation. 01314 _loramac.reset_ongoing_tx(); 01315 lora_state_machine(DEVICE_STATE_IDLE); 01316 break; 01317 case 1: // (iii, iv) 01318 _compliance_test.app_data_size = 2; 01319 break; 01320 case 2: // Enable confirmed messages (v) 01321 _compliance_test.is_tx_confirmed = true; 01322 _compliance_test.state = 1; 01323 break; 01324 case 3: // Disable confirmed messages (vi) 01325 _compliance_test.is_tx_confirmed = false; 01326 _compliance_test.state = 1; 01327 break; 01328 case 4: // (vii) 01329 _compliance_test.app_data_size = mcps_indication->buffer_size ; 01330 01331 _compliance_test.app_data_buffer[0] = 4; 01332 for (uint8_t i = 1; i < MIN(_compliance_test.app_data_size, LORAMAC_PHY_MAXPAYLOAD); ++i) { 01333 _compliance_test.app_data_buffer[i] = mcps_indication->buffer [i] + 1; 01334 } 01335 01336 send_compliance_test_frame_to_mac(); 01337 break; 01338 case 5: // (viii) 01339 _loramac.setup_link_check_request(); 01340 break; 01341 case 6: // (ix) 01342 // Disable TestMode and revert back to normal operation 01343 _compliance_test.is_tx_confirmed = true; 01344 _compliance_test.app_port = MBED_CONF_LORA_APP_PORT; 01345 _compliance_test.app_data_size = LORAWAN_COMPLIANCE_TEST_DATA_SIZE; 01346 _compliance_test.downlink_counter = 0; 01347 _compliance_test.running = false; 01348 01349 _loramac.enable_adaptive_datarate(MBED_CONF_LORA_ADR_ON); 01350 01351 #if MBED_CONF_LORA_PHY == 0 01352 _loramac.LoRaMacTestSetDutyCycleOn(MBED_CONF_LORA_DUTY_CYCLE_ON); 01353 #endif 01354 _loramac.join(true); 01355 break; 01356 case 7: // (x) 01357 if (mcps_indication->buffer_size == 3) { 01358 loramac_mlme_req_t mlme_req; 01359 mlme_req.type = MLME_TXCW ; 01360 mlme_req.cw_tx_mode.timeout = (uint16_t)((mcps_indication->buffer [1] << 8) | mcps_indication->buffer [2]); 01361 _loramac.mlme_request(&mlme_req); 01362 } else if (mcps_indication->buffer_size == 7) { 01363 loramac_mlme_req_t mlme_req; 01364 mlme_req.type = MLME_TXCW_1 ; 01365 mlme_req.cw_tx_mode.timeout = (uint16_t)((mcps_indication->buffer [1] << 8) 01366 | mcps_indication->buffer [2]); 01367 mlme_req.cw_tx_mode.frequency = (uint32_t)((mcps_indication->buffer [3] << 16) 01368 | (mcps_indication->buffer [4] << 8) 01369 | mcps_indication->buffer [5]) * 100; 01370 mlme_req.cw_tx_mode.power = mcps_indication->buffer [6]; 01371 _loramac.mlme_request(&mlme_req); 01372 } 01373 _compliance_test.state = 1; 01374 break; 01375 } 01376 } 01377 } 01378 #endif 01379
Generated on Tue Jul 12 2022 12:44:32 by
1.7.2