From bf6f45a05bb66ae317c44da03eace1f7298a2c22 Mon Sep 17 00:00:00 2001 From: Unknown Date: Fri, 26 Apr 2019 13:48:16 -0400 Subject: [PATCH] PHY Class B handling Support class b beacon and ping slot rx configuration --- features/lorawan/lorastack/phy/LoRaPHY.cpp | 238 +++++++++++++++++---- features/lorawan/lorastack/phy/LoRaPHY.h | 91 +++++++- 2 files changed, 289 insertions(+), 40 deletions(-) diff --git a/features/lorawan/lorastack/phy/LoRaPHY.cpp b/features/lorawan/lorastack/phy/LoRaPHY.cpp index 26e807b040..aaee6b8bc6 100644 --- a/features/lorawan/lorastack/phy/LoRaPHY.cpp +++ b/features/lorawan/lorastack/phy/LoRaPHY.cpp @@ -42,6 +42,13 @@ SPDX-License-Identifier: BSD-3-Clause #define DEVICE_DOES_NOT_SUPPORT_TIME 0 #define DEVICE_SUPPORTS_TIME 1 +#define BEACON_PREAMBLE_LENGTH 10.0f +#define BEACON_COMMON_FRAME_SIZE 15 +#define BEACON_BANDWIDTH 500000 +#define BEACON_CODING_RATE 1 +#define BEACON_CRC_ON false +#define BEACON_FIXED_LEN true + LoRaPHY::LoRaPHY() : _radio(NULL), _lora_time(NULL), @@ -414,23 +421,22 @@ float LoRaPHY::compute_symb_timeout_fsk(uint8_t phy_dr) } -void LoRaPHY::get_rx_window_params(float t_symb, uint8_t min_rx_symb, - float error_fudge, float wakeup_time, - uint32_t *window_length, uint32_t *window_length_ms, - int32_t *window_offset, - uint8_t phy_dr) +void LoRaPHY::get_rx_window_params(float t_symb, float max_preamble_len, + uint8_t min_rx_symb, float error_fudge, + float wakeup_time, uint32_t *window_length, + int32_t *window_offset, uint8_t phy_dr) { float target_rx_window_offset; float window_len_in_ms; if (phy_params.fsk_supported && phy_dr == phy_params.max_rx_datarate) { - min_rx_symb = MAX_PREAMBLE_LENGTH; + min_rx_symb = max_preamble_len; } // We wish to be as close as possible to the actual start of data, i.e., // we are interested in the preamble symbols which are at the tail of the // preamble sequence. - target_rx_window_offset = (MAX_PREAMBLE_LENGTH - min_rx_symb) * t_symb; //in ms + target_rx_window_offset = (max_preamble_len - min_rx_symb) * t_symb; //in ms // Actual window offset in ms in response to timing error fudge factor and // radio wakeup/turned around time. @@ -873,6 +879,7 @@ void LoRaPHY::compute_rx_win_params(int8_t datarate, uint8_t min_rx_symbols, rx_config_params_t *rx_conf_params) { float t_symbol = 0.0f; + float max_preamble_len = MAX_PREAMBLE_LENGTH; // Get the datarate, perform a boundary check rx_conf_params->datarate = MIN(datarate, phy_params.max_rx_datarate); @@ -888,32 +895,75 @@ void LoRaPHY::compute_rx_win_params(int8_t datarate, uint8_t min_rx_symbols, ((uint32_t *)phy_params.bandwidths.table)[rx_conf_params->datarate]); } - if (rx_conf_params->rx_slot == RX_SLOT_WIN_1) { - rx_conf_params->frequency = phy_params.channels.channel_list[rx_conf_params->channel].frequency; + switch (rx_conf_params->rx_slot) { + case RX_SLOT_WIN_1: + rx_conf_params->frequency = phy_params.channels.channel_list[rx_conf_params->channel].frequency; + break; + case RX_SLOT_BEACON: + max_preamble_len = BEACON_PREAMBLE_LENGTH; + break; + case RX_SLOT_WIN_UNICAST_PING_SLOT: + case RX_SLOT_WIN_MULTICAST_PING_SLOT: + case RX_SLOT_WIN_2: + case RX_SLOT_WIN_CLASS_C: + break; + default: + MBED_ASSERT(false); } - get_rx_window_params(t_symbol, min_rx_symbols, (float) rx_error, MBED_CONF_LORA_WAKEUP_TIME, - &rx_conf_params->window_timeout, &rx_conf_params->window_timeout_ms, - &rx_conf_params->window_offset, + get_rx_window_params(t_symbol, max_preamble_len, min_rx_symbols, + (float) rx_error, MBED_CONF_LORA_WAKEUP_TIME, + &rx_conf_params->window_timeout, &rx_conf_params->window_offset, rx_conf_params->datarate); } -uint32_t LoRaPHY::get_rx_time_on_air(uint8_t modem, uint16_t pkt_len) -{ - uint32_t toa = 0; - - _radio->lock(); - toa = _radio->time_on_air((radio_modems_t) modem, pkt_len); - _radio->unlock(); - - return toa; -} bool LoRaPHY::rx_config(rx_config_params_t *rx_conf) { - uint8_t dr = rx_conf->datarate; + radio_modems_t modem; + int8_t dr = rx_conf->datarate; + int8_t phy_dr = 0; uint8_t max_payload = 0; - uint8_t phy_dr = 0; + uint32_t frequency = rx_conf->frequency; + uint16_t preamble_len = MBED_CONF_LORA_DOWNLINK_PREAMBLE_LENGTH; + bool fixed_len = false; + bool iq_invert = true; + + _radio->lock(); + + if (_radio->get_status() != RF_IDLE) { + _radio->unlock(); + return false; + } + + _radio->unlock(); + + switch (rx_conf->rx_slot) { + case RX_SLOT_WIN_1: + frequency = get_rx1_frequency(rx_conf->channel); + rx_conf->frequency = frequency; + break; + case RX_SLOT_WIN_UNICAST_PING_SLOT: + case RX_SLOT_WIN_MULTICAST_PING_SLOT: + // Frequency must be set by compute_ping_win_params + MBED_ASSERT(rx_conf->frequency); + frequency = rx_conf->frequency; + break; + case RX_SLOT_BEACON: + // Frequency must be set by compute_beacon_win_params + MBED_ASSERT(rx_conf->frequency); + preamble_len = MBED_CONF_LORA_BEACON_PREAMBLE_LENGTH; + iq_invert = false; + fixed_len = true; + max_payload = BEACON_COMMON_FRAME_SIZE + phy_params.beacon.rfu1_size + + phy_params.beacon.rfu2_size; + break; + case RX_SLOT_WIN_2: + case RX_SLOT_WIN_CLASS_C: + break; + default: + MBED_ASSERT(false); + } // Read the physical datarate from the datarates table uint8_t *datarate_table = (uint8_t *) phy_params.datarates.table; @@ -922,6 +972,15 @@ bool LoRaPHY::rx_config(rx_config_params_t *rx_conf) phy_dr = datarate_table[dr]; + // Calculate max payload for datarate + if (rx_conf->rx_slot != RX_SLOT_BEACON) { + if (rx_conf->is_repeater_supported) { + max_payload = payload_with_repeater_table[dr] + LORA_MAC_FRMPAYLOAD_OVERHEAD; + } else { + max_payload = payload_table[dr] + LORA_MAC_FRMPAYLOAD_OVERHEAD; + } + } + _radio->lock(); _radio->set_channel(rx_conf->frequency); @@ -933,20 +992,14 @@ bool LoRaPHY::rx_config(rx_config_params_t *rx_conf) rx_conf->window_timeout, false, 0, true, 0, 0, false, rx_conf->is_rx_continuous); } else { - rx_conf->modem_type = MODEM_LORA; - _radio->set_rx_config((radio_modems_t) rx_conf->modem_type, rx_conf->bandwidth, phy_dr, 1, 0, - MAX_PREAMBLE_LENGTH, - rx_conf->window_timeout, false, 0, false, 0, 0, - true, rx_conf->is_rx_continuous); + modem = MODEM_LORA; + _radio->set_rx_config(MODEM_LORA, rx_conf->bandwidth, phy_dr, 1, 0, + preamble_len, + rx_conf->window_timeout, fixed_len, max_payload, false, 0, 0, + iq_invert, rx_conf->is_rx_continuous); } - if (rx_conf->is_repeater_supported) { - max_payload = payload_with_repeater_table[dr]; - } else { - max_payload = payload_table[dr]; - } - - _radio->set_max_payload_length((radio_modems_t) rx_conf->modem_type, max_payload + LORA_MAC_FRMPAYLOAD_OVERHEAD); + _radio->set_max_payload_length(modem, max_payload); _radio->unlock(); @@ -1483,3 +1536,116 @@ uint32_t LoRaPHY::get_rejoin_max_count() const return _rejoin_max_count; } +uint8_t LoRaPHY::accept_ping_slot_channel_req(uint32_t frequency, uint8_t datarate) +{ + uint8_t status = 0; + + // A value of 0 instructs the device to use the default configuration + if ((frequency == 0) || (lookup_band_for_frequency(frequency) != -1)) { + status |= 1 << 0; + } + + if ((datarate == 0) || verify_rx_datarate(datarate)) { + status |= 1 << 1; + } + + if (status == 0x03) { + phy_params.ping_slot_frequency = frequency; + phy_params.ping_slot_datarate = datarate; + } + + return status; +} + +uint8_t LoRaPHY::accept_beacon_frequency_request(uint32_t frequency) +{ + uint8_t status = 0; + + // A value of 0 instructs the device to use the default configuration + if ((frequency == 0) || (lookup_band_for_frequency(frequency) != -1)) { + phy_params.beacon.alternate_frequency = frequency; + status |= 1 << 0; + } + + return status; +} + +void LoRaPHY::get_beacon_rfu_size(uint8_t &rfu1, uint8_t &rfu2) +{ + rfu1 = phy_params.beacon.rfu1_size; + rfu2 = phy_params.beacon.rfu2_size; +} + +uint32_t LoRaPHY::get_beacon_frequency(uint32_t beacon_time) +{ + return phy_params.beacon.default_frequency; +} + +void LoRaPHY::compute_beacon_win_params(uint32_t beacon_time, uint8_t min_rx_symbols, + uint32_t rx_error, rx_config_params_t *config) +{ + config->datarate = phy_params.beacon.datarate; + + // Apply the alternative frequency, if it is available + if (phy_params.beacon.alternate_frequency) { + config->frequency = phy_params.beacon.alternate_frequency; + } else { + config->frequency = get_beacon_frequency(beacon_time); + MBED_ASSERT(config->frequency != 0); + } + + compute_rx_win_params(config->datarate, min_rx_symbols, rx_error, config); +} + + +void LoRaPHY::compute_ping_win_params(uint32_t beacon_time, uint32_t dev_addr, + uint8_t min_rx_symbols, uint32_t rx_error, + rx_config_params_t *config) +{ + // Apply the alternative frequency, if it is available + if (phy_params.ping_slot_frequency) { + config->frequency = phy_params.ping_slot_frequency; + } else { + config->frequency = get_ping_slot_frequency(dev_addr, beacon_time); + MBED_ASSERT(config->frequency != 0); + } + + // Apply the alternative datarate, if it is available + if (phy_params.ping_slot_datarate) { + config->datarate = phy_params.ping_slot_datarate; + } else { + config->datarate = phy_params.beacon.datarate; + } + + compute_rx_win_params(config->datarate, min_rx_symbols, rx_error, config); +} + +uint32_t LoRaPHY::get_rx1_frequency(uint8_t channel) +{ + return phy_params.channels.channel_list[channel].frequency; +} + +uint32_t LoRaPHY::get_ping_slot_frequency(uint32_t dev_addr, uint32_t beacon_time) +{ + return phy_params.ping_slot_default_frequency; +} + +uint32_t LoRaPHY::compute_beacon_time_on_air() +{ + uint8_t beacon_length; + uint8_t phy_dr; + + beacon_length = BEACON_COMMON_FRAME_SIZE + phy_params.beacon.rfu1_size + + phy_params.beacon.rfu2_size; + + // Read the physical datarate from the datarates table + phy_dr = ((uint8_t *)phy_params.datarates.table)[phy_params.beacon.datarate]; + + return _radio->lora_time_on_air(BEACON_PREAMBLE_LENGTH, + phy_dr, + BEACON_BANDWIDTH, + BEACON_CODING_RATE, + BEACON_CRC_ON, + BEACON_FIXED_LEN, + beacon_length); +} \ No newline at end of file diff --git a/features/lorawan/lorastack/phy/LoRaPHY.h b/features/lorawan/lorastack/phy/LoRaPHY.h index caca28212a..5572349941 100644 --- a/features/lorawan/lorastack/phy/LoRaPHY.h +++ b/features/lorawan/lorastack/phy/LoRaPHY.h @@ -414,6 +414,42 @@ public: */ void reset_to_default_values(loramac_protocol_params *params, bool init = false); + /** + * @brief accept_ping_slot_channel_req Makes decision whether to accept + * or reject PingSlotChannelReq MAC command. + * + * @param frequency The unicast ping slot channel + * + * @return True to let the MAC know that the request is + * accepted and MAC can apply Ping slot channel received + * form Network Server. Otherwise false is returned. + */ + + /** + * @brief accept_ping_slot_channel_req Makes decision whether to accept + * or reject PIngSlotChannelReq MAC command. + * + * @param frequency The unicast ping slot channel + * + * @return Status bits RFU[7:2], DrOk[1], FreqOk[0]. If status bit is 1 the + * parameter is compatible. If either status bit is zero, the request + * fails. + */ + virtual uint8_t accept_ping_slot_channel_req(uint32_t frequency, uint8_t datarate); + + /** + * @brief accept_beacon_frequency_request Makes decision whether to accept + * or reject BeaconFreqReq MAC command. + * + * @param frequency The frequency at which beacons will be broadcast + * + * @return 1 to let the MAC know that the device can use the frequency + * @return 1 to let the MAC know that the request is accepted and + * MAC can apply Beacon frequency received form Network Server. + * Otherwise 0 is returned. + */ + virtual uint8_t accept_beacon_frequency_request(uint32_t frequency); + public: /** * @brief get_next_lower_tx_datarate Gets the next lower datarate @@ -600,6 +636,50 @@ public: //Verifiers */ uint32_t get_rejoin_max_count() const; + virtual void compute_beacon_win_params(uint32_t beacon_time, uint8_t min_rx_symbols, + uint32_t rx_error, rx_config_params_t *config); + + /** + * @brief get_beacon_rfu_size Gets the current region beacon RFU field sizes + */ + virtual void get_beacon_rfu_size(uint8_t &rfu1, uint8_t &rfu2); + + /** + * @brief get_beacon_frequency Computes beacon frequency + * @param beacon_time beacon time used to compute beacon frequency + * @return beacon frequency + */ + virtual uint32_t get_beacon_frequency(uint32_t beacon_time); + + /*! + * Computes the ping slot frequency, window timeout and offset. + * + * @param [in] beacon_time The current beacon period time + * + * @param [in] devaddr Device address for ping frequency computation + * + * @param [in] min_rx_symbols The minimum number of symbols required to + * detect an RX frame. + * + * @param [in] rx_error The maximum timing error of the receiver + * in milliseconds. The receiver will turn on + * in a [-rxError : +rxError] ms interval around + * RxOffset. + * + * @param [out] rx_conf_params Pointer to the structure that needs to be + * filled with receive window parameters. + */ + virtual void compute_ping_win_params(uint32_t beacon_time, uint32_t devaddr, + uint8_t min_rx_symbols, uint32_t rx_error, + rx_config_params_t *config); + + /** + * @brief compute_beacon_time_on_air + * @param compute_beacon_time_on_air computes beacon frame time on air + * @return time on air in milliseconds + */ + virtual uint32_t compute_beacon_time_on_air(); + protected: LoRaPHY(); @@ -666,10 +746,9 @@ protected: /** * Computes the RX window timeout and the RX window offset. */ - void get_rx_window_params(float t_symbol, uint8_t min_rx_symbols, - float rx_error, float wakeup_time, - uint32_t *window_length, uint32_t *window_length_ms, - int32_t *window_offset, + void get_rx_window_params(float t_symbol, float max_preamble_len, + uint8_t min_rx_symbols, float rx_error, float wakeup_time, + uint32_t *window_length, int32_t *window_offset, uint8_t phy_dr); /** @@ -698,6 +777,10 @@ protected: bool is_datarate_supported(const int8_t datarate) const; + virtual uint32_t get_rx1_frequency(uint8_t channel); + + virtual uint32_t get_ping_slot_frequency(uint32_t dev_addr, uint32_t beacon_time); + private: /**