From 207ae2dedf71ec10772ece24602fb14824b33edd Mon Sep 17 00:00:00 2001 From: Hasnain Virk Date: Mon, 13 Aug 2018 11:22:31 +0300 Subject: [PATCH 1/4] Adding FSB selection feature for US915 PHY User can now define a custom frequency sub-band for the US915 PHY. FSB_Usage.txt defines how this parameter will be configured. --- features/lorawan/FSB_Usage.txt | 35 +++++++++ .../lorawan/lorastack/phy/LoRaPHYUS915.cpp | 77 ++++++++++--------- features/lorawan/mbed_lib.json | 4 + 3 files changed, 79 insertions(+), 37 deletions(-) create mode 100644 features/lorawan/FSB_Usage.txt diff --git a/features/lorawan/FSB_Usage.txt b/features/lorawan/FSB_Usage.txt new file mode 100644 index 0000000000..f7f3621aa9 --- /dev/null +++ b/features/lorawan/FSB_Usage.txt @@ -0,0 +1,35 @@ +Frequency sub-bands in US915/AU915: + + US915/AU915 PHYs define channel structures which can support up-to 72 channels for upstream. + First 64 channels (0-63), occupy 125 kHz and the last 8 channels (64-71) occupy 500 kHz. + However, most of the base stations available in the market support 8 or 16 channels. + Network acquisition can become costly if the device have no prior knowledge of active channel plan and it enables + all 72 channels to begin with. + + LoRaWAN 1.0.2 Regional parameters specification refers to a strategy of probing a set of nine channels (8 + 1) for + joining process. According to that strategy the device is supposed to alternatively select a channel from a set of + 8, 125 kHz channels and a 500 kHz channel. + For example send a join request alternatively on a randomly selected channel from a set of 0-7 channels and + channel 64 which is the first 500 kHz channel. + + Once the device has joined the network (in case of OTAA) or have sent the first uplink (in case of ABP), the network + may send a LinkAdrReq mac command to set the channel mask to be used. Please note that these PHY layers do not + support CFList so LinkAdrReq is the way the network tells you what channel plan to use. + + Mbed LoRaWAN stack can be configured to use a particular frequency sub-band (FSB) which means that we don't have to + probe all sets of channels. "fsb-mask" in lorawan/mbed_lib.json is the parameter which can be used to tell the + system which FSB or a set of FSBs to use. By default the "fsb-mask" is set to "{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x00FF}" + that means all channels are active, i.e., 64 125 kHz channels and 8 500 kHz channels are active. If the user wishes + to use a custom FSB, he/she needs to set appropriate mask as the value of "fsb-mask". For example: + If the user wishes to use the first FSB, i.e., first 8 125 kHz channels (0-7) and the first 500 kHz channel: + "fsb-mask" = "{0x00FF, 0x0000, 0x0000, 0x0000, 0x0001}" + Similarly, if the user wishes to use second FSB, i.e., 2nd set of 8 125 kHz channels (8-15) and the 2nd 500 kHz + channel: + "fsb-mask" = "{0xFF00, 0x0000, 0x0000, 0x0000, 0x0002}" + + You can also combine FSBs if your base station supports more than 8 channels. For example: + "fsb-mask" = "{0x00FF, 0x0000, 0x0000, 0xFF00, 0x0081}" + will mean use channels 0-7(125 kHz) + channel 64 (500 KHz) and channels 56-63 (125 kHz) + channel 71 (500 kHz). + + Please note that for Certification requirements, you need to alternate between 125 kHz and 500 kHz channels and that's + why before joining you should not set a mask that enables only 500 kHz or only 125 kHz channels. \ No newline at end of file diff --git a/features/lorawan/lorastack/phy/LoRaPHYUS915.cpp b/features/lorawan/lorastack/phy/LoRaPHYUS915.cpp index c4a565d88b..1864bc71c4 100644 --- a/features/lorawan/lorastack/phy/LoRaPHYUS915.cpp +++ b/features/lorawan/lorastack/phy/LoRaPHYUS915.cpp @@ -204,25 +204,27 @@ static const int8_t datarate_offsets_US915[5][4] = /*! * Maximum payload with respect to the datarate index. Cannot operate with repeater. */ -static const uint8_t max_payloads_US915[] = { 11, 53, 125, 242, 242, 0, 0, 0, 53, 129, 242, 242, 242, 242, 0, 0 }; +static const uint8_t max_payloads_US915[] = {11, 53, 125, 242, 242, 0, 0, 0, 53, 129, 242, 242, 242, 242, 0, 0}; /*! * Maximum payload with respect to the datarate index. Can operate with repeater. */ static const uint8_t max_payloads_with_repeater_US915[] = {11, 53, 125, 242, 242, 0, 0, 0, 33, 109, 222, 222, 222, 222, 0, 0}; +static const uint16_t fsb_mask[] = MBED_CONF_LORA_FSB_MASK; + LoRaPHYUS915::LoRaPHYUS915() { bands[0] = US915_BAND0; // Channels - // 125 kHz channels + // 125 kHz channels - Upstream for (uint8_t i = 0; i < US915_MAX_NB_CHANNELS - 8; i++) { channels[i].frequency = 902300000 + i * 200000; channels[i].dr_range.value = ( DR_3 << 4) | DR_0; channels[i].band = 0; } - // 500 kHz channels + // 500 kHz channels - Upstream for (uint8_t i = US915_MAX_NB_CHANNELS - 8; i < US915_MAX_NB_CHANNELS; i++) { channels[i].frequency = 903000000 + (i - ( US915_MAX_NB_CHANNELS - 8)) * 1600000; channels[i].dr_range.value = ( DR_4 << 4) | DR_4; @@ -230,11 +232,16 @@ LoRaPHYUS915::LoRaPHYUS915() } // ChannelsMask - default_channel_mask[0] = 0xFFFF; - default_channel_mask[1] = 0xFFFF; - default_channel_mask[2] = 0xFFFF; - default_channel_mask[3] = 0xFFFF; - default_channel_mask[4] = 0x00FF; + for (uint8_t i = 0; i < US915_MAX_NB_CHANNELS; i++) { + if (i == (US915_MAX_NB_CHANNELS - 1)) { + // 64 - 71, 500 kHz channels will get enabled + default_channel_mask[i] = 0x00FF & fsb_mask[i]; + continue; + } + + // 0 - 63 125 kHz channels will get enabled + default_channel_mask[i] = 0xFFFF & fsb_mask[i]; + } memset(channel_mask, 0, sizeof(channel_mask)); memset(current_channel_mask, 0, sizeof(current_channel_mask)); @@ -242,7 +249,7 @@ LoRaPHYUS915::LoRaPHYUS915() // Copy channels default mask copy_channel_mask(channel_mask, default_channel_mask, US915_CHANNEL_MASK_SIZE); - // current channel masks keep track what of the + // current channel masks keep track of the // channels previously used, i.e., which channels should be avoided in // next transmission copy_channel_mask(current_channel_mask, channel_mask, US915_CHANNEL_MASK_SIZE); @@ -346,7 +353,7 @@ void LoRaPHYUS915::restore_default_channels() // Copy channels default mask copy_channel_mask(channel_mask, default_channel_mask, US915_CHANNEL_MASK_SIZE); - for ( uint8_t i = 0; i < US915_CHANNEL_MASK_SIZE; i++ ) { + for (uint8_t i = 0; i < US915_CHANNEL_MASK_SIZE; i++) { // Copy-And the channels mask current_channel_mask[i] &= channel_mask[i]; } @@ -384,10 +391,11 @@ bool LoRaPHYUS915::rx_config(rx_config_params_t* config) _radio->lock(); - _radio->set_channel( frequency ); + _radio->set_channel(frequency); // Radio configuration - _radio->set_rx_config(MODEM_LORA, config->bandwidth, phy_dr, 1, 0, 8, + _radio->set_rx_config(MODEM_LORA, config->bandwidth, phy_dr, 1, 0, + MBED_CONF_LORA_DOWNLINK_PREAMBLE_LENGTH, config->window_timeout, false, 0, false, 0, 0, true, config->is_rx_continuous); _radio->unlock(); @@ -429,7 +437,8 @@ bool LoRaPHYUS915::tx_config(tx_config_params_t* config, int8_t* tx_power, _radio->set_channel(channels[config->channel].frequency); - _radio->set_tx_config(MODEM_LORA, phy_tx_power, 0, bandwidth, phy_dr, 1, 8, + _radio->set_tx_config(MODEM_LORA, phy_tx_power, 0, bandwidth, phy_dr, 1, + MBED_CONF_LORA_UPLINK_PREAMBLE_LENGTH, false, true, 0, 0, false, 3000); // Setup maximum payload lenght of the radio driver @@ -478,20 +487,20 @@ uint8_t LoRaPHYUS915::link_ADR_request(adr_req_params_t* params, if (adr_settings.ch_mask_ctrl == 6) { // Enable all 125 kHz channels - temp_channel_masks[0] = 0xFFFF; - temp_channel_masks[1] = 0xFFFF; - temp_channel_masks[2] = 0xFFFF; - temp_channel_masks[3] = 0xFFFF; + for (uint8_t i = 0; i < US915_CHANNEL_MASK_SIZE - 1; i++) { + temp_channel_masks[i] = 0xFFFF; + } + // Apply chMask to channels 64 to 71 temp_channel_masks[4] = adr_settings.channel_mask; } else if (adr_settings.ch_mask_ctrl == 7) { // Disable all 125 kHz channels - temp_channel_masks[0] = 0x0000; - temp_channel_masks[1] = 0x0000; - temp_channel_masks[2] = 0x0000; - temp_channel_masks[3] = 0x0000; + for (uint8_t i = 0; i < US915_CHANNEL_MASK_SIZE - 1; i++) { + temp_channel_masks[i] = 0x0000; + } + // Apply chMask to channels 64 to 71 temp_channel_masks[4] = adr_settings.channel_mask; @@ -531,11 +540,9 @@ uint8_t LoRaPHYUS915::link_ADR_request(adr_req_params_t* params, // Copy Mask copy_channel_mask(channel_mask, temp_channel_masks, US915_CHANNEL_MASK_SIZE); - current_channel_mask[0] &= channel_mask[0]; - current_channel_mask[1] &= channel_mask[1]; - current_channel_mask[2] &= channel_mask[2]; - current_channel_mask[3] &= channel_mask[3]; - current_channel_mask[4] = channel_mask[4]; + for (uint8_t i = 0; i < US915_CHANNEL_MASK_SIZE; i++) { + current_channel_mask[i] &= channel_mask[i]; + } } // Update status variables @@ -553,7 +560,7 @@ uint8_t LoRaPHYUS915::accept_rx_param_setup_req(rx_param_setup_req_t* params) uint32_t freq = params->frequency; // Verify radio frequency - if ((_radio->check_rf_frequency( freq ) == false) + if ((_radio->check_rf_frequency(freq) == false) || (freq < US915_FIRST_RX1_CHANNEL) || (freq > US915_LAST_RX1_CHANNEL) || (((freq - (uint32_t) US915_FIRST_RX1_CHANNEL) % (uint32_t) US915_STEPWIDTH_RX1_CHANNEL) != 0)) { @@ -588,9 +595,6 @@ int8_t LoRaPHYUS915::get_alternate_DR(uint8_t nb_trials) { int8_t datarate = 0; - // Re-enable 500 kHz default channels - channel_mask[4] = 0x00FF; - if ((nb_trials & 0x01) == 0x01) { datarate = DR_4; } else { @@ -616,11 +620,10 @@ lorawan_status_t LoRaPHYUS915::set_next_channel(channel_selection_params_t* para copy_channel_mask(current_channel_mask, channel_mask, 4); } - // Check other channels - if (params->current_datarate >= DR_4) { - if ((current_channel_mask[4] & 0x00FF ) == 0) { - current_channel_mask[4] = channel_mask[4]; - } + // Update the 500 kHz channels in the running mask + if ((params->current_datarate >= DR_4) + && (current_channel_mask[4] & 0x00FF) == 0) { + current_channel_mask[4] = channel_mask[4]; } if (params->aggregate_timeoff <= _lora_time->get_elapsed_time(params->last_aggregate_tx_time)) { @@ -641,9 +644,9 @@ lorawan_status_t LoRaPHYUS915::set_next_channel(channel_selection_params_t* para if (nb_enabled_channels > 0) { // We found a valid channel - *channel = enabled_channels[get_random( 0, nb_enabled_channels - 1 )]; + *channel = enabled_channels[get_random(0, nb_enabled_channels - 1)]; // Disable the channel in the mask - disable_channel(current_channel_mask, *channel, US915_MAX_NB_CHANNELS - 8); + disable_channel(current_channel_mask, *channel, US915_MAX_NB_CHANNELS); *time = 0; return LORAWAN_STATUS_OK; diff --git a/features/lorawan/mbed_lib.json b/features/lorawan/mbed_lib.json index a233118d3b..bb488319b9 100644 --- a/features/lorawan/mbed_lib.json +++ b/features/lorawan/mbed_lib.json @@ -80,6 +80,10 @@ "uplink-preamble-length": { "help": "Number of preamble symbols to transmit. Must be <= 8", "value": 8 + }, + "fsb-mask": { + "help": "FSB mask for upstream [Only for US915, US915_HYBRID & AU915] Check lorawan/FSB_Usage.txt for more details", + "value": "{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x00FF}" } } } From dc56a06646772d79823335218e6156faf44c6501 Mon Sep 17 00:00:00 2001 From: Hasnain Virk Date: Thu, 16 Aug 2018 12:51:02 +0300 Subject: [PATCH 2/4] Enabling FSB support in AU915 PHY Just like US915 PHY, user can define a custom FSB mask for AU915 PHY. This helps deployments where base stations do not portray full feature channel sets and choose to stick with sub-bands. --- .../lorawan/lorastack/phy/LoRaPHYAU915.cpp | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/features/lorawan/lorastack/phy/LoRaPHYAU915.cpp b/features/lorawan/lorastack/phy/LoRaPHYAU915.cpp index 0c779b39f7..938075172e 100644 --- a/features/lorawan/lorastack/phy/LoRaPHYAU915.cpp +++ b/features/lorawan/lorastack/phy/LoRaPHYAU915.cpp @@ -220,6 +220,7 @@ static const uint8_t max_payload_AU915[] = { 51, 51, 51, 115, 242, 242, static const uint8_t max_payload_with_repeater_AU915[] = { 51, 51, 51, 115, 222, 222, 222, 0, 33, 109, 222, 222, 222, 222, 0, 0 }; +static const uint16_t fsb_mask[] = MBED_CONF_LORA_FSB_MASK; LoRaPHYAU915::LoRaPHYAU915() { @@ -244,11 +245,17 @@ LoRaPHYAU915::LoRaPHYAU915() // All channels are default channels here // Join request needs to alternate between 125 KHz and 500 KHz channels // randomly. - default_channel_mask[0] = 0xFFFF; - default_channel_mask[1] = 0xFFFF; - default_channel_mask[2] = 0xFFFF; - default_channel_mask[3] = 0xFFFF; - default_channel_mask[4] = 0x00FF; + // ChannelsMask + for (uint8_t i = 0; i < AU915_MAX_NB_CHANNELS; i++) { + if (i == (AU915_MAX_NB_CHANNELS - 1)) { + // 64 - 71, 500 kHz channels will get enabled + default_channel_mask[i] = 0x00FF & fsb_mask[i]; + continue; + } + + // 0 - 63 125 kHz channels will get enabled + default_channel_mask[i] = 0xFFFF & fsb_mask[i]; + } memset(channel_mask, 0, sizeof(channel_mask)); memset(current_channel_mask, 0, sizeof(current_channel_mask)); @@ -445,18 +452,18 @@ uint8_t LoRaPHYAU915::link_ADR_request(adr_req_params_t* params, if (adr_settings.ch_mask_ctrl == 6) { // Enable all 125 kHz channels - temp_channel_masks[0] = 0xFFFF; - temp_channel_masks[1] = 0xFFFF; - temp_channel_masks[2] = 0xFFFF; - temp_channel_masks[3] = 0xFFFF; + for (uint8_t i = 0; i < AU915_CHANNEL_MASK_SIZE - 1; i++) { + temp_channel_masks[i] = 0xFFFF; + } + // Apply chMask to channels 64 to 71 temp_channel_masks[4] = adr_settings.channel_mask; } else if (adr_settings.ch_mask_ctrl == 7) { // Disable all 125 kHz channels - temp_channel_masks[0] = 0x0000; - temp_channel_masks[1] = 0x0000; - temp_channel_masks[2] = 0x0000; - temp_channel_masks[3] = 0x0000; + for (uint8_t i = 0; i < AU915_CHANNEL_MASK_SIZE - 1; i++) { + temp_channel_masks[i] = 0x0000; + } + // Apply chMask to channels 64 to 71 temp_channel_masks[4] = adr_settings.channel_mask; } else if (adr_settings.ch_mask_ctrl == 5) { @@ -493,11 +500,9 @@ uint8_t LoRaPHYAU915::link_ADR_request(adr_req_params_t* params, // Copy Mask copy_channel_mask(channel_mask, temp_channel_masks, AU915_CHANNEL_MASK_SIZE); - current_channel_mask[0] &= channel_mask[0]; - current_channel_mask[1] &= channel_mask[1]; - current_channel_mask[2] &= channel_mask[2]; - current_channel_mask[3] &= channel_mask[3]; - current_channel_mask[4] = channel_mask[4]; + for (uint8_t i = 0; i < AU915_CHANNEL_MASK_SIZE; i++) { + current_channel_mask[i] &= channel_mask[i]; + } } // Update status variables @@ -548,9 +553,6 @@ int8_t LoRaPHYAU915::get_alternate_DR(uint8_t nb_trials) { int8_t datarate = 0; - // Re-enable 500 kHz default channels - channel_mask[4] = 0x00FF; - if ((nb_trials & 0x01) == 0x01) { datarate = DR_6; } else { @@ -576,11 +578,10 @@ lorawan_status_t LoRaPHYAU915::set_next_channel(channel_selection_params_t* next } // Check other channels - if (next_chan_params->current_datarate >= DR_6) { - if ((current_channel_mask[4] & 0x00FF) == 0) { - // fall back to 500 kHz default channels - current_channel_mask[4] = channel_mask[4]; - } + if ((next_chan_params->current_datarate >= DR_6) + && (current_channel_mask[4] & 0x00FF) == 0) { + // fall back to 500 kHz default channels + current_channel_mask[4] = channel_mask[4]; } if (next_chan_params->aggregate_timeoff <= _lora_time->get_elapsed_time(next_chan_params->last_aggregate_tx_time)) { @@ -605,8 +606,7 @@ lorawan_status_t LoRaPHYAU915::set_next_channel(channel_selection_params_t* next // We found a valid channel *channel = enabled_channels[get_random(0, nb_enabled_channels - 1)]; // Disable the channel in the mask - disable_channel(current_channel_mask, *channel, - AU915_MAX_NB_CHANNELS - 8); + disable_channel(current_channel_mask, *channel, AU915_MAX_NB_CHANNELS); *time = 0; return LORAWAN_STATUS_OK; From 8f0bb07390b6dfd04bd4aeff99364027aad476b1 Mon Sep 17 00:00:00 2001 From: Hasnain Virk Date: Thu, 16 Aug 2018 12:59:12 +0300 Subject: [PATCH 3/4] Removing US915Hybrid PHY This phy implementation was just to support a single sub-band in US region. As we have decided to make FSBs configurable, we do not need this class anymore. --- .../lorastack/phy/LoRaPHYUS915Hybrid.cpp | 791 ------------------ .../lorastack/phy/LoRaPHYUS915Hybrid.h | 116 --- .../lorawan/lorastack/phy/loraphy_target.h | 5 - features/lorawan/mbed_lib.json | 4 +- 4 files changed, 2 insertions(+), 914 deletions(-) delete mode 100644 features/lorawan/lorastack/phy/LoRaPHYUS915Hybrid.cpp delete mode 100644 features/lorawan/lorastack/phy/LoRaPHYUS915Hybrid.h diff --git a/features/lorawan/lorastack/phy/LoRaPHYUS915Hybrid.cpp b/features/lorawan/lorastack/phy/LoRaPHYUS915Hybrid.cpp deleted file mode 100644 index ed35e3b0bb..0000000000 --- a/features/lorawan/lorastack/phy/LoRaPHYUS915Hybrid.cpp +++ /dev/null @@ -1,791 +0,0 @@ -/** - * @file LoRaPHYUS915Hybrid.cpp - * - * @brief Implements LoRaPHY for US 915 MHz Hybrid band - * - * \code - * ______ _ - * / _____) _ | | - * ( (____ _____ ____ _| |_ _____ ____| |__ - * \____ \| ___ | (_ _) ___ |/ ___) _ \ - * _____) ) ____| | | || |_| ____( (___| | | | - * (______/|_____)_|_|_| \__)_____)\____)_| |_| - * (C)2013 Semtech - * ___ _____ _ ___ _ _____ ___ ___ ___ ___ - * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| - * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| - * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| - * embedded.connectivity.solutions=============== - * - * \endcode - * - * - * 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 "LoRaPHYUS915Hybrid.h" -#include "lora_phy_ds.h" - -/*! - * Minimal datarate that can be used by the node - */ -#define US915_HYBRID_TX_MIN_DATARATE DR_0 - -/*! - * Maximal datarate that can be used by the node - */ -#define US915_HYBRID_TX_MAX_DATARATE DR_4 - -/*! - * Minimal datarate that can be used by the node - */ -#define US915_HYBRID_RX_MIN_DATARATE DR_8 - -/*! - * Maximal datarate that can be used by the node - */ -#define US915_HYBRID_RX_MAX_DATARATE DR_13 - -/*! - * Default datarate used by the node - */ -#define US915_HYBRID_DEFAULT_DATARATE DR_0 - -/*! - * Minimal Rx1 receive datarate offset - */ -#define US915_HYBRID_MIN_RX1_DR_OFFSET 0 - -/*! - * Maximal Rx1 receive datarate offset - */ -#define US915_HYBRID_MAX_RX1_DR_OFFSET 3 - -/*! - * Default Rx1 receive datarate offset - */ -#define US915_HYBRID_DEFAULT_RX1_DR_OFFSET 0 - -/*! - * Minimal Tx output power that can be used by the node - */ -#define US915_HYBRID_MIN_TX_POWER TX_POWER_10 - -/*! - * Maximal Tx output power that can be used by the node - */ -#define US915_HYBRID_MAX_TX_POWER TX_POWER_0 - -/*! - * Default Tx output power used by the node - */ -#define US915_HYBRID_DEFAULT_TX_POWER TX_POWER_0 - -/*! - * Default Max ERP - */ -#define US915_HYBRID_DEFAULT_MAX_ERP 30.0f - -/*! - * ADR Ack limit - */ -#define US915_HYBRID_ADR_ACK_LIMIT 64 - -/*! - * ADR Ack delay - */ -#define US915_HYBRID_ADR_ACK_DELAY 32 - -/*! - * Enabled or disabled the duty cycle - */ -#define US915_HYBRID_DUTY_CYCLE_ENABLED 0 - -/*! - * Maximum RX window duration - */ -#define US915_HYBRID_MAX_RX_WINDOW 3000 - -/*! - * Receive delay 1 - */ -#define US915_HYBRID_RECEIVE_DELAY1 1000 - -/*! - * Receive delay 2 - */ -#define US915_HYBRID_RECEIVE_DELAY2 2000 - -/*! - * Join accept delay 1 - */ -#define US915_HYBRID_JOIN_ACCEPT_DELAY1 5000 - -/*! - * Join accept delay 2 - */ -#define US915_HYBRID_JOIN_ACCEPT_DELAY2 6000 - -/*! - * Maximum frame counter gap - */ -#define US915_HYBRID_MAX_FCNT_GAP 16384 - -/*! - * Ack timeout - */ -#define US915_HYBRID_ACKTIMEOUT 2000 - -/*! - * Random ack timeout limits - */ -#define US915_HYBRID_ACK_TIMEOUT_RND 1000 - -/*! - * Second reception window channel frequency definition. - */ -#define US915_HYBRID_RX_WND_2_FREQ 923300000 - -/*! - * Second reception window channel datarate definition. - */ -#define US915_HYBRID_RX_WND_2_DR DR_8 - -/*! - * Band 0 definition - * { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff } - */ -static const band_t US915_HYBRID_BAND0 = { 1, US915_HYBRID_MAX_TX_POWER, 0, 0, 0 }; // 100.0 % - -/*! - * Defines the first channel for RX window 1 for US band - */ -#define US915_HYBRID_FIRST_RX1_CHANNEL ( (uint32_t) 923300000 ) - -/*! - * Defines the last channel for RX window 1 for US band - */ -#define US915_HYBRID_LAST_RX1_CHANNEL ( (uint32_t) 927500000 ) - -/*! - * Defines the step width of the channels for RX window 1 - */ -#define US915_HYBRID_STEPWIDTH_RX1_CHANNEL ( (uint32_t) 600000 ) - -/*! - * Data rates table definition - */ -static const uint8_t datarates_US915_HYBRID[] = { 10, 9, 8, 7, 8, 0, 0, 0, 12, 11, 10, 9, 8, 7, 0, 0 }; - -/*! - * Bandwidths table definition in Hz - */ -static const uint32_t bandwidths_US915_HYBRID[] = { 125000, 125000, 125000, 125000, 500000, 0, 0, 0, 500000, 500000, 500000, 500000, 500000, 500000, 0, 0 }; - -/*! - * Up/Down link data rates offset definition - */ -static const int8_t datarate_offsets_US915_HYBRID[5][4] = -{ - { DR_10, DR_9 , DR_8 , DR_8 }, // DR_0 - { DR_11, DR_10, DR_9 , DR_8 }, // DR_1 - { DR_12, DR_11, DR_10, DR_9 }, // DR_2 - { DR_13, DR_12, DR_11, DR_10 }, // DR_3 - { DR_13, DR_13, DR_12, DR_11 }, // DR_4 -}; - -/*! - * Maximum payload with respect to the datarate index. Cannot operate with repeater. - */ -static const uint8_t max_payloads_US915_HYBRID[] = { 11, 53, 125, 242, 242, 0, 0, 0, 53, 129, 242, 242, 242, 242, 0, 0 }; - -/*! - * Maximum payload with respect to the datarate index. Can operate with repeater. - */ -static const uint8_t max_payloads_with_repeater_US915_HYBRID[] = { 11, 53, 125, 242, 242, 0, 0, 0, 33, 109, 222, 222, 222, 222, 0, 0 }; - -LoRaPHYUS915Hybrid::LoRaPHYUS915Hybrid() -{ - bands[0] = US915_HYBRID_BAND0; - - // Channels - // 125 kHz channels - for (uint8_t i = 0; i < US915_HYBRID_MAX_NB_CHANNELS - 8; i++) { - channels[i].frequency = 902300000 + i * 200000; - channels[i].dr_range.value = ( DR_3 << 4 ) | DR_0; - channels[i].band = 0; - } - - // 500 kHz channels - for (uint8_t i = US915_HYBRID_MAX_NB_CHANNELS - 8; i < US915_HYBRID_MAX_NB_CHANNELS; i++) { - channels[i].frequency = 903000000 + (i - (US915_HYBRID_MAX_NB_CHANNELS - 8)) * 1600000; - channels[i].dr_range.value = ( DR_4 << 4 ) | DR_4; - channels[i].band = 0; - } - - // ChannelsMask - default_channel_mask[0] = 0x00FF; - default_channel_mask[1] = 0x0000; - default_channel_mask[2] = 0x0000; - default_channel_mask[3] = 0x0000; - default_channel_mask[4] = 0x0001; - - memset(channel_mask, 0, sizeof(channel_mask)); - memset(current_channel_mask, 0, sizeof(current_channel_mask)); - - // Copy channels default mask - copy_channel_mask(channel_mask, default_channel_mask, US915_HYBRID_CHANNEL_MASK_SIZE); - - // Copy into channels mask remaining - copy_channel_mask(current_channel_mask, channel_mask, US915_HYBRID_CHANNEL_MASK_SIZE); - - // set default channels - phy_params.channels.channel_list = channels; - phy_params.channels.channel_list_size = US915_HYBRID_MAX_NB_CHANNELS; - phy_params.channels.mask = channel_mask; - phy_params.channels.default_mask = default_channel_mask; - phy_params.channels.mask_size = US915_HYBRID_CHANNEL_MASK_SIZE; - - // set bands for US915_HYBRID spectrum - phy_params.bands.table = (void *) bands; - phy_params.bands.size = US915_HYBRID_MAX_NB_BANDS; - - // set bandwidths available in US915_HYBRID spectrum - phy_params.bandwidths.table = (void *) bandwidths_US915_HYBRID; - phy_params.bandwidths.size = 16; - - // set data rates available in US915_HYBRID spectrum - phy_params.datarates.table = (void *) datarates_US915_HYBRID; - phy_params.datarates.size = 16; - - // set payload sizes with respect to data rates - phy_params.payloads.table = (void *) max_payloads_US915_HYBRID; - phy_params.payloads.size = 16; - phy_params.payloads_with_repeater.table = (void *) max_payloads_with_repeater_US915_HYBRID; - phy_params.payloads_with_repeater.size = 16; - - // dwell time setting - phy_params.ul_dwell_time_setting = 0; - phy_params.dl_dwell_time_setting = 0; - - // set initial and default parameters - phy_params.duty_cycle_enabled = US915_HYBRID_DUTY_CYCLE_ENABLED; - phy_params.accept_tx_param_setup_req = false; - phy_params.fsk_supported = false; - phy_params.cflist_supported = false; - phy_params.dl_channel_req_supported = false; - phy_params.custom_channelplans_supported = false; - phy_params.default_channel_cnt = US915_HYBRID_MAX_NB_CHANNELS; - phy_params.max_channel_cnt = US915_HYBRID_MAX_NB_CHANNELS; - phy_params.cflist_channel_cnt = 0; - phy_params.min_tx_datarate = US915_HYBRID_TX_MIN_DATARATE; - phy_params.max_tx_datarate = US915_HYBRID_TX_MAX_DATARATE; - phy_params.min_rx_datarate = US915_HYBRID_RX_MIN_DATARATE; - phy_params.max_rx_datarate = US915_HYBRID_RX_MAX_DATARATE; - phy_params.default_datarate = US915_HYBRID_DEFAULT_DATARATE; - phy_params.default_max_datarate = US915_HYBRID_TX_MAX_DATARATE; - phy_params.min_rx1_dr_offset = US915_HYBRID_MIN_RX1_DR_OFFSET; - phy_params.max_rx1_dr_offset = US915_HYBRID_MAX_RX1_DR_OFFSET; - phy_params.default_rx1_dr_offset = US915_HYBRID_DEFAULT_RX1_DR_OFFSET; - phy_params.min_tx_power = US915_HYBRID_MIN_TX_POWER; - phy_params.max_tx_power = US915_HYBRID_MAX_TX_POWER; - phy_params.default_tx_power = US915_HYBRID_DEFAULT_TX_POWER; - phy_params.default_max_eirp = 0; - phy_params.default_antenna_gain = 0; - phy_params.adr_ack_limit = US915_HYBRID_ADR_ACK_LIMIT; - phy_params.adr_ack_delay = US915_HYBRID_ADR_ACK_DELAY; - phy_params.max_rx_window = US915_HYBRID_MAX_RX_WINDOW; - phy_params.recv_delay1 = US915_HYBRID_RECEIVE_DELAY1; - phy_params.recv_delay2 = US915_HYBRID_RECEIVE_DELAY2; - - phy_params.join_accept_delay1 = US915_HYBRID_JOIN_ACCEPT_DELAY1; - phy_params.join_accept_delay2 = US915_HYBRID_JOIN_ACCEPT_DELAY2; - phy_params.max_fcnt_gap = US915_HYBRID_MAX_FCNT_GAP; - phy_params.ack_timeout = US915_HYBRID_ACKTIMEOUT; - phy_params.ack_timeout_rnd = US915_HYBRID_ACK_TIMEOUT_RND; - phy_params.rx_window2_datarate = US915_HYBRID_RX_WND_2_DR; - phy_params.rx_window2_frequency = US915_HYBRID_RX_WND_2_FREQ; -} - -LoRaPHYUS915Hybrid::~LoRaPHYUS915Hybrid() -{ -} - -void LoRaPHYUS915Hybrid::restore_default_channels() -{ - // Copy channels default mask - copy_channel_mask(channel_mask, default_channel_mask, US915_HYBRID_CHANNEL_MASK_SIZE); - - for (uint8_t i = 0; i < US915_HYBRID_CHANNEL_MASK_SIZE; i++) { - // Copy-And the channels mask - current_channel_mask[i] &= channel_mask[i]; - } -} - -bool LoRaPHYUS915Hybrid::get_next_ADR(bool restore_channel_mask, int8_t& dr_out, - int8_t& tx_power_out, uint32_t& adr_ack_cnt) -{ - bool adrAckReq = false; - - uint16_t ack_limit_plus_delay = phy_params.adr_ack_limit + phy_params.adr_ack_delay; - - if (dr_out == phy_params.min_tx_datarate) { - adr_ack_cnt = 0; - return adrAckReq; - } - - if (adr_ack_cnt < phy_params.adr_ack_limit) { - return adrAckReq; - } - - // ADR ack counter is larger than ADR-ACK-LIMIT - adrAckReq = true; - tx_power_out = phy_params.max_tx_power; - - - if (adr_ack_cnt >= ack_limit_plus_delay) { - if ((adr_ack_cnt % phy_params.adr_ack_delay) == 1) { - // Decrease the datarate - dr_out = get_next_lower_tx_datarate(dr_out); - - if (dr_out == phy_params.min_tx_datarate) { - // We must set adrAckReq to false as soon as we reach the lowest datarate - adrAckReq = false; - if (restore_channel_mask) { - // Re-enable default channels - reenable_500khz_channels(channel_mask[4], channel_mask); - } - } - } - } - - return adrAckReq; -} - -bool LoRaPHYUS915Hybrid::rx_config(rx_config_params_t* config) -{ - int8_t dr = config->datarate; - uint8_t max_payload = 0; - int8_t phy_dr = 0; - uint32_t frequency = config->frequency; - - _radio->lock(); - - if (_radio->get_status() != RF_IDLE) { - - _radio->unlock(); - return false; - - } - - _radio->unlock(); - - if (config->rx_slot == RX_SLOT_WIN_1) { - // Apply window 1 frequency - frequency = US915_HYBRID_FIRST_RX1_CHANNEL + (config->channel % 8) * US915_HYBRID_STEPWIDTH_RX1_CHANNEL; - } - - // Read the physical datarate from the datarates table - phy_dr = datarates_US915_HYBRID[dr]; - - _radio->lock(); - - _radio->set_channel( frequency ); - - // Radio configuration - _radio->set_rx_config(MODEM_LORA, config->bandwidth, phy_dr, 1, 0, 8, - config->window_timeout, false, 0, false, 0, 0, true, - config->is_rx_continuous); - - _radio->unlock(); - - if (config->is_repeater_supported == true) { - max_payload = max_payloads_with_repeater_US915_HYBRID[dr]; - } else { - max_payload = max_payloads_US915_HYBRID[dr]; - } - - _radio->lock(); - _radio->set_max_payload_length(MODEM_LORA, max_payload + LORA_MAC_FRMPAYLOAD_OVERHEAD); - _radio->unlock(); - - return true; -} - -bool LoRaPHYUS915Hybrid::tx_config(tx_config_params_t* config, int8_t* tx_power, - lorawan_time_t* tx_toa) -{ - int8_t phy_dr = datarates_US915_HYBRID[config->datarate]; - - int8_t tx_power_limited = limit_tx_power(config->tx_power, - bands[channels[config->channel].band].max_tx_pwr, - config->datarate); - - uint32_t bandwidth = get_bandwidth (config->datarate); - int8_t phy_tx_power = 0; - - // Calculate physical TX power - phy_tx_power = compute_tx_power(tx_power_limited, US915_HYBRID_DEFAULT_MAX_ERP, 0); - - _radio->lock(); - - _radio->set_channel( channels[config->channel].frequency ); - - _radio->set_tx_config(MODEM_LORA, phy_tx_power, 0, bandwidth, phy_dr, 1, 8, - false, true, 0, 0, false, 3000); - - // Setup maximum payload lenght of the radio driver - _radio->set_max_payload_length(MODEM_LORA, config->pkt_len); - - // Get the time-on-air of the next tx frame - *tx_toa = _radio->time_on_air(MODEM_LORA, config->pkt_len); - - _radio->unlock(); - *tx_power = tx_power_limited; - - return true; -} - -uint8_t LoRaPHYUS915Hybrid::link_ADR_request(adr_req_params_t* params, - int8_t* dr_out, int8_t* tx_power_out, - uint8_t* nb_rep_out, - uint8_t* nb_bytes_parsed) -{ - uint8_t status = 0x07; - link_adr_params_t adr_settings; - uint8_t next_idx = 0; - uint8_t bytes_processed = 0; - uint16_t temp_channel_mask[US915_HYBRID_CHANNEL_MASK_SIZE] = {0, 0, 0, 0, 0}; - - verify_adr_params_t verify_params; - - // Initialize local copy of channels mask - copy_channel_mask(temp_channel_mask, channel_mask, US915_HYBRID_CHANNEL_MASK_SIZE); - - while (bytes_processed < params->payload_size) { - next_idx = parse_link_ADR_req(&(params->payload[bytes_processed]), - &adr_settings); - - if (next_idx == 0) { - break; // break loop, since no more request has been found - } - - // Update bytes processed - bytes_processed += next_idx; - - // Revert status, as we only check the last ADR request for the channel mask KO - status = 0x07; - - if (adr_settings.ch_mask_ctrl == 6) { - // Enable all 125 kHz channels - temp_channel_mask[0] = 0xFFFF; - temp_channel_mask[1] = 0xFFFF; - temp_channel_mask[2] = 0xFFFF; - temp_channel_mask[3] = 0xFFFF; - // Apply chMask to channels 64 to 71 - temp_channel_mask[4] = adr_settings.channel_mask; - } else if( adr_settings.ch_mask_ctrl == 7 ) { - // Disable all 125 kHz channels - temp_channel_mask[0] = 0x0000; - temp_channel_mask[1] = 0x0000; - temp_channel_mask[2] = 0x0000; - temp_channel_mask[3] = 0x0000; - // Apply chMask to channels 64 to 71 - temp_channel_mask[4] = adr_settings.channel_mask; - } else if( adr_settings.ch_mask_ctrl == 5 ) { - // RFU - status &= 0xFE; // Channel mask KO - } else { - temp_channel_mask[adr_settings.ch_mask_ctrl] = adr_settings.channel_mask; - } - } - - // FCC 15.247 paragraph F mandates to hop on at least 2 125 kHz channels - if ((adr_settings.datarate < DR_4) && - (num_active_channels( temp_channel_mask, 0, 4 ) < 2)) { - status &= 0xFE; // Channel mask KO - } - - if( validate_channel_mask(temp_channel_mask ) == false) { - status &= 0xFE; // Channel mask KO - } - - verify_params.status = status; - verify_params.adr_enabled = params->adr_enabled; - verify_params.datarate = adr_settings.datarate; - verify_params.tx_power = adr_settings.tx_power; - verify_params.nb_rep = adr_settings.nb_rep; - verify_params.current_datarate = params->current_datarate; - verify_params.current_tx_power = params->current_tx_power; - verify_params.current_nb_rep = params->current_nb_rep; - verify_params.channel_mask = temp_channel_mask; - - - // Verify the parameters and update, if necessary - status = verify_link_ADR_req(&verify_params, &adr_settings.datarate, - &adr_settings.tx_power, &adr_settings.nb_rep); - - // Update channelsMask if everything is correct - if (status == 0x07) { - // Copy Mask - copy_channel_mask(channel_mask, temp_channel_mask, US915_HYBRID_CHANNEL_MASK_SIZE); - - current_channel_mask[0] &= channel_mask[0]; - current_channel_mask[1] &= channel_mask[1]; - current_channel_mask[2] &= channel_mask[2]; - current_channel_mask[3] &= channel_mask[3]; - current_channel_mask[4] = channel_mask[4]; - } - - // Update status variables - *dr_out = adr_settings.datarate; - *tx_power_out = adr_settings.tx_power; - *nb_rep_out = adr_settings.nb_rep; - *nb_bytes_parsed = bytes_processed; - - return status; -} - -uint8_t LoRaPHYUS915Hybrid::accept_rx_param_setup_req(rx_param_setup_req_t* params) -{ - uint8_t status = 0x07; - uint32_t freq = params->frequency; - - // Verify radio frequency - if ((_radio->check_rf_frequency(freq) == false) - || (freq < US915_HYBRID_FIRST_RX1_CHANNEL) - || (freq > US915_HYBRID_LAST_RX1_CHANNEL) - || (((freq - ( uint32_t ) US915_HYBRID_FIRST_RX1_CHANNEL) % (uint32_t) US915_HYBRID_STEPWIDTH_RX1_CHANNEL) != 0)) { - status &= 0xFE; // Channel frequency KO - } - - // Verify datarate - if (val_in_range(params->datarate, US915_HYBRID_RX_MIN_DATARATE, US915_HYBRID_RX_MAX_DATARATE) == 0) { - status &= 0xFD; // Datarate KO - } - - if ((val_in_range(params->datarate, DR_5, DR_7) == 1) - || (params->datarate > DR_13)) { - status &= 0xFD; // Datarate KO - } - - // Verify datarate offset - if (val_in_range(params->dr_offset, US915_HYBRID_MIN_RX1_DR_OFFSET, US915_HYBRID_MAX_RX1_DR_OFFSET) == 0) { - status &= 0xFB; // Rx1DrOffset range KO - } - - return status; -} - -int8_t LoRaPHYUS915Hybrid::get_alternate_DR(uint8_t nb_trials) -{ - int8_t datarate = 0; - - // Re-enable 500 kHz default channels - reenable_500khz_channels(channel_mask[4], channel_mask); - - if ((nb_trials & 0x01) == 0x01) { - datarate = DR_4; - } else { - datarate = DR_0; - } - - return datarate; -} - -lorawan_status_t LoRaPHYUS915Hybrid::set_next_channel(channel_selection_params_t* params, - uint8_t* channel, lorawan_time_t* time, - lorawan_time_t* aggregate_timeOff) -{ - uint8_t nb_enabled_channels = 0; - uint8_t delay_tx = 0; - uint8_t enabled_channels[US915_HYBRID_MAX_NB_CHANNELS] = {0}; - lorawan_time_t next_tx_delay = 0; - - // Count 125kHz channels - if (num_active_channels(current_channel_mask, 0, 4) == 0) { - // Reactivate default channels - copy_channel_mask(current_channel_mask, channel_mask, 4); - } - - // Check other channels - if (params->current_datarate >= DR_4) { - if ((current_channel_mask[4] & 0x00FF ) == 0) { - current_channel_mask[4] = channel_mask[4]; - } - } - - if (params->aggregate_timeoff <= _lora_time->get_elapsed_time( params->last_aggregate_tx_time)) { - // Reset Aggregated time off - *aggregate_timeOff = 0; - - // Update bands Time OFF - next_tx_delay = update_band_timeoff(params->joined, - params->dc_enabled, bands, - US915_HYBRID_MAX_NB_BANDS); - - // Search how many channels are enabled - nb_enabled_channels = enabled_channel_count(params->current_datarate, - current_channel_mask, - enabled_channels, &delay_tx); - } else { - delay_tx++; - next_tx_delay = params->aggregate_timeoff - _lora_time->get_elapsed_time(params->last_aggregate_tx_time); - } - - if (nb_enabled_channels > 0) { - - // We found a valid channel - *channel = enabled_channels[get_random(0, nb_enabled_channels - 1)]; - // Disable the channel in the mask - disable_channel(current_channel_mask, *channel, US915_HYBRID_MAX_NB_CHANNELS - 8); - - *time = 0; - return LORAWAN_STATUS_OK; - - } else { - - if (delay_tx > 0) { - // Delay transmission due to AggregatedTimeOff or to a band time off - *time = next_tx_delay; - return LORAWAN_STATUS_DUTYCYCLE_RESTRICTED; - } - - // Datarate not supported by any channel - *time = 0; - return LORAWAN_STATUS_NO_CHANNEL_FOUND; - } -} - -void LoRaPHYUS915Hybrid::set_tx_cont_mode(cw_mode_params_t* params, uint32_t given_frequency) -{ - (void)given_frequency; - - int8_t tx_power_limited = limit_tx_power(params->tx_power, - bands[channels[params->channel].band].max_tx_pwr, - params->datarate); - - int8_t phy_tx_power = 0; - uint32_t frequency = channels[params->channel].frequency; - - // Calculate physical TX power - phy_tx_power = compute_tx_power(tx_power_limited, US915_HYBRID_DEFAULT_MAX_ERP, 0); - - _radio->lock(); - _radio->set_tx_continuous_wave(frequency, phy_tx_power, params->timeout); - _radio->unlock(); -} - -uint8_t LoRaPHYUS915Hybrid::apply_DR_offset(int8_t dr, int8_t drOffset) -{ - int8_t datarate = datarate_offsets_US915_HYBRID[dr][drOffset]; - - if (datarate < 0) { - datarate = DR_0; - } - - return datarate; -} - - -void LoRaPHYUS915Hybrid::reenable_500khz_channels(uint16_t mask, uint16_t* channelsMask) -{ - uint16_t blockMask = mask; - - for (uint8_t i = 0, j = 0; i < 4; i++, j += 2) { - channelsMask[i] = 0; - if ((blockMask & (1 << j)) != 0) { - channelsMask[i] |= 0x00FF; - } - - if ((blockMask & (1 << (j + 1))) != 0) { - channelsMask[i] |= 0xFF00; - } - } - - channelsMask[4] = blockMask; -} - -int8_t LoRaPHYUS915Hybrid::limit_tx_power(int8_t txPower, int8_t maxBandTxPower, - int8_t datarate) -{ - int8_t txPowerResult = txPower; - - // Limit tx power to the band max - txPowerResult = MAX(txPower, maxBandTxPower); - - if (datarate == DR_4) { - - // Limit tx power to max 26dBm - txPowerResult = MAX(txPower, TX_POWER_2); - - } else { - - if (num_active_channels(channel_mask, 0, 4) < 50) { - // Limit tx power to max 21dBm - txPowerResult = MAX(txPower, TX_POWER_5); - } - } - - return txPowerResult; -} - -bool LoRaPHYUS915Hybrid::validate_channel_mask(uint16_t* channel_masks) -{ - bool mask_state = false; - - uint16_t block1 = 0; - uint16_t block2 = 0; - uint8_t index = 0; - uint16_t temp_channel_masks[US915_HYBRID_CHANNEL_MASK_SIZE]; - - // Copy channels mask to not change the input - for (uint8_t i = 0; i < 4; i++) { - temp_channel_masks[i] = channel_masks[i]; - } - - for(uint8_t i = 0; i < 4; i++) { - block1 = temp_channel_masks[i] & 0x00FF; - block2 = temp_channel_masks[i] & 0xFF00; - - if (count_bits(block1, 16) > 1) { - - temp_channel_masks[i] &= block1; - temp_channel_masks[4] = 1 << ( i * 2 ); - mask_state = true; - index = i; - break; - - } else if( count_bits( block2, 16 ) > 1 ) { - - temp_channel_masks[i] &= block2; - temp_channel_masks[4] = 1 << ( i * 2 + 1 ); - mask_state = true; - index = i; - break; - - } - } - - // Do change the channel mask, if we have found a valid block. - if (mask_state == true) { - // Copy channels mask back again - for (uint8_t i = 0; i < 4; i++) { - channel_masks[i] = temp_channel_masks[i]; - - if (i != index) { - channel_masks[i] = 0; - } - } - - channel_masks[4] = temp_channel_masks[4]; - } - - return mask_state; -} diff --git a/features/lorawan/lorastack/phy/LoRaPHYUS915Hybrid.h b/features/lorawan/lorastack/phy/LoRaPHYUS915Hybrid.h deleted file mode 100644 index af59d7343a..0000000000 --- a/features/lorawan/lorastack/phy/LoRaPHYUS915Hybrid.h +++ /dev/null @@ -1,116 +0,0 @@ -/** - * @file LoRaPHYUS915Hybrid.h - * - * @brief Implements LoRaPHY for US 915 MHz Hybrid band - * - * \code - * ______ _ - * / _____) _ | | - * ( (____ _____ ____ _| |_ _____ ____| |__ - * \____ \| ___ | (_ _) ___ |/ ___) _ \ - * _____) ) ____| | | || |_| ____( (___| | | | - * (______/|_____)_|_|_| \__)_____)\____)_| |_| - * (C)2013 Semtech - * ___ _____ _ ___ _ _____ ___ ___ ___ ___ - * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| - * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| - * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| - * embedded.connectivity.solutions=============== - * - * \endcode - * - * - * 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 - * - */ - -#ifndef MBED_OS_LORAPHY_US915_HYBRID_H_ -#define MBED_OS_LORAPHY_US915_HYBRID_H_ - -#include "LoRaPHY.h" - -/*! - * LoRaMac maximum number of channels - */ -#define US915_HYBRID_MAX_NB_CHANNELS 72 - -/*! - * LoRaMac maximum number of bands - */ -#define US915_HYBRID_MAX_NB_BANDS 1 - -#define US915_HYBRID_CHANNEL_MASK_SIZE 5 - - -class LoRaPHYUS915Hybrid : public LoRaPHY { - -public: - - LoRaPHYUS915Hybrid(); - virtual ~LoRaPHYUS915Hybrid(); - - virtual void restore_default_channels(); - - virtual bool get_next_ADR(bool restore_channel_mask, int8_t& dr_out, - int8_t& tx_power_out, uint32_t& adr_ack_cnt); - - virtual bool rx_config(rx_config_params_t* rxConfig); - - virtual bool tx_config(tx_config_params_t* tx_config, int8_t* tx_power, - lorawan_time_t* tx_toa); - - virtual uint8_t link_ADR_request(adr_req_params_t* params, - int8_t* dr_out, int8_t* tx_power_out, - uint8_t* nb_rep_out, - uint8_t* nb_bytes_parsed); - - virtual uint8_t accept_rx_param_setup_req(rx_param_setup_req_t* params); - - virtual int8_t get_alternate_DR(uint8_t nb_trials); - - virtual lorawan_status_t set_next_channel(channel_selection_params_t* params, - uint8_t* channel, lorawan_time_t* time, - lorawan_time_t* aggregate_timeoff); - - virtual void set_tx_cont_mode(cw_mode_params_t* continuousWave, - uint32_t frequency = 0); - - virtual uint8_t apply_DR_offset(int8_t dr, int8_t dr_offset); - -private: - int8_t limit_tx_power(int8_t tx_power, int8_t max_band_tx_power, int8_t datarate); - bool validate_channel_mask(uint16_t* channel_mask); - void reenable_500khz_channels(uint16_t mask, uint16_t* channel_mask); - - /*! - * LoRaMAC channels - */ - channel_params_t channels[US915_HYBRID_MAX_NB_CHANNELS]; - - /*! - * LoRaMac bands - */ - band_t bands[US915_HYBRID_MAX_NB_BANDS]; - - /*! - * LoRaMac channels mask - */ - uint16_t channel_mask[US915_HYBRID_CHANNEL_MASK_SIZE]; - - /*! - * Previously used channel mask - */ - uint16_t current_channel_mask[US915_HYBRID_CHANNEL_MASK_SIZE]; - - /*! - * LoRaMac default channel mask - */ - uint16_t default_channel_mask[US915_HYBRID_CHANNEL_MASK_SIZE]; -}; - -#endif /* MBED_OS_LORAPHY_US915HYBRID_H_ */ diff --git a/features/lorawan/lorastack/phy/loraphy_target.h b/features/lorawan/lorastack/phy/loraphy_target.h index 0354fdac8a..480cf3a3bb 100644 --- a/features/lorawan/lorastack/phy/loraphy_target.h +++ b/features/lorawan/lorastack/phy/loraphy_target.h @@ -29,7 +29,6 @@ #define LORA_REGION_IN865 0x16 #define LORA_REGION_KR920 0x17 #define LORA_REGION_US915 0x18 -#define LORA_REGION_US915_HYBRID 0x19 //DO NOT USE integer values in mbed_app.json! //These are defined for backward compatibility and @@ -43,7 +42,6 @@ #define LORA_REGION_6 0x16 #define LORA_REGION_7 0x17 #define LORA_REGION_8 0x18 -#define LORA_REGION_9 0x19 //Since 0 would be equal to any undefined value we need to handle this in a other way #define mbed_lora_concat_(x) LORA_REGION_##x @@ -77,9 +75,6 @@ #elif LORA_REGION == LORA_REGION_US915 #include "lorawan/lorastack/phy/LoRaPHYUS915.h" #define LoRaPHY_region LoRaPHYUS915 - #elif LORA_REGION == LORA_REGION_US915_HYBRID - #include "lorawan/lorastack/phy/LoRaPHYUS915Hybrid.h" - #define LoRaPHY_region LoRaPHYUS915Hybrid #else #error "Invalid region configuration, update mbed_app.json with correct MBED_CONF_LORA_PHY value" #endif //MBED_CONF_LORA_PHY == VALUE diff --git a/features/lorawan/mbed_lib.json b/features/lorawan/mbed_lib.json index bb488319b9..9f825c02d2 100644 --- a/features/lorawan/mbed_lib.json +++ b/features/lorawan/mbed_lib.json @@ -2,7 +2,7 @@ "name": "lora", "config": { "phy": { - "help": "LoRa PHY region: EU868, AS923, AU915, CN470, CN779, EU433, IN865, KR920, US915, US915_HYBRID", + "help": "LoRa PHY region: EU868, AS923, AU915, CN470, CN779, EU433, IN865, KR920, US915", "value": "EU868" }, "over-the-air-activation": { @@ -82,7 +82,7 @@ "value": 8 }, "fsb-mask": { - "help": "FSB mask for upstream [Only for US915, US915_HYBRID & AU915] Check lorawan/FSB_Usage.txt for more details", + "help": "FSB mask for upstream [Only for US915 & AU915] Check lorawan/FSB_Usage.txt for more details", "value": "{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x00FF}" } } From 9b2507d71aa89b544a15ac072fcb845fa4d7ec60 Mon Sep 17 00:00:00 2001 From: Hasnain Virk Date: Tue, 21 Aug 2018 16:13:30 +0300 Subject: [PATCH 4/4] Adding helpers for Channel mask manipulation A few protected member functions are introduced in LoRaPHY class that help manipulate channel masks in various ways. --- features/lorawan/lorastack/phy/LoRaPHY.cpp | 39 +++++++++++++++++++ features/lorawan/lorastack/phy/LoRaPHY.h | 20 ++++++++++ .../lorawan/lorastack/phy/LoRaPHYAU915.cpp | 33 ++++++---------- .../lorawan/lorastack/phy/LoRaPHYUS915.cpp | 37 +++++++----------- 4 files changed, 84 insertions(+), 45 deletions(-) diff --git a/features/lorawan/lorastack/phy/LoRaPHY.cpp b/features/lorawan/lorastack/phy/LoRaPHY.cpp index b6131db844..7a8462fa8e 100644 --- a/features/lorawan/lorastack/phy/LoRaPHY.cpp +++ b/features/lorawan/lorastack/phy/LoRaPHY.cpp @@ -248,6 +248,45 @@ void LoRaPHY::copy_channel_mask(uint16_t *dest_mask, uint16_t *src_mask, uint8_t } } +void LoRaPHY::intersect_channel_mask(const uint16_t *source, + uint16_t *destination, uint8_t size) +{ + if (!source || !destination || size == 0) { + return; + } + + for (uint8_t i = 0; i < size; i++) { + destination[i] &= source[i]; + } +} + +void LoRaPHY::fill_channel_mask_with_fsb(const uint16_t *expectation, + const uint16_t *fsb_mask, + uint16_t *destination, + uint8_t size) +{ + if (!expectation || !fsb_mask || !destination || size == 0) { + return; + } + + for (uint8_t i = 0; i < size; i++) { + destination[i] = expectation[i] & fsb_mask[i]; + } + +} + +void LoRaPHY::fill_channel_mask_with_value(uint16_t *channel_mask, + uint16_t value, uint8_t size) +{ + if (!channel_mask || size == 0) { + return; + } + + for (uint8_t i = 0; i < size; i++) { + channel_mask[i] = value; + } +} + void LoRaPHY::set_last_tx_done(uint8_t channel, bool joined, lorawan_time_t last_tx_done_time) { band_t *band_table = (band_t *) phy_params.bands.table; diff --git a/features/lorawan/lorastack/phy/LoRaPHY.h b/features/lorawan/lorastack/phy/LoRaPHY.h index 21885298e1..5b4ed32b8b 100644 --- a/features/lorawan/lorastack/phy/LoRaPHY.h +++ b/features/lorawan/lorastack/phy/LoRaPHY.h @@ -535,6 +535,26 @@ public: //Verifiers protected: LoRaPHY(); + /** + * Sets the intersection of source and destination channel masks + * into the destination. + */ + void intersect_channel_mask(const uint16_t *source, uint16_t *destination, + uint8_t size); + + /** + * Fills channel mask array based upon the provided FSB mask + */ + void fill_channel_mask_with_fsb(const uint16_t *expectation, + const uint16_t *fsb_mask, + uint16_t *channel_mask, uint8_t size); + + /** + * Fills channel mask array with a given value + */ + void fill_channel_mask_with_value(uint16_t *channel_mask, + uint16_t value, uint8_t size); + /** * Looks up corresponding band for a frequency. Returns -1 if not in any band. */ diff --git a/features/lorawan/lorastack/phy/LoRaPHYAU915.cpp b/features/lorawan/lorastack/phy/LoRaPHYAU915.cpp index 938075172e..357d382844 100644 --- a/features/lorawan/lorastack/phy/LoRaPHYAU915.cpp +++ b/features/lorawan/lorastack/phy/LoRaPHYAU915.cpp @@ -222,6 +222,8 @@ static const uint8_t max_payload_with_repeater_AU915[] = { 51, 51, 51, 115, static const uint16_t fsb_mask[] = MBED_CONF_LORA_FSB_MASK; +static const uint16_t full_channel_mask [] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x00FF}; + LoRaPHYAU915::LoRaPHYAU915() { bands[0] = AU915_BAND0; @@ -244,18 +246,10 @@ LoRaPHYAU915::LoRaPHYAU915() // Initialize channels default mask // All channels are default channels here // Join request needs to alternate between 125 KHz and 500 KHz channels - // randomly. - // ChannelsMask - for (uint8_t i = 0; i < AU915_MAX_NB_CHANNELS; i++) { - if (i == (AU915_MAX_NB_CHANNELS - 1)) { - // 64 - 71, 500 kHz channels will get enabled - default_channel_mask[i] = 0x00FF & fsb_mask[i]; - continue; - } - - // 0 - 63 125 kHz channels will get enabled - default_channel_mask[i] = 0xFFFF & fsb_mask[i]; - } + // randomly. Fill in the default channel mask depending upon the given + // fsb_mask + fill_channel_mask_with_fsb(full_channel_mask, fsb_mask, + default_channel_mask, AU915_CHANNEL_MASK_SIZE); memset(channel_mask, 0, sizeof(channel_mask)); memset(current_channel_mask, 0, sizeof(current_channel_mask)); @@ -452,17 +446,15 @@ uint8_t LoRaPHYAU915::link_ADR_request(adr_req_params_t* params, if (adr_settings.ch_mask_ctrl == 6) { // Enable all 125 kHz channels - for (uint8_t i = 0; i < AU915_CHANNEL_MASK_SIZE - 1; i++) { - temp_channel_masks[i] = 0xFFFF; - } + fill_channel_mask_with_value(temp_channel_masks, 0xFFFF, + AU915_CHANNEL_MASK_SIZE - 1); // Apply chMask to channels 64 to 71 temp_channel_masks[4] = adr_settings.channel_mask; } else if (adr_settings.ch_mask_ctrl == 7) { // Disable all 125 kHz channels - for (uint8_t i = 0; i < AU915_CHANNEL_MASK_SIZE - 1; i++) { - temp_channel_masks[i] = 0x0000; - } + fill_channel_mask_with_value(temp_channel_masks, 0x0000, + AU915_CHANNEL_MASK_SIZE - 1); // Apply chMask to channels 64 to 71 temp_channel_masks[4] = adr_settings.channel_mask; @@ -500,9 +492,8 @@ uint8_t LoRaPHYAU915::link_ADR_request(adr_req_params_t* params, // Copy Mask copy_channel_mask(channel_mask, temp_channel_masks, AU915_CHANNEL_MASK_SIZE); - for (uint8_t i = 0; i < AU915_CHANNEL_MASK_SIZE; i++) { - current_channel_mask[i] &= channel_mask[i]; - } + intersect_channel_mask(channel_mask, current_channel_mask, + AU915_CHANNEL_MASK_SIZE); } // Update status variables diff --git a/features/lorawan/lorastack/phy/LoRaPHYUS915.cpp b/features/lorawan/lorastack/phy/LoRaPHYUS915.cpp index 1864bc71c4..a531de055b 100644 --- a/features/lorawan/lorastack/phy/LoRaPHYUS915.cpp +++ b/features/lorawan/lorastack/phy/LoRaPHYUS915.cpp @@ -212,6 +212,7 @@ static const uint8_t max_payloads_US915[] = {11, 53, 125, 242, 242, 0, 0, 0, 53, static const uint8_t max_payloads_with_repeater_US915[] = {11, 53, 125, 242, 242, 0, 0, 0, 33, 109, 222, 222, 222, 222, 0, 0}; static const uint16_t fsb_mask[] = MBED_CONF_LORA_FSB_MASK; +static const uint16_t full_channel_mask [] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x00FF}; LoRaPHYUS915::LoRaPHYUS915() { @@ -231,17 +232,9 @@ LoRaPHYUS915::LoRaPHYUS915() channels[i].band = 0; } - // ChannelsMask - for (uint8_t i = 0; i < US915_MAX_NB_CHANNELS; i++) { - if (i == (US915_MAX_NB_CHANNELS - 1)) { - // 64 - 71, 500 kHz channels will get enabled - default_channel_mask[i] = 0x00FF & fsb_mask[i]; - continue; - } - - // 0 - 63 125 kHz channels will get enabled - default_channel_mask[i] = 0xFFFF & fsb_mask[i]; - } + // Fill-up default channel mask and apply FSB mask too + fill_channel_mask_with_fsb(full_channel_mask, fsb_mask, + default_channel_mask, US915_CHANNEL_MASK_SIZE); memset(channel_mask, 0, sizeof(channel_mask)); memset(current_channel_mask, 0, sizeof(current_channel_mask)); @@ -353,10 +346,8 @@ void LoRaPHYUS915::restore_default_channels() // Copy channels default mask copy_channel_mask(channel_mask, default_channel_mask, US915_CHANNEL_MASK_SIZE); - for (uint8_t i = 0; i < US915_CHANNEL_MASK_SIZE; i++) { - // Copy-And the channels mask - current_channel_mask[i] &= channel_mask[i]; - } + // Update running channel mask + intersect_channel_mask(channel_mask, current_channel_mask, US915_CHANNEL_MASK_SIZE); } bool LoRaPHYUS915::rx_config(rx_config_params_t* config) @@ -487,9 +478,8 @@ uint8_t LoRaPHYUS915::link_ADR_request(adr_req_params_t* params, if (adr_settings.ch_mask_ctrl == 6) { // Enable all 125 kHz channels - for (uint8_t i = 0; i < US915_CHANNEL_MASK_SIZE - 1; i++) { - temp_channel_masks[i] = 0xFFFF; - } + fill_channel_mask_with_value(temp_channel_masks, 0xFFFF, + US915_CHANNEL_MASK_SIZE - 1); // Apply chMask to channels 64 to 71 temp_channel_masks[4] = adr_settings.channel_mask; @@ -497,9 +487,8 @@ uint8_t LoRaPHYUS915::link_ADR_request(adr_req_params_t* params, } else if (adr_settings.ch_mask_ctrl == 7) { // Disable all 125 kHz channels - for (uint8_t i = 0; i < US915_CHANNEL_MASK_SIZE - 1; i++) { - temp_channel_masks[i] = 0x0000; - } + fill_channel_mask_with_value(temp_channel_masks, 0x0000, + US915_CHANNEL_MASK_SIZE - 1); // Apply chMask to channels 64 to 71 temp_channel_masks[4] = adr_settings.channel_mask; @@ -540,9 +529,9 @@ uint8_t LoRaPHYUS915::link_ADR_request(adr_req_params_t* params, // Copy Mask copy_channel_mask(channel_mask, temp_channel_masks, US915_CHANNEL_MASK_SIZE); - for (uint8_t i = 0; i < US915_CHANNEL_MASK_SIZE; i++) { - current_channel_mask[i] &= channel_mask[i]; - } + // update running channel mask + intersect_channel_mask(channel_mask, current_channel_mask, + US915_CHANNEL_MASK_SIZE); } // Update status variables