Knight KE / Mbed OS Game_Master
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers LoRaMacCommand.cpp Source File

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 }