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 #include "mbed-trace/mbed_trace.h" 00029 #define TRACE_GROUP "LMACC" 00030 00031 /** 00032 * LoRaMAC max EIRP (dBm) table. 00033 */ 00034 static const uint8_t max_eirp_table[] = { 8, 10, 12, 13, 14, 16, 18, 20, 21, 24, 26, 27, 29, 30, 33, 36 }; 00035 00036 00037 LoRaMacCommand::LoRaMacCommand() 00038 { 00039 mac_cmd_in_next_tx = false; 00040 sticky_mac_cmd = false; 00041 mac_cmd_buf_idx = 0; 00042 mac_cmd_buf_idx_to_repeat = 0; 00043 00044 memset(mac_cmd_buffer, 0, sizeof(mac_cmd_buffer)); 00045 memset(mac_cmd_buffer_to_repeat, 0, sizeof(mac_cmd_buffer_to_repeat)); 00046 } 00047 00048 void LoRaMacCommand::clear_command_buffer() 00049 { 00050 mac_cmd_buf_idx = 0; 00051 } 00052 00053 uint8_t LoRaMacCommand::get_mac_cmd_length() const 00054 { 00055 return mac_cmd_buf_idx; 00056 } 00057 00058 uint8_t *LoRaMacCommand::get_mac_commands_buffer() 00059 { 00060 return mac_cmd_buffer; 00061 } 00062 00063 void LoRaMacCommand::parse_mac_commands_to_repeat() 00064 { 00065 uint8_t i = 0; 00066 uint8_t cmd_cnt = 0; 00067 00068 for (i = 0; i < mac_cmd_buf_idx; i++) { 00069 switch (mac_cmd_buffer[i]) { 00070 // STICKY 00071 case MOTE_MAC_DL_CHANNEL_ANS : 00072 case MOTE_MAC_RX_PARAM_SETUP_ANS : { // 1 byte payload 00073 mac_cmd_buffer_to_repeat[cmd_cnt++] = mac_cmd_buffer[i++]; 00074 mac_cmd_buffer_to_repeat[cmd_cnt++] = mac_cmd_buffer[i]; 00075 break; 00076 } 00077 case MOTE_MAC_RX_TIMING_SETUP_ANS : { // 0 byte payload 00078 mac_cmd_buffer_to_repeat[cmd_cnt++] = mac_cmd_buffer[i]; 00079 break; 00080 } 00081 00082 // NON-STICKY 00083 case MOTE_MAC_DEV_STATUS_ANS : { // 2 bytes payload 00084 i += 2; 00085 break; 00086 } 00087 case MOTE_MAC_LINK_ADR_ANS : 00088 case MOTE_MAC_NEW_CHANNEL_ANS : { // 1 byte payload 00089 i++; 00090 break; 00091 } 00092 case MOTE_MAC_TX_PARAM_SETUP_ANS : 00093 case MOTE_MAC_DUTY_CYCLE_ANS : 00094 case MOTE_MAC_LINK_CHECK_REQ : { // 0 byte payload 00095 break; 00096 } 00097 default: 00098 break; 00099 } 00100 } 00101 00102 if (cmd_cnt > 0) { 00103 mac_cmd_in_next_tx = true; 00104 } else { 00105 mac_cmd_in_next_tx = false; 00106 } 00107 mac_cmd_buf_idx_to_repeat = cmd_cnt; 00108 } 00109 00110 00111 void LoRaMacCommand::clear_repeat_buffer() 00112 { 00113 mac_cmd_buf_idx_to_repeat = 0; 00114 } 00115 00116 void LoRaMacCommand::copy_repeat_commands_to_buffer() 00117 { 00118 memcpy(&mac_cmd_buffer[mac_cmd_buf_idx], mac_cmd_buffer_to_repeat, mac_cmd_buf_idx_to_repeat); 00119 mac_cmd_buf_idx += mac_cmd_buf_idx_to_repeat; 00120 } 00121 00122 uint8_t LoRaMacCommand::get_repeat_commands_length() const 00123 { 00124 return mac_cmd_buf_idx_to_repeat; 00125 } 00126 00127 void LoRaMacCommand::clear_mac_commands_in_next_tx() 00128 { 00129 mac_cmd_in_next_tx = false; 00130 } 00131 00132 bool LoRaMacCommand::is_mac_command_in_next_tx() const 00133 { 00134 return mac_cmd_in_next_tx; 00135 } 00136 00137 void LoRaMacCommand::clear_sticky_mac_cmd() 00138 { 00139 sticky_mac_cmd = false; 00140 } 00141 00142 bool LoRaMacCommand::has_sticky_mac_cmd() const 00143 { 00144 return sticky_mac_cmd; 00145 } 00146 00147 lorawan_status_t LoRaMacCommand::process_mac_commands(const uint8_t *payload, uint8_t mac_index, 00148 uint8_t commands_size, uint8_t snr, 00149 loramac_mlme_confirm_t & mlme_conf, 00150 lora_mac_system_params_t &mac_sys_params, 00151 LoRaPHY &lora_phy) 00152 { 00153 uint8_t status = 0; 00154 lorawan_status_t ret_value = LORAWAN_STATUS_OK; 00155 00156 while (mac_index < commands_size) { 00157 // Decode Frame MAC commands 00158 switch (payload[mac_index++]) { 00159 case SRV_MAC_LINK_CHECK_ANS : 00160 mlme_conf.status = LORAMAC_EVENT_INFO_STATUS_OK ; 00161 mlme_conf.demod_margin = payload[mac_index++]; 00162 mlme_conf.nb_gateways = payload[mac_index++]; 00163 break; 00164 case SRV_MAC_LINK_ADR_REQ : { 00165 adr_req_params_t linkAdrReq; 00166 int8_t linkAdrDatarate = DR_0; 00167 int8_t linkAdrTxPower = TX_POWER_0; 00168 uint8_t linkAdrNbRep = 0; 00169 uint8_t linkAdrNbBytesParsed = 0; 00170 00171 // Fill parameter structure 00172 linkAdrReq.payload = &payload[mac_index - 1]; 00173 linkAdrReq.payload_size = commands_size - (mac_index - 1); 00174 linkAdrReq.adr_enabled = mac_sys_params.adr_on ; 00175 linkAdrReq.ul_dwell_time = mac_sys_params.uplink_dwell_time ; 00176 linkAdrReq.current_datarate = mac_sys_params.channel_data_rate ; 00177 linkAdrReq.current_tx_power = mac_sys_params.channel_tx_power ; 00178 linkAdrReq.current_nb_rep = mac_sys_params.retry_num ; 00179 00180 // Process the ADR requests 00181 status = lora_phy.link_ADR_request(&linkAdrReq, 00182 &linkAdrDatarate, 00183 &linkAdrTxPower, 00184 &linkAdrNbRep, 00185 &linkAdrNbBytesParsed); 00186 00187 if ((status & 0x07) == 0x07) { 00188 mac_sys_params.channel_data_rate = linkAdrDatarate; 00189 mac_sys_params.channel_tx_power = linkAdrTxPower; 00190 mac_sys_params.retry_num = linkAdrNbRep; 00191 } 00192 00193 // Add the answers to the buffer 00194 for (uint8_t i = 0; i < (linkAdrNbBytesParsed / 5); i++) { 00195 ret_value = add_link_adr_ans(status); 00196 } 00197 // Update MAC index 00198 mac_index += linkAdrNbBytesParsed - 1; 00199 } 00200 break; 00201 case SRV_MAC_DUTY_CYCLE_REQ : 00202 mac_sys_params.max_duty_cycle = payload[mac_index++]; 00203 mac_sys_params.aggregated_duty_cycle = 1 << mac_sys_params.max_duty_cycle ; 00204 ret_value = add_duty_cycle_ans(); 00205 break; 00206 case SRV_MAC_RX_PARAM_SETUP_REQ : { 00207 rx_param_setup_req_t rxParamSetupReq; 00208 00209 rxParamSetupReq.dr_offset = (payload[mac_index] >> 4) & 0x07; 00210 rxParamSetupReq.datarate = payload[mac_index] & 0x0F; 00211 mac_index++; 00212 00213 rxParamSetupReq.frequency = (uint32_t) payload[mac_index++]; 00214 rxParamSetupReq.frequency |= (uint32_t) payload[mac_index++] << 8; 00215 rxParamSetupReq.frequency |= (uint32_t) payload[mac_index++] << 16; 00216 rxParamSetupReq.frequency *= 100; 00217 00218 // Perform request on region 00219 status = lora_phy.accept_rx_param_setup_req(&rxParamSetupReq); 00220 00221 if ((status & 0x07) == 0x07) { 00222 mac_sys_params.rx2_channel .datarate = rxParamSetupReq.datarate; 00223 mac_sys_params.rx2_channel .frequency = rxParamSetupReq.frequency; 00224 mac_sys_params.rx1_dr_offset = rxParamSetupReq.dr_offset; 00225 } 00226 ret_value = add_rx_param_setup_ans(status); 00227 } 00228 break; 00229 case SRV_MAC_DEV_STATUS_REQ : { 00230 uint8_t battery_level = BAT_LEVEL_NO_MEASURE ; 00231 if (_battery_level_cb) { 00232 battery_level = _battery_level_cb(); 00233 } 00234 ret_value = add_dev_status_ans(battery_level, snr & 0x3F); 00235 break; 00236 } 00237 case SRV_MAC_NEW_CHANNEL_REQ : { 00238 channel_params_t chParam; 00239 int8_t channel_id = payload[mac_index++]; 00240 00241 chParam.frequency = (uint32_t) payload[mac_index++]; 00242 chParam.frequency |= (uint32_t) payload[mac_index++] << 8; 00243 chParam.frequency |= (uint32_t) payload[mac_index++] << 16; 00244 chParam.frequency *= 100; 00245 chParam.rx1_frequency = 0; 00246 chParam.dr_range.value = payload[mac_index++]; 00247 00248 status = lora_phy.request_new_channel(channel_id, &chParam); 00249 00250 ret_value = add_new_channel_ans(status); 00251 } 00252 break; 00253 case SRV_MAC_RX_TIMING_SETUP_REQ : { 00254 uint8_t delay = payload[mac_index++] & 0x0F; 00255 00256 if (delay == 0) { 00257 delay++; 00258 } 00259 mac_sys_params.recv_delay1 = delay * 1000; 00260 mac_sys_params.recv_delay2 = mac_sys_params.recv_delay1 + 1000; 00261 ret_value = add_rx_timing_setup_ans(); 00262 } 00263 break; 00264 case SRV_MAC_TX_PARAM_SETUP_REQ : { 00265 uint8_t eirpDwellTime = payload[mac_index++]; 00266 uint8_t ul_dwell_time; 00267 uint8_t dl_dwell_time; 00268 uint8_t max_eirp; 00269 00270 ul_dwell_time = 0; 00271 dl_dwell_time = 0; 00272 00273 if ((eirpDwellTime & 0x20) == 0x20) { 00274 dl_dwell_time = 1; 00275 } 00276 if ((eirpDwellTime & 0x10) == 0x10) { 00277 ul_dwell_time = 1; 00278 } 00279 max_eirp = eirpDwellTime & 0x0F; 00280 00281 // Check the status for correctness 00282 if (lora_phy.accept_tx_param_setup_req(ul_dwell_time, dl_dwell_time)) { 00283 // Accept command 00284 mac_sys_params.uplink_dwell_time = ul_dwell_time; 00285 mac_sys_params.downlink_dwell_time = dl_dwell_time; 00286 mac_sys_params.max_eirp = max_eirp_table[max_eirp]; 00287 // Add command response 00288 ret_value = add_tx_param_setup_ans(); 00289 } 00290 } 00291 break; 00292 case SRV_MAC_DL_CHANNEL_REQ : { 00293 uint8_t channel_id = payload[mac_index++]; 00294 uint32_t rx1_frequency; 00295 00296 rx1_frequency = (uint32_t) payload[mac_index++]; 00297 rx1_frequency |= (uint32_t) payload[mac_index++] << 8; 00298 rx1_frequency |= (uint32_t) payload[mac_index++] << 16; 00299 rx1_frequency *= 100; 00300 status = lora_phy.dl_channel_request(channel_id, rx1_frequency); 00301 00302 ret_value = add_dl_channel_ans(status); 00303 } 00304 break; 00305 default: 00306 // Unknown command. ABORT MAC commands processing 00307 ret_value = LORAWAN_STATUS_UNSUPPORTED; 00308 } 00309 } 00310 return ret_value; 00311 } 00312 00313 bool LoRaMacCommand::is_sticky_mac_command_pending() 00314 { 00315 if (mac_cmd_buf_idx_to_repeat > 0) { 00316 return true; 00317 } 00318 return false; 00319 } 00320 00321 int32_t LoRaMacCommand::cmd_buffer_remaining() const 00322 { 00323 // The maximum buffer length must take MAC commands to re-send into account. 00324 return sizeof(mac_cmd_buffer) - mac_cmd_buf_idx_to_repeat - mac_cmd_buf_idx; 00325 } 00326 00327 void LoRaMacCommand::set_batterylevel_callback(mbed::Callback<uint8_t(void)> battery_level) 00328 { 00329 _battery_level_cb = battery_level; 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 12:44:30 by
1.7.2