mbed-os/features/lorawan/lorastack/mac/LoRaMacChannelPlan.cpp

244 lines
7.7 KiB
C++

/**
/ _____) _ | |
( (____ _____ ____ _| |_ _____ ____| |__
\____ \| ___ | (_ _) ___ |/ ___) _ \
_____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
(C)2013 Semtech
___ _____ _ ___ _ _____ ___ ___ ___ ___
/ __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
\__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
|___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
embedded.connectivity.solutions===============
Description: LoRaWAN stack layer that controls both MAC and PHY underneath
License: Revised BSD License, see LICENSE.TXT file include in the project
Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE )
Copyright (c) 2017, Arm Limited and affiliates.
SPDX-License-Identifier: BSD-3-Clause
*/
#include "lorastack/mac/LoRaMacChannelPlan.h"
LoRaMacChannelPlan::LoRaMacChannelPlan() : _lora_phy(NULL), _mib(NULL)
{
}
LoRaMacChannelPlan::~LoRaMacChannelPlan()
{
}
void LoRaMacChannelPlan::activate_channelplan_subsystem(LoRaPHY *phy, LoRaMacMib *mib)
{
_lora_phy = phy;
_mib = mib;
}
lorawan_status_t LoRaMacChannelPlan::set_plan(const lorawan_channelplan_t& plan)
{
channel_params_t mac_layer_ch_params;
lorawan_status_t status;
get_phy_params_t get_phy;
phy_param_t phy_param;
uint8_t max_num_channels;
// Check if the PHY layer supports custom channel plans or not.
get_phy.attribute = PHY_CUSTOM_CHANNEL_PLAN_SUPPORT;
phy_param = _lora_phy->get_phy_params(&get_phy);
if (!phy_param.value) {
return LORAWAN_STATUS_SERVICE_UNKNOWN;
}
// Check first how many channels the selected PHY layer supports
get_phy.attribute = PHY_MAX_NB_CHANNELS;
phy_param = _lora_phy->get_phy_params(&get_phy);
max_num_channels = (uint8_t) phy_param.value;
// check if user is setting more channels than supported
if (plan.nb_channels > max_num_channels) {
return LORAWAN_STATUS_PARAMETER_INVALID;
}
for (uint8_t i = 0; i < plan.nb_channels; i++) {
mac_layer_ch_params.band = plan.channels[i].ch_param.band;
mac_layer_ch_params.dr_range.fields.max = plan.channels[i].ch_param.dr_range.fields.max;
mac_layer_ch_params.dr_range.fields.min = plan.channels[i].ch_param.dr_range.fields.min;
mac_layer_ch_params.dr_range.value = plan.channels[i].ch_param.dr_range.value;
mac_layer_ch_params.frequency = plan.channels[i].ch_param.frequency;
mac_layer_ch_params.rx1_frequency = plan.channels[i].ch_param.rx1_frequency;
status = _lora_phy->add_channel(&mac_layer_ch_params, plan.channels[i].id);
if (status != LORAWAN_STATUS_OK) {
return status;
}
}
return LORAWAN_STATUS_OK;
}
lorawan_status_t LoRaMacChannelPlan::get_plan(lorawan_channelplan_t& plan,
loramac_protocol_params *params)
{
if (params == NULL) {
return LORAWAN_STATUS_PARAMETER_INVALID;
}
loramac_mib_req_confirm_t mib_confirm;
lorawan_status_t status;
get_phy_params_t get_phy;
phy_param_t phy_param;
uint8_t max_num_channels;
uint16_t *channel_mask;
uint8_t count = 0;
// Check if the PHY layer supports custom channel plans or not.
get_phy.attribute = PHY_CUSTOM_CHANNEL_PLAN_SUPPORT;
phy_param = _lora_phy->get_phy_params(&get_phy);
if (!phy_param.value) {
return LORAWAN_STATUS_SERVICE_UNKNOWN;
}
// Check first how many channels the selected PHY layer supports
get_phy.attribute = PHY_MAX_NB_CHANNELS;
phy_param = _lora_phy->get_phy_params(&get_phy);
max_num_channels = (uint8_t) phy_param.value;
// Now check the Default channel mask
get_phy.attribute = PHY_CHANNEL_MASK;
phy_param = _lora_phy->get_phy_params(&get_phy);
channel_mask = phy_param.channel_mask;
// Request Mib to get channels
memset(&mib_confirm, 0, sizeof(mib_confirm));
mib_confirm.type = MIB_CHANNELS;
status = _mib->get_request(&mib_confirm, params);
if (status != LORAWAN_STATUS_OK) {
return status;
}
for (uint8_t i = 0; i < max_num_channels; i++) {
// skip the channels which are not enabled
if (_lora_phy->mask_bit_test(channel_mask, i) == 0) {
continue;
}
// otherwise add them to the channel_plan struct
plan.channels[count].id = i;
plan.channels[count].ch_param.frequency = mib_confirm.param.channel_list[i].frequency;
plan.channels[count].ch_param.dr_range.value = mib_confirm.param.channel_list[i].dr_range.value;
plan.channels[count].ch_param.dr_range.fields.min = mib_confirm.param.channel_list[i].dr_range.fields.min;
plan.channels[count].ch_param.dr_range.fields.max = mib_confirm.param.channel_list[i].dr_range.fields.max;
plan.channels[count].ch_param.band = mib_confirm.param.channel_list[i].band;
plan.channels[count].ch_param.rx1_frequency = mib_confirm.param.channel_list[i].rx1_frequency;
count++;
}
plan.nb_channels = count;
return LORAWAN_STATUS_OK;
}
lorawan_status_t LoRaMacChannelPlan::remove_plan()
{
lorawan_status_t status = LORAWAN_STATUS_OK;
get_phy_params_t get_phy;
phy_param_t phy_param;
uint8_t max_num_channels;
uint16_t *channel_mask;
uint16_t *default_channel_mask;
// Check if the PHY layer supports custom channel plans or not.
get_phy.attribute = PHY_CUSTOM_CHANNEL_PLAN_SUPPORT;
phy_param = _lora_phy->get_phy_params(&get_phy);
if (!phy_param.value) {
return LORAWAN_STATUS_SERVICE_UNKNOWN;
}
// Check first how many channels the selected PHY layer supports
get_phy.attribute = PHY_MAX_NB_CHANNELS;
phy_param = _lora_phy->get_phy_params(&get_phy);
max_num_channels = (uint8_t) phy_param.value;
// Now check the channel mask for enabled channels
get_phy.attribute = PHY_CHANNEL_MASK;
phy_param = _lora_phy->get_phy_params(&get_phy);
channel_mask = phy_param.channel_mask;
// Now check the channel mask for default channels
get_phy.attribute = PHY_DEFAULT_CHANNEL_MASK;
phy_param = _lora_phy->get_phy_params(&get_phy);
default_channel_mask = phy_param.channel_mask;
for (uint8_t i = 0; i < max_num_channels; i++) {
// skip any default channels
if (_lora_phy->mask_bit_test(default_channel_mask, i) != 0) {
continue;
}
// skip any channels which are not currently enabled
if (_lora_phy->mask_bit_test(channel_mask, i) == 0) {
continue;
}
status = remove_single_channel(i);
if (status != LORAWAN_STATUS_OK) {
return status;
}
}
return status;
}
lorawan_status_t LoRaMacChannelPlan::remove_single_channel(uint8_t channel_id)
{
get_phy_params_t get_phy;
phy_param_t phy_param;
uint8_t max_num_channels;
// Check if the PHY layer supports custom channel plans or not.
get_phy.attribute = PHY_CUSTOM_CHANNEL_PLAN_SUPPORT;
phy_param = _lora_phy->get_phy_params(&get_phy);
if (!phy_param.value) {
return LORAWAN_STATUS_SERVICE_UNKNOWN;
}
// Check first how many channels the selected PHY layer supports
get_phy.attribute = PHY_MAX_NB_CHANNELS;
phy_param = _lora_phy->get_phy_params(&get_phy);
max_num_channels = (uint8_t) phy_param.value;
// According to specification channel IDs start from 0 and last valid
// channel ID is N-1 where N=MAX_NUM_CHANNELS.
// So any ID which is larger or equal to the Max number of channels is invalid
if (channel_id >= max_num_channels) {
return LORAWAN_STATUS_PARAMETER_INVALID;
}
if (_lora_phy->remove_channel(channel_id) == false) {
return LORAWAN_STATUS_PARAMETER_INVALID;
}
_lora_phy->put_radio_to_sleep();
return LORAWAN_STATUS_OK;
}