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.
LoRaMacCommand.cpp
00001 /** 00002 / _____) _ | | 00003 ( (____ _____ ____ _| |_ _____ ____| |__ 00004 \____ \| ___ | (_ _) ___ |/ ___) _ \ 00005 _____) ) ____| | | || |_| ____( (___| | | | 00006 (______/|_____)_|_|_| \__)_____)\____)_| |_| 00007 (C)2013 Semtech 00008 ___ _____ _ ___ _ _____ ___ ___ ___ ___ 00009 / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| 00010 \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| 00011 |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| 00012 embedded.connectivity.solutions=============== 00013 00014 Description: LoRa MAC layer implementation 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 Copyright (c) 2017, Arm Limited and affiliates. 00021 00022 SPDX-License-Identifier: BSD-3-Clause 00023 */ 00024 00025 #include "LoRaMacCommand.h" 00026 #include "LoRaMac.h" 00027 00028 #if defined(FEATURE_COMMON_PAL) 00029 #include "mbed_trace.h" 00030 #define TRACE_GROUP "LMACC" 00031 #else 00032 #define tr_debug(...) (void(0)) //dummies if feature common pal is not added 00033 #define tr_info(...) (void(0)) //dummies if feature common pal is not added 00034 #define tr_error(...) (void(0)) //dummies if feature common pal is not added 00035 #endif //defined(FEATURE_COMMON_PAL) 00036 00037 /** 00038 * LoRaMAC max EIRP (dBm) table. 00039 */ 00040 static const uint8_t max_eirp_table[] = { 8, 10, 12, 13, 14, 16, 18, 20, 21, 24, 26, 27, 29, 30, 33, 36 }; 00041 00042 00043 LoRaMacCommand::LoRaMacCommand() 00044 { 00045 mac_cmd_in_next_tx = false; 00046 sticky_mac_cmd = false; 00047 mac_cmd_buf_idx = 0; 00048 mac_cmd_buf_idx_to_repeat = 0; 00049 00050 memset(mac_cmd_buffer, 0, sizeof(mac_cmd_buffer)); 00051 memset(mac_cmd_buffer_to_repeat, 0, sizeof(mac_cmd_buffer_to_repeat)); 00052 } 00053 00054 void LoRaMacCommand::clear_command_buffer() 00055 { 00056 mac_cmd_buf_idx = 0; 00057 } 00058 00059 uint8_t LoRaMacCommand::get_mac_cmd_length() const 00060 { 00061 return mac_cmd_buf_idx; 00062 } 00063 00064 uint8_t *LoRaMacCommand::get_mac_commands_buffer() 00065 { 00066 return mac_cmd_buffer; 00067 } 00068 00069 void LoRaMacCommand::parse_mac_commands_to_repeat() 00070 { 00071 uint8_t i = 0; 00072 uint8_t cmd_cnt = 0; 00073 00074 for (i = 0; i < mac_cmd_buf_idx; i++) { 00075 switch (mac_cmd_buffer[i]) { 00076 // STICKY 00077 case MOTE_MAC_DL_CHANNEL_ANS : 00078 case MOTE_MAC_RX_PARAM_SETUP_ANS : { // 1 byte payload 00079 mac_cmd_buffer_to_repeat[cmd_cnt++] = mac_cmd_buffer[i++]; 00080 mac_cmd_buffer_to_repeat[cmd_cnt++] = mac_cmd_buffer[i]; 00081 break; 00082 } 00083 case MOTE_MAC_RX_TIMING_SETUP_ANS : { // 0 byte payload 00084 mac_cmd_buffer_to_repeat[cmd_cnt++] = mac_cmd_buffer[i]; 00085 break; 00086 } 00087 00088 // NON-STICKY 00089 case MOTE_MAC_DEV_STATUS_ANS : { // 2 bytes payload 00090 i += 2; 00091 break; 00092 } 00093 case MOTE_MAC_LINK_ADR_ANS : 00094 case MOTE_MAC_NEW_CHANNEL_ANS : { // 1 byte payload 00095 i++; 00096 break; 00097 } 00098 case MOTE_MAC_TX_PARAM_SETUP_ANS : 00099 case MOTE_MAC_DUTY_CYCLE_ANS : 00100 case MOTE_MAC_LINK_CHECK_REQ : { // 0 byte payload 00101 break; 00102 } 00103 default: 00104 break; 00105 } 00106 } 00107 00108 if (cmd_cnt > 0) { 00109 mac_cmd_in_next_tx = true; 00110 } else { 00111 mac_cmd_in_next_tx = false; 00112 } 00113 mac_cmd_buf_idx_to_repeat = cmd_cnt; 00114 } 00115 00116 00117 void LoRaMacCommand::clear_repeat_buffer() 00118 { 00119 mac_cmd_buf_idx_to_repeat = 0; 00120 } 00121 00122 void LoRaMacCommand::copy_repeat_commands_to_buffer() 00123 { 00124 memcpy(&mac_cmd_buffer[mac_cmd_buf_idx], mac_cmd_buffer_to_repeat, mac_cmd_buf_idx_to_repeat); 00125 mac_cmd_buf_idx += mac_cmd_buf_idx_to_repeat; 00126 } 00127 00128 uint8_t LoRaMacCommand::get_repeat_commands_length() const 00129 { 00130 return mac_cmd_buf_idx_to_repeat; 00131 } 00132 00133 void LoRaMacCommand::clear_mac_commands_in_next_tx() 00134 { 00135 mac_cmd_in_next_tx = false; 00136 } 00137 00138 bool LoRaMacCommand::is_mac_command_in_next_tx() const 00139 { 00140 return mac_cmd_in_next_tx; 00141 } 00142 00143 void LoRaMacCommand::clear_sticky_mac_cmd() 00144 { 00145 sticky_mac_cmd = false; 00146 } 00147 00148 bool LoRaMacCommand::has_sticky_mac_cmd() const 00149 { 00150 return sticky_mac_cmd; 00151 } 00152 00153 lorawan_status_t LoRaMacCommand::process_mac_commands(const uint8_t *payload, uint8_t mac_index, 00154 uint8_t commands_size, uint8_t snr, 00155 loramac_mlme_confirm_t & mlme_conf, 00156 lora_mac_system_params_t &mac_sys_params, 00157 LoRaPHY &lora_phy) 00158 { 00159 uint8_t status = 0; 00160 lorawan_status_t ret_value = LORAWAN_STATUS_OK; 00161 00162 while (mac_index < commands_size) { 00163 // Decode Frame MAC commands 00164 switch (payload[mac_index++]) { 00165 case SRV_MAC_LINK_CHECK_ANS : 00166 mlme_conf.status = LORAMAC_EVENT_INFO_STATUS_OK ; 00167 mlme_conf.demod_margin = payload[mac_index++]; 00168 mlme_conf.nb_gateways = payload[mac_index++]; 00169 break; 00170 case SRV_MAC_LINK_ADR_REQ : { 00171 adr_req_params_t linkAdrReq; 00172 int8_t linkAdrDatarate = DR_0; 00173 int8_t linkAdrTxPower = TX_POWER_0; 00174 uint8_t linkAdrNbRep = 0; 00175 uint8_t linkAdrNbBytesParsed = 0; 00176 00177 // Fill parameter structure 00178 linkAdrReq.payload = &payload[mac_index - 1]; 00179 linkAdrReq.payload_size = commands_size - (mac_index - 1); 00180 linkAdrReq.adr_enabled = mac_sys_params.adr_on ; 00181 linkAdrReq.ul_dwell_time = mac_sys_params.uplink_dwell_time ; 00182 linkAdrReq.current_datarate = mac_sys_params.channel_data_rate ; 00183 linkAdrReq.current_tx_power = mac_sys_params.channel_tx_power ; 00184 linkAdrReq.current_nb_rep = mac_sys_params.retry_num ; 00185 00186 // Process the ADR requests 00187 status = lora_phy.link_ADR_request(&linkAdrReq, 00188 &linkAdrDatarate, 00189 &linkAdrTxPower, 00190 &linkAdrNbRep, 00191 &linkAdrNbBytesParsed); 00192 00193 if ((status & 0x07) == 0x07) { 00194 mac_sys_params.channel_data_rate = linkAdrDatarate; 00195 mac_sys_params.channel_tx_power = linkAdrTxPower; 00196 mac_sys_params.retry_num = linkAdrNbRep; 00197 } 00198 00199 // Add the answers to the buffer 00200 for (uint8_t i = 0; i < (linkAdrNbBytesParsed / 5); i++) { 00201 ret_value = add_link_adr_ans(status); 00202 } 00203 // Update MAC index 00204 mac_index += linkAdrNbBytesParsed - 1; 00205 } 00206 break; 00207 case SRV_MAC_DUTY_CYCLE_REQ : 00208 mac_sys_params.max_duty_cycle = payload[mac_index++]; 00209 mac_sys_params.aggregated_duty_cycle = 1 << mac_sys_params.max_duty_cycle ; 00210 ret_value = add_duty_cycle_ans(); 00211 break; 00212 case SRV_MAC_RX_PARAM_SETUP_REQ : { 00213 rx_param_setup_req_t rxParamSetupReq; 00214 00215 rxParamSetupReq.dr_offset = (payload[mac_index] >> 4) & 0x07; 00216 rxParamSetupReq.datarate = payload[mac_index] & 0x0F; 00217 mac_index++; 00218 00219 rxParamSetupReq.frequency = (uint32_t) payload[mac_index++]; 00220 rxParamSetupReq.frequency |= (uint32_t) payload[mac_index++] << 8; 00221 rxParamSetupReq.frequency |= (uint32_t) payload[mac_index++] << 16; 00222 rxParamSetupReq.frequency *= 100; 00223 00224 // Perform request on region 00225 status = lora_phy.accept_rx_param_setup_req(&rxParamSetupReq); 00226 00227 if ((status & 0x07) == 0x07) { 00228 mac_sys_params.rx2_channel .datarate = rxParamSetupReq.datarate; 00229 mac_sys_params.rx2_channel .frequency = rxParamSetupReq.frequency; 00230 mac_sys_params.rx1_dr_offset = rxParamSetupReq.dr_offset; 00231 } 00232 ret_value = add_rx_param_setup_ans(status); 00233 } 00234 break; 00235 case SRV_MAC_DEV_STATUS_REQ : { 00236 uint8_t battery_level = BAT_LEVEL_NO_MEASURE ; 00237 if (_battery_level_cb) { 00238 battery_level = _battery_level_cb(); 00239 } 00240 ret_value = add_dev_status_ans(battery_level, snr & 0x3F); 00241 break; 00242 } 00243 case SRV_MAC_NEW_CHANNEL_REQ : { 00244 channel_params_t chParam; 00245 int8_t channel_id = payload[mac_index++]; 00246 00247 chParam.frequency = (uint32_t) payload[mac_index++]; 00248 chParam.frequency |= (uint32_t) payload[mac_index++] << 8; 00249 chParam.frequency |= (uint32_t) payload[mac_index++] << 16; 00250 chParam.frequency *= 100; 00251 chParam.rx1_frequency = 0; 00252 chParam.dr_range.value = payload[mac_index++]; 00253 00254 status = lora_phy.request_new_channel(channel_id, &chParam); 00255 00256 ret_value = add_new_channel_ans(status); 00257 } 00258 break; 00259 case SRV_MAC_RX_TIMING_SETUP_REQ : { 00260 uint8_t delay = payload[mac_index++] & 0x0F; 00261 00262 if (delay == 0) { 00263 delay++; 00264 } 00265 mac_sys_params.recv_delay1 = delay * 1000; 00266 mac_sys_params.recv_delay2 = mac_sys_params.recv_delay1 + 1000; 00267 ret_value = add_rx_timing_setup_ans(); 00268 } 00269 break; 00270 case SRV_MAC_TX_PARAM_SETUP_REQ : { 00271 uint8_t eirpDwellTime = payload[mac_index++]; 00272 uint8_t ul_dwell_time; 00273 uint8_t dl_dwell_time; 00274 uint8_t max_eirp; 00275 00276 ul_dwell_time = 0; 00277 dl_dwell_time = 0; 00278 00279 if ((eirpDwellTime & 0x20) == 0x20) { 00280 dl_dwell_time = 1; 00281 } 00282 if ((eirpDwellTime & 0x10) == 0x10) { 00283 ul_dwell_time = 1; 00284 } 00285 max_eirp = eirpDwellTime & 0x0F; 00286 00287 // Check the status for correctness 00288 if (lora_phy.accept_tx_param_setup_req(ul_dwell_time, dl_dwell_time)) { 00289 // Accept command 00290 mac_sys_params.uplink_dwell_time = ul_dwell_time; 00291 mac_sys_params.downlink_dwell_time = dl_dwell_time; 00292 mac_sys_params.max_eirp = max_eirp_table[max_eirp]; 00293 // Add command response 00294 ret_value = add_tx_param_setup_ans(); 00295 } 00296 } 00297 break; 00298 case SRV_MAC_DL_CHANNEL_REQ : { 00299 uint8_t channel_id = payload[mac_index++]; 00300 uint32_t rx1_frequency; 00301 00302 rx1_frequency = (uint32_t) payload[mac_index++]; 00303 rx1_frequency |= (uint32_t) payload[mac_index++] << 8; 00304 rx1_frequency |= (uint32_t) payload[mac_index++] << 16; 00305 rx1_frequency *= 100; 00306 status = lora_phy.dl_channel_request(channel_id, rx1_frequency); 00307 00308 ret_value = add_dl_channel_ans(status); 00309 } 00310 break; 00311 default: 00312 // Unknown command. ABORT MAC commands processing 00313 ret_value = LORAWAN_STATUS_UNSUPPORTED; 00314 } 00315 } 00316 return ret_value; 00317 } 00318 00319 bool LoRaMacCommand::is_sticky_mac_command_pending() 00320 { 00321 if (mac_cmd_buf_idx_to_repeat > 0) { 00322 return true; 00323 } 00324 return false; 00325 } 00326 00327 int32_t LoRaMacCommand::cmd_buffer_remaining() const 00328 { 00329 // The maximum buffer length must take MAC commands to re-send into account. 00330 return sizeof(mac_cmd_buffer) - mac_cmd_buf_idx_to_repeat - mac_cmd_buf_idx; 00331 } 00332 00333 void LoRaMacCommand::set_batterylevel_callback(mbed::Callback<uint8_t(void)> battery_level) 00334 { 00335 _battery_level_cb = battery_level; 00336 } 00337 00338 lorawan_status_t LoRaMacCommand::add_link_check_req() 00339 { 00340 lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR; 00341 if (cmd_buffer_remaining() > 0) { 00342 mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_LINK_CHECK_REQ ; 00343 // No payload for this command 00344 ret = LORAWAN_STATUS_OK; 00345 mac_cmd_in_next_tx = true; 00346 } 00347 return ret; 00348 } 00349 00350 lorawan_status_t LoRaMacCommand::add_link_adr_ans(uint8_t status) 00351 { 00352 lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR; 00353 if (cmd_buffer_remaining() > 1) { 00354 mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_LINK_ADR_ANS ; 00355 mac_cmd_buffer[mac_cmd_buf_idx++] = status; 00356 ret = LORAWAN_STATUS_OK; 00357 mac_cmd_in_next_tx = true; 00358 } 00359 return ret; 00360 } 00361 00362 lorawan_status_t LoRaMacCommand::add_duty_cycle_ans() 00363 { 00364 lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR; 00365 if (cmd_buffer_remaining() > 0) { 00366 mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_DUTY_CYCLE_ANS ; 00367 // No payload for this answer 00368 ret = LORAWAN_STATUS_OK; 00369 mac_cmd_in_next_tx = true; 00370 } 00371 return ret; 00372 } 00373 00374 lorawan_status_t LoRaMacCommand::add_rx_param_setup_ans(uint8_t status) 00375 { 00376 lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR; 00377 if (cmd_buffer_remaining() > 1) { 00378 mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_RX_PARAM_SETUP_ANS ; 00379 // Status: Datarate ACK, Channel ACK 00380 mac_cmd_buffer[mac_cmd_buf_idx++] = status; 00381 // This is a sticky MAC command answer. Setup indication 00382 sticky_mac_cmd = true; 00383 ret = LORAWAN_STATUS_OK; 00384 mac_cmd_in_next_tx = true; 00385 } 00386 return ret; 00387 } 00388 00389 lorawan_status_t LoRaMacCommand::add_dev_status_ans(uint8_t battery, uint8_t margin) 00390 { 00391 lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR; 00392 if (cmd_buffer_remaining() > 2) { 00393 mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_DEV_STATUS_ANS ; 00394 // 1st byte Battery 00395 // 2nd byte Margin 00396 mac_cmd_buffer[mac_cmd_buf_idx++] = battery; 00397 mac_cmd_buffer[mac_cmd_buf_idx++] = margin; 00398 ret = LORAWAN_STATUS_OK; 00399 mac_cmd_in_next_tx = true; 00400 } 00401 return ret; 00402 } 00403 00404 lorawan_status_t LoRaMacCommand::add_new_channel_ans(uint8_t status) 00405 { 00406 lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR; 00407 if (cmd_buffer_remaining() > 1) { 00408 mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_NEW_CHANNEL_ANS ; 00409 // Status: Datarate range OK, Channel frequency OK 00410 mac_cmd_buffer[mac_cmd_buf_idx++] = status; 00411 ret = LORAWAN_STATUS_OK; 00412 mac_cmd_in_next_tx = true; 00413 } 00414 return ret; 00415 } 00416 00417 lorawan_status_t LoRaMacCommand::add_rx_timing_setup_ans() 00418 { 00419 lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR; 00420 if (cmd_buffer_remaining() > 0) { 00421 mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_RX_TIMING_SETUP_ANS ; 00422 // No payload for this answer 00423 // This is a sticky MAC command answer. Setup indication 00424 sticky_mac_cmd = true; 00425 ret = LORAWAN_STATUS_OK; 00426 mac_cmd_in_next_tx = true; 00427 } 00428 return ret; 00429 } 00430 00431 lorawan_status_t LoRaMacCommand::add_tx_param_setup_ans() 00432 { 00433 lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR; 00434 if (cmd_buffer_remaining() > 0) { 00435 mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_TX_PARAM_SETUP_ANS ; 00436 // No payload for this answer 00437 ret = LORAWAN_STATUS_OK; 00438 mac_cmd_in_next_tx = true; 00439 } 00440 return ret; 00441 } 00442 00443 lorawan_status_t LoRaMacCommand::add_dl_channel_ans(uint8_t status) 00444 { 00445 lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR; 00446 if (cmd_buffer_remaining() > 0) { 00447 mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_DL_CHANNEL_ANS ; 00448 // Status: Uplink frequency exists, Channel frequency OK 00449 mac_cmd_buffer[mac_cmd_buf_idx++] = status; 00450 // This is a sticky MAC command answer. Setup indication 00451 sticky_mac_cmd = true; 00452 ret = LORAWAN_STATUS_OK; 00453 mac_cmd_in_next_tx = true; 00454 } 00455 return ret; 00456 }
Generated on Tue Jul 12 2022 12:32:32 by
