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.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
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 LoRaMacCommand::LoRaMacCommand() 00037 { 00038 sticky_mac_cmd = false; 00039 mac_cmd_buf_idx = 0; 00040 mac_cmd_buf_idx_to_repeat = 0; 00041 00042 memset(mac_cmd_buffer, 0, sizeof(mac_cmd_buffer)); 00043 memset(mac_cmd_buffer_to_repeat, 0, sizeof(mac_cmd_buffer_to_repeat)); 00044 } 00045 00046 void LoRaMacCommand::clear_command_buffer() 00047 { 00048 mac_cmd_buf_idx = 0; 00049 } 00050 00051 uint8_t LoRaMacCommand::get_mac_cmd_length() const 00052 { 00053 return mac_cmd_buf_idx; 00054 } 00055 00056 uint8_t *LoRaMacCommand::get_mac_commands_buffer() 00057 { 00058 return mac_cmd_buffer; 00059 } 00060 00061 void LoRaMacCommand::parse_mac_commands_to_repeat() 00062 { 00063 uint8_t i = 0; 00064 uint8_t cmd_cnt = 0; 00065 00066 for (i = 0; i < mac_cmd_buf_idx; i++) { 00067 switch (mac_cmd_buffer[i]) { 00068 // STICKY 00069 case MOTE_MAC_DL_CHANNEL_ANS : 00070 case MOTE_MAC_RX_PARAM_SETUP_ANS : { // 1 byte payload 00071 mac_cmd_buffer_to_repeat[cmd_cnt++] = mac_cmd_buffer[i++]; 00072 mac_cmd_buffer_to_repeat[cmd_cnt++] = mac_cmd_buffer[i]; 00073 break; 00074 } 00075 case MOTE_MAC_RX_TIMING_SETUP_ANS : { // 0 byte payload 00076 mac_cmd_buffer_to_repeat[cmd_cnt++] = mac_cmd_buffer[i]; 00077 break; 00078 } 00079 00080 // NON-STICKY 00081 case MOTE_MAC_DEV_STATUS_ANS : { // 2 bytes payload 00082 i += 2; 00083 break; 00084 } 00085 case MOTE_MAC_LINK_ADR_ANS : 00086 case MOTE_MAC_NEW_CHANNEL_ANS : { // 1 byte payload 00087 i++; 00088 break; 00089 } 00090 case MOTE_MAC_TX_PARAM_SETUP_ANS : 00091 case MOTE_MAC_DUTY_CYCLE_ANS : 00092 case MOTE_MAC_LINK_CHECK_REQ : { // 0 byte payload 00093 break; 00094 } 00095 default: { 00096 MBED_ASSERT(false); 00097 } 00098 } 00099 } 00100 00101 mac_cmd_buf_idx_to_repeat = cmd_cnt; 00102 } 00103 00104 void LoRaMacCommand::clear_repeat_buffer() 00105 { 00106 mac_cmd_buf_idx_to_repeat = 0; 00107 } 00108 00109 void LoRaMacCommand::copy_repeat_commands_to_buffer() 00110 { 00111 memcpy(&mac_cmd_buffer[mac_cmd_buf_idx], mac_cmd_buffer_to_repeat, mac_cmd_buf_idx_to_repeat); 00112 mac_cmd_buf_idx += mac_cmd_buf_idx_to_repeat; 00113 } 00114 00115 uint8_t LoRaMacCommand::get_repeat_commands_length() const 00116 { 00117 return mac_cmd_buf_idx_to_repeat; 00118 } 00119 00120 void LoRaMacCommand::clear_sticky_mac_cmd() 00121 { 00122 sticky_mac_cmd = false; 00123 } 00124 00125 bool LoRaMacCommand::has_sticky_mac_cmd() const 00126 { 00127 return sticky_mac_cmd; 00128 } 00129 00130 lorawan_status_t LoRaMacCommand::process_mac_commands(const uint8_t *payload, uint8_t mac_index, 00131 uint8_t commands_size, uint8_t snr, 00132 loramac_mlme_confirm_t &mlme_conf, 00133 lora_mac_system_params_t &mac_sys_params, 00134 LoRaPHY &lora_phy) 00135 { 00136 uint8_t status = 0; 00137 lorawan_status_t ret_value = LORAWAN_STATUS_OK; 00138 00139 while (mac_index < commands_size) { 00140 // Decode Frame MAC commands 00141 switch (payload[mac_index++]) { 00142 case SRV_MAC_LINK_CHECK_ANS : 00143 mlme_conf.status = LORAMAC_EVENT_INFO_STATUS_OK ; 00144 mlme_conf.demod_margin = payload[mac_index++]; 00145 mlme_conf.nb_gateways = payload[mac_index++]; 00146 break; 00147 case SRV_MAC_LINK_ADR_REQ : { 00148 adr_req_params_t link_adr_req; 00149 int8_t link_adr_dr = DR_0; 00150 int8_t link_adr_txpower = TX_POWER_0; 00151 uint8_t link_adr_nbtrans = 0; 00152 uint8_t link_adr_nb_bytes_parsed = 0; 00153 00154 // Fill parameter structure 00155 link_adr_req.payload = &payload[mac_index - 1]; 00156 link_adr_req.payload_size = commands_size - (mac_index - 1); 00157 link_adr_req.adr_enabled = mac_sys_params.adr_on ; 00158 link_adr_req.ul_dwell_time = mac_sys_params.uplink_dwell_time ; 00159 link_adr_req.current_datarate = mac_sys_params.channel_data_rate ; 00160 link_adr_req.current_tx_power = mac_sys_params.channel_tx_power ; 00161 link_adr_req.current_nb_trans = mac_sys_params.nb_trans ; 00162 00163 // Process the ADR requests 00164 status = lora_phy.link_ADR_request(&link_adr_req, 00165 &link_adr_dr, 00166 &link_adr_txpower, 00167 &link_adr_nbtrans, 00168 &link_adr_nb_bytes_parsed); 00169 00170 // If nothing was consumed, we have a malformed packet at our hand 00171 // we bin everything and return. link_adr_nb_bytes_parsed being 0 is 00172 // a magic identifier letting us know that there are payload inconsistencies 00173 if (link_adr_nb_bytes_parsed == 0) { 00174 return LORAWAN_STATUS_UNSUPPORTED; 00175 } 00176 00177 if ((status & 0x07) == 0x07) { 00178 mac_sys_params.channel_data_rate = link_adr_dr; 00179 mac_sys_params.channel_tx_power = link_adr_txpower; 00180 mac_sys_params.nb_trans = link_adr_nbtrans; 00181 } 00182 00183 // Add the answers to the buffer 00184 for (uint8_t i = 0; i < (link_adr_nb_bytes_parsed / 5); i++) { 00185 ret_value = add_link_adr_ans(status); 00186 } 00187 // Update MAC index 00188 mac_index += link_adr_nb_bytes_parsed - 1; 00189 } 00190 break; 00191 case SRV_MAC_DUTY_CYCLE_REQ : 00192 mac_sys_params.max_duty_cycle = payload[mac_index++]; 00193 mac_sys_params.aggregated_duty_cycle = 1 << mac_sys_params.max_duty_cycle ; 00194 ret_value = add_duty_cycle_ans(); 00195 break; 00196 case SRV_MAC_RX_PARAM_SETUP_REQ : { 00197 rx_param_setup_req_t rxParamSetupReq; 00198 00199 rxParamSetupReq.dr_offset = (payload[mac_index] >> 4) & 0x07; 00200 rxParamSetupReq.datarate = payload[mac_index++] & 0x0F; 00201 00202 rxParamSetupReq.frequency = (uint32_t) payload[mac_index++]; 00203 rxParamSetupReq.frequency |= (uint32_t) payload[mac_index++] << 8; 00204 rxParamSetupReq.frequency |= (uint32_t) payload[mac_index++] << 16; 00205 rxParamSetupReq.frequency *= 100; 00206 00207 // Perform request on region 00208 status = lora_phy.accept_rx_param_setup_req(&rxParamSetupReq); 00209 00210 if ((status & 0x07) == 0x07) { 00211 mac_sys_params.rx2_channel .datarate = rxParamSetupReq.datarate; 00212 mac_sys_params.rx2_channel .frequency = rxParamSetupReq.frequency; 00213 mac_sys_params.rx1_dr_offset = rxParamSetupReq.dr_offset; 00214 } 00215 ret_value = add_rx_param_setup_ans(status); 00216 } 00217 break; 00218 case SRV_MAC_DEV_STATUS_REQ : { 00219 uint8_t battery_level = BAT_LEVEL_NO_MEASURE ; 00220 if (_battery_level_cb) { 00221 battery_level = _battery_level_cb(); 00222 } 00223 ret_value = add_dev_status_ans(battery_level, snr & 0x3F); 00224 break; 00225 } 00226 case SRV_MAC_NEW_CHANNEL_REQ : { 00227 channel_params_t chParam; 00228 int8_t channel_id = payload[mac_index++]; 00229 00230 chParam.frequency = (uint32_t) payload[mac_index++]; 00231 chParam.frequency |= (uint32_t) payload[mac_index++] << 8; 00232 chParam.frequency |= (uint32_t) payload[mac_index++] << 16; 00233 chParam.frequency *= 100; 00234 chParam.rx1_frequency = 0; 00235 chParam.dr_range.value = payload[mac_index++]; 00236 00237 status = lora_phy.request_new_channel(channel_id, &chParam); 00238 00239 ret_value = add_new_channel_ans(status); 00240 } 00241 break; 00242 case SRV_MAC_RX_TIMING_SETUP_REQ : { 00243 uint8_t delay = payload[mac_index++] & 0x0F; 00244 00245 if (delay == 0) { 00246 delay++; 00247 } 00248 mac_sys_params.recv_delay1 = delay * 1000; 00249 mac_sys_params.recv_delay2 = mac_sys_params.recv_delay1 + 1000; 00250 ret_value = add_rx_timing_setup_ans(); 00251 } 00252 break; 00253 case SRV_MAC_TX_PARAM_SETUP_REQ : { 00254 uint8_t eirpDwellTime = payload[mac_index++]; 00255 uint8_t ul_dwell_time; 00256 uint8_t dl_dwell_time; 00257 uint8_t max_eirp; 00258 00259 ul_dwell_time = 0; 00260 dl_dwell_time = 0; 00261 00262 if ((eirpDwellTime & 0x20) == 0x20) { 00263 dl_dwell_time = 1; 00264 } 00265 if ((eirpDwellTime & 0x10) == 0x10) { 00266 ul_dwell_time = 1; 00267 } 00268 max_eirp = eirpDwellTime & 0x0F; 00269 00270 // Check the status for correctness 00271 if (lora_phy.accept_tx_param_setup_req(ul_dwell_time, dl_dwell_time)) { 00272 // Accept command 00273 mac_sys_params.uplink_dwell_time = ul_dwell_time; 00274 mac_sys_params.downlink_dwell_time = dl_dwell_time; 00275 mac_sys_params.max_eirp = max_eirp_table[max_eirp]; 00276 // Add command response 00277 ret_value = add_tx_param_setup_ans(); 00278 } 00279 } 00280 break; 00281 case SRV_MAC_DL_CHANNEL_REQ : { 00282 uint8_t channel_id = payload[mac_index++]; 00283 uint32_t rx1_frequency; 00284 00285 rx1_frequency = (uint32_t) payload[mac_index++]; 00286 rx1_frequency |= (uint32_t) payload[mac_index++] << 8; 00287 rx1_frequency |= (uint32_t) payload[mac_index++] << 16; 00288 rx1_frequency *= 100; 00289 status = lora_phy.dl_channel_request(channel_id, rx1_frequency); 00290 00291 ret_value = add_dl_channel_ans(status); 00292 } 00293 break; 00294 default: 00295 // Unknown command. ABORT MAC commands processing 00296 tr_error("Invalid MAC command (0x%X)!", payload[mac_index]); 00297 return LORAWAN_STATUS_UNSUPPORTED; 00298 } 00299 } 00300 return ret_value; 00301 } 00302 00303 int32_t LoRaMacCommand::cmd_buffer_remaining() const 00304 { 00305 // The maximum buffer length must take MAC commands to re-send into account. 00306 return sizeof(mac_cmd_buffer) - mac_cmd_buf_idx_to_repeat - mac_cmd_buf_idx; 00307 } 00308 00309 void LoRaMacCommand::set_batterylevel_callback(mbed::Callback<uint8_t(void)> battery_level) 00310 { 00311 _battery_level_cb = battery_level; 00312 } 00313 00314 lorawan_status_t LoRaMacCommand::add_link_check_req() 00315 { 00316 lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR; 00317 if (cmd_buffer_remaining() > 0) { 00318 mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_LINK_CHECK_REQ ; 00319 // No payload for this command 00320 ret = LORAWAN_STATUS_OK; 00321 } 00322 return ret; 00323 } 00324 00325 lorawan_status_t LoRaMacCommand::add_link_adr_ans(uint8_t status) 00326 { 00327 lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR; 00328 if (cmd_buffer_remaining() > 1) { 00329 mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_LINK_ADR_ANS ; 00330 mac_cmd_buffer[mac_cmd_buf_idx++] = status; 00331 ret = LORAWAN_STATUS_OK; 00332 } 00333 return ret; 00334 } 00335 00336 lorawan_status_t LoRaMacCommand::add_duty_cycle_ans() 00337 { 00338 lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR; 00339 if (cmd_buffer_remaining() > 0) { 00340 mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_DUTY_CYCLE_ANS ; 00341 // No payload for this answer 00342 ret = LORAWAN_STATUS_OK; 00343 } 00344 return ret; 00345 } 00346 00347 lorawan_status_t LoRaMacCommand::add_rx_param_setup_ans(uint8_t status) 00348 { 00349 lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR; 00350 if (cmd_buffer_remaining() > 1) { 00351 mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_RX_PARAM_SETUP_ANS ; 00352 // Status: Datarate ACK, Channel ACK 00353 mac_cmd_buffer[mac_cmd_buf_idx++] = status; 00354 // This is a sticky MAC command answer. Setup indication 00355 sticky_mac_cmd = true; 00356 ret = LORAWAN_STATUS_OK; 00357 } 00358 return ret; 00359 } 00360 00361 lorawan_status_t LoRaMacCommand::add_dev_status_ans(uint8_t battery, uint8_t margin) 00362 { 00363 lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR; 00364 if (cmd_buffer_remaining() > 2) { 00365 mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_DEV_STATUS_ANS ; 00366 // 1st byte Battery 00367 // 2nd byte Margin 00368 mac_cmd_buffer[mac_cmd_buf_idx++] = battery; 00369 mac_cmd_buffer[mac_cmd_buf_idx++] = margin; 00370 ret = LORAWAN_STATUS_OK; 00371 } 00372 return ret; 00373 } 00374 00375 lorawan_status_t LoRaMacCommand::add_new_channel_ans(uint8_t status) 00376 { 00377 lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR; 00378 if (cmd_buffer_remaining() > 1) { 00379 mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_NEW_CHANNEL_ANS ; 00380 // Status: Datarate range OK, Channel frequency OK 00381 mac_cmd_buffer[mac_cmd_buf_idx++] = status; 00382 ret = LORAWAN_STATUS_OK; 00383 } 00384 return ret; 00385 } 00386 00387 lorawan_status_t LoRaMacCommand::add_rx_timing_setup_ans() 00388 { 00389 lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR; 00390 if (cmd_buffer_remaining() > 0) { 00391 mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_RX_TIMING_SETUP_ANS ; 00392 // No payload for this answer 00393 // This is a sticky MAC command answer. Setup indication 00394 sticky_mac_cmd = true; 00395 ret = LORAWAN_STATUS_OK; 00396 } 00397 return ret; 00398 } 00399 00400 lorawan_status_t LoRaMacCommand::add_tx_param_setup_ans() 00401 { 00402 lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR; 00403 if (cmd_buffer_remaining() > 0) { 00404 mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_TX_PARAM_SETUP_ANS ; 00405 // No payload for this answer 00406 ret = LORAWAN_STATUS_OK; 00407 } 00408 return ret; 00409 } 00410 00411 lorawan_status_t LoRaMacCommand::add_dl_channel_ans(uint8_t status) 00412 { 00413 lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR; 00414 if (cmd_buffer_remaining() > 1) { 00415 mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_DL_CHANNEL_ANS ; 00416 // Status: Uplink frequency exists, Channel frequency OK 00417 mac_cmd_buffer[mac_cmd_buf_idx++] = status; 00418 // This is a sticky MAC command answer. Setup indication 00419 sticky_mac_cmd = true; 00420 ret = LORAWAN_STATUS_OK; 00421 } 00422 return ret; 00423 }
Generated on Tue Jul 12 2022 13:54:26 by
