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