From f35ed14f76fa3fc449bde4b99fd596ebe7913159 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Tue, 18 Feb 2020 18:09:28 +0100 Subject: [PATCH] SRSENB: refactored PHY common UE database --- .../srslte/interfaces/rrc_interface_types.h | 12 +- srsenb/hdr/phy/cc_worker.h | 24 +- srsenb/hdr/phy/phy_common.h | 130 +---- srsenb/hdr/phy/phy_ue_db.h | 247 +++++++++ srsenb/hdr/phy/sf_worker.h | 4 +- srsenb/src/phy/cc_worker.cc | 213 ++------ srsenb/src/phy/phy.cc | 40 +- srsenb/src/phy/phy_common.cc | 193 +------ srsenb/src/phy/phy_ue_db.cc | 504 ++++++++++++++++++ srsenb/src/phy/sf_worker.cc | 15 +- srsenb/test/phy/enb_phy_test.cc | 103 ++-- 11 files changed, 921 insertions(+), 564 deletions(-) create mode 100644 srsenb/hdr/phy/phy_ue_db.h create mode 100644 srsenb/src/phy/phy_ue_db.cc diff --git a/lib/include/srslte/interfaces/rrc_interface_types.h b/lib/include/srslte/interfaces/rrc_interface_types.h index 4002ce076..f70db8866 100644 --- a/lib/include/srslte/interfaces/rrc_interface_types.h +++ b/lib/include/srslte/interfaces/rrc_interface_types.h @@ -509,9 +509,9 @@ struct phy_cfg_t { void set_defaults() { - ZERO_OBJECT(ul_cfg); - ZERO_OBJECT(dl_cfg); - ZERO_OBJECT(prach_cfg); + ul_cfg = {}; + dl_cfg = {}; + prach_cfg = {}; // CommonConfig defaults for non-zero values ul_cfg.pucch.delta_pucch_shift = 1; @@ -552,9 +552,9 @@ struct phy_cfg_t { ul_cfg.pucch.sr_configured = false; } - srslte_dl_cfg_t dl_cfg; - srslte_ul_cfg_t ul_cfg; - srslte_prach_cfg_t prach_cfg; + srslte_dl_cfg_t dl_cfg = {}; + srslte_ul_cfg_t ul_cfg = {}; + srslte_prach_cfg_t prach_cfg = {}; }; struct mbsfn_sf_cfg_t { diff --git a/srsenb/hdr/phy/cc_worker.h b/srsenb/hdr/phy/cc_worker.h index 09a548164..048a93795 100644 --- a/srsenb/hdr/phy/cc_worker.h +++ b/srsenb/hdr/phy/cc_worker.h @@ -42,7 +42,7 @@ public: cf_t* get_buffer_tx(uint32_t antenna_idx); void set_tti(uint32_t tti); - int add_rnti(uint16_t rnti, bool is_temporal); + int add_rnti(uint16_t rnti, bool is_pcell, bool is_temporal); void rem_rnti(uint16_t rnti); uint32_t get_nof_rnti(); @@ -53,7 +53,6 @@ public: int read_pucch_d(cf_t* pusch_d); void start_plot(); - void set_config_dedicated(uint16_t rnti, const srslte::phy_cfg_t& dedicated); void work_ul(const srslte_ul_sf_cfg_t& ul_sf, stack_interface_phy_lte::ul_sched_t& ul_grants); void work_dl(const srslte_dl_sf_cfg_t& dl_sf_cfg, stack_interface_phy_lte::dl_sched_t& dl_grants, @@ -74,9 +73,6 @@ private: int encode_pdcch_ul(stack_interface_phy_lte::ul_sched_grant_t* grants, uint32_t nof_grants); int decode_pucch(); - void send_uci_data(uint16_t rnti, srslte_uci_cfg_t* uci_cfg, srslte_uci_value_t* uci_value); - bool fill_uci_cfg(uint16_t rnti, bool aperiodic_cqi_request, srslte_uci_cfg_t* uci_cfg); - /* Common objects */ srslte::log* log_h = nullptr; phy_common* phy = nullptr; @@ -85,7 +81,6 @@ private: cf_t* signal_buffer_rx[SRSLTE_MAX_PORTS] = {}; cf_t* signal_buffer_tx[SRSLTE_MAX_PORTS] = {}; uint32_t tti_rx = 0, tti_tx_dl = 0, tti_tx_ul = 0; - uint32_t t_rx = 0, t_tx_dl = 0, t_tx_ul = 0; srslte_enb_dl_t enb_dl = {}; srslte_enb_ul_t enb_ul = {}; @@ -99,32 +94,23 @@ private: class ue { public: - ue(uint16_t id, phy_common* phy) + explicit ue(uint16_t rnti_, bool pcell_) : rnti(rnti_), pcell(pcell_) { - // Copy common configuartion - ul_cfg = phy->ul_cfg_com; - dl_cfg = phy->dl_cfg_com; - - // Fill RNTI - rnti = id; - dl_cfg.pdsch.rnti = rnti; - ul_cfg.pusch.rnti = rnti; - ul_cfg.pucch.rnti = rnti; + // Do nothing } bool is_grant_available = false; srslte_phich_grant_t phich_grant = {}; - srslte_dl_cfg_t dl_cfg = {}; - srslte_ul_cfg_t ul_cfg = {}; - void metrics_read(phy_metrics_t* metrics); void metrics_dl(uint32_t mcs); void metrics_ul(uint32_t mcs, float rssi, float sinr, float turbo_iters); + bool is_pcell() { return pcell; }; private: uint32_t rnti = 0; phy_metrics_t metrics = {}; + bool pcell; }; // Component carrier index diff --git a/srsenb/hdr/phy/phy_common.h b/srsenb/hdr/phy/phy_common.h index 8d42034bb..568da5fc7 100644 --- a/srsenb/hdr/phy/phy_common.h +++ b/srsenb/hdr/phy/phy_common.h @@ -23,6 +23,7 @@ #define SRSENB_PHCH_COMMON_H #include "phy_interfaces.h" +#include "srsenb/hdr/phy/phy_ue_db.h" #include "srslte/common/gen_mch_tables.h" #include "srslte/common/interfaces_common.h" #include "srslte/common/log.h" @@ -42,7 +43,7 @@ namespace srsenb { class phy_common { public: - phy_common(uint32_t nof_workers); + explicit phy_common(uint32_t nof_workers); ~phy_common(); void set_nof_workers(uint32_t nof_workers); @@ -132,110 +133,10 @@ public: stack_interface_phy_lte::ul_sched_list_t ul_grants[TTIMOD_SZ] = {}; stack_interface_phy_lte::dl_sched_list_t dl_grants[TTIMOD_SZ] = {}; - // Map of pending ACKs for each user - typedef struct { - srslte_uci_cfg_ack_t ack[SRSLTE_MAX_CARRIERS]; - } pending_ack_t; - - class common_ue - { - public: - pending_ack_t pending_ack[TTIMOD_SZ] = {}; - uint8_t ri = 0; - uint32_t pcell_idx = 0; - srslte_ra_tb_t last_tb[SRSLTE_MAX_HARQ_PROC] = {}; - std::map scell_map; - }; - - std::map common_ue_db; - /** - * Adds or modifies a user in the UE database setting. This function requires a list of cells indexes for the UE. The - * first element of the list must be the PCell and the rest will be SCell in the order - * - * @param rnti identifier of the user - * @param cell_index_list List of the eNb cell indexes for carrier aggregation + * UE Database object, direct public access, all PHY threads should be able to access this attribute directly */ - void ue_db_addmod_rnti(uint16_t rnti, const std::vector& cell_index_list); - - /** - * Removes a whole UE entry from the UE database - * - * @param rnti identifier of the UE - */ - void ue_db_rem_rnti(uint16_t rnti); - - /** - * Removes all the pending ACKs of all the RNTIs for a given TTI - * - * @param tti is the given TTI to clear - */ - void ue_db_clear_tti_pending_ack(uint32_t tti); - - /** - * Sets the pending ACK for a given TTI in a given Component Carrier and user (RNTI is a member of the DCI) - * - * @param tti is the given TTI to fill - * @param cc_idx the carrier where the DCI is scheduled - * @param dci carries the Transport Block and required scheduling information - * - */ - void ue_db_set_ack_pending(uint32_t tti, uint32_t cc_idx, const srslte_dci_dl_t& dci); - - /** - * Requests ACK information for a given RNTI that needs to acknowledge PDSCH transmissions in the cc_idx cell/carrier. - * - * @param tti is the given TTI to fill - * @param cc_idx the carrier where the DCI is scheduled - * @param rnti is the UE identifier - * @param uci_cfg_ack vector pointing at the UCI configuration - * - */ - void ue_db_get_ack_pending(uint32_t tti, - uint32_t cc_idx, - uint16_t rnti, - srslte_uci_cfg_ack_t uci_cfg_ack[SRSLTE_MAX_CARRIERS]); - - /** - * Provides the number of aggregated cells for a given RNTI - * @param rnti UE's RNTI - * @return the number of aggregated cells if the RNTI exists, otherwise it returns 0 - */ - uint32_t ue_db_get_nof_ca_cells(uint16_t rnti); - - /** - * Provides the PCell index of a given UE from its RNTI - * @param rnti UE's RNTI - * @return the index of the PCell if it exists, the number of cells otherwise - */ - uint32_t ue_db_get_cc_pcell(uint16_t rnti); - - /** - * Requests the eNb cell index of given RNTI from its scell_idx - * - * @param rnti the UE temporal ID - * @param scell_idx the UE SCell index, use 0 for PCell index - * @return the eNb cell index if found, the number of eNb cells otherwise - * - */ - uint32_t ue_db_get_cc_scell(uint16_t rnti, uint32_t scell_idx); - - /** - * - * @param rnti - * @param ri - */ - void ue_db_set_ri(uint16_t rnti, uint8_t ri); - - /** - * - * @param rnti - * @return - */ - uint8_t ue_db_get_ri(uint16_t rnti); - - void ue_db_set_last_ul_tb(uint16_t rnti, uint32_t pid, srslte_ra_tb_t tb); - srslte_ra_tb_t ue_db_get_last_ul_tb(uint16_t rnti, uint32_t pid); + phy_ue_db ue_db; void configure_mbsfn(phy_interface_stack_lte::phy_cfg_mbsfn_t* cfg); void build_mch_table(); @@ -251,22 +152,17 @@ private: uint32_t nof_workers = 0; uint32_t max_workers = 0; - std::mutex user_mutex = {}; - - bool have_mtch_stop = false; - pthread_mutex_t mtch_mutex = {}; - pthread_cond_t mtch_cvar = {}; - phy_interface_stack_lte::phy_cfg_mbsfn_t mbsfn = {}; - bool sib13_configured = false; - bool mcch_configured = false; - uint8_t mch_table[40] = {}; - uint8_t mcch_table[10] = {}; - uint32_t mch_period_stop = 0; - uint8_t mch_sf_idx_lut[10] = {}; + bool have_mtch_stop = false; + pthread_mutex_t mtch_mutex = {}; + pthread_cond_t mtch_cvar = {}; + phy_interface_stack_lte::phy_cfg_mbsfn_t mbsfn = {}; + bool sib13_configured = false; + bool mcch_configured = false; + uint8_t mch_table[40] = {}; + uint8_t mcch_table[10] = {}; + uint32_t mch_period_stop = 0; bool is_mch_subframe(srslte_mbsfn_cfg_t* cfg, uint32_t phy_tti); bool is_mcch_subframe(srslte_mbsfn_cfg_t* cfg, uint32_t phy_tti); - - void add_rnti(uint16_t rnti); }; } // namespace srsenb diff --git a/srsenb/hdr/phy/phy_ue_db.h b/srsenb/hdr/phy/phy_ue_db.h new file mode 100644 index 000000000..bfe6697f0 --- /dev/null +++ b/srsenb/hdr/phy/phy_ue_db.h @@ -0,0 +1,247 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * srsLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#ifndef SRSENB_PHY_UE_DB_H_ +#define SRSENB_PHY_UE_DB_H_ + +#include "phy_interfaces.h" +#include +#include +#include +#include + +namespace srsenb { + +class phy_ue_db +{ +private: + /** + * SCell Configuration state indicates whether the SCell has been configured from the RRC set and activated from the + * MAC layer. + * + * Initially the the state is default and it goes to deactivated as soon as it is configured from RRC, then it can + * transition to active as soon as the MAC indicates so. + * + * +---------+ Set SCell Configuration +-------------+ SCell activation +--------+ + * | Default | --------------------------->| Deactivated |--------------------->| Active | + * +---------+ +-------------+ +--------+ + * ^ ^ ^ | | + * | | | | | + * --+ | | SCell deactivation | | + * | +---------------------------------+ | + * | Reconfigure SCell | + * | Remove SCell configuration | + * +-----------------------------------------------------------------------------+ + */ + typedef enum { + scell_state_default = 0, ///< Default values, not configured, not active + scell_state_deactivated, ///< Configured from RRC but not activated + scell_state_active ///< PCell or activated from MAC + } scell_state_t; + + /** + * SCell information for the UE database + */ + typedef struct { + scell_state_t state = scell_state_default; ///< Configuration state + uint32_t cc_idx = 0; ///< Corresponding eNb cell/carrier index + uint8_t last_ri = 0; ///< Last reported rank indicator + srslte_ra_tb_t last_tb[SRSLTE_MAX_HARQ_PROC] = {}; ///< Stores last PUSCH Resource allocation + srslte::phy_cfg_t phy_cfg; ///< Configuration, it has a default constructor + } scell_info_t; + + /** + * UE object stored in the PHY common database + */ + struct common_ue { + srslte_pdsch_ack_t pdsch_ack[TTIMOD_SZ] = {}; ///< Pending acknowledgements for this SCell + scell_info_t scell_info[SRSLTE_MAX_CARRIERS]; ///< SCell information, indexed by scell_idx + }; + + /** + * UE database indexed by RNTI + */ + std::map ue_db; + + /** + * Concurrency protection mutex, allowed modifications from const methods. + */ + mutable std::mutex mutex; + + /** + * Stack interface + */ + stack_interface_phy_lte* stack = nullptr; + + /** + * Cell list + */ + const phy_cell_cfg_list_t* cell_cfg_list = nullptr; + + /** + * Internal RNTI addition, it is not thread safe protected + * + * @param rnti identifier of the UE + */ + inline void _add_rnti(uint16_t rnti); + + /** + * Internal pending ACK clear for a given RNTI and TTI, it is not thread safe protected + * + * @param tti is the given TTI (requires assertion prior to call) + * @param rnti identifier of the UE (requires assertion prior to call) + */ + inline void _clear_tti_pending_rnti(uint32_t tti, uint16_t rnti); + + /** + * Helper method to set the constant attributes of a given RNTI after the configuration is set + * + * @param rnti identifier of the UE (requires assertion prior to call) + */ + inline void _set_config_rnti(uint16_t rnti); + + /** + * Gets the SCell index for a given RNTI and a eNb cell/carrier. It returns the SCell index (0 if PCell) if the cc_idx + * is found among the configured cells/carriers. Otherwise, it returns SRSLTE_MAX_CARRIERS. + * + * @param rnti identifier of the UE (requires assertion prior to call) + * @param cc_idx the eNb cell/carrier index to look for in the RNTI. + * @return the SCell index as described above. + */ + inline uint32_t _get_scell_idx(uint16_t rnti, uint32_t cc_idx) const; + +public: + /** + * Initialises the UE database with the stack and cell list + * @param stack_ptr points to the stack (read/write) + * @param cell_cfg_list_ points to the cell configuration list (read only) + */ + void init(stack_interface_phy_lte* stack_ptr, const phy_cell_cfg_list_t& cell_cfg_list_) + { + stack = stack_ptr; + cell_cfg_list = &cell_cfg_list_; + } + + /** + * Adds or modifies a user in the UE database setting. This function requires the physical layer configuration coming + * from the RRC in order to extract cross carrier information such as channel quality reporting configuration. The + * first element of the list must be the PCell and the rest will be SCell in the order + * + * @param rnti identifier of the user + * @param phy_rrc_dedicated_list List of the eNb physical layer configuration coming for the RRC + */ + void addmod_rnti(uint16_t rnti, const phy_interface_rrc_lte::phy_rrc_dedicated_list_t& phy_rrc_dedicated_list); + + /** + * Removes a whole UE entry from the UE database + * + * @param rnti identifier of the UE + */ + void rem_rnti(uint16_t rnti); + + /** + * Activates or deactivates configured SCells for a given RNTI and SCell index (UE SCell index), index 0 is reserved + * for PCell + * @param rnti identifier of the UE + * @param scell_idx + * @param activate + */ + void activate_deactivate_scell(uint16_t rnti, uint32_t scell_idx, bool activate); + + /** + * Get the current physical layer configuration for an RNTI and an eNb cell/carrier + * + * @param rnti identifier of the UE + * @param cc_idx the eNb cell/carrier identifier + */ + srslte::phy_cfg_t get_config(uint16_t rnti, uint32_t cc_idx) const; + + /** + * Removes all the pending ACKs of all the RNTIs for a given TTI + * + * @param tti is the given TTI to clear + */ + void clear_tti_pending_ack(uint32_t tti); + + /** + * Sets the pending ACK for a given TTI in a given Component Carrier and user (RNTI is a member of the DCI) + * + * @param tti is the given TTI to fill + * @param cc_idx the carrier where the DCI is scheduled + * @param dci carries the Transport Block and required scheduling information + * + */ + void set_ack_pending(uint32_t tti, uint32_t cc_idx, const srslte_dci_dl_t& dci); + + /** + * Fills the Uplink Control Information (UCI) configuration and returns true/false idicating if UCI bits are required. + * @param tti the current UL reception TTI + * @param cc_idx the eNb cell/carrier where the UL receiption is happening + * @param rnti is the UE identifier + * @param aperiodic_cqi_request indicates if aperiodic CQI was requested + * @param uci_cfg brings the UCI configuration + * @return true if UCI decoding is required and false otherwise + */ + bool fill_uci_cfg(uint32_t tti, + uint32_t cc_idx, + uint16_t rnti, + bool aperiodic_cqi_request, + srslte_uci_cfg_t& uci_cfg) const; + + /** + * Sends the decoded Uplink Control Information by PUCCH or PUSCH to MAC + * @param tti the current TTI + * @param rnti is the UE identifier + * @param uci_cfg is the UCI configuration + * @param uci_value is the UCI received value + */ + void send_uci_data(uint32_t tti, + uint16_t rnti, + uint32_t cc_idx, + const srslte_uci_cfg_t& uci_cfg, + const srslte_uci_value_t& uci_value); + + /** + * Set the latest UL Transport Block resource allocation for a given RNTI, eNb cell/carrier and UL HARQ process + * identifier. + * + * @param rnti the UE temporal ID + * @param cc_idx the cell/carrier origin of the transmission + * @param pid HARQ process identifier + * @param tb the Resource Allocation for the PUSCH transport block + */ + void set_last_ul_tb(uint16_t rnti, uint32_t cc_idx, uint32_t pid, srslte_ra_tb_t tb); + + /** + * Get the latest UL Transport Block resource allocation for a given RNTI, eNb cell/carrier and UL HARQ process + * identifier. It returns the resource allocation if the RNTI and cell/eNb are valid, otherwise it will return an + * default Resource allocation (all zeros by default). + * + * @param rnti the UE temporal ID + * @param cc_idx the cell/carrier origin of the transmission + * @param pid HARQ process identifier + * @return the Resource Allocation for the PUSCH transport block + */ + srslte_ra_tb_t get_last_ul_tb(uint16_t rnti, uint32_t cc_idx, uint32_t pid) const; +}; + +} // namespace srsenb +#endif // SRSENB_PHY_UE_DB_H_ diff --git a/srsenb/hdr/phy/sf_worker.h b/srsenb/hdr/phy/sf_worker.h index cfd82e552..5eb389bc7 100644 --- a/srsenb/hdr/phy/sf_worker.h +++ b/srsenb/hdr/phy/sf_worker.h @@ -42,7 +42,7 @@ public: cf_t* get_buffer_rx(uint32_t cc_idx, uint32_t antenna_idx); void set_time(uint32_t tti, uint32_t tx_worker_cnt, srslte_timestamp_t tx_time); - int add_rnti(uint16_t rnti, uint32_t cc_idx, bool is_temporal); + int add_rnti(uint16_t rnti, uint32_t cc_idx, bool is_pcell, bool is_temporal); void rem_rnti(uint16_t rnti); uint32_t get_nof_rnti(); @@ -53,8 +53,6 @@ public: int read_pucch_d(cf_t* pusch_d); void start_plot(); - void set_config_dedicated(uint16_t rnti, uint32_t cc_idx, const srslte::phy_cfg_t& dedicated); - uint32_t get_metrics(phy_metrics_t metrics[ENB_METRICS_MAX_USERS]); private: diff --git a/srsenb/src/phy/cc_worker.cc b/srsenb/src/phy/cc_worker.cc index 2ce6cbd79..7ae93c062 100644 --- a/srsenb/src/phy/cc_worker.cc +++ b/srsenb/src/phy/cc_worker.cc @@ -126,14 +126,14 @@ void cc_worker::init(phy_common* phy_, srslte::log* log_h_, uint32_t cc_idx_) } /* Setup SI-RNTI in PHY */ - add_rnti(SRSLTE_SIRNTI, false); + add_rnti(SRSLTE_SIRNTI, false, false); /* Setup P-RNTI in PHY */ - add_rnti(SRSLTE_PRNTI, false); + add_rnti(SRSLTE_PRNTI, false, false); /* Setup RA-RNTI in PHY */ for (int i = 0; i < 10; i++) { - add_rnti(1 + i, false); + add_rnti(1 + i, false, false); } if (srslte_softbuffer_tx_init(&temp_mbsfn_softbuffer, nof_prb)) { @@ -177,13 +177,9 @@ void cc_worker::set_tti(uint32_t tti_) tti_rx = tti_; tti_tx_dl = TTI_TX(tti_rx); tti_tx_ul = TTI_RX_ACK(tti_rx); - - t_tx_dl = TTIMOD(tti_tx_dl); - t_rx = TTIMOD(tti_rx); - t_tx_ul = TTIMOD(tti_tx_ul); } -int cc_worker::add_rnti(uint16_t rnti, bool is_temporal) +int cc_worker::add_rnti(uint16_t rnti, bool is_pcell, bool is_temporal) { if (!is_temporal && !ue_db.count(rnti)) { @@ -198,7 +194,7 @@ int cc_worker::add_rnti(uint16_t rnti, bool is_temporal) mutex.lock(); // Create user unless already exists if (!ue_db.count(rnti)) { - ue_db[rnti] = new ue(rnti, phy); + ue_db[rnti] = new ue(rnti, is_pcell); } mutex.unlock(); @@ -246,22 +242,6 @@ uint32_t cc_worker::get_nof_rnti() return ue_db.size(); } -void cc_worker::set_config_dedicated(uint16_t rnti, const srslte::phy_cfg_t& dedicated) -{ - std::lock_guard lock(mutex); - - if (ue_db.count(rnti)) { - ue_db[rnti]->ul_cfg = dedicated.ul_cfg; - ue_db[rnti]->ul_cfg.pucch.threshold_format1 = SRSLTE_PUCCH_DEFAULT_THRESHOLD_FORMAT1; - ue_db[rnti]->ul_cfg.pucch.rnti = rnti; - ue_db[rnti]->ul_cfg.pusch.rnti = rnti; - ue_db[rnti]->dl_cfg = dedicated.dl_cfg; - ue_db[rnti]->dl_cfg.pdsch.rnti = rnti; - } else { - Error("Setting config dedicated: rnti=0x%x does not exist\n", rnti); - } -} - void cc_worker::work_ul(const srslte_ul_sf_cfg_t& ul_sf_cfg, stack_interface_phy_lte::ul_sched_t& ul_grants) { std::lock_guard lock(mutex); @@ -313,126 +293,28 @@ void cc_worker::work_dl(const srslte_dl_sf_cfg_t& dl_sf_cfg, srslte_enb_dl_gen_signal(&enb_dl); } -bool cc_worker::fill_uci_cfg(uint16_t rnti, bool aperiodic_cqi_request, srslte_uci_cfg_t* uci_cfg) -{ - bool uci_required = false; - - bzero(uci_cfg, sizeof(srslte_uci_cfg_t)); - - // Check if SR opportunity (will only be used in PUCCH) - uci_cfg->is_scheduling_request_tti = (srslte_ue_ul_sr_send_tti(&ue_db[rnti]->ul_cfg.pucch, tti_rx) == 1); - - uci_required |= uci_cfg->is_scheduling_request_tti; - - // Get pending ACKs from PDSCH - phy->ue_db_get_ack_pending(tti_rx, cc_idx, rnti, uci_cfg->ack); - uint32_t nof_total_ack = srslte_uci_cfg_total_ack(uci_cfg); - uci_required |= (nof_total_ack != 0); - - // if UCI is required and the PCell is not the only cell - if (uci_required && nof_total_ack != uci_cfg->ack[0].nof_acks) { - // More than one carrier requires ACKs - for (uint32_t cc = 0; cc < phy->ue_db_get_nof_ca_cells(rnti); cc++) { - // Assume all aggregated carriers are on the same transmission mode - uci_cfg->ack[cc].nof_acks = (ue_db[rnti]->dl_cfg.tm < SRSLTE_TM3) ? 1 : 2; - } - } - - // Get pending CQI reports for this TTI - if (srslte_enb_dl_gen_cqi_periodic( - &enb_dl.cell, &ue_db[rnti]->dl_cfg, tti_rx, phy->ue_db_get_ri(rnti), &uci_cfg->cqi)) { - uci_required = true; - } else if (aperiodic_cqi_request) { - srslte_enb_dl_gen_cqi_aperiodic(&enb_dl.cell, &ue_db[rnti]->dl_cfg, phy->ue_db_get_ri(rnti), &uci_cfg->cqi); - uci_required = true; - } - - return uci_required; -} - -void cc_worker::send_uci_data(uint16_t rnti, srslte_uci_cfg_t* uci_cfg, srslte_uci_value_t* uci_value) -{ - // Notify SR - if (uci_cfg->is_scheduling_request_tti && uci_value->scheduling_request) { - phy->stack->sr_detected(tti_rx, rnti); - } - - /* If only one ACK is required, it can be for TB0 or TB1 */ - uint32_t ack_idx = 0; - for (uint32_t ue_scell_idx = 0; ue_scell_idx < SRSLTE_MAX_CARRIERS; ue_scell_idx++) { - uint32_t cc_ack_idx = phy->ue_db_get_cc_scell(rnti, ue_scell_idx); - if (cc_ack_idx < phy->get_nof_carriers()) { - - // For each transport block... - for (uint32_t tb = 0; tb < uci_cfg->ack[ue_scell_idx].nof_acks; tb++) { - // Check if the SCell ACK was pending - if (uci_cfg->ack[ue_scell_idx].pending_tb[tb]) { - bool ack = uci_value->ack.ack_value[ack_idx]; - bool valid = uci_value->ack.valid; - phy->stack->ack_info(tti_rx, rnti, cc_ack_idx, tb, ack && valid); - } - ack_idx++; - } - } - } - - // Notify CQI only if CRC is valid - if (uci_value->cqi.data_crc) { - if (uci_cfg->cqi.data_enable) { - uint8_t cqi_value = 0; - switch (uci_cfg->cqi.type) { - case SRSLTE_CQI_TYPE_WIDEBAND: - cqi_value = uci_value->cqi.wideband.wideband_cqi; - break; - case SRSLTE_CQI_TYPE_SUBBAND: - cqi_value = uci_value->cqi.subband.subband_cqi; - break; - case SRSLTE_CQI_TYPE_SUBBAND_HL: - cqi_value = uci_value->cqi.subband_hl.wideband_cqi_cw0; - break; - case SRSLTE_CQI_TYPE_SUBBAND_UE: - cqi_value = uci_value->cqi.subband_ue.wideband_cqi; - break; - } - phy->stack->cqi_info(tti_rx, rnti, 0, cqi_value); - } - if (uci_cfg->cqi.ri_len) { - phy->stack->ri_info(tti_rx, 0, rnti, uci_value->ri); - phy->ue_db_set_ri(rnti, uci_value->ri); - } - if (uci_cfg->cqi.pmi_present) { - uint8_t pmi_value = 0; - switch (uci_cfg->cqi.type) { - case SRSLTE_CQI_TYPE_WIDEBAND: - pmi_value = uci_value->cqi.wideband.pmi; - break; - case SRSLTE_CQI_TYPE_SUBBAND_HL: - pmi_value = uci_value->cqi.subband_hl.pmi; - break; - default: - Error("CQI type=%d not implemented for PMI\n", uci_cfg->cqi.type); - break; - } - phy->stack->pmi_info(tti_rx, rnti, 0, pmi_value); - } - } -} - int cc_worker::decode_pusch(stack_interface_phy_lte::ul_sched_grant_t* grants, uint32_t nof_pusch) { srslte_pusch_res_t pusch_res; - for (uint32_t i = 0; i < nof_pusch; i++) { - uint16_t rnti = grants[i].dci.rnti; + // Get grant itself and RNTI + auto& ul_grant = grants[i]; + uint16_t rnti = ul_grant.dci.rnti; + if (rnti) { + // Get UE configuration + srslte::phy_cfg_t phy_cfg = phy->ue_db.get_config(rnti, cc_idx); + srslte_ul_cfg_t& ul_cfg = phy_cfg.ul_cfg; + // mark this tti as having an ul dci to avoid pucch ue_db[rnti]->is_grant_available = true; - fill_uci_cfg(rnti, grants->dci.cqi_request, &ue_db[rnti]->ul_cfg.pusch.uci_cfg); + // Fill UCI configuration + phy->ue_db.fill_uci_cfg(tti_rx, cc_idx, rnti, grants->dci.cqi_request, phy_cfg.ul_cfg.pucch.uci_cfg); // Compute UL grant - srslte_pusch_grant_t* grant = &ue_db[rnti]->ul_cfg.pusch.grant; - if (srslte_ra_ul_dci_to_grant(&enb_ul.cell, &ul_sf, &ue_db[rnti]->ul_cfg.hopping, &grants[i].dci, grant)) { + srslte_pusch_grant_t& grant = phy_cfg.ul_cfg.pusch.grant; + if (srslte_ra_ul_dci_to_grant(&enb_ul.cell, &ul_sf, &ul_cfg.hopping, &ul_grant.dci, &grant)) { Error("Computing PUSCH dci\n"); return SRSLTE_ERROR; } @@ -441,25 +323,25 @@ int cc_worker::decode_pusch(stack_interface_phy_lte::ul_sched_grant_t* grants, u // Handle Format0 adaptive retx // Use last TBS for this TB in case of mcs>28 - if (grants[i].dci.tb.mcs_idx > 28) { - grant->tb = phy->ue_db_get_last_ul_tb(rnti, ul_pid); - Info("RETX: mcs=%d, old_tbs=%d pid=%d\n", grants[i].dci.tb.mcs_idx, grant->tb.tbs, ul_pid); + if (ul_grant.dci.tb.mcs_idx > 28) { + grant.tb = phy->ue_db.get_last_ul_tb(rnti, cc_idx, ul_pid); + Info("RETX: mcs=%d, old_tbs=%d pid=%d\n", grants[i].dci.tb.mcs_idx, grant.tb.tbs, ul_pid); } - phy->ue_db_set_last_ul_tb(rnti, ul_pid, grant->tb); + phy->ue_db.set_last_ul_tb(rnti, cc_idx, ul_pid, grant.tb); // Run PUSCH decoder - pusch_res = {}; - ue_db[rnti]->ul_cfg.pusch.softbuffers.rx = grants[i].softbuffer_rx; - pusch_res.data = grants[i].data; + pusch_res = {}; + ul_cfg.pusch.softbuffers.rx = grants[i].softbuffer_rx; + pusch_res.data = grants[i].data; if (pusch_res.data) { - if (srslte_enb_ul_get_pusch(&enb_ul, &ul_sf, &ue_db[rnti]->ul_cfg.pusch, &pusch_res)) { + if (srslte_enb_ul_get_pusch(&enb_ul, &ul_sf, &ul_cfg.pusch, &pusch_res)) { Error("Decoding PUSCH\n"); return SRSLTE_ERROR; } } // Save PHICH scheduling for this user. Each user can have just 1 PUSCH dci per TTI - ue_db[rnti]->phich_grant.n_prb_lowest = grant->n_prb_tilde[0]; + ue_db[rnti]->phich_grant.n_prb_lowest = grant.n_prb_tilde[0]; ue_db[rnti]->phich_grant.n_dmrs = grants[i].dci.n_dmrs; float snr_db = enb_ul.chest_res.snr_db; @@ -479,18 +361,18 @@ int cc_worker::decode_pusch(stack_interface_phy_lte::ul_sched_grant_t* grants, u } // Send UCI data to MAC - send_uci_data(rnti, &ue_db[rnti]->ul_cfg.pusch.uci_cfg, &pusch_res.uci); + phy->ue_db.send_uci_data(tti_rx, rnti, cc_idx, ul_cfg.pusch.uci_cfg, pusch_res.uci); // Notify MAC new received data and HARQ Indication value if (pusch_res.data) { - phy->stack->crc_info(tti_rx, rnti, cc_idx, grant->tb.tbs / 8, pusch_res.crc); + phy->stack->crc_info(tti_rx, rnti, cc_idx, grant.tb.tbs / 8, pusch_res.crc); // Save metrics stats ue_db[rnti]->metrics_ul(grants[i].dci.tb.mcs_idx, 0, snr_db, pusch_res.avg_iterations_block); // Logging char str[512]; - srslte_pusch_rx_info(&ue_db[rnti]->ul_cfg.pusch, &pusch_res, str, 512); + srslte_pusch_rx_info(&ul_cfg.pusch, &pusch_res, str, 512); Info("PUSCH: %s, snr=%.1f dB\n", str, snr_db); } } @@ -500,24 +382,25 @@ int cc_worker::decode_pusch(stack_interface_phy_lte::ul_sched_grant_t* grants, u int cc_worker::decode_pucch() { - srslte_pucch_res_t pucch_res; - ZERO_OBJECT(pucch_res); + srslte_pucch_res_t pucch_res = {}; for (auto& iter : ue_db) { - auto rnti = (uint16_t)iter.first; + auto rnti = (uint16_t)iter.first; + auto phy_cfg = phy->ue_db.get_config(rnti, cc_idx); + auto& ul_cfg = phy_cfg.ul_cfg; // If it's a User RNTI and doesn't have PUSCH grant in this TTI - if (SRSLTE_RNTI_ISUSER(rnti) && !ue_db[rnti]->is_grant_available) { + if (SRSLTE_RNTI_ISUSER(rnti) && !ue_db[rnti]->is_grant_available && ue_db[rnti]->is_pcell()) { // Check if user needs to receive PUCCH - if (fill_uci_cfg(rnti, false, &ue_db[rnti]->ul_cfg.pucch.uci_cfg)) { + if (phy->ue_db.fill_uci_cfg(tti_rx, cc_idx, rnti, false, ul_cfg.pucch.uci_cfg)) { // Decode PUCCH - if (srslte_enb_ul_get_pucch(&enb_ul, &ul_sf, &ue_db[rnti]->ul_cfg.pucch, &pucch_res)) { + if (srslte_enb_ul_get_pucch(&enb_ul, &ul_sf, &ul_cfg.pucch, &pucch_res)) { ERROR("Error getting PUCCH\n"); return SRSLTE_ERROR; } // Notify MAC of RL status (skip SR subframes) - if (!ue_db[rnti]->ul_cfg.pucch.uci_cfg.is_scheduling_request_tti) { + if (!ul_cfg.pucch.uci_cfg.is_scheduling_request_tti) { if (pucch_res.correlation < PUCCH_RL_CORR_TH) { Debug("PUCCH: Radio-Link failure corr=%.1f\n", pucch_res.correlation); phy->stack->rl_failure(rnti); @@ -527,12 +410,12 @@ int cc_worker::decode_pucch() } // Send UCI data to MAC - send_uci_data(rnti, &ue_db[rnti]->ul_cfg.pucch.uci_cfg, &pucch_res.uci_data); + phy->ue_db.send_uci_data(tti_rx, rnti, cc_idx, ul_cfg.pucch.uci_cfg, pucch_res.uci_data); // Logging char str[512]; - srslte_pucch_rx_info(&ue_db[rnti]->ul_cfg.pucch, &pucch_res.uci_data, str, 512); - Info("PUCCH: %s, corr=%.1f\n", str, pucch_res.correlation); + srslte_pucch_rx_info(&ul_cfg.pucch, &pucch_res.uci_data, str, 512); + Info("PUCCH: cc=%d; %s, corr=%.1f\n", cc_idx, str, pucch_res.correlation); } } } @@ -627,22 +510,24 @@ int cc_worker::encode_pdsch(stack_interface_phy_lte::dl_sched_grant_t* grants, u /* Scales the Resources Elements affected by the power allocation (p_b) */ // srslte_enb_dl_prepare_power_allocation(&enb_dl); for (uint32_t i = 0; i < nof_grants; i++) { - uint16_t rnti = grants[i].dci.rnti; + uint16_t rnti = grants[i].dci.rnti; + auto phy_cfg = phy->ue_db.get_config(rnti, cc_idx); + srslte_dl_cfg_t& dl_cfg = phy_cfg.dl_cfg; + if (rnti && ue_db.count(rnti)) { // Compute DL grant - if (srslte_ra_dl_dci_to_grant( - &enb_dl.cell, &dl_sf, ue_db[rnti]->dl_cfg.tm, false, &grants[i].dci, &ue_db[rnti]->dl_cfg.pdsch.grant)) { + if (srslte_ra_dl_dci_to_grant(&enb_dl.cell, &dl_sf, dl_cfg.tm, false, &grants[i].dci, &dl_cfg.pdsch.grant)) { Error("Computing DL grant\n"); } // Set soft buffer for (uint32_t j = 0; j < SRSLTE_MAX_CODEWORDS; j++) { - ue_db[rnti]->dl_cfg.pdsch.softbuffers.tx[j] = grants[i].softbuffer_tx[j]; + dl_cfg.pdsch.softbuffers.tx[j] = grants[i].softbuffer_tx[j]; } // Encode PDSCH - if (srslte_enb_dl_put_pdsch(&enb_dl, &ue_db[rnti]->dl_cfg.pdsch, grants[i].data)) { + if (srslte_enb_dl_put_pdsch(&enb_dl, &dl_cfg.pdsch, grants[i].data)) { Error("Error putting PDSCH %d\n", i); return SRSLTE_ERROR; } @@ -650,13 +535,13 @@ int cc_worker::encode_pdsch(stack_interface_phy_lte::dl_sched_grant_t* grants, u // Save pending ACK if (SRSLTE_RNTI_ISUSER(rnti)) { // Push whole DCI - phy->ue_db_set_ack_pending(tti_tx_ul, cc_idx, grants[i].dci); + phy->ue_db.set_ack_pending(tti_tx_ul, cc_idx, grants[i].dci); } if (LOG_THIS(rnti)) { // Logging char str[512]; - srslte_pdsch_tx_info(&ue_db[rnti]->dl_cfg.pdsch, str, 512); + srslte_pdsch_tx_info(&dl_cfg.pdsch, str, 512); Info("PDSCH: cc=%d, %s, tti_tx_dl=%d\n", cc_idx, str, tti_tx_dl); } diff --git a/srsenb/src/phy/phy.cc b/srsenb/src/phy/phy.cc index 0ed3e905c..5bdc7b840 100644 --- a/srsenb/src/phy/phy.cc +++ b/srsenb/src/phy/phy.cc @@ -195,11 +195,15 @@ uint32_t phy::tti_to_subf(uint32_t tti) int phy::add_rnti(uint16_t rnti, uint32_t pcell_index, bool is_temporal) { if (SRSLTE_RNTI_ISUSER(rnti)) { - workers_common.ue_db_addmod_rnti(rnti, {pcell_index}); + // Create default PHY configuration with the desired PCell index + phy_interface_rrc_lte::phy_rrc_dedicated_list_t phy_rrc_dedicated_list(1); + phy_rrc_dedicated_list[0].cc_idx = pcell_index; + + workers_common.ue_db.addmod_rnti(rnti, phy_rrc_dedicated_list); } for (uint32_t i = 0; i < nof_workers; i++) { - if (workers[i].add_rnti(rnti, pcell_index, is_temporal)) { + if (workers[i].add_rnti(rnti, pcell_index, true, is_temporal)) { return SRSLTE_ERROR; } } @@ -210,7 +214,7 @@ int phy::add_rnti(uint16_t rnti, uint32_t pcell_index, bool is_temporal) void phy::rem_rnti(uint16_t rnti) { if (SRSLTE_RNTI_ISUSER(rnti)) { - workers_common.ue_db_rem_rnti(rnti); + workers_common.ue_db.rem_rnti(rnti); } for (uint32_t i = 0; i < nof_workers; i++) { workers[i].rem_rnti(rnti); @@ -224,7 +228,10 @@ void phy::set_mch_period_stop(uint32_t stop) void phy::set_activation_deactivation_scell(uint16_t rnti, bool activation[SRSLTE_MAX_CARRIERS]) { - Info("Set activation/deactivation not implemented\n"); + // Iterate all elements except 0 that is reserved for primary cell + for (uint32_t scell_idx = 1; scell_idx < SRSLTE_MAX_CARRIERS; scell_idx++) { + workers_common.ue_db.activate_deactivate_scell(rnti, scell_idx, activation[scell_idx]); + } } void phy::get_metrics(phy_metrics_t metrics[ENB_METRICS_MAX_USERS]) @@ -261,28 +268,21 @@ void phy::get_metrics(phy_metrics_t metrics[ENB_METRICS_MAX_USERS]) void phy::set_config_dedicated(uint16_t rnti, const phy_rrc_dedicated_list_t& dedicated_list) { - // Create list, empty by default - std::vector scell_idx_list; + // Update UE Database + workers_common.ue_db.addmod_rnti(rnti, dedicated_list); + + // Iterate over the list and add the RNTIs + for (uint32_t scell_idx = 0; scell_idx < dedicated_list.size(); scell_idx++) { + auto& config = dedicated_list[scell_idx]; - for (const auto& config : dedicated_list) { // Configure only if active, ignore otherwise - if (config.configured) { - // Set PCell/SCell index in list - scell_idx_list.push_back(config.cc_idx); - - // Configure workers + if (scell_idx != 0 && config.configured) { + // Add RNTI to workers for (uint32_t w = 0; w < nof_workers; w++) { - // Add RNTI to worker - workers[w].add_rnti(rnti, config.cc_idx, false); - - // Configure RNTI - workers[w].set_config_dedicated(rnti, config.cc_idx, config.phy_cfg); + workers[w].add_rnti(rnti, config.cc_idx, false, false); } } } - - // Finally, set UE database - workers_common.ue_db_addmod_rnti(rnti, scell_idx_list); } void phy::configure_mbsfn(sib_type2_s* sib2, sib_type13_r9_s* sib13, mcch_msg_s mcch) diff --git a/srsenb/src/phy/phy_common.cc b/srsenb/src/phy/phy_common.cc index 44502e79a..2985c1271 100644 --- a/srsenb/src/phy/phy_common.cc +++ b/srsenb/src/phy/phy_common.cc @@ -46,7 +46,7 @@ using namespace asn1::rrc; namespace srsenb { -phy_common::phy_common(uint32_t max_workers_) : tx_sem(max_workers_), cell_list() +phy_common::phy_common(uint32_t max_workers_) : tx_sem(max_workers_), cell_list(), ue_db() { params.max_prach_offset_us = 20; max_workers = max_workers_; @@ -109,6 +109,9 @@ bool phy_common::init(const phy_cell_cfg_list_t& cell_list_, is_first_tx = true; + // Set UE PHY data-base stack + ue_db.init(stack, cell_list); + reset(); return true; } @@ -158,194 +161,6 @@ void phy_common::worker_end(uint32_t tti, stack->tti_clock(); } -void phy_common::ue_db_clear_tti_pending_ack(uint32_t tti) -{ - std::lock_guard lock(user_mutex); - - for (auto& iter : common_ue_db) { - common_ue& ue = iter.second; - - // Reset all pending ACKs in all carriers - ue.pending_ack[TTIMOD(tti)] = {}; - } -} - -void phy_common::ue_db_addmod_rnti(uint16_t rnti, const std::vector& cell_index_list) -{ - std::lock_guard lock(user_mutex); - - // Create new user if did not exist - if (!common_ue_db.count(rnti)) { - add_rnti(rnti); - } - - // Get UE by reference - common_ue& ue = common_ue_db[rnti]; - - // Clear SCell map to avoid overlap from previous calls - ue.scell_map.clear(); - - // Add SCells to map - for (uint32_t i = 0; i < cell_index_list.size(); i++) { - common_ue_db[rnti].scell_map[cell_index_list[i]] = i; - } -} - -// Private function not mutexed -void phy_common::add_rnti(uint16_t rnti) -{ - for (auto& pending_ack : common_ue_db[rnti].pending_ack) { - pending_ack = {}; - } -} - -void phy_common::ue_db_rem_rnti(uint16_t rnti) -{ - std::lock_guard lock(user_mutex); - if (!common_ue_db.count(rnti)) { - common_ue_db.erase(rnti); - } -} - -void phy_common::ue_db_set_ack_pending(uint32_t tti, uint32_t cc_idx, const srslte_dci_dl_t& dci) -{ - std::lock_guard lock(user_mutex); - - // Check if the UE exists - if (!common_ue_db.count(dci.rnti)) { - return; - } - - // Check Component Carrier is part of UE SCell map - common_ue& ue = common_ue_db[dci.rnti]; - if (!ue.scell_map.count(cc_idx)) { - return; - } - - uint32_t scell_idx = ue.scell_map[cc_idx]; - uint32_t tti_idx = TTIMOD(tti); - pending_ack_t& pending_ack = ue.pending_ack[tti_idx]; // Assume it has been zero'ed for the TTI - - // Set DCI info - pending_ack.ack[scell_idx].grant_cc_idx = scell_idx; // No cross carrier scheduling supported - pending_ack.ack[scell_idx].ncce[0] = dci.location.ncce; - - // Set TB info - for (uint32_t i = 0; i < srslte_dci_format_max_tb(dci.format); i++) { - if (SRSLTE_DCI_IS_TB_EN(dci.tb[i])) { - pending_ack.ack[scell_idx].pending_tb[i] = true; - pending_ack.ack[scell_idx].nof_acks++; - } - } -} - -void phy_common::ue_db_get_ack_pending(uint32_t tti, - uint32_t cc_idx, - uint16_t rnti, - srslte_uci_cfg_ack_t uci_cfg_ack[SRSLTE_MAX_CARRIERS]) -{ - std::lock_guard lock(user_mutex); - - // Check if the UE exists - if (!common_ue_db.count(rnti)) { - return; - } - - common_ue& ue = common_ue_db[rnti]; - uint32_t tti_idx = TTIMOD(tti); - - // Check Component Carrier is the UE PCell - if (common_ue_db[rnti].pcell_idx == cc_idx) { - srslte_uci_cfg_ack_t* pending_acks = ue.pending_ack[tti_idx].ack; - - for (uint32_t i = 0; i < SRSLTE_MAX_CARRIERS; i++) { - // Copy pending acks - uci_cfg_ack[i] = pending_acks[i]; - - // Reset stored pending acks - pending_acks[i] = {}; - } - } else { - for (uint32_t i = 0; i < SRSLTE_MAX_CARRIERS; i++) { - // Set all to zeros, equivalent to no UCI data - uci_cfg_ack[i] = {}; - } - } -} - -uint32_t phy_common::ue_db_get_nof_ca_cells(uint16_t rnti) -{ - std::lock_guard lock(user_mutex); - auto ret = 0; - if (common_ue_db.count(rnti)) { - ret = common_ue_db[rnti].scell_map.size(); - } - return ret; -} - -uint32_t phy_common::ue_db_get_cc_pcell(uint16_t rnti) -{ - std::lock_guard lock(user_mutex); - auto ret = static_cast(cell_list.size()); - if (common_ue_db.count(rnti)) { - ret = common_ue_db[rnti].pcell_idx; - } - return ret; -} - -uint32_t phy_common::ue_db_get_cc_scell(uint16_t rnti, uint32_t scell_idx) -{ - std::lock_guard lock(user_mutex); - - if (common_ue_db.count(rnti)) { - auto& ue = common_ue_db[rnti]; - for (auto& it : ue.scell_map) { - if (it.second == scell_idx) { - return it.first; - } - } - } - - return static_cast(cell_list.size()); -} - -void phy_common::ue_db_set_ri(uint16_t rnti, uint8_t ri) -{ - std::lock_guard lock(user_mutex); - if (common_ue_db.count(rnti)) { - common_ue_db[rnti].ri = ri; - } -} - -uint8_t phy_common::ue_db_get_ri(uint16_t rnti) -{ - std::lock_guard lock(user_mutex); - uint8_t ret = 0; - if (common_ue_db.count(rnti)) { - ret = common_ue_db[rnti].ri; - } - return ret; -} - -void phy_common::ue_db_set_last_ul_tb(uint16_t rnti, uint32_t pid, srslte_ra_tb_t tb) -{ - std::lock_guard lock(user_mutex); - if (!common_ue_db.count(rnti)) { - add_rnti(rnti); - } - common_ue_db[rnti].last_tb[pid % SRSLTE_MAX_HARQ_PROC] = tb; -} - -srslte_ra_tb_t phy_common::ue_db_get_last_ul_tb(uint16_t rnti, uint32_t pid) -{ - std::lock_guard lock(user_mutex); - srslte_ra_tb_t ret = {}; - if (common_ue_db.count(rnti)) { - ret = common_ue_db[rnti].last_tb[pid % SRSLTE_FDD_NOF_HARQ]; - } - return ret; -} - void phy_common::set_mch_period_stop(uint32_t stop) { pthread_mutex_lock(&mtch_mutex); diff --git a/srsenb/src/phy/phy_ue_db.cc b/srsenb/src/phy/phy_ue_db.cc new file mode 100644 index 000000000..85ff2da72 --- /dev/null +++ b/srsenb/src/phy/phy_ue_db.cc @@ -0,0 +1,504 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * srsLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include "srsenb/hdr/phy/phy_ue_db.h" + +using namespace srsenb; + +inline void phy_ue_db::_add_rnti(uint16_t rnti) +{ + // Private function not mutexed + + // Assert RNTI does NOT exist + if (ue_db.count(rnti)) { + return; + } + + // Create new UE by accesing it + ue_db[rnti].scell_info[0] = {}; + + // Get UE + common_ue& ue = ue_db[rnti]; + + // Load default values to PCell + ue.scell_info[0].phy_cfg.set_defaults(); + + // Set constant configuration fields + _set_config_rnti(rnti); + + // PCell shall be active by default + ue.scell_info[0].state = scell_state_active; + + // Iterate all pending ACK + for (uint32_t tti = 0; tti < TTIMOD_SZ; tti++) { + _clear_tti_pending_rnti(tti, rnti); + } +} + +inline void phy_ue_db::_clear_tti_pending_rnti(uint32_t tti, uint16_t rnti) +{ + // Private function not mutexed, no need to assert RNTI or TTI + + // Get UE + common_ue& ue = ue_db[rnti]; + + srslte_pdsch_ack_t& pdsch_ack = ue.pdsch_ack[tti]; + + // Reset ACK information + pdsch_ack = {}; + + uint32_t nof_active_cc = 0; + for (auto& scell_info : ue.scell_info) { + if (scell_info.state == scell_state_active) { + nof_active_cc++; + } + } + + // Copy essentials + pdsch_ack.transmission_mode = ue.scell_info[0].phy_cfg.dl_cfg.tm; + pdsch_ack.nof_cc = nof_active_cc; + pdsch_ack.ack_nack_feedback_mode = ue.scell_info[0].phy_cfg.ul_cfg.pucch.ack_nack_feedback_mode; + pdsch_ack.simul_cqi_ack = ue.scell_info[0].phy_cfg.ul_cfg.pucch.simul_cqi_ack; +} + +inline void phy_ue_db::_set_config_rnti(uint16_t rnti) +{ + // Private function not mutexed, no need to assert RNTI or TTI + + // Get UE + common_ue& ue = ue_db[rnti]; + + // Iterate all cells/carriers + for (auto& scell_info : ue.scell_info) { + scell_info.phy_cfg.dl_cfg.pdsch.rnti = rnti; + scell_info.phy_cfg.ul_cfg.pucch.rnti = rnti; + scell_info.phy_cfg.ul_cfg.pusch.rnti = rnti; + scell_info.phy_cfg.ul_cfg.pucch.threshold_format1 = SRSLTE_PUCCH_DEFAULT_THRESHOLD_FORMAT1; + scell_info.phy_cfg.ul_cfg.pucch.threshold_data_valid_format1a = SRSLTE_PUCCH_DEFAULT_THRESHOLD_FORMAT1A; + scell_info.phy_cfg.ul_cfg.pucch.threshold_data_valid_format2 = SRSLTE_PUCCH_DEFAULT_THRESHOLD_FORMAT2; + } +} + +inline uint32_t phy_ue_db::_get_scell_idx(uint16_t rnti, uint32_t cc_idx) const +{ + uint32_t scell_idx = 0; + const common_ue& ue = ue_db.at(rnti); + + for (scell_idx = 0; scell_idx < SRSLTE_MAX_CARRIERS; scell_idx++) { + const scell_info_t& scell_info = ue.scell_info[scell_idx]; + if (scell_info.cc_idx == cc_idx && scell_info.state != scell_state_deactivated) { + return scell_idx; + } + } + + return scell_idx; +} + +void phy_ue_db::clear_tti_pending_ack(uint32_t tti) +{ + std::lock_guard lock(mutex); + + // Iterate all UEs + for (auto& iter : ue_db) { + _clear_tti_pending_rnti(TTIMOD(tti), iter.first); + } +} + +void phy_ue_db::addmod_rnti(uint16_t rnti, + const phy_interface_rrc_lte::phy_rrc_dedicated_list_t& phy_rrc_dedicated_list) +{ + std::lock_guard lock(mutex); + + // Create new user if did not exist + if (!ue_db.count(rnti)) { + _add_rnti(rnti); + } + + // Get UE by reference + common_ue& ue = ue_db[rnti]; + + // Iterate PHY RRC configuration for each cell/carrier + for (uint32_t scell_idx = 0; scell_idx < phy_rrc_dedicated_list.size() && scell_idx < SRSLTE_MAX_CARRIERS; + scell_idx++) { + auto& phy_rrc_dedicated = phy_rrc_dedicated_list[scell_idx]; + // Configured, add/modify entry in the scell_info map + auto& scell_info = ue.scell_info[scell_idx]; + + if (phy_rrc_dedicated.configured) { + // Set SCell information + scell_info.cc_idx = phy_rrc_dedicated.cc_idx; + scell_info.phy_cfg = phy_rrc_dedicated.phy_cfg; + + // Set constant configuration fields + _set_config_rnti(rnti); + + // Set SCell state, all deactivated by default except PCell + scell_info.state = scell_idx == 0 ? scell_state_active : scell_state_deactivated; + } else { + // Cell without configuration shall be default + scell_info.state = scell_state_default; + } + } + + // Iterate the rest of SCells + for (uint32_t scell_idx = phy_rrc_dedicated_list.size(); scell_idx < SRSLTE_MAX_CARRIERS; scell_idx++) { + // Set state of these to default + ue.scell_info[scell_idx].state = scell_state_default; + } +} + +void phy_ue_db::rem_rnti(uint16_t rnti) +{ + std::lock_guard lock(mutex); + + if (ue_db.count(rnti)) { + ue_db.erase(rnti); + } +} + +/** + * UE Database Assert macros. These macros avoid repeating code for asserting RNTI, eNb cell/carrier index, SCell + * indexes and so on. + * + * They are const friendly. All the methods they use of the attributes are const, so they do not modify any attribute. + */ +#define UE_DB_ASSERT_RNTI(RNTI, RET) \ + do { \ + if (not ue_db.count(RNTI)) { \ + /*ERROR("Trying to access RNTI x%x, it does not exist.\n", RNTI);*/ \ + return RET; \ + } \ + } while (false) + +#define UE_DB_ASSERT_CELL(RNTI, CC_IDX, RET) \ + do { \ + /* Check if the UE exists */ \ + UE_DB_ASSERT_RNTI(RNTI, RET); \ + \ + /* Check Component Carrier is part of UE SCell map*/ \ + if (_get_scell_idx(RNTI, CC_IDX) == SRSLTE_MAX_CARRIERS) { \ + ERROR("Trying to access cell/carrier index %d in RNTI x%x. It does not exist.\n", CC_IDX, RNTI); \ + return RET; \ + } \ + \ + /* Check SCell index is in range */ \ + const uint32_t scell_idx = _get_scell_idx(RNTI, CC_IDX); \ + if (scell_idx == SRSLTE_MAX_CARRIERS) { \ + ERROR("Corrupted SCell index %d for RNTI x%x and cell/carrier index %d\n", scell_idx, RNTI, CC_IDX); \ + return RET; \ + } \ + } while (false) + +#define UE_DB_ASSERT_ACTIVE_CELL(RNTI, CC_IDX, RET) \ + do { \ + /* Assert RNTI exists and eNb cell/carrier is configured */ \ + UE_DB_ASSERT_CELL(RNTI, CC_IDX, RET); \ + \ + /* Check SCell is active */ \ + auto& scell_info = ue_db.at(RNTI).scell_info[_get_scell_idx(RNTI, CC_IDX)]; \ + if (scell_info.state != scell_state_active) { \ + ERROR("Failed to assert active cell/carrier %d for RNTI x%x", CC_IDX, RNTI); \ + return RET; \ + } \ + } while (false) + +#define UE_DB_ASSERT_PCELL(RNTI, CC_IDX, RET) \ + do { \ + /* Assert RNTI exists and eNb cell/carrier is configured */ \ + UE_DB_ASSERT_CELL(RNTI, CC_IDX, RET); \ + \ + /* CC_IDX is the RNTI PCell */ \ + if (_get_scell_idx(RNTI, CC_IDX) != 0) { \ + return RET; \ + } \ + } while (false) + +#define UE_DB_ASSERT_SCELL(RNTI, SCELL_IDX, RET) \ + do { \ + /* Assert RNTI exists and eNb cell/carrier is configured */ \ + UE_DB_ASSERT_RNTI(RNTI, RET); \ + \ + /* Check SCell index is in range */ \ + if (SCELL_IDX >= SRSLTE_MAX_CARRIERS) { \ + ERROR("Out-of-bounds SCell index %d for RNTI x%x.\n", SCELL_IDX, RNTI); \ + return RET; \ + } \ + } while (false) + +#define UE_DB_ASSERT_ACTIVE_SCELL(RNTI, SCELL_IDX, RET) \ + do { \ + /* Assert RNTI exists and eNb cell/carrier is configured */ \ + UE_DB_ASSERT_SCELL(RNTI, SCELL_IDX, RET); \ + \ + /* Check SCell is active */ \ + auto& scell_info = ue_db.at(RNTI).scell_info[SCELL_IDX]; \ + if (scell_info.state != scell_state_active) { \ + ERROR("Failed to assert active SCell %d for RNTI x%x", SCELL_IDX, RNTI); \ + return RET; \ + } \ + } while (false) + +#define UE_DB_ASSERT_STACK(RET) \ + do { \ + if (not stack) { \ + return RET; \ + } \ + } while (false) + +#define UE_DB_ASSERT_CELL_LIST_CFG(RET) \ + do { \ + if (not cell_cfg_list) { \ + return RET; \ + } \ + } while (false) + +void phy_ue_db::activate_deactivate_scell(uint16_t rnti, uint32_t scell_idx, bool activate) +{ + // Assert RNTI and SCell are valid + UE_DB_ASSERT_SCELL(rnti, scell_idx, /* void */); + + auto& scell_info = ue_db[rnti].scell_info[scell_idx]; + + // If scell is default only complain + if (activate and scell_info.state == scell_state_default) { + ERROR("RNTI x%x SCell %d has received an activation MAC command but it was not configured\n", rnti, scell_idx); + return; + } + + // Set scell state + scell_info.state = (activate) ? scell_state_active : scell_state_deactivated; +} + +srslte::phy_cfg_t phy_ue_db::get_config(uint16_t rnti, uint32_t cc_idx) const +{ + std::lock_guard lock(mutex); + + UE_DB_ASSERT_ACTIVE_CELL(rnti, cc_idx, {}); + + return ue_db.at(rnti).scell_info[_get_scell_idx(rnti, cc_idx)].phy_cfg; +} + +void phy_ue_db::set_ack_pending(uint32_t tti, uint32_t cc_idx, const srslte_dci_dl_t& dci) +{ + std::lock_guard lock(mutex); + + // Assert rnti and cell exits and it is active + UE_DB_ASSERT_ACTIVE_CELL(dci.rnti, cc_idx, /* void */); + + common_ue& ue = ue_db[dci.rnti]; + uint32_t scell_idx = _get_scell_idx(dci.rnti, cc_idx); + + srslte_pdsch_ack_cc_t& pdsch_ack_cc = ue.pdsch_ack[TTIMOD(tti)].cc[scell_idx]; + pdsch_ack_cc.M = 1; ///< Hardcoded for FDD + + // Fill PDSCH ACK information + srslte_pdsch_ack_m_t& pdsch_ack_m = pdsch_ack_cc.m[0]; ///< Assume FDD only + pdsch_ack_m.present = true; + pdsch_ack_m.resource.grant_cc_idx = cc_idx; ///< Assumes no cross-carrier scheduling + pdsch_ack_m.resource.v_dai_dl = 0; ///< Ignore for FDD + pdsch_ack_m.resource.n_cce = dci.location.ncce; + pdsch_ack_m.resource.tpc_for_pucch = dci.tpc_pucch; + + // Set TB info + for (uint32_t i = 0; i < srslte_dci_format_max_tb(dci.format); i++) { + if (SRSLTE_DCI_IS_TB_EN(dci.tb[i])) { + pdsch_ack_m.value[i] = true; + pdsch_ack_m.k++; + } + } +} + +bool phy_ue_db::fill_uci_cfg(uint32_t tti, + uint32_t cc_idx, + uint16_t rnti, + bool aperiodic_cqi_request, + srslte_uci_cfg_t& uci_cfg) const +{ + std::lock_guard lock(mutex); + + // Assert rnti and cell exits and it is active + UE_DB_ASSERT_PCELL(rnti, cc_idx, false); + + // Assert Cell List configuration + UE_DB_ASSERT_CELL_LIST_CFG(false); + + const auto& ue = ue_db.at(rnti); + const auto& pcell_cfg = ue.scell_info[0].phy_cfg; + bool uci_required = false; + + uci_cfg = {}; + + // Check if SR opportunity (will only be used in PUCCH) + uci_cfg.is_scheduling_request_tti = (srslte_ue_ul_sr_send_tti(&pcell_cfg.ul_cfg.pucch, tti) == 1); + uci_required |= uci_cfg.is_scheduling_request_tti; + + // Get pending CQI reports for this TTI, stops at first CC reporting + bool periodic_cqi_required = false; + for (uint32_t scell_idx = 0; scell_idx < SRSLTE_MAX_CARRIERS and not periodic_cqi_required; scell_idx++) { + const scell_info_t& scell_info = ue.scell_info[scell_idx]; + const srslte_dl_cfg_t& dl_cfg = scell_info.phy_cfg.dl_cfg; + + if (scell_info.state == scell_state_active) { + const srslte_cell_t& cell = cell_cfg_list->at(scell_info.cc_idx).cell; + + // Check if CQI report is required + periodic_cqi_required = srslte_enb_dl_gen_cqi_periodic(&cell, &dl_cfg, tti, scell_info.last_ri, &uci_cfg.cqi); + + // Save SCell index for using it after + uci_cfg.cqi.scell_index = scell_idx; + } + } + uci_required |= periodic_cqi_required; + + // If no periodic CQI report required, check aperiodic reporting + if ((not periodic_cqi_required) and aperiodic_cqi_request) { + // Aperiodic only supported for PCell + const scell_info_t& pcell_info = ue.scell_info[0]; + const srslte_cell_t& cell = cell_cfg_list->at(pcell_info.cc_idx).cell; + const srslte_dl_cfg_t& dl_cfg = pcell_info.phy_cfg.dl_cfg; + + uci_required = srslte_enb_dl_gen_cqi_aperiodic(&cell, &dl_cfg, pcell_info.last_ri, &uci_cfg.cqi); + } + + // Get pending ACKs from PDSCH + srslte_dl_sf_cfg_t dl_sf_cfg = {}; + dl_sf_cfg.tti = tti; + const srslte_cell_t& cell = cell_cfg_list->at(ue.scell_info[0].cc_idx).cell; + srslte_enb_dl_gen_ack(&cell, &dl_sf_cfg, &ue.pdsch_ack[TTIMOD(tti)], &uci_cfg); + uci_required |= (srslte_uci_cfg_total_ack(&uci_cfg) > 0); + + // Return whether UCI needs to be decoded + return uci_required; +} + +void phy_ue_db::send_uci_data(uint32_t tti, + uint16_t rnti, + uint32_t cc_idx, + const srslte_uci_cfg_t& uci_cfg, + const srslte_uci_value_t& uci_value) +{ + std::lock_guard lock(mutex); + + // Assert UE RNTI database entry and eNb cell/carrier must be primary cell + UE_DB_ASSERT_PCELL(rnti, cc_idx, /* void */); + + // Assert Stack + UE_DB_ASSERT_STACK(/* void */); + + // Notify SR + if (uci_cfg.is_scheduling_request_tti && uci_value.scheduling_request) { + stack->sr_detected(tti, rnti); + } + + // Get UE + common_ue& ue = ue_db.at(rnti); + + // Get ACK info + srslte_pdsch_ack_t& pdsch_ack = ue.pdsch_ack[TTIMOD(tti)]; + srslte_enb_dl_get_ack(&cell_cfg_list->at(ue.scell_info[0].cc_idx).cell, &uci_value, &pdsch_ack); + + // Iterate over the ACK information + for (uint32_t scell_idx = 0; scell_idx < SRSLTE_MAX_CARRIERS; scell_idx++) { + const srslte_pdsch_ack_cc_t& pdsch_ack_cc = pdsch_ack.cc[scell_idx]; + for (uint32_t m = 0; m < pdsch_ack_cc.M; m++) { + if (pdsch_ack_cc.m[m].present) { + for (uint32_t tb = 0; tb < pdsch_ack_cc.m[m].k; tb++) { + stack->ack_info(tti, rnti, ue.scell_info[scell_idx].cc_idx, tb, pdsch_ack_cc.m[m].value[tb] == 1); + } + } + } + } + + // Assert the SCell exists and it is active + UE_DB_ASSERT_ACTIVE_SCELL(rnti, uci_cfg.cqi.scell_index, /* void */); + + // Get CQI carrier index + auto& cqi_scell_info = ue_db.at(rnti).scell_info[uci_cfg.cqi.scell_index]; + uint32_t cqi_cc_idx = cqi_scell_info.cc_idx; + + // Notify CQI only if CRC is valid + if (uci_value.cqi.data_crc) { + // Channel quality indicator itself + if (uci_cfg.cqi.data_enable) { + uint8_t cqi_value = 0; + switch (uci_cfg.cqi.type) { + case SRSLTE_CQI_TYPE_WIDEBAND: + cqi_value = uci_value.cqi.wideband.wideband_cqi; + break; + case SRSLTE_CQI_TYPE_SUBBAND: + cqi_value = uci_value.cqi.subband.subband_cqi; + break; + case SRSLTE_CQI_TYPE_SUBBAND_HL: + cqi_value = uci_value.cqi.subband_hl.wideband_cqi_cw0; + break; + case SRSLTE_CQI_TYPE_SUBBAND_UE: + cqi_value = uci_value.cqi.subband_ue.wideband_cqi; + break; + } + stack->cqi_info(tti, rnti, cqi_cc_idx, cqi_value); + } + + // Rank indicator (TM3 and TM4) + if (uci_cfg.cqi.ri_len) { + stack->ri_info(tti, cqi_cc_idx, rnti, uci_value.ri); + cqi_scell_info.last_ri = uci_value.ri; + } + + // Precoding Matrix indicator (TM4) + if (uci_cfg.cqi.pmi_present) { + uint8_t pmi_value = 0; + switch (uci_cfg.cqi.type) { + case SRSLTE_CQI_TYPE_WIDEBAND: + pmi_value = uci_value.cqi.wideband.pmi; + break; + case SRSLTE_CQI_TYPE_SUBBAND_HL: + pmi_value = uci_value.cqi.subband_hl.pmi; + break; + default: + ERROR("CQI type=%d not implemented for PMI\n", uci_cfg.cqi.type); + break; + } + stack->pmi_info(tti, rnti, cqi_cc_idx, pmi_value); + } + } +} + +void phy_ue_db::set_last_ul_tb(uint16_t rnti, uint32_t cc_idx, uint32_t pid, srslte_ra_tb_t tb) +{ + std::lock_guard lock(mutex); + + // Assert UE DB entry + UE_DB_ASSERT_ACTIVE_CELL(rnti, cc_idx, /* void */); + + // Save resource allocation + ue_db.at(rnti).scell_info[_get_scell_idx(rnti, cc_idx)].last_tb[pid % SRSLTE_FDD_NOF_HARQ] = tb; +} + +srslte_ra_tb_t phy_ue_db::get_last_ul_tb(uint16_t rnti, uint32_t cc_idx, uint32_t pid) const +{ + std::lock_guard lock(mutex); + + // Assert UE DB entry + UE_DB_ASSERT_ACTIVE_CELL(rnti, cc_idx, {}); + + // Returns the latest stored UL transmission grant + return ue_db.at(rnti).scell_info[_get_scell_idx(rnti, cc_idx)].last_tb[pid % SRSLTE_FDD_NOF_HARQ]; +} diff --git a/srsenb/src/phy/sf_worker.cc b/srsenb/src/phy/sf_worker.cc index b21bfce0c..51d96f4a7 100644 --- a/srsenb/src/phy/sf_worker.cc +++ b/srsenb/src/phy/sf_worker.cc @@ -136,12 +136,12 @@ void sf_worker::set_time(uint32_t tti_, uint32_t tx_worker_cnt_, srslte_timestam } } -int sf_worker::add_rnti(uint16_t rnti, uint32_t cc_idx, bool is_temporal) +int sf_worker::add_rnti(uint16_t rnti, uint32_t cc_idx, bool is_pcell, bool is_temporal) { int ret = SRSLTE_ERROR; if (cc_idx < cc_workers.size()) { - cc_workers[cc_idx]->add_rnti(rnti, is_temporal); + cc_workers[cc_idx]->add_rnti(rnti, true, is_temporal); ret = SRSLTE_SUCCESS; } @@ -160,15 +160,6 @@ uint32_t sf_worker::get_nof_rnti() return cc_workers[0]->get_nof_rnti(); } -void sf_worker::set_config_dedicated(uint16_t rnti, uint32_t cc_idx, const srslte::phy_cfg_t& dedicated) -{ - if (cc_idx < cc_workers.size()) { - cc_workers[cc_idx]->set_config_dedicated(rnti, dedicated); - } else { - log_h->error("cc_idx %d exceeds the number of carriers (%ld)\n", cc_idx, cc_workers.size()); - } -} - void sf_worker::work_imp() { std::lock_guard lock(work_mutex); @@ -232,7 +223,7 @@ void sf_worker::work_imp() dl_sf.non_mbsfn_region = mbsfn_cfg.non_mbsfn_region_length; // Prepare for receive ACK for DL grants in t_tx_dl+4 - phy->ue_db_clear_tti_pending_ack(tti_tx_ul); + phy->ue_db.clear_tti_pending_ack(tti_tx_ul); // Process DL for (uint32_t cc = 0; cc < cc_workers.size(); cc++) { diff --git a/srsenb/test/phy/enb_phy_test.cc b/srsenb/test/phy/enb_phy_test.cc index f55abfc07..1b343da66 100644 --- a/srsenb/test/phy/enb_phy_test.cc +++ b/srsenb/test/phy/enb_phy_test.cc @@ -291,9 +291,16 @@ private: uint32_t tti; } tti_sr_info_t; - std::queue tti_dl_info_sched_queue; - std::queue tti_dl_info_ack_queue; - std::queue tti_sr_info_queue; + typedef struct { + uint32_t tti; + uint32_t cc_idx; + uint32_t cqi; + } tti_cqi_info_t; + + std::queue tti_dl_info_sched_queue; + std::queue tti_dl_info_ack_queue; + std::queue tti_sr_info_queue; + std::queue tti_cqi_info_queue; public: explicit dummy_stack(uint16_t rnti_) : log_h("STACK"), ue_rnti(rnti_), random_gen(srslte_random_init(0)) @@ -302,6 +309,7 @@ public: srslte_softbuffer_tx_init(&softbuffer_tx, SRSLTE_MAX_PRB); srslte_softbuffer_rx_init(&softbuffer_rx, SRSLTE_MAX_PRB); data = srslte_vec_u8_malloc(150000); + memset(data, 0, 150000); } ~dummy_stack() @@ -312,6 +320,8 @@ public: if (data) { free(data); } + + srslte_random_free(random_gen); } int sr_detected(uint32_t tti, uint16_t rnti) override @@ -323,6 +333,7 @@ public: notify_sr_detected(); log_h.info("Received SR tti=%d; rnti=x%x\n", tti, rnti); + return SRSLTE_SUCCESS; } int rach_detected(uint32_t tti, uint32_t primary_cc_idx, uint32_t preamble_idx, uint32_t time_adv) override @@ -342,8 +353,17 @@ public: } int cqi_info(uint32_t tti, uint16_t rnti, uint32_t cc_idx, uint32_t cqi_value) override { + tti_cqi_info_t tti_cqi_info = {}; + tti_cqi_info.tti = tti; + tti_cqi_info.cc_idx = cc_idx; + tti_cqi_info.cqi = cqi_value; + tti_cqi_info_queue.push(tti_cqi_info); + notify_cqi_info(); - return 0; + + log_h.info("Received CQI tti=%d; rnti=x%x; cc_idx=%d; cqi=%d;\n", tti, rnti, cc_idx, cqi_value); + + return SRSLTE_SUCCESS; } int snr_info(uint32_t tti, uint16_t rnti, uint32_t cc_idx, float snr_db) override { @@ -461,17 +481,21 @@ public: while (tti_sr_info_queue.size() > 1) { tti_sr_info_t tti_sr_info1 = tti_sr_info_queue.front(); - // Check first TTI - TESTASSERT(tti_sr_info1.tti % 20 == 0); - // POP first from queue tti_sr_info_queue.pop(); // Get second, do not pop tti_sr_info_t& tti_sr_info2 = tti_sr_info_queue.front(); - // Make sure the TTI difference is 20 uint32_t elapsed_tti = ((tti_sr_info2.tti + 10240) - tti_sr_info1.tti) % 10240; + + // Log SR info + log_h.info("SR: tti1=%d; tti2=%d; elapsed %d;\n", tti_sr_info1.tti, tti_sr_info2.tti, elapsed_tti); + + // Check first TTI + TESTASSERT(tti_sr_info1.tti % 20 == 0); + + // Make sure the TTI difference is 20 TESTASSERT(elapsed_tti == 20); } @@ -540,7 +564,7 @@ public: } // Set RNTI - srslte_ue_dl_set_rnti(ue_dl, rnti); + srslte_ue_dl_set_rnti(ue_dl, dedicated.dl_cfg.pdsch.rnti); // Allocate UE UL auto* ue_ul = (srslte_ue_ul_t*)srslte_vec_malloc(sizeof(srslte_ue_ul_t)); @@ -560,7 +584,7 @@ public: } // Set RNTI - srslte_ue_ul_set_rnti(ue_ul, rnti); + srslte_ue_ul_set_rnti(ue_ul, dedicated.ul_cfg.pusch.rnti); } // Initialise softbuffer @@ -604,6 +628,9 @@ public: free(b); } } + if (tx_data) { + free(tx_data); + } srslte_softbuffer_tx_free(&softbuffer_tx); } @@ -629,9 +656,9 @@ public: for (uint32_t i = 0; i < buffers.size(); i++) { srslte_dci_dl_t dci_dl[SRSLTE_MAX_DCI_MSG] = {}; srslte_ue_dl_cfg_t ue_dl_cfg = {}; - // ue_dl_cfg.cfg.cqi_report.periodic_configured = true; - // ue_dl_cfg.cfg.cqi_report.periodic_mode = SRSLTE_CQI_MODE_12; - // ue_dl_cfg.cfg.cqi_report.pmi_idx = 16 + i; + ue_dl_cfg.cfg = dedicated.dl_cfg; + ue_dl_cfg.cfg.cqi_report.periodic_mode = SRSLTE_CQI_MODE_12; + ue_dl_cfg.cfg.cqi_report.pmi_idx += i; ue_dl_cfg.cfg.pdsch.rnti = rnti; srslte_ue_dl_decode_fft_estimate(ue_dl_v[i], &sf_dl_cfg, &ue_dl_cfg); @@ -673,7 +700,7 @@ public: TESTASSERT(nof_ul_grants >= SRSLTE_SUCCESS); // Generate CQI periodic if required - srslte_ue_dl_gen_cqi_periodic(ue_dl_v[i], &ue_dl_cfg, 0x0f, sf_dl_cfg.tti, &uci_data); + srslte_ue_dl_gen_cqi_periodic(ue_dl_v[i], &ue_dl_cfg, 0x0f, sf_ul_cfg.tti, &uci_data); } // Work UL @@ -764,20 +791,24 @@ public: enb_phy.add_rnti(rnti, pcell_index, false); // Configure UE PHY - uint32_t pcell_idx = 0; + bool activation[SRSLTE_MAX_CARRIERS] = {}; + uint32_t pcell_idx = 0; srsenb::phy_interface_rrc_lte::phy_rrc_dedicated_list_t dedicated_list(4); for (uint32_t i = 0; i < 4; i++) { - common_dedicated.dl_cfg.cqi_report.pmi_idx = 16 + i; - dedicated_list[i].cc_idx = (i + pcell_idx) % phy_cfg.phy_cell_cfg.size(); - dedicated_list[i].configured = true; - dedicated_list[i].phy_cfg = common_dedicated; + dedicated_list[i].cc_idx = (i + pcell_idx) % phy_cfg.phy_cell_cfg.size(); + dedicated_list[i].configured = true; + dedicated_list[i].phy_cfg = common_dedicated; + dedicated_list[i].phy_cfg.dl_cfg.cqi_report.pmi_idx += i; // Disable SCell stuff if (i != pcell_index) { dedicated_list[i].phy_cfg.ul_cfg.pucch.sr_configured = false; } + + activation[i] = true; } enb_phy.set_config_dedicated(rnti, dedicated_list); + enb_phy.set_activation_deactivation_scell(rnti, activation); } ~phy_test_bench() @@ -802,10 +833,10 @@ public: int main(int argc, char** argv) { - int ret = SRSLTE_SUCCESS; srsenb::phy_args_t phy_args; - phy_args.log.phy_level = "info"; + phy_args.log.phy_level = "info"; + phy_args.nof_phy_threads = 1; ///< Set number of phy threads to 1 for avoiding concurrency issues srsenb::phy_cfg_t phy_cfg = {}; for (uint32_t i = 0; i < 4; i++) { @@ -831,24 +862,28 @@ int main(int argc, char** argv) phy_cfg.prach_cnfg.prach_cfg_info.zero_correlation_zone_cfg = 5; // Set UE dedicated configuration - srslte::phy_cfg_t dedicated = {}; - dedicated.ul_cfg.pucch.ack_nack_feedback_mode = SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_PUCCH3; - dedicated.ul_cfg.pucch.delta_pucch_shift = 1; - dedicated.ul_cfg.pucch.n_rb_2 = 0; - dedicated.ul_cfg.pucch.N_cs = 0; - dedicated.ul_cfg.pucch.n_pucch_sr = 1; - dedicated.ul_cfg.pucch.N_pucch_1 = 2; - dedicated.ul_cfg.pucch.n_pucch_2 = 3; - dedicated.ul_cfg.pucch.simul_cqi_ack = true; - dedicated.ul_cfg.pucch.sr_configured = true; - dedicated.ul_cfg.pucch.I_sr = 5; + srslte::phy_cfg_t dedicated = {}; + dedicated.ul_cfg.pucch.ack_nack_feedback_mode = SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_PUCCH3; + dedicated.ul_cfg.pucch.delta_pucch_shift = 1; + dedicated.ul_cfg.pucch.n_rb_2 = 2; + dedicated.ul_cfg.pucch.N_cs = 0; + dedicated.ul_cfg.pucch.n_pucch_sr = 1; + dedicated.ul_cfg.pucch.N_pucch_1 = 2; + dedicated.ul_cfg.pucch.n_pucch_2 = 5; + dedicated.ul_cfg.pucch.simul_cqi_ack = true; + dedicated.ul_cfg.pucch.sr_configured = true; + dedicated.ul_cfg.pucch.I_sr = 5; + dedicated.dl_cfg.cqi_report.periodic_configured = true; + dedicated.dl_cfg.cqi_report.pmi_idx = 25; + dedicated.dl_cfg.cqi_report.periodic_mode = SRSLTE_CQI_MODE_20; std::unique_ptr test_bench = std::unique_ptr(new phy_test_bench(phy_args, phy_cfg, 0x1234, 0, dedicated)); - for (uint32_t i = 0; i < 128; i++) { + // Run Simulation + for (uint32_t i = 0; i < 256; i++) { TESTASSERT(test_bench->run_tti() >= SRSLTE_SUCCESS); } - return ret; + return SRSLTE_SUCCESS; }