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