Nicolas Borla / Mbed OS BBR_1Ebene
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 #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 }