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 batteryLevel = BAT_LEVEL_NO_MEASURE ; 00237 // we don't have a mechanism at the moment to measure 00238 // battery levels 00239 ret_value = add_dev_status_ans(batteryLevel, snr & 0x3F); 00240 break; 00241 } 00242 case SRV_MAC_NEW_CHANNEL_REQ : { 00243 channel_params_t chParam; 00244 int8_t channel_id = payload[mac_index++]; 00245 00246 chParam.frequency = (uint32_t) payload[mac_index++]; 00247 chParam.frequency |= (uint32_t) payload[mac_index++] << 8; 00248 chParam.frequency |= (uint32_t) payload[mac_index++] << 16; 00249 chParam.frequency *= 100; 00250 chParam.rx1_frequency = 0; 00251 chParam.dr_range.value = payload[mac_index++]; 00252 00253 status = lora_phy.request_new_channel(channel_id, &chParam); 00254 00255 ret_value = add_new_channel_ans(status); 00256 } 00257 break; 00258 case SRV_MAC_RX_TIMING_SETUP_REQ : { 00259 uint8_t delay = payload[mac_index++] & 0x0F; 00260 00261 if (delay == 0) { 00262 delay++; 00263 } 00264 mac_sys_params.recv_delay1 = delay * 1000; 00265 mac_sys_params.recv_delay2 = mac_sys_params.recv_delay1 + 1000; 00266 ret_value = add_rx_timing_setup_ans(); 00267 } 00268 break; 00269 case SRV_MAC_TX_PARAM_SETUP_REQ : { 00270 uint8_t eirpDwellTime = payload[mac_index++]; 00271 uint8_t ul_dwell_time; 00272 uint8_t dl_dwell_time; 00273 uint8_t max_eirp; 00274 00275 ul_dwell_time = 0; 00276 dl_dwell_time = 0; 00277 00278 if ((eirpDwellTime & 0x20) == 0x20) { 00279 dl_dwell_time = 1; 00280 } 00281 if ((eirpDwellTime & 0x10) == 0x10) { 00282 ul_dwell_time = 1; 00283 } 00284 max_eirp = eirpDwellTime & 0x0F; 00285 00286 // Check the status for correctness 00287 if (lora_phy.accept_tx_param_setup_req(ul_dwell_time, dl_dwell_time)) { 00288 // Accept command 00289 mac_sys_params.uplink_dwell_time = ul_dwell_time; 00290 mac_sys_params.downlink_dwell_time = dl_dwell_time; 00291 mac_sys_params.max_eirp = max_eirp_table[max_eirp]; 00292 // Add command response 00293 ret_value = add_tx_param_setup_ans(); 00294 } 00295 } 00296 break; 00297 case SRV_MAC_DL_CHANNEL_REQ : { 00298 uint8_t channel_id = payload[mac_index++]; 00299 uint32_t rx1_frequency; 00300 00301 rx1_frequency = (uint32_t) payload[mac_index++]; 00302 rx1_frequency |= (uint32_t) payload[mac_index++] << 8; 00303 rx1_frequency |= (uint32_t) payload[mac_index++] << 16; 00304 rx1_frequency *= 100; 00305 status = lora_phy.dl_channel_request(channel_id, rx1_frequency); 00306 00307 ret_value = add_dl_channel_ans(status); 00308 } 00309 break; 00310 default: 00311 // Unknown command. ABORT MAC commands processing 00312 ret_value = LORAWAN_STATUS_UNSUPPORTED; 00313 } 00314 } 00315 return ret_value; 00316 } 00317 00318 bool LoRaMacCommand::is_sticky_mac_command_pending() 00319 { 00320 if (mac_cmd_buf_idx_to_repeat > 0) { 00321 return true; 00322 } 00323 return false; 00324 } 00325 00326 int32_t LoRaMacCommand::cmd_buffer_remaining() const 00327 { 00328 // The maximum buffer length must take MAC commands to re-send into account. 00329 return sizeof(mac_cmd_buffer) - mac_cmd_buf_idx_to_repeat - mac_cmd_buf_idx; 00330 } 00331 00332 lorawan_status_t LoRaMacCommand::add_link_check_req() 00333 { 00334 lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR; 00335 if (cmd_buffer_remaining() > 0) { 00336 mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_LINK_CHECK_REQ ; 00337 // No payload for this command 00338 ret = LORAWAN_STATUS_OK; 00339 mac_cmd_in_next_tx = true; 00340 } 00341 return ret; 00342 } 00343 00344 lorawan_status_t LoRaMacCommand::add_link_adr_ans(uint8_t status) 00345 { 00346 lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR; 00347 if (cmd_buffer_remaining() > 1) { 00348 mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_LINK_ADR_ANS ; 00349 mac_cmd_buffer[mac_cmd_buf_idx++] = status; 00350 ret = LORAWAN_STATUS_OK; 00351 mac_cmd_in_next_tx = true; 00352 } 00353 return ret; 00354 } 00355 00356 lorawan_status_t LoRaMacCommand::add_duty_cycle_ans() 00357 { 00358 lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR; 00359 if (cmd_buffer_remaining() > 0) { 00360 mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_DUTY_CYCLE_ANS ; 00361 // No payload for this answer 00362 ret = LORAWAN_STATUS_OK; 00363 mac_cmd_in_next_tx = true; 00364 } 00365 return ret; 00366 } 00367 00368 lorawan_status_t LoRaMacCommand::add_rx_param_setup_ans(uint8_t status) 00369 { 00370 lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR; 00371 if (cmd_buffer_remaining() > 1) { 00372 mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_RX_PARAM_SETUP_ANS ; 00373 // Status: Datarate ACK, Channel ACK 00374 mac_cmd_buffer[mac_cmd_buf_idx++] = status; 00375 // This is a sticky MAC command answer. Setup indication 00376 sticky_mac_cmd = true; 00377 ret = LORAWAN_STATUS_OK; 00378 mac_cmd_in_next_tx = true; 00379 } 00380 return ret; 00381 } 00382 00383 lorawan_status_t LoRaMacCommand::add_dev_status_ans(uint8_t battery, uint8_t margin) 00384 { 00385 lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR; 00386 if (cmd_buffer_remaining() > 2) { 00387 mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_DEV_STATUS_ANS ; 00388 // 1st byte Battery 00389 // 2nd byte Margin 00390 mac_cmd_buffer[mac_cmd_buf_idx++] = battery; 00391 mac_cmd_buffer[mac_cmd_buf_idx++] = margin; 00392 ret = LORAWAN_STATUS_OK; 00393 mac_cmd_in_next_tx = true; 00394 } 00395 return ret; 00396 } 00397 00398 lorawan_status_t LoRaMacCommand::add_new_channel_ans(uint8_t status) 00399 { 00400 lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR; 00401 if (cmd_buffer_remaining() > 1) { 00402 mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_NEW_CHANNEL_ANS ; 00403 // Status: Datarate range OK, Channel frequency OK 00404 mac_cmd_buffer[mac_cmd_buf_idx++] = status; 00405 ret = LORAWAN_STATUS_OK; 00406 mac_cmd_in_next_tx = true; 00407 } 00408 return ret; 00409 } 00410 00411 lorawan_status_t LoRaMacCommand::add_rx_timing_setup_ans() 00412 { 00413 lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR; 00414 if (cmd_buffer_remaining() > 0) { 00415 mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_RX_TIMING_SETUP_ANS ; 00416 // No payload for this answer 00417 // This is a sticky MAC command answer. Setup indication 00418 sticky_mac_cmd = true; 00419 ret = LORAWAN_STATUS_OK; 00420 mac_cmd_in_next_tx = true; 00421 } 00422 return ret; 00423 } 00424 00425 lorawan_status_t LoRaMacCommand::add_tx_param_setup_ans() 00426 { 00427 lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR; 00428 if (cmd_buffer_remaining() > 0) { 00429 mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_TX_PARAM_SETUP_ANS ; 00430 // No payload for this answer 00431 ret = LORAWAN_STATUS_OK; 00432 mac_cmd_in_next_tx = true; 00433 } 00434 return ret; 00435 } 00436 00437 lorawan_status_t LoRaMacCommand::add_dl_channel_ans(uint8_t status) 00438 { 00439 lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR; 00440 if (cmd_buffer_remaining() > 0) { 00441 mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_DL_CHANNEL_ANS ; 00442 // Status: Uplink frequency exists, Channel frequency OK 00443 mac_cmd_buffer[mac_cmd_buf_idx++] = status; 00444 // This is a sticky MAC command answer. Setup indication 00445 sticky_mac_cmd = true; 00446 ret = LORAWAN_STATUS_OK; 00447 mac_cmd_in_next_tx = true; 00448 } 00449 return ret; 00450 }
Generated on Tue Jul 12 2022 18:18:38 by
1.7.2