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