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