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