diff --git a/CHANGELOG b/CHANGELOG index 728322820..0569c19bd 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,18 @@ Change Log for Releases ======================= +## 21.04 + * Rename project from srsLTE to srsRAN + * Add initial 5G NSA support to srsUE (including x86-optimized FEC and PHY layer) + * Add PDCP discard support + * Add UL power control, measurement gaps and a new proportional fair scheduler to srsENB + * Extend GTP-U tunneling to support tunnel forwarding over S1 + * Optimize many data structures, remove dynamic memory allocations in data plane + * Improved S1AP error handling and enhanced event reporting + * Update ASN.1 packing/unpacking, RRC to Rel 15.11, S1AP to Rel 16.1 + * Update PCAP writer to use UDP framing + * Other bug-fixes and improved stability and performance in all parts + ## 20.10.1 * Fix bug in srsENB that effectively disabled UL HARQ diff --git a/README.md b/README.md index da526758c..381166fc5 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ srsRAN is a 4G/5G software radio suite developed by SRS (www.softwareradiosystem See the srsRAN project pages (www.srsran.com) for documentation, guides and project news. It includes: - * srsUE - a complete SDR LTE UE application featuring all layers from PHY to IP + * srsUE - a complete SDR 4G/5G UE application featuring all layers from PHY to IP * srsENB - a complete SDR LTE eNodeB application * srsEPC - a light-weight LTE core network implementation with MME, HSS and S/P-GW * a highly modular set of common libraries for PHY, MAC, RLC, PDCP, RRC, NAS, S1AP and GW layers. @@ -58,7 +58,8 @@ srsENB Features --------------- * FDD configuration - * Round Robin MAC scheduler with FAPI-like C++ API + * IntraENB- and InterENB (S1) mobility support + * Proportional-fair and Round Robin MAC scheduler with FAPI-like C++ API * SR support * Periodic and Aperiodic CQI feedback support * Standard S1AP and GTP-U interfaces to the Core Network diff --git a/cmake/modules/SRSRANVersion.cmake b/cmake/modules/SRSRANVersion.cmake index bde5234f5..bf95f7925 100644 --- a/cmake/modules/SRSRANVersion.cmake +++ b/cmake/modules/SRSRANVersion.cmake @@ -18,8 +18,8 @@ # and at http://www.gnu.org/licenses/. # -SET(SRSRAN_VERSION_MAJOR 20) -SET(SRSRAN_VERSION_MINOR 10) -SET(SRSRAN_VERSION_PATCH 1) +SET(SRSRAN_VERSION_MAJOR 21) +SET(SRSRAN_VERSION_MINOR 04) +SET(SRSRAN_VERSION_PATCH 0) SET(SRSRAN_VERSION_STRING "${SRSRAN_VERSION_MAJOR}.${SRSRAN_VERSION_MINOR}.${SRSRAN_VERSION_PATCH}") SET(SRSRAN_SOVERSION 0) diff --git a/lib/include/srsran/adt/bounded_bitset.h b/lib/include/srsran/adt/bounded_bitset.h index f0beabed2..d1f734296 100644 --- a/lib/include/srsran/adt/bounded_bitset.h +++ b/lib/include/srsran/adt/bounded_bitset.h @@ -35,6 +35,116 @@ constexpr uint32_t ceil_div(uint32_t x, uint32_t y) return (x + y - 1) / y; } +template +Integer mask_msb_zeros(size_t N) +{ + static_assert(std::is_unsigned::value, "T must be unsigned integer"); + return (N == 0) ? static_cast(-1) : (N == sizeof(Integer) * 8U) ? 0 : (static_cast(-1) >> (N)); +} + +template +Integer mask_lsb_ones(size_t N) +{ + return mask_msb_zeros(sizeof(Integer) * 8U - N); +} + +template +Integer mask_msb_ones(size_t N) +{ + return ~mask_msb_zeros(N); +} + +template +Integer mask_lsb_zeros(size_t N) +{ + return ~mask_lsb_ones(N); +} + +namespace detail { + +template +struct zerobit_counter { + static Integer msb_count(Integer value) + { + if (value == 0) { + return std::numeric_limits::digits; + } + Integer ret = 0; + for (Integer shift = std::numeric_limits::digits >> 1; shift != 0; shift >>= 1) { + Integer tmp = value >> shift; + if (tmp != 0) { + value = tmp; + } else { + ret |= shift; + } + } + return ret; + } + static Integer lsb_count(Integer value) + { + if (value == 0) { + return std::numeric_limits::digits; + } + Integer ret = 0; + for (Integer shift = std::numeric_limits::digits >> 1, mask = std::numeric_limits::max() >> shift; + shift != 0; + shift >>= 1, mask >>= shift) { + if ((value & mask) == 0) { + value >>= shift; + ret |= shift; + } + } + return ret; + } +}; + +#ifdef __GNUC__ // clang and gcc +/// Specializations for unsigned +template +struct zerobit_counter { + static Integer msb_count(Integer value) + { + return (value) ? __builtin_clz(value) : std::numeric_limits::digits; + } + static Integer lsb_count(Integer value) + { + return (value) ? __builtin_ctz(value) : std::numeric_limits::digits; + } +}; +#endif + +#ifdef __GNUC__ // clang and gcc +/// Specializations for unsigned long +template +struct zerobit_counter { + static Integer msb_count(Integer value) + { + return (value) ? __builtin_clzl(value) : std::numeric_limits::digits; + } + static Integer lsb_count(Integer value) + { + return (value) ? __builtin_ctzl(value) : std::numeric_limits::digits; + } +}; +#endif + +} // namespace detail + +/// uses lsb as zero position +template +Integer find_first_msb_one(Integer value) +{ + return (value) ? (sizeof(Integer) * 8U - 1 - detail::zerobit_counter::msb_count(value)) + : std::numeric_limits::digits; +} + +/// uses lsb as zero position +template +Integer find_first_lsb_one(Integer value) +{ + return detail::zerobit_counter::lsb_count(value); +} + template class bounded_bitset { @@ -109,8 +219,7 @@ public: bounded_bitset& fill(size_t startpos, size_t endpos, bool value = true) { - assert_within_bounds_(startpos, false); - assert_within_bounds_(endpos, false); + assert_range_bounds_(startpos, endpos); // NOTE: can be optimized if (value) { for (size_t i = startpos; i < endpos; ++i) { @@ -124,6 +233,19 @@ public: return *this; } + int find_lowest(size_t startpos, size_t endpos, bool value = true) const noexcept + { + assert_range_bounds_(startpos, endpos); + if (startpos == endpos) { + return -1; + } + + if (not reversed) { + return find_first_(startpos, endpos, value); + } + return find_first_reversed_(startpos, endpos, value); + } + bool all() const noexcept { const size_t nw = nof_words_(); @@ -282,33 +404,35 @@ private: } } - bool test_(size_t pos) const noexcept + size_t get_bitidx_(size_t bitpos) const noexcept { return reversed ? size() - 1 - bitpos : bitpos; } + + bool test_(size_t bitpos) const noexcept { - pos = reversed ? size() - 1 - pos : pos; - return ((get_word_(pos) & maskbit(pos)) != static_cast(0)); + bitpos = get_bitidx_(bitpos); + return ((get_word_(bitpos) & maskbit(bitpos)) != static_cast(0)); } - void set_(size_t pos) noexcept + void set_(size_t bitpos) noexcept { - pos = reversed ? size() - 1 - pos : pos; - get_word_(pos) |= maskbit(pos); + bitpos = get_bitidx_(bitpos); + get_word_(bitpos) |= maskbit(bitpos); } - void reset_(size_t pos) noexcept + void reset_(size_t bitpos) noexcept { - pos = reversed ? size() - 1 - pos : pos; - get_word_(pos) &= ~(maskbit(pos)); + bitpos = get_bitidx_(bitpos); + get_word_(bitpos) &= ~(maskbit(bitpos)); } size_t nof_words_() const noexcept { return size() > 0 ? (size() - 1) / bits_per_word + 1 : 0; } - word_t& get_word_(size_t pos) noexcept { return buffer[pos / bits_per_word]; } + word_t& get_word_(size_t bitidx) noexcept { return buffer[bitidx / bits_per_word]; } - const word_t& get_word_(size_t pos) const { return buffer[pos / bits_per_word]; } + const word_t& get_word_(size_t bitidx) const { return buffer[bitidx / bits_per_word]; } size_t word_idx_(size_t pos) const { return pos / bits_per_word; } - void assert_within_bounds_(size_t pos, bool strict) const + void assert_within_bounds_(size_t pos, bool strict) const noexcept { srsran_assert(pos < size() or (not strict and pos == size()), "ERROR: index=%zd is out-of-bounds for bitset of size=%zd", @@ -316,9 +440,98 @@ private: size()); } - static word_t maskbit(size_t pos) { return (static_cast(1)) << (pos % bits_per_word); } + void assert_range_bounds_(size_t startpos, size_t endpos) const noexcept + { + srsran_assert(startpos <= endpos and endpos <= size(), + "ERROR: range [%zd, %zd) out-of-bounds for bitsize of size=%zd", + startpos, + endpos, + size()); + } + + static word_t maskbit(size_t pos) noexcept { return (static_cast(1)) << (pos % bits_per_word); } + + static size_t max_nof_words_() noexcept { return (N - 1) / bits_per_word + 1; } + + int find_last_(size_t startpos, size_t endpos, bool value) const noexcept + { + size_t startword = startpos / bits_per_word; + size_t lastword = (endpos - 1) / bits_per_word; - static size_t max_nof_words_() { return (N - 1) / bits_per_word + 1; } + for (size_t i = lastword; i != startpos - 1; --i) { + word_t w = buffer[i]; + if (not value) { + w = ~w; + } + + if (i == startword) { + size_t offset = startpos % bits_per_word; + w &= (reversed) ? mask_msb_zeros(offset) : mask_lsb_zeros(offset); + } + if (i == lastword) { + size_t offset = (endpos - 1) % bits_per_word; + w &= (reversed) ? mask_msb_ones(offset + 1) : mask_lsb_ones(offset + 1); + } + if (w != 0) { + return static_cast(i * bits_per_word + find_first_msb_one(w)); + } + } + return -1; + } + + int find_first_(size_t startpos, size_t endpos, bool value) const noexcept + { + size_t startword = startpos / bits_per_word; + size_t lastword = (endpos - 1) / bits_per_word; + + for (size_t i = startword; i <= lastword; ++i) { + word_t w = buffer[i]; + if (not value) { + w = ~w; + } + + if (i == startword) { + size_t offset = startpos % bits_per_word; + w &= mask_lsb_zeros(offset); + } + if (i == lastword) { + size_t offset = (endpos - 1) % bits_per_word; + w &= mask_lsb_ones(offset + 1); + } + if (w != 0) { + return static_cast(i * bits_per_word + find_first_lsb_one(w)); + } + } + return -1; + } + + int find_first_reversed_(size_t startpos, size_t endpos, bool value) const noexcept + { + size_t startbitpos = get_bitidx_(startpos), lastbitpos = get_bitidx_(endpos - 1); + size_t startword = startbitpos / bits_per_word; + size_t lastword = lastbitpos / bits_per_word; + + for (size_t i = startword; i != lastword - 1; --i) { + word_t w = buffer[i]; + if (not value) { + w = ~w; + } + + if (i == startword) { + size_t offset = startbitpos % bits_per_word; + w &= mask_lsb_ones(offset + 1); + } + if (i == lastword) { + size_t offset = lastbitpos % bits_per_word; + w &= mask_lsb_zeros(offset); + } + if (w != 0) { + word_t pos = find_first_msb_one(w); + return static_cast(size() - 1 - (pos + i * bits_per_word)); + } + } + return -1; + } }; template diff --git a/lib/include/srsran/adt/expected.h b/lib/include/srsran/adt/expected.h index f4ff07aa9..a031af9b4 100644 --- a/lib/include/srsran/adt/expected.h +++ b/lib/include/srsran/adt/expected.h @@ -45,15 +45,15 @@ class expected public: expected() : has_val(true), val(T{}) {} - expected(T&& t) : has_val(true), val(std::forward(t)) {} + expected(T&& t) noexcept : has_val(true), val(std::move(t)) {} expected(const T& t) : has_val(true), val(t) {} - expected(E&& e) : has_val(false), unexpected(std::forward(e)) {} + expected(E&& e) noexcept : has_val(false), unexpected(std::move(e)) {} expected(const E& e) : has_val(false), unexpected(e) {} template < typename U, typename std::enable_if::value and not is_expected::type>::value, int>::type = 0> - explicit expected(U&& u) : has_val(true), val(std::forward(u)) + explicit expected(U&& u) noexcept : has_val(true), val(std::forward(u)) {} expected(const expected& other) { diff --git a/lib/include/srsran/asn1/rrc_nr_utils.h b/lib/include/srsran/asn1/rrc_nr_utils.h index f9e81f227..c93902381 100644 --- a/lib/include/srsran/asn1/rrc_nr_utils.h +++ b/lib/include/srsran/asn1/rrc_nr_utils.h @@ -57,6 +57,10 @@ struct sched_request_res_cfg_s; struct dmrs_ul_cfg_s; struct beta_offsets_s; struct uci_on_pusch_s; +struct zp_csi_rs_res_s; +struct nzp_csi_rs_res_s; +struct pdsch_serving_cell_cfg_s; +struct freq_info_dl_s; } // namespace rrc_nr } // namespace asn1 @@ -97,12 +101,17 @@ bool make_phy_dmrs_additional_pos(const asn1::rrc_nr::dmrs_ul_cfg_s& dmrs_ul_cfg bool make_phy_beta_offsets(const asn1::rrc_nr::beta_offsets_s& beta_offsets, srsran_beta_offsets_t* srsran_beta_offsets); bool make_phy_pusch_scaling(const asn1::rrc_nr::uci_on_pusch_s& uci_on_pusch, float* scaling); +bool make_phy_zp_csi_rs_resource(const asn1::rrc_nr::zp_csi_rs_res_s & zp_csi_rs_res, srsran_csi_rs_zp_resource_t* zp_csi_rs_resource); +bool make_phy_nzp_csi_rs_resource(const asn1::rrc_nr::nzp_csi_rs_res_s & nzp_csi_rs_res, srsran_csi_rs_nzp_resource_t* csi_rs_nzp_resource); +bool make_phy_carrier_cfg(const asn1::rrc_nr::freq_info_dl_s &freq_info_dl, srsran_carrier_nr_t* carrier_nr); /*************************** * MAC Config **************************/ logical_channel_config_t make_mac_logical_channel_cfg_t(uint8_t lcid, const asn1::rrc_nr::lc_ch_cfg_s& asn1_type); rach_nr_cfg_t make_mac_rach_cfg(const asn1::rrc_nr::rach_cfg_common_s& asn1_type); bool make_mac_phr_cfg_t(const asn1::rrc_nr::phr_cfg_s& asn1_type, phr_cfg_nr_t* phr_cfg_nr); +bool make_mac_dl_harq_cfg_nr_t(const asn1::rrc_nr::pdsch_serving_cell_cfg_s& asn1_type, + dl_harq_cfg_nr_t* out_dl_harq_cfg_nr); /*************************** * RLC Config **************************/ diff --git a/lib/include/srsran/common/lte_common.h b/lib/include/srsran/common/common_lte.h similarity index 96% rename from lib/include/srsran/common/lte_common.h rename to lib/include/srsran/common/common_lte.h index 9801b0a8d..01a8dc9b4 100644 --- a/lib/include/srsran/common/lte_common.h +++ b/lib/include/srsran/common/common_lte.h @@ -19,8 +19,8 @@ * */ -#ifndef SRSRAN_LTE_COMMON_H -#define SRSRAN_LTE_COMMON_H +#ifndef SRSRAN_COMMON_LTE_H +#define SRSRAN_COMMON_LTE_H #include #include @@ -97,4 +97,4 @@ inline const char* get_drb_name(lte_drb drb_id) } // namespace srsran -#endif // SRSRAN_LTE_COMMON_H +#endif // SRSRAN_COMMON_LTE_H diff --git a/lib/include/srsran/common/common_nr.h b/lib/include/srsran/common/common_nr.h new file mode 100644 index 000000000..0257938e3 --- /dev/null +++ b/lib/include/srsran/common/common_nr.h @@ -0,0 +1,99 @@ + +/** + * + * \section COPYRIGHT + * + * Copyright 2012-2021 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#ifndef SRSRAN_COMMON_NR_H +#define SRSRAN_COMMON_NR_H + +#include +#include + +namespace srsran { + +// Radio Bearers +enum class nr_srb { srb0, srb1, srb2, srb3, count }; +const uint32_t MAX_NR_SRB_ID = 3; +enum class nr_drb { + drb1 = 1, + drb2, + drb3, + drb4, + drb5, + drb6, + drb7, + drb8, + drb9, + drb10, + drb11, + drb12, + drb13, + drb14, + drb15, + drb16, + drb17, + drb18, + drb19, + drb20, + drb21, + drb22, + drb23, + drb24, + drb25, + drb26, + drb27, + drb28, + drb29, + invalid +}; +const uint32_t MAX_NR_DRB_ID = 29; +const uint32_t MAX_NR_NOF_BEARERS = MAX_NR_DRB_ID + MAX_NR_SRB_ID; + +constexpr bool is_nr_lcid(uint32_t lcid) +{ + return lcid < MAX_NR_NOF_BEARERS; +} +constexpr bool is_nr_srb(uint32_t srib) +{ + return srib <= MAX_NR_SRB_ID; +} +inline const char* get_srb_name(nr_srb srb_id) +{ + static const char* names[] = {"SRB0", "SRB1", "SRB2", "SRB3", "invalid SRB id"}; + return names[(uint32_t)(srb_id < nr_srb::count ? srb_id : nr_srb::count)]; +} +constexpr uint32_t srb_to_lcid(nr_srb srb_id) +{ + return static_cast(srb_id); +} +constexpr nr_srb nr_lcid_to_srb(uint32_t lcid) +{ + return static_cast(lcid); +} +constexpr nr_drb nr_drb_id_to_drb(uint32_t drb_id) +{ + return static_cast(drb_id); +} +constexpr bool is_nr_drb(uint32_t drib) +{ + return drib > MAX_NR_SRB_ID and is_nr_lcid(drib); +} +inline const char* get_drb_name(nr_drb drb_id) +{ + static const char* names[] = {"DRB1", "DRB2", "DRB3", "DRB4", "DRB5", "DRB6", "DRB7", "DRB8", + "DRB9", "DRB10", "DRB11", "DRB12", "DRB13", "DRB14", "DRB15", "DRB16", + "DRB17", "DRB18", "DRB19", "DRB20", "DRB21", "DRB22", "DRB23", "DRB24", + "DRB25", "DRB26", "DRB27", "DRB28", "DRB29", "invalid DRB id"}; + return names[(uint32_t)(drb_id < nr_drb::invalid ? drb_id : nr_drb::invalid) - 1]; +} +} // namespace srsran + +#endif // SRSRAN_COMMON_NR_H \ No newline at end of file diff --git a/lib/include/srsran/common/thread_pool.h b/lib/include/srsran/common/thread_pool.h index a34696a46..b290856c3 100644 --- a/lib/include/srsran/common/thread_pool.h +++ b/lib/include/srsran/common/thread_pool.h @@ -29,13 +29,13 @@ #ifndef SRSRAN_THREAD_POOL_H #define SRSRAN_THREAD_POOL_H +#include "srsran/adt/circular_buffer.h" #include "srsran/adt/move_callback.h" #include "srsran/srslog/srslog.h" #include #include #include #include -#include #include #include #include @@ -98,7 +98,9 @@ private: class task_thread_pool { - using task_t = srsran::move_callback; + using task_t = srsran::move_callback; + static constexpr uint32_t max_task_shift = 14; + static constexpr uint32_t max_task_num = 1u << max_task_shift; public: task_thread_pool(uint32_t nof_workers = 1, bool start_deferred = false, int32_t prio_ = -1, uint32_t mask_ = 255); @@ -139,7 +141,7 @@ private: uint32_t mask = 255; srslog::basic_logger& logger; - std::queue pending_tasks; + srsran::dyn_circular_buffer pending_tasks; std::vector > workers; mutable std::mutex queue_mutex; std::condition_variable cv_empty; diff --git a/lib/include/srsran/interfaces/gnb_interfaces.h b/lib/include/srsran/interfaces/gnb_interfaces.h index 97dced355..5486d4f23 100644 --- a/lib/include/srsran/interfaces/gnb_interfaces.h +++ b/lib/include/srsran/interfaces/gnb_interfaces.h @@ -158,9 +158,10 @@ public: class rrc_interface_rlc_nr { public: - virtual void read_pdu_pcch(uint8_t* payload, uint32_t payload_size) = 0; - virtual void max_retx_attempted(uint16_t rnti) = 0; - virtual void write_pdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t sdu) = 0; + virtual void read_pdu_pcch(uint8_t* payload, uint32_t payload_size) = 0; + virtual void max_retx_attempted(uint16_t rnti) = 0; + virtual void write_pdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t sdu) = 0; + virtual const char* get_rb_name(uint32_t lcid) = 0; }; class rrc_interface_pdcp_nr { diff --git a/lib/include/srsran/interfaces/mac_interface_types.h b/lib/include/srsran/interfaces/mac_interface_types.h index 3b4282179..b6a196ca1 100644 --- a/lib/include/srsran/interfaces/mac_interface_types.h +++ b/lib/include/srsran/interfaces/mac_interface_types.h @@ -96,6 +96,13 @@ struct ul_harq_cfg_t { } }; +/// NR specific config for DL HARQ with configurable number of processes +struct dl_harq_cfg_nr_t { + uint8_t nof_procs; // Number of HARQ processes used in the DL + dl_harq_cfg_nr_t() { reset(); } + void reset() { nof_procs = SRSRAN_DEFAULT_HARQ_PROC_DL_NR; } +}; + struct rach_cfg_t { bool enabled; uint32_t nof_preambles; @@ -154,7 +161,7 @@ struct sr_cfg_item_nr_t { #define SRSRAN_MAX_MAX_NR_OF_SR_CFG_PER_CELL_GROUP (8) struct sr_cfg_nr_t { - bool enabled; + bool enabled; uint8_t num_items; sr_cfg_item_nr_t item[SRSRAN_MAX_MAX_NR_OF_SR_CFG_PER_CELL_GROUP]; }; diff --git a/lib/include/srsran/interfaces/nr_common_interface_types.h b/lib/include/srsran/interfaces/nr_common_interface_types.h deleted file mode 100644 index 00289b42b..000000000 --- a/lib/include/srsran/interfaces/nr_common_interface_types.h +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Copyright 2013-2021 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 SRSRAN_COMMON_NR_H -#define SRSRAN_COMMON_NR_H - -namespace srsran { - -// NR Radio Bearer Id - -enum rb_id_nr_t { NR_SRB0, NR_SRB1, NR_SRB2, NR_SRB3, NR_DRB1, RB_ID_NR_N_ITEMS }; -inline const char* to_string(rb_id_nr_t rb_id) -{ - const static char* names[] = {"SRB0", "SRB1", "SRB2", "SRB3", "DRB1"}; - return (rb_id < rb_id_nr_t::RB_ID_NR_N_ITEMS) ? names[rb_id] : "invalid bearer id"; -} -inline bool is_srb(rb_id_nr_t lcid) -{ - return lcid <= rb_id_nr_t::NR_SRB3; -} -inline bool is_drb(rb_id_nr_t lcid) -{ - return not is_srb(lcid) and lcid <= rb_id_nr_t::RB_ID_NR_N_ITEMS; -} -inline int get_drb_id(rb_id_nr_t rb_id) -{ - return is_drb(rb_id) ? (rb_id - 3) : -1; -} - -} // namespace srsran - -#endif // SRSRAN_NR_COMMON_INTERFACE_TYPES_H diff --git a/lib/include/srsran/interfaces/pdcp_interface_types.h b/lib/include/srsran/interfaces/pdcp_interface_types.h index dfea173cb..01497acd7 100644 --- a/lib/include/srsran/interfaces/pdcp_interface_types.h +++ b/lib/include/srsran/interfaces/pdcp_interface_types.h @@ -135,7 +135,8 @@ public: uint8_t sn_len_, pdcp_t_reordering_t t_reordering_, pdcp_discard_timer_t discard_timer_, - bool status_report_required_) : + bool status_report_required_, + srsran::srsran_rat_t rat_) : bearer_id(bearer_id_), rb_type(rb_type_), tx_direction(tx_direction_), @@ -143,7 +144,8 @@ public: sn_len(sn_len_), t_reordering(t_reordering_), discard_timer(discard_timer_), - status_report_required(status_report_required_) + status_report_required(status_report_required_), + rat(rat_) { hdr_len_bytes = ceilf((float)sn_len / 8); } @@ -157,6 +159,7 @@ public: pdcp_t_reordering_t t_reordering = pdcp_t_reordering_t::ms500; pdcp_discard_timer_t discard_timer = pdcp_discard_timer_t::infinity; + srsran::srsran_rat_t rat = srsran::srsran_rat_t::lte; bool status_report_required = false; diff --git a/lib/include/srsran/interfaces/rrc_nr_interface_types.h b/lib/include/srsran/interfaces/rrc_nr_interface_types.h index 35818b4b5..909d64859 100644 --- a/lib/include/srsran/interfaces/rrc_nr_interface_types.h +++ b/lib/include/srsran/interfaces/rrc_nr_interface_types.h @@ -41,856 +41,9 @@ struct phy_cfg_nr_t { srsran_pdcch_cfg_nr_t pdcch = {}; srsran_ue_dl_nr_harq_ack_cfg_t harq_ack = {}; srsran_csi_hl_cfg_t csi = {}; - - phy_cfg_nr_t() - { - // physicalCellGroupConfig - // pdsch-HARQ-ACK-Codebook: dynamic (1) - harq_ack.harq_ack_codebook = srsran_pdsch_harq_ack_codebook_dynamic; - - // commonControlResourceSet - // controlResourceSetId: 1 - // frequencyDomainResources: ff0000000000 - // duration: 1 - // cce-REG-MappingType: nonInterleaved (1) - // nonInterleaved: NULL - // precoderGranularity: sameAsREG-bundle (0) - pdcch.coreset[1].coreset_id = 1; - pdcch.coreset[1].precoder_granularity = srsran_coreset_precoder_granularity_reg_bundle; - pdcch.coreset[1].duration = 1; - pdcch.coreset[1].mapping_type = srsran_coreset_mapping_type_non_interleaved; - for (uint32_t i = 0; i < SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE; i++) { - pdcch.coreset[1].freq_resources[i] = (i < 8); - } - pdcch.coreset_present[1] = true; - - // spCellConfigDedicated - // initialDownlinkBWP - // pdcch-Config: setup (1) - // setup - // controlResourceSetToAddModList: 1 item - // Item 0 - // ControlResourceSet - // controlResourceSetId: 2 - // frequencyDomainResources: ff0000000000 [bit length 45, 3 LSB pad bits, 1111 1111 0000 - // 0000 0000 0000 0000 0000 0000 0000 0000 0... decimal value 35046933135360] - // duration: 1 - // cce-REG-MappingType: nonInterleaved (1) - // nonInterleaved: NULL - // precoderGranularity: sameAsREG-bundle (0) - pdcch.coreset[2].id = 2; - pdcch.coreset[2].precoder_granularity = srsran_coreset_precoder_granularity_reg_bundle; - pdcch.coreset[2].duration = 1; - pdcch.coreset[2].mapping_type = srsran_coreset_mapping_type_non_interleaved; - for (uint32_t i = 0; i < SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE; i++) { - pdcch.coreset[2].freq_resources[i] = (i < 8); - } - pdcch.coreset_present[2] = true; - - // pdsch-Config: setup (1) - // setup - // dmrs-DownlinkForPDSCH-MappingTypeA: setup (1) - // setup - // dmrs-AdditionalPosition: pos1 (1) - // tci-StatesToAddModList: 1 item - // Item 0 - // TCI-State - // tci-StateId: 0 - // qcl-Type1 - // referenceSignal: ssb (1) - // ssb: 0 - // qcl-Type: typeD (3) - // resourceAllocation: resourceAllocationType1 (1) - // rbg-Size: config1 (0) - // prb-BundlingType: staticBundling (0) - // staticBundling - // bundleSize: wideband (1) - // zp-CSI-RS-ResourceToAddModList: 1 item - // Item 0 - // ZP-CSI-RS-Resource - // zp-CSI-RS-ResourceId: 0 - // resourceMapping - // frequencyDomainAllocation: row4 (2) - // row4: 80 [bit length 3, 5 LSB pad bits, 100. .... - // decimal value 4] - // nrofPorts: p4 (2) - // firstOFDMSymbolInTimeDomain: 8 - // cdm-Type: fd-CDM2 (1) - // density: one (1) - // one: NULL - // freqBand - // startingRB: 0 - // nrofRBs: 52 - // periodicityAndOffset: slots80 (9) - // slots80: 1 - // p-ZP-CSI-RS-ResourceSet: setup (1) - // setup - // zp-CSI-RS-ResourceSetId: 0 - // zp-CSI-RS-ResourceIdList: 1 item - // Item 0 - // ZP-CSI-RS-ResourceId: 0 - srsran_csi_rs_zp_resource_t zp_csi_rs_resource0 = {}; - zp_csi_rs_resource0.resource_mapping.row = srsran_csi_rs_resource_mapping_row_4; - zp_csi_rs_resource0.resource_mapping.frequency_domain_alloc[0] = true; - zp_csi_rs_resource0.resource_mapping.frequency_domain_alloc[1] = false; - zp_csi_rs_resource0.resource_mapping.frequency_domain_alloc[2] = false; - zp_csi_rs_resource0.resource_mapping.nof_ports = 4; - zp_csi_rs_resource0.resource_mapping.first_symbol_idx = 8; - zp_csi_rs_resource0.resource_mapping.cdm = srsran_csi_rs_cdm_fd_cdm2; - zp_csi_rs_resource0.resource_mapping.density = srsran_csi_rs_resource_mapping_density_one; - zp_csi_rs_resource0.resource_mapping.freq_band.start_rb = 0; - zp_csi_rs_resource0.resource_mapping.freq_band.nof_rb = 52; - zp_csi_rs_resource0.periodicity.period = 80; - zp_csi_rs_resource0.periodicity.offset = 1; - pdsch.p_zp_csi_rs_set.data[0] = zp_csi_rs_resource0; - pdsch.p_zp_csi_rs_set.count = 1; - - // pdsch-ConfigCommon: setup (1) - // setup - // pdsch-TimeDomainAllocationList: 2 items - // Item 0 - // PDSCH-TimeDomainResourceAllocation - // mappingType: typeA (0) - // startSymbolAndLength: 40 - // Item 1 - // PDSCH-TimeDomainResourceAllocation - // mappingType: typeA (0) - // startSymbolAndLength: 57 - pdsch.common_time_ra[0].mapping_type = srsran_sch_mapping_type_A; - pdsch.common_time_ra[0].sliv = 40; - pdsch.common_time_ra[0].k = 0; - pdsch.common_time_ra[1].mapping_type = srsran_sch_mapping_type_A; - pdsch.common_time_ra[1].sliv = 57; - pdsch.common_time_ra[1].k = 0; - pdsch.nof_common_time_ra = 2; - - // pusch-ConfigCommon: setup (1) - // setup - // pusch-TimeDomainAllocationList: 2 items - // Item 0 - // PUSCH-TimeDomainResourceAllocation - // k2: 4 - // mappingType: typeA (0) - // startSymbolAndLength: 27 - // Item 1 - // PUSCH-TimeDomainResourceAllocation - // k2: 5 - // mappingType: typeA (0) - // startSymbolAndLength: 27 - // p0-NominalWithGrant: -90dBm - pusch.common_time_ra[0].mapping_type = srsran_sch_mapping_type_A; - pusch.common_time_ra[0].sliv = 27; - pusch.common_time_ra[0].k = 4; - pusch.common_time_ra[1].mapping_type = srsran_sch_mapping_type_A; - pusch.common_time_ra[1].sliv = 27; - pusch.common_time_ra[1].k = 5; - pusch.nof_common_time_ra = 2; - - // pusch-Config: setup (1) - // setup - // dmrs-UplinkForPUSCH-MappingTypeA: setup (1) - // setup - // dmrs-AdditionalPosition: pos1 (1) - // transformPrecodingDisabled - pusch.dmrs_typeA.additional_pos = srsran_dmrs_sch_add_pos_1; - pusch.dmrs_typeA.present = true; - // pusch-PowerControl - // msg3-Alpha: alpha1 (7) - // p0-NominalWithoutGrant: -90dBm - // p0-AlphaSets: 1 item - // Item 0 - // P0-PUSCH-AlphaSet - // p0-PUSCH-AlphaSetId: 0 - // p0: 0dB - // alpha: alpha1 (7) - // pathlossReferenceRSToAddModList: 1 item - // Item 0 - // PUSCH-PathlossReferenceRS - // pusch-PathlossReferenceRS-Id: 0 - // referenceSignal: ssb-Index (0) - // ssb-Index: 0 - // sri-PUSCH-MappingToAddModList: 1 item - // Item 0 - // SRI-PUSCH-PowerControl - // sri-PUSCH-PowerControlId: 0 - // sri-PUSCH-PathlossReferenceRS-Id: 0 - // sri-P0-PUSCH-AlphaSetId: 0 - // sri-PUSCH-ClosedLoopIndex: i0 (0) - // resourceAllocation: resourceAllocationType1 (1) - // uci-OnPUSCH: setup (1) - // setup - // betaOffsets: semiStatic (1) - // semiStatic - // betaOffsetACK-Index1: 9 - // betaOffsetACK-Index2: 9 - // betaOffsetACK-Index3: 9 - pusch.beta_offsets.ack_index1 = 9; - pusch.beta_offsets.ack_index2 = 9; - pusch.beta_offsets.ack_index3 = 9; - - // betaOffsetCSI-Part1-Index1: 6 - // betaOffsetCSI-Part1-Index2: 6 - pusch.beta_offsets.csi1_index1 = 6; - pusch.beta_offsets.csi1_index2 = 6; - - // betaOffsetCSI-Part2-Index1: 6 - // betaOffsetCSI-Part2-Index2: 6 - pusch.beta_offsets.csi2_index1 = 6; - pusch.beta_offsets.csi2_index2 = 6; - - // scaling: f1 (3) - pusch.scaling = 1; - - // pucch-Config: setup (1) - // setup - // resourceSetToAddModList: 2 items - pucch.enabled = true; - // Item 0 - // PUCCH-ResourceSet - // pucch-ResourceSetId: 0 - // resourceList: 8 items - // Item 0 - // PUCCH-ResourceId: 0 - // Item 1 - // PUCCH-ResourceId: 1 - // Item 2 - // PUCCH-ResourceId: 2 - // Item 3 - // PUCCH-ResourceId: 3 - // Item 4 - // PUCCH-ResourceId: 4 - // Item 5 - // PUCCH-ResourceId: 5 - // Item 6 - // PUCCH-ResourceId: 6 - // Item 7 - // PUCCH-ResourceId: 7 - pucch.sets[0].nof_resources = 8; - - // Item 1 - // PUCCH-ResourceSet - // pucch-ResourceSetId: 1 - // resourceList: 8 items - // Item 0 - // PUCCH-ResourceId: 8 - // Item 1 - // PUCCH-ResourceId: 9 - // Item 2 - // PUCCH-ResourceId: 10 - // Item 3 - // PUCCH-ResourceId: 11 - // Item 4 - // PUCCH-ResourceId: 12 - // Item 5 - // PUCCH-ResourceId: 13 - // Item 6 - // PUCCH-ResourceId: 14 - // Item 7 - // PUCCH-ResourceId: 15 - pucch.sets[1].nof_resources = 8; - - // resourceToAddModList: 18 items - // Item 0 - // PUCCH-Resource - // pucch-ResourceId: 0 - // startingPRB: 0 - // format: format1 (1) - // format1 - // initialCyclicShift: 0 - // nrofSymbols: 14 - // startingSymbolIndex: 0 - // timeDomainOCC: 0 - pucch.sets[0].resources[0].format = SRSRAN_PUCCH_NR_FORMAT_1; - pucch.sets[0].resources[0].starting_prb = 0; - pucch.sets[0].resources[0].initial_cyclic_shift = 0; - pucch.sets[0].resources[0].nof_symbols = 14; - pucch.sets[0].resources[0].start_symbol_idx = 0; - pucch.sets[0].resources[0].time_domain_occ = 0; - - // Item 1 - // PUCCH-Resource - // pucch-ResourceId: 1 - // startingPRB: 0 - // format: format1 (1) - // format1 - // initialCyclicShift: 4 - // nrofSymbols: 14 - // startingSymbolIndex: 0 - // timeDomainOCC: 0 - pucch.sets[0].resources[1].format = SRSRAN_PUCCH_NR_FORMAT_1; - pucch.sets[0].resources[1].starting_prb = 0; - pucch.sets[0].resources[1].initial_cyclic_shift = 4; - pucch.sets[0].resources[1].nof_symbols = 14; - pucch.sets[0].resources[1].start_symbol_idx = 0; - pucch.sets[0].resources[1].time_domain_occ = 0; - - // Item 2 - // PUCCH-Resource - // pucch-ResourceId: 2 - // startingPRB: 0 - // format: format1 (1) - // format1 - // initialCyclicShift: 8 - // nrofSymbols: 14 - // startingSymbolIndex: 0 - // timeDomainOCC: 0 - pucch.sets[0].resources[2].format = SRSRAN_PUCCH_NR_FORMAT_1; - pucch.sets[0].resources[2].starting_prb = 0; - pucch.sets[0].resources[2].initial_cyclic_shift = 8; - pucch.sets[0].resources[2].nof_symbols = 14; - pucch.sets[0].resources[2].start_symbol_idx = 0; - pucch.sets[0].resources[2].time_domain_occ = 0; - - // Item 3 - // PUCCH-Resource - // pucch-ResourceId: 3 - // startingPRB: 0 - // format: format1 (1) - // format1 - // initialCyclicShift: 0 - // nrofSymbols: 14 - // startingSymbolIndex: 0 - // timeDomainOCC: 1 - pucch.sets[0].resources[3].format = SRSRAN_PUCCH_NR_FORMAT_1; - pucch.sets[0].resources[3].starting_prb = 0; - pucch.sets[0].resources[3].initial_cyclic_shift = 0; - pucch.sets[0].resources[3].nof_symbols = 14; - pucch.sets[0].resources[3].start_symbol_idx = 0; - pucch.sets[0].resources[3].time_domain_occ = 1; - - // Item 4 - // PUCCH-Resource - // pucch-ResourceId: 4 - // startingPRB: 0 - // format: format1 (1) - // format1 - // initialCyclicShift: 4 - // nrofSymbols: 14 - // startingSymbolIndex: 0 - // timeDomainOCC: 1 - pucch.sets[0].resources[4].format = SRSRAN_PUCCH_NR_FORMAT_1; - pucch.sets[0].resources[4].starting_prb = 0; - pucch.sets[0].resources[4].initial_cyclic_shift = 4; - pucch.sets[0].resources[4].nof_symbols = 14; - pucch.sets[0].resources[4].start_symbol_idx = 0; - pucch.sets[0].resources[4].time_domain_occ = 1; - - // Item 5 - // PUCCH-Resource - // pucch-ResourceId: 5 - // startingPRB: 0 - // format: format1 (1) - // format1 - // initialCyclicShift: 8 - // nrofSymbols: 14 - // startingSymbolIndex: 0 - // timeDomainOCC: 1 - pucch.sets[0].resources[5].format = SRSRAN_PUCCH_NR_FORMAT_1; - pucch.sets[0].resources[5].starting_prb = 0; - pucch.sets[0].resources[5].initial_cyclic_shift = 8; - pucch.sets[0].resources[5].nof_symbols = 14; - pucch.sets[0].resources[5].start_symbol_idx = 0; - pucch.sets[0].resources[5].time_domain_occ = 1; - - // Item 6 - // PUCCH-Resource - // pucch-ResourceId: 6 - // startingPRB: 0 - // format: format1 (1) - // format1 - // initialCyclicShift: 0 - // nrofSymbols: 14 - // startingSymbolIndex: 0 - // timeDomainOCC: 2 - pucch.sets[0].resources[6].format = SRSRAN_PUCCH_NR_FORMAT_1; - pucch.sets[0].resources[6].starting_prb = 0; - pucch.sets[0].resources[6].initial_cyclic_shift = 0; - pucch.sets[0].resources[6].nof_symbols = 14; - pucch.sets[0].resources[6].start_symbol_idx = 0; - pucch.sets[0].resources[6].time_domain_occ = 2; - - // Item 7 - // PUCCH-Resource - // pucch-ResourceId: 7 - // startingPRB: 0 - // format: format1 (1) - // format1 - // initialCyclicShift: 4 - // nrofSymbols: 14 - // startingSymbolIndex: 0 - // timeDomainOCC: 2 - pucch.sets[0].resources[7].format = SRSRAN_PUCCH_NR_FORMAT_1; - pucch.sets[0].resources[7].starting_prb = 0; - pucch.sets[0].resources[7].initial_cyclic_shift = 0; - pucch.sets[0].resources[7].nof_symbols = 14; - pucch.sets[0].resources[7].start_symbol_idx = 0; - pucch.sets[0].resources[7].time_domain_occ = 2; - - // Item 8 - // PUCCH-Resource - // pucch-ResourceId: 8 - // startingPRB: 51 - // format: format2 (2) - // format2 - // nrofPRBs: 1 - // nrofSymbols: 2 - // startingSymbolIndex: 0 - pucch.sets[1].resources[0].format = SRSRAN_PUCCH_NR_FORMAT_2; - pucch.sets[1].resources[0].starting_prb = 51; - pucch.sets[1].resources[0].nof_prb = 1; - pucch.sets[1].resources[0].nof_symbols = 2; - pucch.sets[1].resources[0].start_symbol_idx = 0; - - // Item 9 - // PUCCH-Resource - // pucch-ResourceId: 9 - // startingPRB: 51 - // format: format2 (2) - // format2 - // nrofPRBs: 1 - // nrofSymbols: 2 - // startingSymbolIndex: 2 - pucch.sets[1].resources[1].format = SRSRAN_PUCCH_NR_FORMAT_2; - pucch.sets[1].resources[1].starting_prb = 51; - pucch.sets[1].resources[1].nof_prb = 1; - pucch.sets[1].resources[1].nof_symbols = 2; - pucch.sets[1].resources[1].start_symbol_idx = 2; - - // Item 10 - // PUCCH-Resource - // pucch-ResourceId: 10 - // startingPRB: 51 - // format: format2 (2) - // format2 - // nrofPRBs: 1 - // nrofSymbols: 2 - // startingSymbolIndex: 4 - pucch.sets[1].resources[2].format = SRSRAN_PUCCH_NR_FORMAT_2; - pucch.sets[1].resources[2].starting_prb = 51; - pucch.sets[1].resources[2].nof_prb = 1; - pucch.sets[1].resources[2].nof_symbols = 2; - pucch.sets[1].resources[2].start_symbol_idx = 4; - - // Item 11 - // PUCCH-Resource - // pucch-ResourceId: 11 - // startingPRB: 51 - // format: format2 (2) - // format2 - // nrofPRBs: 1 - // nrofSymbols: 2 - // startingSymbolIndex: 6 - pucch.sets[1].resources[3].format = SRSRAN_PUCCH_NR_FORMAT_2; - pucch.sets[1].resources[3].starting_prb = 51; - pucch.sets[1].resources[3].nof_prb = 1; - pucch.sets[1].resources[3].nof_symbols = 2; - pucch.sets[1].resources[3].start_symbol_idx = 6; - - // Item 12 - // PUCCH-Resource - // pucch-ResourceId: 12 - // startingPRB: 51 - // format: format2 (2) - // format2 - // nrofPRBs: 1 - // nrofSymbols: 2 - // startingSymbolIndex: 8 - pucch.sets[1].resources[4].format = SRSRAN_PUCCH_NR_FORMAT_2; - pucch.sets[1].resources[4].starting_prb = 51; - pucch.sets[1].resources[4].nof_prb = 1; - pucch.sets[1].resources[4].nof_symbols = 2; - pucch.sets[1].resources[4].start_symbol_idx = 8; - - // Item 13 - // PUCCH-Resource - // pucch-ResourceId: 13 - // startingPRB: 51 - // format: format2 (2) - // format2 - // nrofPRBs: 1 - // nrofSymbols: 2 - // startingSymbolIndex: 10 - pucch.sets[1].resources[5].format = SRSRAN_PUCCH_NR_FORMAT_2; - pucch.sets[1].resources[5].starting_prb = 51; - pucch.sets[1].resources[5].nof_prb = 1; - pucch.sets[1].resources[5].nof_symbols = 2; - pucch.sets[1].resources[5].start_symbol_idx = 10; - - // Item 14 - // PUCCH-Resource - // pucch-ResourceId: 14 - // startingPRB: 51 - // format: format2 (2) - // format2 - // nrofPRBs: 1 - // nrofSymbols: 2 - // startingSymbolIndex: 12 - pucch.sets[1].resources[6].format = SRSRAN_PUCCH_NR_FORMAT_2; - pucch.sets[1].resources[6].starting_prb = 51; - pucch.sets[1].resources[6].nof_prb = 1; - pucch.sets[1].resources[6].nof_symbols = 2; - pucch.sets[1].resources[6].start_symbol_idx = 12; - - // Item 15 - // PUCCH-Resource - // pucch-ResourceId: 15 - // startingPRB: 1 - // format: format2 (2) - // format2 - // nrofPRBs: 1 - // nrofSymbols: 2 - // startingSymbolIndex: 0 - pucch.sets[1].resources[7].format = SRSRAN_PUCCH_NR_FORMAT_2; - pucch.sets[1].resources[7].starting_prb = 51; - pucch.sets[1].resources[7].nof_prb = 1; - pucch.sets[1].resources[7].nof_symbols = 2; - pucch.sets[1].resources[7].start_symbol_idx = 2; - - // Item 16 - // PUCCH-Resource - // pucch-ResourceId: 16 - // startingPRB: 0 - // format: format1 (1) - // format1 - // initialCyclicShift: 8 - // nrofSymbols: 14 - // startingSymbolIndex: 0 - // timeDomainOCC: 2 - pucch.sr_resources[1].resource.format = SRSRAN_PUCCH_NR_FORMAT_1; - pucch.sr_resources[1].resource.starting_prb = 0; - pucch.sr_resources[1].resource.initial_cyclic_shift = 8; - pucch.sr_resources[1].resource.nof_symbols = 14; - pucch.sr_resources[1].resource.start_symbol_idx = 0; - pucch.sr_resources[1].resource.time_domain_occ = 2; - - // Item 17 - // PUCCH-Resource - // pucch-ResourceId: 17 - // startingPRB: 1 - // format: format2 (2) - // format2 - // nrofPRBs: 1 - // nrofSymbols: 2 - // startingSymbolIndex: 2 - srsran_pucch_nr_resource_t pucch_res_17 = {}; - pucch_res_17.starting_prb = 1; - pucch_res_17.format = SRSRAN_PUCCH_NR_FORMAT_2; - pucch_res_17.nof_prb = 1; - pucch_res_17.nof_symbols = 2; - pucch_res_17.start_symbol_idx = 2; - - // format1: setup (1) - // setup - // format2: setup (1) - // setup - // maxCodeRate: zeroDot25 (2) - for (uint32_t i = 0; i < SRSRAN_PUCCH_NR_MAX_NOF_SETS; i++) { - srsran_pucch_nr_resource_set_t* set = &pucch.sets[i]; - for (uint32_t j = 0; j < set->nof_resources; j++) { - if (set->resources[j].format == SRSRAN_PUCCH_NR_FORMAT_2) { - set->resources[j].max_code_rate = 2; // 0.25 - } - } - } - pucch_res_17.max_code_rate = 2; - - // schedulingRequestResourceToAddModList: 1 item - // Item 0 - // SchedulingRequestResourceConfig - // schedulingRequestResourceId: 1 - // schedulingRequestID: 0 - // periodicityAndOffset: sl40 (10) - // sl40: 8 - // resource: 16 - pucch.sr_resources[1].sr_id = 0; - pucch.sr_resources[1].period = 40; - pucch.sr_resources[1].offset = 8; - pucch.sr_resources[1].configured = true; - - // dl-DataToUL-ACK: 7 items - // Item 0 - // dl-DataToUL-ACK item: 8 - // Item 1 - // dl-DataToUL-ACK item: 7 - // Item 2 - // dl-DataToUL-ACK item: 6 - // Item 3 - // dl-DataToUL-ACK item: 5 - // Item 4 - // dl-DataToUL-ACK item: 4 - // Item 5 - // dl-DataToUL-ACK item: 12 - // Item 6 - // dl-DataToUL-ACK item: 11 - harq_ack.dl_data_to_ul_ack[0] = 8; - harq_ack.dl_data_to_ul_ack[1] = 7; - harq_ack.dl_data_to_ul_ack[2] = 6; - harq_ack.dl_data_to_ul_ack[3] = 5; - harq_ack.dl_data_to_ul_ack[4] = 4; - harq_ack.dl_data_to_ul_ack[5] = 12; - harq_ack.dl_data_to_ul_ack[6] = 11; - harq_ack.nof_dl_data_to_ul_ack = 7; - - // nzp-CSI-RS-ResourceToAddModList: 5 items - // Item 0 - // NZP-CSI-RS-Resource - // nzp-CSI-RS-ResourceId: 0 - // resourceMapping - // frequencyDomainAllocation: row2 (1) - // row2: 8000 [bit length 12, 4 LSB pad bits, 1000 0000 0000 .... decimal value 2048] - // nrofPorts: p1 (0) - // firstOFDMSymbolInTimeDomain: 4 - // cdm-Type: noCDM (0) - // density: one (1) - // one: NULL - // freqBand - // startingRB: 0 - // nrofRBs: 52 - // powerControlOffset: 0dB - // powerControlOffsetSS: db0 (1) - // scramblingID: 0 - // periodicityAndOffset: slots80 (9) - // slots80: 1 - // qcl-InfoPeriodicCSI-RS: 0 - srsran_csi_rs_nzp_resource_t nzp_resource_0 = {}; - nzp_resource_0.resource_mapping.row = srsran_csi_rs_resource_mapping_row_2; - nzp_resource_0.resource_mapping.frequency_domain_alloc[0] = true; - nzp_resource_0.resource_mapping.frequency_domain_alloc[1] = false; - nzp_resource_0.resource_mapping.frequency_domain_alloc[2] = false; - nzp_resource_0.resource_mapping.frequency_domain_alloc[3] = false; - nzp_resource_0.resource_mapping.frequency_domain_alloc[4] = false; - nzp_resource_0.resource_mapping.frequency_domain_alloc[5] = false; - nzp_resource_0.resource_mapping.frequency_domain_alloc[6] = false; - nzp_resource_0.resource_mapping.frequency_domain_alloc[7] = false; - nzp_resource_0.resource_mapping.frequency_domain_alloc[8] = false; - nzp_resource_0.resource_mapping.frequency_domain_alloc[9] = false; - nzp_resource_0.resource_mapping.frequency_domain_alloc[10] = false; - nzp_resource_0.resource_mapping.frequency_domain_alloc[11] = false; - nzp_resource_0.resource_mapping.nof_ports = 1; - nzp_resource_0.resource_mapping.first_symbol_idx = 4; - nzp_resource_0.resource_mapping.cdm = srsran_csi_rs_cdm_nocdm; - nzp_resource_0.resource_mapping.density = srsran_csi_rs_resource_mapping_density_one; - nzp_resource_0.resource_mapping.freq_band.start_rb = 0; - nzp_resource_0.resource_mapping.freq_band.nof_rb = 52; - nzp_resource_0.power_control_offset = 0; - nzp_resource_0.power_control_offset_ss = 0; - nzp_resource_0.scrambling_id = 0; - nzp_resource_0.periodicity.period = 80; - nzp_resource_0.periodicity.offset = 1; - - // Item 1 - // NZP-CSI-RS-Resource - // nzp-CSI-RS-ResourceId: 1 - // resourceMapping - // frequencyDomainAllocation: row1 (0) - // row1: 10 [bit length 4, 4 LSB pad bits, 0001 .... decimal value 1] - // nrofPorts: p1 (0) - // firstOFDMSymbolInTimeDomain: 4 - // cdm-Type: noCDM (0) - // density: three (2) - // three: NULL - // freqBand - // startingRB: 0 - // nrofRBs: 52 - // powerControlOffset: 0dB - // powerControlOffsetSS: db0 (1) - // scramblingID: 0 - // periodicityAndOffset: slots40 (7) - // slots40: 11 - // qcl-InfoPeriodicCSI-RS: 0 - srsran_csi_rs_nzp_resource_t nzp_resource_1 = {}; - nzp_resource_1.resource_mapping.row = srsran_csi_rs_resource_mapping_row_1; - nzp_resource_1.resource_mapping.frequency_domain_alloc[0] = false; - nzp_resource_1.resource_mapping.frequency_domain_alloc[1] = false; - nzp_resource_1.resource_mapping.frequency_domain_alloc[2] = false; - nzp_resource_1.resource_mapping.frequency_domain_alloc[3] = true; - nzp_resource_1.resource_mapping.nof_ports = 1; - nzp_resource_1.resource_mapping.first_symbol_idx = 4; - nzp_resource_1.resource_mapping.cdm = srsran_csi_rs_cdm_nocdm; - nzp_resource_1.resource_mapping.density = srsran_csi_rs_resource_mapping_density_three; - nzp_resource_1.resource_mapping.freq_band.start_rb = 0; - nzp_resource_1.resource_mapping.freq_band.nof_rb = 52; - nzp_resource_1.power_control_offset = 0; - nzp_resource_1.power_control_offset_ss = 0; - nzp_resource_1.scrambling_id = 0; - nzp_resource_1.periodicity.period = 40; - nzp_resource_1.periodicity.offset = 11; - // Item 2 - // NZP-CSI-RS-Resource - // nzp-CSI-RS-ResourceId: 2 - // resourceMapping - // frequencyDomainAllocation: row1 (0) - // row1: 10 [bit length 4, 4 LSB pad bits, 0001 .... decimal value 1] - // nrofPorts: p1 (0) - // firstOFDMSymbolInTimeDomain: 8 - // cdm-Type: noCDM (0) - // density: three (2) - // three: NULL - // freqBand - // startingRB: 0 - // nrofRBs: 52 - // powerControlOffset: 0dB - // powerControlOffsetSS: db0 (1) - // scramblingID: 0 - // periodicityAndOffset: slots40 (7) - // slots40: 11 - // qcl-InfoPeriodicCSI-RS: 0 - srsran_csi_rs_nzp_resource_t nzp_resource_2 = {}; - nzp_resource_2.resource_mapping.row = srsran_csi_rs_resource_mapping_row_1; - nzp_resource_2.resource_mapping.frequency_domain_alloc[0] = false; - nzp_resource_2.resource_mapping.frequency_domain_alloc[1] = false; - nzp_resource_2.resource_mapping.frequency_domain_alloc[2] = false; - nzp_resource_2.resource_mapping.frequency_domain_alloc[3] = true; - nzp_resource_2.resource_mapping.nof_ports = 1; - nzp_resource_2.resource_mapping.first_symbol_idx = 8; - nzp_resource_2.resource_mapping.cdm = srsran_csi_rs_cdm_nocdm; - nzp_resource_2.resource_mapping.density = srsran_csi_rs_resource_mapping_density_three; - nzp_resource_2.resource_mapping.freq_band.start_rb = 0; - nzp_resource_2.resource_mapping.freq_band.nof_rb = 52; - nzp_resource_2.power_control_offset = 0; - nzp_resource_2.power_control_offset_ss = 0; - nzp_resource_2.scrambling_id = 0; - nzp_resource_2.periodicity.period = 40; - nzp_resource_2.periodicity.offset = 11; - // Item 3 - // NZP-CSI-RS-Resource - // nzp-CSI-RS-ResourceId: 3 - // resourceMapping - // frequencyDomainAllocation: row1 (0) - // row1: 10 [bit length 4, 4 LSB pad bits, 0001 .... decimal value 1] - // nrofPorts: p1 (0) - // firstOFDMSymbolInTimeDomain: 4 - // cdm-Type: noCDM (0) - // density: three (2) - // three: NULL - // freqBand - // startingRB: 0 - // nrofRBs: 52 - // powerControlOffset: 0dB - // powerControlOffsetSS: db0 (1) - // scramblingID: 0 - // periodicityAndOffset: slots40 (7) - // slots40: 12 - // qcl-InfoPeriodicCSI-RS: 0 - srsran_csi_rs_nzp_resource_t nzp_resource_3 = {}; - nzp_resource_3.resource_mapping.row = srsran_csi_rs_resource_mapping_row_1; - nzp_resource_3.resource_mapping.frequency_domain_alloc[0] = false; - nzp_resource_3.resource_mapping.frequency_domain_alloc[1] = false; - nzp_resource_3.resource_mapping.frequency_domain_alloc[2] = false; - nzp_resource_3.resource_mapping.frequency_domain_alloc[3] = true; - nzp_resource_3.resource_mapping.nof_ports = 1; - nzp_resource_3.resource_mapping.first_symbol_idx = 4; - nzp_resource_3.resource_mapping.cdm = srsran_csi_rs_cdm_nocdm; - nzp_resource_3.resource_mapping.density = srsran_csi_rs_resource_mapping_density_three; - nzp_resource_3.resource_mapping.freq_band.start_rb = 0; - nzp_resource_3.resource_mapping.freq_band.nof_rb = 52; - nzp_resource_3.power_control_offset = 0; - nzp_resource_3.power_control_offset_ss = 0; - nzp_resource_3.scrambling_id = 0; - nzp_resource_3.periodicity.period = 40; - nzp_resource_3.periodicity.offset = 12; - // Item 4 - // NZP-CSI-RS-Resource - // nzp-CSI-RS-ResourceId: 4 - // resourceMapping - // frequencyDomainAllocation: row1 (0) - // row1: 10 [bit length 4, 4 LSB pad bits, 0001 .... decimal value 1] - // nrofPorts: p1 (0) - // firstOFDMSymbolInTimeDomain: 8 - // cdm-Type: noCDM (0) - // density: three (2) - // three: NULL - // freqBand - // startingRB: 0 - // nrofRBs: 52 - // powerControlOffset: 0dB - // powerControlOffsetSS: db0 (1) - // scramblingID: 0 - // periodicityAndOffset: slots40 (7) - // slots40: 12 - // qcl-InfoPeriodicCSI-RS: 0 - srsran_csi_rs_nzp_resource_t nzp_resource_4 = {}; - nzp_resource_4.resource_mapping.row = srsran_csi_rs_resource_mapping_row_1; - nzp_resource_4.resource_mapping.frequency_domain_alloc[0] = false; - nzp_resource_4.resource_mapping.frequency_domain_alloc[1] = false; - nzp_resource_4.resource_mapping.frequency_domain_alloc[2] = false; - nzp_resource_4.resource_mapping.frequency_domain_alloc[3] = true; - nzp_resource_4.resource_mapping.nof_ports = 1; - nzp_resource_4.resource_mapping.first_symbol_idx = 8; - nzp_resource_4.resource_mapping.cdm = srsran_csi_rs_cdm_nocdm; - nzp_resource_4.resource_mapping.density = srsran_csi_rs_resource_mapping_density_three; - nzp_resource_4.resource_mapping.freq_band.start_rb = 0; - nzp_resource_4.resource_mapping.freq_band.nof_rb = 52; - nzp_resource_4.power_control_offset = 0; - nzp_resource_4.power_control_offset_ss = 0; - nzp_resource_4.scrambling_id = 0; - nzp_resource_4.periodicity.period = 40; - nzp_resource_4.periodicity.offset = 12; - // zp-CSI-RS-ResourceSetToAddModList: 2 items - // Item 0 - // NZP-CSI-RS-ResourceSet - // nzp-CSI-ResourceSetId: 0 - // nzp-CSI-RS-Resources: 1 item - // Item 0 - // NZP-CSI-RS-ResourceId: 0 - pdsch.nzp_csi_rs_sets[0].data[0] = nzp_resource_0; - pdsch.nzp_csi_rs_sets[0].count = 1; - pdsch.nzp_csi_rs_sets[0].trs_info = false; - // Item 1 - // NZP-CSI-RS-ResourceSet - // nzp-CSI-ResourceSetId: 1 - // nzp-CSI-RS-Resources: 4 items - // Item 0 - // NZP-CSI-RS-ResourceId: 1 - // Item 1 - // NZP-CSI-RS-ResourceId: 2 - // Item 2 - // NZP-CSI-RS-ResourceId: 3 - // Item 3 - // NZP-CSI-RS-ResourceId: 4 - // trs-Info: true (0) - pdsch.nzp_csi_rs_sets[1].data[0] = nzp_resource_1; - pdsch.nzp_csi_rs_sets[1].data[1] = nzp_resource_2; - pdsch.nzp_csi_rs_sets[1].data[2] = nzp_resource_3; - pdsch.nzp_csi_rs_sets[1].data[3] = nzp_resource_4; - pdsch.nzp_csi_rs_sets[1].count = 4; - pdsch.nzp_csi_rs_sets[1].trs_info = true; - // csi-ReportConfigToAddModList: 1 item - // Item 0 - // CSI-ReportConfig - // reportConfigId: 0 - // resourcesForChannelMeasurement: 0 - // csi-IM-ResourcesForInterference: 1 - // reportConfigType: periodic (0) - // periodic - // reportSlotConfig: slots80 (7) - // slots80: 9 - // pucch-CSI-ResourceList: 1 item - // Item 0 - // PUCCH-CSI-Resource - // uplinkBandwidthPartId: 0 - // pucch-Resource: 17 - // reportQuantity: cri-RI-PMI-CQI (1) - // cri-RI-PMI-CQI: NULL - // reportFreqConfiguration - // cqi-FormatIndicator: widebandCQI (0) - // timeRestrictionForChannelMeasurements: notConfigured (1) - // timeRestrictionForInterferenceMeasurements: notConfigured (1) - // groupBasedBeamReporting: disabled (1) - // disabled - // cqi-Table: table2 (1) - // subbandSize: value1 (0) - csi.reports[0].type = SRSRAN_CSI_REPORT_TYPE_PERIODIC; - csi.reports[0].channel_meas_id = 0; - csi.reports[0].interf_meas_present = true; - csi.reports[0].interf_meas_id = 1; - csi.reports[0].periodic.period = 80; - csi.reports[0].periodic.offset = 9; - csi.reports[0].periodic.resource = pucch_res_17; - csi.reports[0].quantity = SRSRAN_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI; - csi.reports[0].freq_cfg = SRSRAN_CSI_REPORT_FREQ_WIDEBAND; - csi.reports[0].cqi_table = SRSRAN_CSI_CQI_TABLE_2; - } + srsran_carrier_nr_t carrier = {}; + + phy_cfg_nr_t() {} /** * @param carrier diff --git a/lib/include/srsran/interfaces/ue_nr_interfaces.h b/lib/include/srsran/interfaces/ue_nr_interfaces.h index f26a35524..4ce0c38fa 100644 --- a/lib/include/srsran/interfaces/ue_nr_interfaces.h +++ b/lib/include/srsran/interfaces/ue_nr_interfaces.h @@ -42,13 +42,31 @@ public: class mac_interface_phy_nr { public: + /// For DL, PDU buffer is allocated and passed to MAC in tb_decoded() + typedef struct { + bool enabled; /// Whether or not PHY should attempt to decode PDSCH + srsran_softbuffer_rx_t* softbuffer; /// Pointer to softbuffer to use + } tb_dl_t; + + /// Struct provided by MAC with all necessary information for PHY + typedef struct { + tb_dl_t tb; // only single TB in DL + } tb_action_dl_t; + typedef struct { - srsran::unique_byte_buffer_t tb[SRSRAN_MAX_TB]; - uint32_t pid; uint16_t rnti; uint32_t tti; + uint8_t pid; // HARQ process ID + uint8_t rv; // Redundancy Version + uint8_t ndi; // Raw new data indicator extracted from DCI + uint32_t tbs; // Transport block size in Bytes } mac_nr_grant_dl_t; + typedef struct { + srsran::unique_byte_buffer_t payload; // TB when decoded successfully, nullptr otherwise + bool ack; // HARQ information + } tb_action_dl_result_t; + // UL grant as conveyed between PHY and MAC typedef struct { uint16_t rnti; @@ -83,8 +101,25 @@ public: virtual sched_rnti_t get_dl_sched_rnti_nr(const uint32_t tti) = 0; virtual sched_rnti_t get_ul_sched_rnti_nr(const uint32_t tti) = 0; - /// Indicate succussfully received TB to MAC. The TB buffer is allocated in the PHY and handed as unique_ptr to MAC - virtual void tb_decoded(const uint32_t cc_idx, mac_nr_grant_dl_t& grant) = 0; + /** + * @brief Indicate reception of DL grant to MAC + * + * The TB buffer is allocated in the PHY and handed as unique_ptr to MAC. + * + * @param cc_idx The carrier index on which the grant has been received + * @param grant Reference to the grant + * @param action Pointer to the TB action to be filled by MAC + */ + virtual void new_grant_dl(const uint32_t cc_idx, const mac_nr_grant_dl_t& grant, tb_action_dl_t* action) = 0; + + /** + * Indicate decoding of PDSCH + * + * @param cc_idx The index of the carrier for which the PDSCH has been decoded + * @param grant The original DL grant + * @param result Payload (if any) and ack information + */ + virtual void tb_decoded(const uint32_t cc_idx, const mac_nr_grant_dl_t& grant, tb_action_dl_result_t result) = 0; /** * @brief Indicate reception of UL grant to MAC @@ -123,6 +158,7 @@ public: virtual int setup_lcid(const srsran::logical_channel_config_t& config) = 0; virtual int set_config(const srsran::bsr_cfg_nr_t& bsr_cfg) = 0; virtual int set_config(const srsran::sr_cfg_nr_t& sr_cfg) = 0; + virtual int set_config(const srsran::dl_harq_cfg_nr_t& dl_hrq_cfg) = 0; virtual void set_config(const srsran::rach_nr_cfg_t& rach_cfg) = 0; virtual int add_tag_config(const srsran::tag_cfg_nr_t& tag_cfg) = 0; virtual int set_config(const srsran::phr_cfg_nr_t& phr_cfg) = 0; diff --git a/lib/include/srsran/phy/ch_estimation/csi_rs_cfg.h b/lib/include/srsran/phy/ch_estimation/csi_rs_cfg.h index 605024347..40c9c883e 100644 --- a/lib/include/srsran/phy/ch_estimation/csi_rs_cfg.h +++ b/lib/include/srsran/phy/ch_estimation/csi_rs_cfg.h @@ -103,6 +103,7 @@ typedef struct SRSRAN_API { * @brief Contains TS 38.331 NZP-CSI-RS-Resource flattened configuration */ typedef struct SRSRAN_API { + uint32_t id; srsran_csi_rs_resource_mapping_t resource_mapping; ///< CSI-RS time/frequency mapping float power_control_offset; ///< -8..15 dB float power_control_offset_ss; ///< -3, 0, 3, 6 dB @@ -123,6 +124,7 @@ typedef struct SRSRAN_API { * @brief Contains TS 38.331 ZP-CSI-RS-Resource flattened configuration */ typedef struct { + uint32_t id; srsran_csi_rs_resource_mapping_t resource_mapping; ///< CSI-RS time/frequency mapping srsran_csi_rs_period_and_offset_t periodicity; } srsran_csi_rs_zp_resource_t; diff --git a/lib/include/srsran/phy/common/phy_common_nr.h b/lib/include/srsran/phy/common/phy_common_nr.h index b4c0a3473..20b7a02e6 100644 --- a/lib/include/srsran/phy/common/phy_common_nr.h +++ b/lib/include/srsran/phy/common/phy_common_nr.h @@ -269,14 +269,29 @@ typedef enum SRSRAN_API { srsran_resource_alloc_dynamic, } srsran_resource_alloc_t; +/** + * @brief Subcarrier spacing 15 or 30 kHz <6GHz and 60 or 120 kHz >6GHz + * @remark Described in TS 38.331 V15.10.0 subcarrier spacing + */ + +typedef enum SRSRAN_API { + srsran_subcarrier_spacing_15kHz = 0, + srsran_subcarrier_spacing_30kHz, + srsran_subcarrier_spacing_60kHz, + srsran_subcarrier_spacing_120kHz, + srsran_subcarrier_spacing_240kHz, +} srsran_subcarrier_spacing_t; + /** * @brief NR carrier parameters. It is a combination of fixed cell and bandwidth-part (BWP) */ typedef struct SRSRAN_API { - uint32_t id; - uint32_t numerology; - uint32_t nof_prb; - uint32_t start; + uint32_t pci; + uint32_t absolute_frequency_ssb; + uint32_t absolute_frequency_point_a; + srsran_subcarrier_spacing_t scs; + uint32_t nof_prb; + uint32_t start; uint32_t max_mimo_layers; ///< @brief DL: Indicates the maximum number of MIMO layers to be used for PDSCH in all BWPs ///< of this serving cell. (see TS 38.212 [17], clause 5.4.2.1). UL: Indicates the maximum ///< MIMO layer to be used for PUSCH in all BWPs of the normal UL of this serving cell (see @@ -319,7 +334,6 @@ typedef struct SRSRAN_API { */ typedef struct SRSRAN_API { uint32_t id; - uint32_t coreset_id; srsran_coreset_mapping_type_t mapping_type; uint32_t duration; bool freq_resources[SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE]; diff --git a/lib/include/srsran/phy/modem/demod_soft.h b/lib/include/srsran/phy/modem/demod_soft.h index 08aff4e89..515dfe087 100644 --- a/lib/include/srsran/phy/modem/demod_soft.h +++ b/lib/include/srsran/phy/modem/demod_soft.h @@ -42,14 +42,4 @@ SRSRAN_API int srsran_demod_soft_demodulate_s(srsran_mod_t modulation, const cf_ SRSRAN_API int srsran_demod_soft_demodulate_b(srsran_mod_t modulation, const cf_t* symbols, int8_t* llr, int nsymbols); -/** - * @brief Soft-demodulates complex symbols into 8-bit LLR. It forces zero symbols produce zero LLRs. - * @param modulation Modulation - * @param symbols Complex symbols - * @param llr 8-bit LLRs - * @param nsymbols Number of symbols - * @return SRSLTE_SUCCESS if the provided pointers are valid, SRSLTE_ERROR code otherwise - */ -SRSRAN_API int srsran_demod_soft_demodulate2_b(srsran_mod_t modulation, const cf_t* symbols, int8_t* llr, int nsymbols); - #endif // SRSRAN_DEMOD_SOFT_H diff --git a/lib/include/srsran/phy/phch/pdsch_nr.h b/lib/include/srsran/phy/phch/pdsch_nr.h index 670c4c864..2c8b5965b 100644 --- a/lib/include/srsran/phy/phch/pdsch_nr.h +++ b/lib/include/srsran/phy/phch/pdsch_nr.h @@ -46,8 +46,6 @@ typedef struct SRSRAN_API { srsran_sch_nr_args_t sch; bool measure_evm; bool measure_time; - bool disable_zero_re_around_dc; ///< PDSCH NR sets the LLR around the DC to zero to avoid noise - uint32_t nof_zero_re_around_dc; ///< Number of RE to set to zero around DC. It uses default value if 0. } srsran_pdsch_nr_args_t; /** @@ -68,8 +66,6 @@ typedef struct SRSRAN_API { uint32_t meas_time_us; srsran_re_pattern_t dmrs_re_pattern; uint32_t nof_rvd_re; - uint32_t nof_zero_re_around_dc; ///< Sets a number of RE surrounding the center of the resource grid to zero. Set to 0 - ///< for disabling. } srsran_pdsch_nr_t; /** diff --git a/lib/include/srsran/phy/phch/phch_cfg_nr.h b/lib/include/srsran/phy/phch/phch_cfg_nr.h index 9ef79ac08..d194913c2 100644 --- a/lib/include/srsran/phy/phch/phch_cfg_nr.h +++ b/lib/include/srsran/phy/phch/phch_cfg_nr.h @@ -173,6 +173,11 @@ typedef struct { uint32_t csi1_index2; ///< Use for more than 11 CSI bits. Set to 13 if absent. uint32_t csi2_index1; ///< Use for up to 11 CSI bits. Set to 13 if absent. uint32_t csi2_index2; ///< Use for more than 11 CSI bits. Set to 13 if absent. + + /// Fix values for testing purposes + float fix_ack; ///< Set to a non-zero value for fixing a beta offset value + float fix_csi1; + float fix_csi2; } srsran_beta_offsets_t; /** @@ -247,11 +252,11 @@ typedef struct SRSRAN_API { /// PUSCH only parameters srsran_uci_cfg_nr_t uci; ///< Uplink Control Information configuration bool enable_transform_precoder; - float beta_harq_ack_offset; - float beta_csi_part1_offset; - float beta_csi_part2_offset; - float scaling; bool freq_hopping_enabled; } srsran_sch_cfg_nr_t; +SRSRAN_API uint32_t srsran_sch_cfg_nr_nof_re(const srsran_sch_cfg_nr_t* sch_cfg); + +SRSRAN_API uint32_t srsran_sch_cfg_nr_info(const srsran_sch_cfg_nr_t* sch_cfg, char* str, uint32_t str_len); + #endif // SRSRAN_PHCH_CFG_NR_H diff --git a/lib/include/srsran/phy/phch/pusch_nr.h b/lib/include/srsran/phy/phch/pusch_nr.h index d384dac23..f6215eaea 100644 --- a/lib/include/srsran/phy/phch/pusch_nr.h +++ b/lib/include/srsran/phy/phch/pusch_nr.h @@ -59,7 +59,7 @@ typedef struct SRSRAN_API { srsran_evm_buffer_t* evm_buffer; bool meas_time_en; uint32_t meas_time_us; - srsran_uci_cfg_nr_t uci_cfg; ///< Internal UCI bits configuration + srsran_re_pattern_t dmrs_re_pattern; uint8_t* g_ulsch; ///< Temporal Encoded UL-SCH data uint8_t* g_ack; ///< Temporal Encoded HARQ-ACK bits uint8_t* g_csi1; ///< Temporal Encoded CSI part 1 bits diff --git a/lib/include/srsran/phy/phch/ra_nr.h b/lib/include/srsran/phy/phch/ra_nr.h index 60f628746..7e8fa5c78 100644 --- a/lib/include/srsran/phy/phch/ra_nr.h +++ b/lib/include/srsran/phy/phch/ra_nr.h @@ -137,12 +137,14 @@ SRSRAN_API int srsran_ra_ul_dci_to_grant_nr(const srsran_carrier_nr_t* carrie * * @remark Implement procedure described in TS 38.213 9.3 UCI reporting in physical uplink shared channel * + * @param carrier Carrier information struct * @param pusch_hl_cfg PUSCH configuration provided by higher layers * @param uci_cfg Uplink Control Information configuration for this PUSCH transmission * @param pusch_cfg PUSCH configuration after applying the procedure * @return SRSRAN_SUCCESS if the procedure is successful, SRSRAN_ERROR code otherwise */ -SRSRAN_API int srsran_ra_ul_set_grant_uci_nr(const srsran_sch_hl_cfg_nr_t* pusch_hl_cfg, +SRSRAN_API int srsran_ra_ul_set_grant_uci_nr(const srsran_carrier_nr_t* carrier, + const srsran_sch_hl_cfg_nr_t* pusch_hl_cfg, const srsran_uci_cfg_nr_t* uci_cfg, srsran_sch_cfg_nr_t* pusch_cfg); diff --git a/lib/include/srsran/phy/phch/sch_cfg_nr.h b/lib/include/srsran/phy/phch/sch_cfg_nr.h index f1c7fcfe3..16b8489cc 100644 --- a/lib/include/srsran/phy/phch/sch_cfg_nr.h +++ b/lib/include/srsran/phy/phch/sch_cfg_nr.h @@ -40,9 +40,8 @@ typedef struct SRSRAN_API { double R; ///< Target LDPC rate int rv; ///< Redundancy version int ndi; ///< New Data Indicator - int pid; ///< HARQ Process ID - uint32_t nof_re; ///< Number of available resource elements to send, known as N_RE - uint32_t nof_bits; ///< Number of available bits to send, known as G + uint32_t nof_re; ///< Number of available resource elements to transmit ULSCH (data) and UCI (control) + uint32_t nof_bits; ///< Number of available bits to send ULSCH uint32_t cw_idx; bool enabled; diff --git a/lib/include/srsran/phy/phch/uci_cfg_nr.h b/lib/include/srsran/phy/phch/uci_cfg_nr.h index 84ceddda9..814e2a7ea 100644 --- a/lib/include/srsran/phy/phch/uci_cfg_nr.h +++ b/lib/include/srsran/phy/phch/uci_cfg_nr.h @@ -71,6 +71,7 @@ typedef struct { float alpha; ///< Higher layer parameter scaling float beta_harq_ack_offset; float beta_csi1_offset; + float beta_csi2_offset; uint32_t nof_re; bool csi_part2_present; } srsran_uci_nr_pusch_cfg_t; diff --git a/lib/include/srsran/upper/pdcp.h b/lib/include/srsran/upper/pdcp.h index fc6af5708..12ff2c1b8 100644 --- a/lib/include/srsran/upper/pdcp.h +++ b/lib/include/srsran/upper/pdcp.h @@ -35,6 +35,10 @@ class pdcp : public srsue::pdcp_interface_rlc, public srsue::pdcp_interface_rrc public: pdcp(srsran::task_sched_handle task_sched_, const char* logname); virtual ~pdcp(); + void init(srsue::rlc_interface_pdcp* rlc_, + srsue::rrc_interface_pdcp* rrc_, + srsue::rrc_interface_pdcp* rrc_nr_, + srsue::gw_interface_pdcp* gw_); void init(srsue::rlc_interface_pdcp* rlc_, srsue::rrc_interface_pdcp* rrc_, srsue::gw_interface_pdcp* gw_); void stop(); @@ -78,9 +82,10 @@ public: void reset_metrics(); private: - srsue::rlc_interface_pdcp* rlc = nullptr; - srsue::rrc_interface_pdcp* rrc = nullptr; - srsue::gw_interface_pdcp* gw = nullptr; + srsue::rlc_interface_pdcp* rlc = nullptr; + srsue::rrc_interface_pdcp* rrc = nullptr; + srsue::rrc_interface_pdcp* rrc_nr = nullptr; + srsue::gw_interface_pdcp* gw = nullptr; srsran::task_sched_handle task_sched; srslog::basic_logger& logger; diff --git a/lib/include/srsran/upper/pdcp_entity_base.h b/lib/include/srsran/upper/pdcp_entity_base.h index bd99ab641..0cf348f35 100644 --- a/lib/include/srsran/upper/pdcp_entity_base.h +++ b/lib/include/srsran/upper/pdcp_entity_base.h @@ -160,7 +160,8 @@ protected: PDCP_SN_LEN_12, pdcp_t_reordering_t::ms500, pdcp_discard_timer_t::infinity, - false}; + false, + srsran_rat_t::lte}; srsran::as_security_config_t sec_cfg = {}; diff --git a/lib/include/srsran/upper/rlc.h b/lib/include/srsran/upper/rlc.h index 95f6fd420..4954842a8 100644 --- a/lib/include/srsran/upper/rlc.h +++ b/lib/include/srsran/upper/rlc.h @@ -48,6 +48,13 @@ public: srsue::rrc_interface_rlc* rrc_, srsran::timer_handler* timers_, uint32_t lcid_); + + void init(srsue::pdcp_interface_rlc* pdcp_, + srsue::rrc_interface_rlc* rrc_, + srsue::rrc_interface_rlc* rrc_nr_, + srsran::timer_handler* timers_, + uint32_t lcid_); + void init(srsue::pdcp_interface_rlc* pdcp_, srsue::rrc_interface_rlc* rrc_, srsran::timer_handler* timers_, @@ -96,10 +103,11 @@ public: private: void reset_metrics(); - byte_buffer_pool* pool = nullptr; srslog::basic_logger& logger; + byte_buffer_pool* pool = nullptr; srsue::pdcp_interface_rlc* pdcp = nullptr; srsue::rrc_interface_rlc* rrc = nullptr; + srsue::rrc_interface_rlc* rrc_nr = nullptr; srsran::timer_handler* timers = nullptr; typedef std::map rlc_map_t; diff --git a/lib/include/srsran/upper/rlc_am_lte.h b/lib/include/srsran/upper/rlc_am_lte.h index 88dd11137..800183563 100644 --- a/lib/include/srsran/upper/rlc_am_lte.h +++ b/lib/include/srsran/upper/rlc_am_lte.h @@ -25,6 +25,7 @@ #include "srsran/adt/accumulators.h" #include "srsran/adt/circular_array.h" #include "srsran/adt/circular_map.h" +#include "srsran/adt/intrusive_list.h" #include "srsran/common/buffer_pool.h" #include "srsran/common/common.h" #include "srsran/common/srsran_assert.h" @@ -42,23 +43,95 @@ namespace srsran { #undef RLC_AM_BUFFER_DEBUG -struct rlc_amd_rx_pdu_t { +class rlc_amd_tx_pdu; +class pdcp_pdu_info; + +/// Pool that manages the allocation of RLC AM PDU Segments to RLC PDUs and tracking of segments ACK state +struct rlc_am_pdu_segment_pool { + const static size_t MAX_POOL_SIZE = 16384; + using rlc_list_tag = default_intrusive_tag; + struct free_list_tag {}; + + /// RLC AM PDU Segment, containing the PDCP SN and RLC SN it has been assigned to, and its current ACK state + struct segment_resource : public intrusive_forward_list_element, + public intrusive_forward_list_element, + public intrusive_double_linked_list_element<> { + const static uint32_t invalid_rlc_sn = std::numeric_limits::max(); + const static uint32_t invalid_pdcp_sn = std::numeric_limits::max() - 1; // -1 for Status Report + + int id() const; + void release_pdcp_sn(); + void release_rlc_sn(); + uint32_t rlc_sn() const { return rlc_sn_; } + uint32_t pdcp_sn() const { return pdcp_sn_; } + bool empty() const { return rlc_sn_ == invalid_rlc_sn and pdcp_sn_ == invalid_pdcp_sn; } + + private: + friend struct rlc_am_pdu_segment_pool; + uint32_t rlc_sn_ = invalid_rlc_sn; + uint32_t pdcp_sn_ = invalid_pdcp_sn; + rlc_am_pdu_segment_pool* parent_pool = nullptr; + }; + + rlc_am_pdu_segment_pool(); + rlc_am_pdu_segment_pool(const rlc_am_pdu_segment_pool&) = delete; + rlc_am_pdu_segment_pool(rlc_am_pdu_segment_pool&&) = delete; + rlc_am_pdu_segment_pool& operator=(const rlc_am_pdu_segment_pool&) = delete; + rlc_am_pdu_segment_pool& operator=(rlc_am_pdu_segment_pool&&) = delete; + bool has_segments() const { return not free_list.empty(); } + bool make_segment(rlc_amd_tx_pdu& rlc_list, pdcp_pdu_info& pdcp_info); + +private: + intrusive_forward_list free_list; + std::array segments; +}; + +/// RLC AM PDU Segment, containing the PDCP SN and RLC SN it has been assigned to, and its current ACK state +using rlc_am_pdu_segment = rlc_am_pdu_segment_pool::segment_resource; + +struct rlc_amd_rx_pdu { rlc_amd_pdu_header_t header; unique_byte_buffer_t buf; uint32_t rlc_sn; + + rlc_amd_rx_pdu() = default; + explicit rlc_amd_rx_pdu(uint32_t rlc_sn_) : rlc_sn(rlc_sn_) {} }; struct rlc_amd_rx_pdu_segments_t { - std::list segments; + std::list segments; }; -struct rlc_amd_tx_pdu_t { +/// Class that contains the parameters and state (e.g. segments) of a RLC PDU +class rlc_amd_tx_pdu +{ + using list_type = intrusive_forward_list; + const static uint32_t invalid_rlc_sn = std::numeric_limits::max(); + + list_type list; + +public: + using iterator = typename list_type::iterator; + using const_iterator = typename list_type::const_iterator; + + const uint32_t rlc_sn = invalid_rlc_sn; + uint32_t retx_count = 0; rlc_amd_pdu_header_t header; unique_byte_buffer_t buf; - pdcp_sn_vector_t pdcp_sns; - uint32_t retx_count; - uint32_t rlc_sn; - bool is_acked; + + explicit rlc_amd_tx_pdu(uint32_t rlc_sn_) : rlc_sn(rlc_sn_) {} + rlc_amd_tx_pdu(const rlc_amd_tx_pdu&) = delete; + rlc_amd_tx_pdu(rlc_amd_tx_pdu&& other) noexcept = default; + rlc_amd_tx_pdu& operator=(const rlc_amd_tx_pdu& other) = delete; + rlc_amd_tx_pdu& operator=(rlc_amd_tx_pdu&& other) = delete; + ~rlc_amd_tx_pdu(); + + // Segment List Interface + void add_segment(rlc_am_pdu_segment& segment) { list.push_front(&segment); } + const_iterator begin() const { return list.begin(); } + const_iterator end() const { return list.end(); } + iterator begin() { return list.begin(); } + iterator end() { return list.end(); } }; struct rlc_amd_retx_t { @@ -73,12 +146,47 @@ struct rlc_sn_info_t { bool is_acked; }; -struct pdcp_sdu_info_t { - uint32_t sn; - bool fully_txed; // Boolean indicating if the SDU is fully transmitted. - bool fully_acked; // Boolean indicating if the SDU is fully acked. This is only necessary temporarely to avoid - // duplicate removal from the queue while processing the status report - std::vector rlc_sn_info_list; // List of RLC PDUs in transit and whether they have been acked or not. +/// Class that contains the parameters and state (e.g. unACKed segments) of a PDCP PDU +class pdcp_pdu_info +{ + using list_type = intrusive_double_linked_list; + + list_type list; // List of unACKed RLC PDUs that contain segments that belong to the PDCP PDU. + +public: + const static uint32_t status_report_sn = std::numeric_limits::max(); + const static uint32_t invalid_pdcp_sn = std::numeric_limits::max() - 1; + + using iterator = typename list_type::iterator; + using const_iterator = typename list_type::const_iterator; + + // Copy is forbidden to avoid multiple PDCP SN references to the same segment + pdcp_pdu_info() = default; + pdcp_pdu_info(pdcp_pdu_info&&) noexcept = default; + pdcp_pdu_info(const pdcp_pdu_info&) noexcept = delete; + pdcp_pdu_info& operator=(const pdcp_pdu_info&) noexcept = delete; + pdcp_pdu_info& operator=(pdcp_pdu_info&&) noexcept = default; + ~pdcp_pdu_info() { clear(); } + + uint32_t sn = invalid_pdcp_sn; + bool fully_txed = false; // Boolean indicating if the SDU is fully transmitted. + + bool fully_acked() const { return fully_txed and list.empty(); } + bool valid() const { return sn != invalid_pdcp_sn; } + + // Interface for list of unACKed RLC segments of the PDCP PDU + void add_segment(rlc_am_pdu_segment& segment) { list.push_front(&segment); } + void ack_segment(rlc_am_pdu_segment& segment); + void clear() + { + sn = invalid_pdcp_sn; + fully_txed = false; + while (not list.empty()) { + ack_segment(list.front()); + } + } + const_iterator begin() const { return list.begin(); } + const_iterator end() const { return list.end(); } }; template @@ -86,8 +194,7 @@ struct rlc_ringbuffer_t { T& add_pdu(size_t sn) { srsran_expect(not has_sn(sn), "The same SN=%zd should not be added twice", sn); - window.overwrite(sn, T{}); - window[sn].rlc_sn = sn; + window.overwrite(sn, T(sn)); return window[sn]; } void remove_pdu(size_t sn) @@ -125,53 +232,56 @@ public: void add_pdcp_sdu(uint32_t sn) { + srsran_expect(sn <= max_pdcp_sn or sn == status_report_sn, "Invalid PDCP SN=%d", sn); srsran_assert(not has_pdcp_sn(sn), "Cannot re-add same PDCP SN twice"); - uint32_t sn_idx = get_idx(sn); - if (buffered_pdus[sn_idx].sn != invalid_sn) { - clear_pdcp_sdu(buffered_pdus[sn_idx].sn); + pdcp_pdu_info& pdu = get_pdu_(sn); + if (pdu.valid()) { + pdu.clear(); + count--; } - buffered_pdus[get_idx(sn)].sn = sn; + pdu.sn = sn; count++; } void clear_pdcp_sdu(uint32_t sn) { - uint32_t sn_idx = get_idx(sn); - if (buffered_pdus[sn_idx].sn == invalid_sn) { + pdcp_pdu_info& pdu = get_pdu_(sn); + if (not pdu.valid()) { return; } - buffered_pdus[sn_idx].sn = invalid_sn; - buffered_pdus[sn_idx].fully_acked = false; - buffered_pdus[sn_idx].fully_txed = false; - buffered_pdus[sn_idx].rlc_sn_info_list.clear(); + pdu.clear(); count--; } - pdcp_sdu_info_t& operator[](uint32_t sn) + pdcp_pdu_info& operator[](uint32_t sn) { - assert(has_pdcp_sn(sn)); - return buffered_pdus[get_idx(sn)]; + srsran_expect(has_pdcp_sn(sn), "Invalid access to non-existent PDCP SN=%d", sn); + return get_pdu_(sn); } bool has_pdcp_sn(uint32_t pdcp_sn) const { - assert(pdcp_sn <= max_pdcp_sn or pdcp_sn == status_report_sn); - return buffered_pdus[get_idx(pdcp_sn)].sn == pdcp_sn; + srsran_expect(pdcp_sn <= max_pdcp_sn or pdcp_sn == status_report_sn, "Invalid PDCP SN=%d", pdcp_sn); + return get_pdu_(pdcp_sn).sn == pdcp_sn; } uint32_t nof_sdus() const { return count; } private: const static size_t max_pdcp_sn = 262143u; - const static size_t max_buffer_idx = 4096u; - const static uint32_t status_report_sn = std::numeric_limits::max(); - const static uint32_t invalid_sn = std::numeric_limits::max() - 1; + const static size_t buffer_size = 4096u; + const static uint32_t status_report_sn = pdcp_pdu_info::status_report_sn; - size_t get_idx(uint32_t sn) const + pdcp_pdu_info& get_pdu_(uint32_t sn) { - return (sn != status_report_sn) ? static_cast(sn % max_buffer_idx) : max_buffer_idx; + return (sn == status_report_sn) ? status_report_pdu : buffered_pdus[static_cast(sn % buffer_size)]; + } + const pdcp_pdu_info& get_pdu_(uint32_t sn) const + { + return (sn == status_report_sn) ? status_report_pdu : buffered_pdus[static_cast(sn % buffer_size)]; } - // size equal to buffer_size + 1 (last element for Status Report) - std::vector buffered_pdus; - uint32_t count = 0; + // size equal to buffer_size + std::vector buffered_pdus; + pdcp_pdu_info status_report_pdu; + uint32_t count = 0; }; class pdu_retx_queue @@ -287,7 +397,7 @@ private: int build_retx_pdu(uint8_t* payload, uint32_t nof_bytes); int build_segment(uint8_t* payload, uint32_t nof_bytes, rlc_amd_retx_t retx); int build_data_pdu(uint8_t* payload, uint32_t nof_bytes); - void update_notification_ack_info(const rlc_amd_tx_pdu_t& tx_pdu); + void update_notification_ack_info(uint32_t rlc_sn); void debug_state(); @@ -299,9 +409,10 @@ private: bool do_status(); void check_sn_reached_max_retx(uint32_t sn); - rlc_am_lte* parent = nullptr; - byte_buffer_pool* pool = nullptr; - srslog::basic_logger& logger; + rlc_am_lte* parent = nullptr; + byte_buffer_pool* pool = nullptr; + srslog::basic_logger& logger; + rlc_am_pdu_segment_pool segment_pool; /**************************************************************************** * Configurable parameters @@ -348,9 +459,9 @@ private: bsr_callback_t bsr_callback; // Tx windows - rlc_ringbuffer_t tx_window; - pdu_retx_queue retx_queue; - pdcp_sn_vector_t notify_info_vec; + rlc_ringbuffer_t tx_window; + pdu_retx_queue retx_queue; + pdcp_sn_vector_t notify_info_vec; // Mutexes std::mutex mutex; @@ -391,7 +502,7 @@ private: bool inside_rx_window(const int16_t sn); void debug_state(); void print_rx_segments(); - bool add_segment_and_check(rlc_amd_rx_pdu_segments_t* pdu, rlc_amd_rx_pdu_t* segment); + bool add_segment_and_check(rlc_amd_rx_pdu_segments_t* pdu, rlc_amd_rx_pdu* segment); rlc_am_lte* parent = nullptr; byte_buffer_pool* pool = nullptr; @@ -422,7 +533,7 @@ private: std::mutex mutex; // Rx windows - rlc_ringbuffer_t rx_window; + rlc_ringbuffer_t rx_window; std::map rx_segments; bool poll_received = false; @@ -474,7 +585,7 @@ uint32_t rlc_am_packed_length(rlc_status_pdu_t* status); uint32_t rlc_am_packed_length(rlc_amd_retx_t retx); bool rlc_am_is_valid_status_pdu(const rlc_status_pdu_t& status); bool rlc_am_is_pdu_segment(uint8_t* payload); -std::string rlc_am_undelivered_sdu_info_to_string(const std::map& info_queue); +std::string rlc_am_undelivered_sdu_info_to_string(const std::map& info_queue); void log_rlc_amd_pdu_header_to_string(srslog::log_channel& log_ch, const rlc_amd_pdu_header_t& header); bool rlc_am_start_aligned(const uint8_t fi); bool rlc_am_end_aligned(const uint8_t fi); diff --git a/lib/include/srsran/upper/rlc_common.h b/lib/include/srsran/upper/rlc_common.h index 1177d2900..a08340d0b 100644 --- a/lib/include/srsran/upper/rlc_common.h +++ b/lib/include/srsran/upper/rlc_common.h @@ -113,10 +113,18 @@ typedef struct { class rlc_amd_pdu_header_t { public: - rlc_amd_pdu_header_t() {} - + rlc_amd_pdu_header_t() = default; rlc_amd_pdu_header_t(const rlc_amd_pdu_header_t& h) { copy(h); } + rlc_amd_pdu_header_t(rlc_amd_pdu_header_t&& h) noexcept { copy(h); } rlc_amd_pdu_header_t& operator=(const rlc_amd_pdu_header_t& h) + { + if (this == &h) { + return *this; + } + copy(h); + return *this; + } + rlc_amd_pdu_header_t& operator=(rlc_amd_pdu_header_t&& h) noexcept { copy(h); return *this; diff --git a/lib/src/asn1/rrc_nr_utils.cc b/lib/src/asn1/rrc_nr_utils.cc index 84af9957c..91f85d32f 100644 --- a/lib/src/asn1/rrc_nr_utils.cc +++ b/lib/src/asn1/rrc_nr_utils.cc @@ -75,6 +75,19 @@ logical_channel_config_t make_mac_logical_channel_cfg_t(uint8_t lcid, const lc_c return logical_channel_config; } +bool make_mac_dl_harq_cfg_nr_t(const pdsch_serving_cell_cfg_s& asn1_type, dl_harq_cfg_nr_t* out_dl_harq_cfg_nr) +{ + dl_harq_cfg_nr_t dl_harq_cfg_nr; + if (asn1_type.nrof_harq_processes_for_pdsch_present) { + dl_harq_cfg_nr.nof_procs = asn1_type.nrof_harq_processes_for_pdsch.to_number(); + } else { + asn1::log_warning("Option nrof_harq_processes_for_pdsch not present"); + return false; + } + *out_dl_harq_cfg_nr = dl_harq_cfg_nr; + return true; +} + bool make_mac_phr_cfg_t(const phr_cfg_s& asn1_type, phr_cfg_nr_t* phr_cfg_nr) { phr_cfg_nr->extended = asn1_type.ext; @@ -208,7 +221,8 @@ srsran::pdcp_config_t make_drb_pdcp_config_t(const uint8_t bearer_id, bool is_ue sn_len, t_reordering, discard_timer, - false); + false, + srsran_rat_t::nr); return cfg; } @@ -319,7 +333,7 @@ bool make_phy_tdd_cfg(const tdd_ul_dl_cfg_common_s& tdd_ul_dl_cfg_common, bool make_phy_harq_ack_cfg(const phys_cell_group_cfg_s& phys_cell_group_cfg, srsran_ue_dl_nr_harq_ack_cfg_t* in_srsran_ue_dl_nr_harq_ack_cfg) { - srsran_ue_dl_nr_harq_ack_cfg_t srsran_ue_dl_nr_harq_ack_cfg; + srsran_ue_dl_nr_harq_ack_cfg_t srsran_ue_dl_nr_harq_ack_cfg = {}; switch (phys_cell_group_cfg.pdsch_harq_ack_codebook) { case phys_cell_group_cfg_s::pdsch_harq_ack_codebook_opts::dynamic_value: srsran_ue_dl_nr_harq_ack_cfg.harq_ack_codebook = srsran_pdsch_harq_ack_codebook_dynamic; @@ -573,8 +587,7 @@ bool make_phy_csi_report(const csi_report_cfg_s& csi_report_cfg, bool make_phy_coreset_cfg(const ctrl_res_set_s& ctrl_res_set, srsran_coreset_t* in_srsran_coreset) { srsran_coreset_t srsran_coreset = {}; - srsran_coreset.coreset_id = ctrl_res_set.ctrl_res_set_id; - + srsran_coreset.id = ctrl_res_set.ctrl_res_set_id; switch (ctrl_res_set.precoder_granularity) { case ctrl_res_set_s::precoder_granularity_opts::same_as_reg_bundle: srsran_coreset.precoder_granularity = srsran_coreset_precoder_granularity_reg_bundle; @@ -585,6 +598,18 @@ bool make_phy_coreset_cfg(const ctrl_res_set_s& ctrl_res_set, srsran_coreset_t* asn1::log_warning("Invalid option for precoder_granularity %s", ctrl_res_set.precoder_granularity.to_string()); return false; }; + + switch (ctrl_res_set.cce_reg_map_type.type()) { + case ctrl_res_set_s::cce_reg_map_type_c_::types_opts::options::interleaved: + srsran_coreset.mapping_type = srsran_coreset_mapping_type_interleaved; + break; + case ctrl_res_set_s::cce_reg_map_type_c_::types_opts::options::non_interleaved: + srsran_coreset.mapping_type = srsran_coreset_mapping_type_non_interleaved; + break; + default: + asn1::log_warning("Invalid option for cce_reg_map_type: %s", ctrl_res_set.cce_reg_map_type.type().to_string()); + return false; + } srsran_coreset.duration = ctrl_res_set.dur; for (uint32_t i = 0; i < SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE; i++) { srsran_coreset.freq_resources[i] = ctrl_res_set.freq_domain_res.get(SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE - 1 - i); @@ -837,6 +862,368 @@ bool make_phy_pusch_scaling(const uci_on_pusch_s& uci_on_pusch, float* in_scalin return true; } +bool make_phy_zp_csi_rs_resource(const asn1::rrc_nr::zp_csi_rs_res_s& zp_csi_rs_res, + srsran_csi_rs_zp_resource_t* out_zp_csi_rs_resource) +{ + srsran_csi_rs_zp_resource_t zp_csi_rs_resource; + zp_csi_rs_resource.id = zp_csi_rs_res.zp_csi_rs_res_id; + switch (zp_csi_rs_res.res_map.freq_domain_alloc.type()) { + case csi_rs_res_map_s::freq_domain_alloc_c_::types_opts::options::row1: + zp_csi_rs_resource.resource_mapping.row = srsran_csi_rs_resource_mapping_row_1; + for (uint32_t i = 0; i < zp_csi_rs_res.res_map.freq_domain_alloc.row1().length(); i++) { + zp_csi_rs_resource.resource_mapping.frequency_domain_alloc[i] = + zp_csi_rs_res.res_map.freq_domain_alloc.row1().get(zp_csi_rs_res.res_map.freq_domain_alloc.row1().length() - + 1 - i); + } + break; + case csi_rs_res_map_s::freq_domain_alloc_c_::types_opts::options::row2: + zp_csi_rs_resource.resource_mapping.row = srsran_csi_rs_resource_mapping_row_2; + for (uint32_t i = 0; i < zp_csi_rs_res.res_map.freq_domain_alloc.row2().length(); i++) { + zp_csi_rs_resource.resource_mapping.frequency_domain_alloc[i] = + zp_csi_rs_res.res_map.freq_domain_alloc.row2().get(zp_csi_rs_res.res_map.freq_domain_alloc.row2().length() - + 1 - i); + } + break; + case csi_rs_res_map_s::freq_domain_alloc_c_::types_opts::options::row4: + zp_csi_rs_resource.resource_mapping.row = srsran_csi_rs_resource_mapping_row_4; + for (uint32_t i = 0; i < zp_csi_rs_res.res_map.freq_domain_alloc.row4().length(); i++) { + zp_csi_rs_resource.resource_mapping.frequency_domain_alloc[i] = + zp_csi_rs_res.res_map.freq_domain_alloc.row4().get(zp_csi_rs_res.res_map.freq_domain_alloc.row4().length() - + 1 - i); + } + break; + case csi_rs_res_map_s::freq_domain_alloc_c_::types_opts::options::other: + zp_csi_rs_resource.resource_mapping.row = srsran_csi_rs_resource_mapping_row_other; + break; + default: + asn1::log_warning("Invalid option for freq_domain_alloc %s", + zp_csi_rs_res.res_map.freq_domain_alloc.type().to_string()); + return false; + } + zp_csi_rs_resource.resource_mapping.nof_ports = zp_csi_rs_res.res_map.nrof_ports.to_number(); + zp_csi_rs_resource.resource_mapping.first_symbol_idx = zp_csi_rs_res.res_map.first_ofdm_symbol_in_time_domain; + + switch (zp_csi_rs_res.res_map.cdm_type) { + case csi_rs_res_map_s::cdm_type_opts::options::no_cdm: + zp_csi_rs_resource.resource_mapping.cdm = srsran_csi_rs_cdm_t::srsran_csi_rs_cdm_nocdm; + break; + case csi_rs_res_map_s::cdm_type_opts::options::fd_cdm2: + zp_csi_rs_resource.resource_mapping.cdm = srsran_csi_rs_cdm_t::srsran_csi_rs_cdm_fd_cdm2; + break; + case csi_rs_res_map_s::cdm_type_opts::options::cdm4_fd2_td2: + zp_csi_rs_resource.resource_mapping.cdm = srsran_csi_rs_cdm_t::srsran_csi_rs_cdm_cdm4_fd2_td2; + break; + case csi_rs_res_map_s::cdm_type_opts::options::cdm8_fd2_td4: + zp_csi_rs_resource.resource_mapping.cdm = srsran_csi_rs_cdm_t::srsran_csi_rs_cdm_cdm8_fd2_td4; + break; + default: + asn1::log_warning("Invalid option for cdm_type %s", zp_csi_rs_res.res_map.cdm_type.to_string()); + return false; + } + + switch (zp_csi_rs_res.res_map.density.type()) { + case csi_rs_res_map_s::density_c_::types_opts::options::dot5: + switch (zp_csi_rs_res.res_map.density.dot5()) { + case csi_rs_res_map_s::density_c_::dot5_opts::options::even_prbs: + zp_csi_rs_resource.resource_mapping.density = srsran_csi_rs_resource_mapping_density_dot5_even; + break; + case csi_rs_res_map_s::density_c_::dot5_opts::options::odd_prbs: + zp_csi_rs_resource.resource_mapping.density = srsran_csi_rs_resource_mapping_density_dot5_odd; + break; + default: + asn1::log_warning("Invalid option for dot5 %s", zp_csi_rs_res.res_map.density.dot5().to_string()); + return false; + } + break; + case csi_rs_res_map_s::density_c_::types_opts::options::one: + zp_csi_rs_resource.resource_mapping.density = srsran_csi_rs_resource_mapping_density_one; + break; + case csi_rs_res_map_s::density_c_::types_opts::options::three: + zp_csi_rs_resource.resource_mapping.density = srsran_csi_rs_resource_mapping_density_three; + break; + case csi_rs_res_map_s::density_c_::types_opts::options::spare: + zp_csi_rs_resource.resource_mapping.density = srsran_csi_rs_resource_mapping_density_spare; + break; + default: + asn1::log_warning("Invalid option for density %s", zp_csi_rs_res.res_map.density.type().to_string()); + return false; + } + zp_csi_rs_resource.resource_mapping.freq_band.nof_rb = zp_csi_rs_res.res_map.freq_band.nrof_rbs; + zp_csi_rs_resource.resource_mapping.freq_band.start_rb = zp_csi_rs_res.res_map.freq_band.start_rb; + if(zp_csi_rs_res.periodicity_and_offset_present){ + switch (zp_csi_rs_res.periodicity_and_offset.type()) + { + case csi_res_periodicity_and_offset_c::types_opts::options::slots4: + zp_csi_rs_resource.periodicity.period = 4; + zp_csi_rs_resource.periodicity.offset = zp_csi_rs_res.periodicity_and_offset.slots4(); + break; + case csi_res_periodicity_and_offset_c::types_opts::options::slots5: + zp_csi_rs_resource.periodicity.period = 5; + zp_csi_rs_resource.periodicity.offset = zp_csi_rs_res.periodicity_and_offset.slots5(); + break; + case csi_res_periodicity_and_offset_c::types_opts::options::slots8: + zp_csi_rs_resource.periodicity.period = 8; + zp_csi_rs_resource.periodicity.offset = zp_csi_rs_res.periodicity_and_offset.slots8(); + break; + case csi_res_periodicity_and_offset_c::types_opts::options::slots10: + zp_csi_rs_resource.periodicity.period = 10; + zp_csi_rs_resource.periodicity.offset = zp_csi_rs_res.periodicity_and_offset.slots10(); + break; + case csi_res_periodicity_and_offset_c::types_opts::options::slots16: + zp_csi_rs_resource.periodicity.period = 16; + zp_csi_rs_resource.periodicity.offset = zp_csi_rs_res.periodicity_and_offset.slots16(); + break; + case csi_res_periodicity_and_offset_c::types_opts::options::slots20: + zp_csi_rs_resource.periodicity.period = 20; + zp_csi_rs_resource.periodicity.offset = zp_csi_rs_res.periodicity_and_offset.slots20(); + break; + case csi_res_periodicity_and_offset_c::types_opts::options::slots32: + zp_csi_rs_resource.periodicity.period = 32; + zp_csi_rs_resource.periodicity.offset = zp_csi_rs_res.periodicity_and_offset.slots32(); + break; + case csi_res_periodicity_and_offset_c::types_opts::options::slots40: + zp_csi_rs_resource.periodicity.period = 40; + zp_csi_rs_resource.periodicity.offset = zp_csi_rs_res.periodicity_and_offset.slots40(); + break; + case csi_res_periodicity_and_offset_c::types_opts::options::slots64: + zp_csi_rs_resource.periodicity.period = 64; + zp_csi_rs_resource.periodicity.offset = zp_csi_rs_res.periodicity_and_offset.slots64(); + break; + case csi_res_periodicity_and_offset_c::types_opts::options::slots80: + zp_csi_rs_resource.periodicity.period = 80; + zp_csi_rs_resource.periodicity.offset = zp_csi_rs_res.periodicity_and_offset.slots80(); + break; + case csi_res_periodicity_and_offset_c::types_opts::options::slots160: + zp_csi_rs_resource.periodicity.period = 160; + zp_csi_rs_resource.periodicity.offset = zp_csi_rs_res.periodicity_and_offset.slots160(); + break; + case csi_res_periodicity_and_offset_c::types_opts::options::slots320: + zp_csi_rs_resource.periodicity.period = 320; + zp_csi_rs_resource.periodicity.offset = zp_csi_rs_res.periodicity_and_offset.slots320(); + break; + case csi_res_periodicity_and_offset_c::types_opts::options::slots640: + zp_csi_rs_resource.periodicity.period = 640; + zp_csi_rs_resource.periodicity.offset = zp_csi_rs_res.periodicity_and_offset.slots640(); + break; + default: + asn1::log_warning("Invalid option for periodicity_and_offset %s", + zp_csi_rs_res.periodicity_and_offset.type().to_string()); + return false; + } + } else { + asn1::log_warning("Option periodicity_and_offset not present"); + return false; + } + + *out_zp_csi_rs_resource = zp_csi_rs_resource; + return true; +} + +bool make_phy_nzp_csi_rs_resource(const asn1::rrc_nr::nzp_csi_rs_res_s& asn1_nzp_csi_rs_res, + srsran_csi_rs_nzp_resource_t* out_csi_rs_nzp_resource) +{ + srsran_csi_rs_nzp_resource_t csi_rs_nzp_resource; + csi_rs_nzp_resource.id = asn1_nzp_csi_rs_res.nzp_csi_rs_res_id; + switch (asn1_nzp_csi_rs_res.res_map.freq_domain_alloc.type()) { + case csi_rs_res_map_s::freq_domain_alloc_c_::types_opts::options::row1: + csi_rs_nzp_resource.resource_mapping.row = srsran_csi_rs_resource_mapping_row_1; + for (uint32_t i = 0; i < asn1_nzp_csi_rs_res.res_map.freq_domain_alloc.row1().length(); i++) { + csi_rs_nzp_resource.resource_mapping.frequency_domain_alloc[i] = + asn1_nzp_csi_rs_res.res_map.freq_domain_alloc.row1().get(asn1_nzp_csi_rs_res.res_map.freq_domain_alloc.row1().length() - + 1 - i); + } + break; + case csi_rs_res_map_s::freq_domain_alloc_c_::types_opts::options::row2: + csi_rs_nzp_resource.resource_mapping.row = srsran_csi_rs_resource_mapping_row_2; + for (uint32_t i = 0; i < asn1_nzp_csi_rs_res.res_map.freq_domain_alloc.row2().length(); i++) { + csi_rs_nzp_resource.resource_mapping.frequency_domain_alloc[i] = + asn1_nzp_csi_rs_res.res_map.freq_domain_alloc.row2().get(asn1_nzp_csi_rs_res.res_map.freq_domain_alloc.row2().length() - + 1 - i); + } + break; + case csi_rs_res_map_s::freq_domain_alloc_c_::types_opts::options::row4: + csi_rs_nzp_resource.resource_mapping.row = srsran_csi_rs_resource_mapping_row_4; + for (uint32_t i = 0; i < asn1_nzp_csi_rs_res.res_map.freq_domain_alloc.row4().length(); i++) { + csi_rs_nzp_resource.resource_mapping.frequency_domain_alloc[i] = + asn1_nzp_csi_rs_res.res_map.freq_domain_alloc.row4().get(asn1_nzp_csi_rs_res.res_map.freq_domain_alloc.row4().length() - + 1 - i); + } + break; + case csi_rs_res_map_s::freq_domain_alloc_c_::types_opts::options::other: + csi_rs_nzp_resource.resource_mapping.row = srsran_csi_rs_resource_mapping_row_other; + break; + default: + asn1::log_warning("Invalid option for freq_domain_alloc %s", + asn1_nzp_csi_rs_res.res_map.freq_domain_alloc.type().to_string()); + return false; + } + + csi_rs_nzp_resource.resource_mapping.nof_ports = asn1_nzp_csi_rs_res.res_map.nrof_ports.to_number(); + csi_rs_nzp_resource.resource_mapping.first_symbol_idx = asn1_nzp_csi_rs_res.res_map.first_ofdm_symbol_in_time_domain; + + switch (asn1_nzp_csi_rs_res.res_map.cdm_type) { + case csi_rs_res_map_s::cdm_type_opts::options::no_cdm: + csi_rs_nzp_resource.resource_mapping.cdm = srsran_csi_rs_cdm_t::srsran_csi_rs_cdm_nocdm; + break; + case csi_rs_res_map_s::cdm_type_opts::options::fd_cdm2: + csi_rs_nzp_resource.resource_mapping.cdm = srsran_csi_rs_cdm_t::srsran_csi_rs_cdm_fd_cdm2; + break; + case csi_rs_res_map_s::cdm_type_opts::options::cdm4_fd2_td2: + csi_rs_nzp_resource.resource_mapping.cdm = srsran_csi_rs_cdm_t::srsran_csi_rs_cdm_cdm4_fd2_td2; + break; + case csi_rs_res_map_s::cdm_type_opts::options::cdm8_fd2_td4: + csi_rs_nzp_resource.resource_mapping.cdm = srsran_csi_rs_cdm_t::srsran_csi_rs_cdm_cdm8_fd2_td4; + break; + default: + asn1::log_warning("Invalid option for cdm_type %s", asn1_nzp_csi_rs_res.res_map.cdm_type.to_string()); + return false; + } + + switch (asn1_nzp_csi_rs_res.res_map.density.type()) { + case csi_rs_res_map_s::density_c_::types_opts::options::dot5: + switch (asn1_nzp_csi_rs_res.res_map.density.dot5()) { + case csi_rs_res_map_s::density_c_::dot5_opts::options::even_prbs: + csi_rs_nzp_resource.resource_mapping.density = srsran_csi_rs_resource_mapping_density_dot5_even; + break; + case csi_rs_res_map_s::density_c_::dot5_opts::options::odd_prbs: + csi_rs_nzp_resource.resource_mapping.density = srsran_csi_rs_resource_mapping_density_dot5_odd; + break; + default: + asn1::log_warning("Invalid option for dot5 %s", asn1_nzp_csi_rs_res.res_map.density.dot5().to_string()); + return false; + } + break; + case csi_rs_res_map_s::density_c_::types_opts::options::one: + csi_rs_nzp_resource.resource_mapping.density = srsran_csi_rs_resource_mapping_density_one; + break; + case csi_rs_res_map_s::density_c_::types_opts::options::three: + csi_rs_nzp_resource.resource_mapping.density = srsran_csi_rs_resource_mapping_density_three; + break; + case csi_rs_res_map_s::density_c_::types_opts::options::spare: + csi_rs_nzp_resource.resource_mapping.density = srsran_csi_rs_resource_mapping_density_spare; + break; + default: + asn1::log_warning("Invalid option for density %s", asn1_nzp_csi_rs_res.res_map.density.type().to_string()); + return false; + } + csi_rs_nzp_resource.resource_mapping.freq_band.nof_rb = asn1_nzp_csi_rs_res.res_map.freq_band.nrof_rbs; + csi_rs_nzp_resource.resource_mapping.freq_band.start_rb = asn1_nzp_csi_rs_res.res_map.freq_band.start_rb; + + csi_rs_nzp_resource.power_control_offset = asn1_nzp_csi_rs_res.pwr_ctrl_offset; + if (asn1_nzp_csi_rs_res.pwr_ctrl_offset_ss_present) { + csi_rs_nzp_resource.power_control_offset_ss = asn1_nzp_csi_rs_res.pwr_ctrl_offset_ss.to_number(); + } + + if(asn1_nzp_csi_rs_res.periodicity_and_offset_present){ + switch (asn1_nzp_csi_rs_res.periodicity_and_offset.type()) + { + case csi_res_periodicity_and_offset_c::types_opts::options::slots4: + csi_rs_nzp_resource.periodicity.period = 4; + csi_rs_nzp_resource.periodicity.offset = asn1_nzp_csi_rs_res.periodicity_and_offset.slots4(); + break; + case csi_res_periodicity_and_offset_c::types_opts::options::slots5: + csi_rs_nzp_resource.periodicity.period = 5; + csi_rs_nzp_resource.periodicity.offset = asn1_nzp_csi_rs_res.periodicity_and_offset.slots5(); + break; + case csi_res_periodicity_and_offset_c::types_opts::options::slots8: + csi_rs_nzp_resource.periodicity.period = 8; + csi_rs_nzp_resource.periodicity.offset = asn1_nzp_csi_rs_res.periodicity_and_offset.slots8(); + break; + case csi_res_periodicity_and_offset_c::types_opts::options::slots10: + csi_rs_nzp_resource.periodicity.period = 10; + csi_rs_nzp_resource.periodicity.offset = asn1_nzp_csi_rs_res.periodicity_and_offset.slots10(); + break; + case csi_res_periodicity_and_offset_c::types_opts::options::slots16: + csi_rs_nzp_resource.periodicity.period = 16; + csi_rs_nzp_resource.periodicity.offset = asn1_nzp_csi_rs_res.periodicity_and_offset.slots16(); + break; + case csi_res_periodicity_and_offset_c::types_opts::options::slots20: + csi_rs_nzp_resource.periodicity.period = 20; + csi_rs_nzp_resource.periodicity.offset = asn1_nzp_csi_rs_res.periodicity_and_offset.slots20(); + break; + case csi_res_periodicity_and_offset_c::types_opts::options::slots32: + csi_rs_nzp_resource.periodicity.period = 32; + csi_rs_nzp_resource.periodicity.offset = asn1_nzp_csi_rs_res.periodicity_and_offset.slots32(); + break; + case csi_res_periodicity_and_offset_c::types_opts::options::slots40: + csi_rs_nzp_resource.periodicity.period = 40; + csi_rs_nzp_resource.periodicity.offset = asn1_nzp_csi_rs_res.periodicity_and_offset.slots40(); + break; + case csi_res_periodicity_and_offset_c::types_opts::options::slots64: + csi_rs_nzp_resource.periodicity.period = 64; + csi_rs_nzp_resource.periodicity.offset = asn1_nzp_csi_rs_res.periodicity_and_offset.slots64(); + break; + case csi_res_periodicity_and_offset_c::types_opts::options::slots80: + csi_rs_nzp_resource.periodicity.period = 80; + csi_rs_nzp_resource.periodicity.offset = asn1_nzp_csi_rs_res.periodicity_and_offset.slots80(); + break; + case csi_res_periodicity_and_offset_c::types_opts::options::slots160: + csi_rs_nzp_resource.periodicity.period = 160; + csi_rs_nzp_resource.periodicity.offset = asn1_nzp_csi_rs_res.periodicity_and_offset.slots160(); + break; + case csi_res_periodicity_and_offset_c::types_opts::options::slots320: + csi_rs_nzp_resource.periodicity.period = 320; + csi_rs_nzp_resource.periodicity.offset = asn1_nzp_csi_rs_res.periodicity_and_offset.slots320(); + break; + case csi_res_periodicity_and_offset_c::types_opts::options::slots640: + csi_rs_nzp_resource.periodicity.period = 640; + csi_rs_nzp_resource.periodicity.offset = asn1_nzp_csi_rs_res.periodicity_and_offset.slots640(); + break; + default: + asn1::log_warning("Invalid option for periodicity_and_offset %s", + asn1_nzp_csi_rs_res.periodicity_and_offset.type().to_string()); + return false; + } + } else { + asn1::log_warning("Option periodicity_and_offset not present"); + return false; + } + + csi_rs_nzp_resource.scrambling_id = asn1_nzp_csi_rs_res.scrambling_id; + + *out_csi_rs_nzp_resource = csi_rs_nzp_resource; + return true; +} + +bool make_phy_carrier_cfg(const freq_info_dl_s& asn1_freq_info_dl, srsran_carrier_nr_t* out_carrier_nr) +{ + srsran_carrier_nr_t carrier_nr = {}; + if (asn1_freq_info_dl.absolute_freq_ssb_present) { + carrier_nr.absolute_frequency_ssb = asn1_freq_info_dl.absolute_freq_ssb_present; + } else { + asn1::log_warning("Option absolute_freq_ssb not present"); + return false; + } + carrier_nr.absolute_frequency_point_a = asn1_freq_info_dl.absolute_freq_point_a; + if (asn1_freq_info_dl.scs_specific_carrier_list.size() != 1) { + asn1::log_warning("Option absolute_freq_ssb not present"); + return false; + } + + carrier_nr.nof_prb = asn1_freq_info_dl.scs_specific_carrier_list[0].carrier_bw; + + switch (asn1_freq_info_dl.scs_specific_carrier_list[0].subcarrier_spacing) { + case subcarrier_spacing_opts::options::khz15: + carrier_nr.scs = srsran_subcarrier_spacing_15kHz; + break; + case subcarrier_spacing_opts::options::khz30: + carrier_nr.scs = srsran_subcarrier_spacing_30kHz; + break; + case subcarrier_spacing_opts::options::khz60: + carrier_nr.scs = srsran_subcarrier_spacing_60kHz; + break; + case subcarrier_spacing_opts::options::khz120: + carrier_nr.scs = srsran_subcarrier_spacing_120kHz; + break; + case subcarrier_spacing_opts::options::khz240: + carrier_nr.scs = srsran_subcarrier_spacing_240kHz; + break; + default: + asn1::log_warning("Not supported subcarrier spacing "); + } + *out_carrier_nr = carrier_nr; + return true; +} } // namespace srsran namespace srsenb { diff --git a/lib/src/asn1/rrc_utils.cc b/lib/src/asn1/rrc_utils.cc index a908d6ffe..ff8373e94 100644 --- a/lib/src/asn1/rrc_utils.cc +++ b/lib/src/asn1/rrc_utils.cc @@ -216,7 +216,8 @@ srsran::pdcp_config_t make_srb_pdcp_config_t(const uint8_t bearer_id, bool is_ue PDCP_SN_LEN_5, pdcp_t_reordering_t::ms500, pdcp_discard_timer_t::infinity, - false); + false, + srsran_rat_t::lte); return cfg; } @@ -229,7 +230,8 @@ srsran::pdcp_config_t make_drb_pdcp_config_t(const uint8_t bearer_id, bool is_ue PDCP_SN_LEN_12, pdcp_t_reordering_t::ms500, pdcp_discard_timer_t::infinity, - false); + false, + srsran_rat_t::lte); return cfg; } @@ -334,7 +336,8 @@ srsran::pdcp_config_t make_drb_pdcp_config_t(const uint8_t bearer_id, bool is_ue sn_len, t_reordering, discard_timer, - status_report_required); + status_report_required, + srsran_rat_t::lte); return cfg; } @@ -388,7 +391,9 @@ void set_mac_cfg_t_rach_cfg_common(mac_cfg_t* cfg, const asn1::rrc::rach_cfg_com cfg->rach_cfg.messagePowerOffsetGroupB = asn1_type.preamb_info.preambs_group_a_cfg.msg_pwr_offset_group_b.to_number(); } else { - cfg->rach_cfg.nof_groupA_preambles = 0; + // If the field is not signalled, the size of the random access preambles group A [6] is equal to + // numberOfRA-Preambles + cfg->rach_cfg.nof_groupA_preambles = cfg->rach_cfg.nof_preambles; } // Power ramping diff --git a/lib/src/common/basic_vnf.cc b/lib/src/common/basic_vnf.cc index b7fd285a7..04f0ad0a3 100644 --- a/lib/src/common/basic_vnf.cc +++ b/lib/src/common/basic_vnf.cc @@ -191,12 +191,14 @@ int srsran_basic_vnf::handle_dl_ind(basic_vnf_api::dl_ind_msg_t* msg) } for (uint32_t i = 0; i < msg->nof_pdus; ++i) { - dl_grant.tb[i] = srsran::make_byte_buffer(); - if (dl_grant.tb[i] && dl_grant.tb[i]->get_tailroom() >= msg->pdus[i].length) { - memcpy(dl_grant.tb[i]->msg, msg->pdus[i].data, msg->pdus[i].length); - dl_grant.tb[i]->N_bytes = msg->pdus[i].length; + srsue::stack_interface_phy_nr::tb_action_dl_result_t result = {}; + result.payload = srsran::make_byte_buffer(); + if (result.payload != nullptr && result.payload->get_tailroom() >= msg->pdus[i].length) { + result.ack = true; + memcpy(result.payload->msg, msg->pdus[i].data, msg->pdus[i].length); + result.payload->N_bytes = msg->pdus[i].length; if (msg->pdus[i].type == basic_vnf_api::PDSCH) { - m_ue_stack->tb_decoded(cc_idx, dl_grant); + m_ue_stack->tb_decoded(cc_idx, dl_grant, std::move(result)); } } else { logger.error("TB too big to fit into buffer (%d)", msg->pdus[i].length); diff --git a/lib/src/common/thread_pool.cc b/lib/src/common/thread_pool.cc index 4ac2bea96..b344ded61 100644 --- a/lib/src/common/thread_pool.cc +++ b/lib/src/common/thread_pool.cc @@ -262,7 +262,7 @@ uint32_t thread_pool::get_nof_workers() *************************************************************************/ task_thread_pool::task_thread_pool(uint32_t nof_workers, bool start_deferred, int32_t prio_, uint32_t mask_) : - logger(srslog::fetch_basic_logger("POOL")), workers(std::max(1u, nof_workers)) + logger(srslog::fetch_basic_logger("POOL")), pending_tasks(max_task_num), workers(std::max(1u, nof_workers)) { if (not start_deferred) { start(prio_, mask_); @@ -331,6 +331,10 @@ void task_thread_pool::push_task(task_t&& task) { { std::lock_guard lock(queue_mutex); + if (pending_tasks.full()) { + logger.error("Cannot push anymore tasks into the queue, maximum size is %u", uint32_t(max_task_num)); + return; + } pending_tasks.push(std::move(task)); } cv_empty.notify_one(); @@ -367,7 +371,7 @@ bool task_thread_pool::worker_t::wait_task(task_t* task) return false; } if (task) { - *task = std::move(parent->pending_tasks.front()); + *task = std::move(parent->pending_tasks.top()); } parent->pending_tasks.pop(); return true; diff --git a/lib/src/phy/ch_estimation/csi_rs.c b/lib/src/phy/ch_estimation/csi_rs.c index 61ba89cf4..9685b86e0 100644 --- a/lib/src/phy/ch_estimation/csi_rs.c +++ b/lib/src/phy/ch_estimation/csi_rs.c @@ -183,7 +183,7 @@ static uint32_t csi_rs_cinit(const srsran_carrier_nr_t* carrier, const srsran_csi_rs_nzp_resource_t* resource, uint32_t l) { - uint32_t n = SRSRAN_SLOT_NR_MOD(carrier->numerology, slot_cfg->idx); + uint32_t n = SRSRAN_SLOT_NR_MOD(carrier->scs, slot_cfg->idx); uint32_t n_id = resource->scrambling_id; return ((SRSRAN_NSYMB_PER_SLOT_NR * n + l + 1UL) * (2UL * n_id) << 10UL) + n_id; diff --git a/lib/src/phy/ch_estimation/dmrs_pdcch.c b/lib/src/phy/ch_estimation/dmrs_pdcch.c index c77bcf052..9673cd391 100644 --- a/lib/src/phy/ch_estimation/dmrs_pdcch.c +++ b/lib/src/phy/ch_estimation/dmrs_pdcch.c @@ -163,13 +163,13 @@ int srsran_dmrs_pdcch_put(const srsran_carrier_nr_t* carrier, } // Use cell id if the DMR scrambling id is not provided by higher layers - uint32_t n_id = carrier->id; + uint32_t n_id = carrier->pci; if (coreset->dmrs_scrambling_id_present) { n_id = coreset->dmrs_scrambling_id; } // Bound slot index - uint32_t slot_idx = SRSRAN_SLOT_NR_MOD(carrier->numerology, slot_cfg->idx); + uint32_t slot_idx = SRSRAN_SLOT_NR_MOD(carrier->scs, slot_cfg->idx); for (uint32_t l = 0; l < coreset->duration; l++) { // Get Cin @@ -359,13 +359,13 @@ int srsran_dmrs_pdcch_estimate(srsran_dmrs_pdcch_estimator_t* q, } // Use cell id if the DMR scrambling id is not provided by higher layers - uint32_t n_id = q->carrier.id; + uint32_t n_id = q->carrier.pci; if (q->coreset.dmrs_scrambling_id_present) { n_id = q->coreset.dmrs_scrambling_id; } // Bound slot index - uint32_t slot_idx = SRSRAN_SLOT_NR_MOD(q->carrier.numerology, slot_cfg->idx); + uint32_t slot_idx = SRSRAN_SLOT_NR_MOD(q->carrier.scs, slot_cfg->idx); // Extract pilots for (uint32_t l = 0; l < q->coreset.duration; l++) { @@ -485,7 +485,7 @@ int srsran_dmrs_pdcch_get_measure(const srsran_dmrs_pdcch_estimator_t* q, // Measure CFO only from the second and third symbols if (l != 0) { // Calculates the time between the previous and the current symbol - float Ts = srsran_symbol_distance_s(l - 1, l, q->carrier.numerology); + float Ts = srsran_symbol_distance_s(l - 1, l, q->carrier.scs); if (isnormal(Ts)) { // Compute phase difference between symbols and convert to Hz cfo_avg_Hz += cargf(corr[l] * conjf(corr[l - 1])) / (2.0f * (float)M_PI * Ts); @@ -504,7 +504,7 @@ int srsran_dmrs_pdcch_get_measure(const srsran_dmrs_pdcch_estimator_t* q, measure->cfo_hz = NAN; } measure->sync_error_us = - sync_err_avg / (4.0e-6f * (float)q->coreset.duration * SRSRAN_SUBC_SPACING_NR(q->carrier.numerology)); + sync_err_avg / (4.0e-6f * (float)q->coreset.duration * SRSRAN_SUBC_SPACING_NR(q->carrier.scs)); // Convert power measurements into logarithmic scale measure->rsrp_dBfs = srsran_convert_power_to_dB(measure->rsrp); diff --git a/lib/src/phy/ch_estimation/dmrs_pucch.c b/lib/src/phy/ch_estimation/dmrs_pucch.c index c146bae07..42c75367b 100644 --- a/lib/src/phy/ch_estimation/dmrs_pucch.c +++ b/lib/src/phy/ch_estimation/dmrs_pucch.c @@ -256,7 +256,7 @@ int srsran_dmrs_pucch_format1_estimate(const srsran_pucch_nr_t* q, // Compute Time Aligment error in microseconds if (isnormal(ta_err)) { - ta_err /= 15e3f * (float)(1U << carrier->numerology); // Convert from normalized frequency to seconds + ta_err /= 15e3f * (float)(1U << carrier->scs); // Convert from normalized frequency to seconds ta_err *= 1e6f; // Convert to micro-seconds ta_err = roundf(ta_err * 10.0f) / 10.0f; // Round to one tenth of micro-second res->ta_us = ta_err; @@ -298,8 +298,8 @@ static uint32_t dmrs_pucch_format2_cinit(const srsran_carrier_nr_t* car const srsran_slot_cfg_t* slot, uint32_t l) { - uint64_t n = SRSRAN_SLOT_NR_MOD(carrier->numerology, slot->idx); - uint64_t n_id = (cfg->scrambling_id_present) ? cfg->scambling_id : carrier->id; + uint64_t n = SRSRAN_SLOT_NR_MOD(carrier->scs, slot->idx); + uint64_t n_id = (cfg->scrambling_id_present) ? cfg->scambling_id : carrier->pci; return SRSRAN_SEQUENCE_MOD((((SRSRAN_NSYMB_PER_SLOT_NR * n + l + 1UL) * (2UL * n_id + 1UL)) << 17UL) + 2UL * n_id); } @@ -418,7 +418,7 @@ int srsran_dmrs_pucch_format2_estimate(const srsran_pucch_nr_t* q, // Compute Time Aligment error in microseconds if (isnormal(ta_err)) { - ta_err /= 15e3f * (float)(1U << carrier->numerology) * 3; // Convert from normalized frequency to seconds + ta_err /= 15e3f * (float)(1U << carrier->scs) * 3; // Convert from normalized frequency to seconds ta_err *= 1e6f; // Convert to micro-seconds ta_err = roundf(ta_err * 10.0f) / 10.0f; // Round to one tenth of micro-second res->ta_us = ta_err; diff --git a/lib/src/phy/ch_estimation/dmrs_sch.c b/lib/src/phy/ch_estimation/dmrs_sch.c index f77377390..23f6c82e8 100644 --- a/lib/src/phy/ch_estimation/dmrs_sch.c +++ b/lib/src/phy/ch_estimation/dmrs_sch.c @@ -512,7 +512,7 @@ static uint32_t srsran_dmrs_sch_seed(const srsran_carrier_nr_t* carrier, const srsran_dmrs_sch_cfg_t* dmrs_cfg = &cfg->dmrs; // Calculate scrambling IDs - uint32_t n_id = carrier->id; + uint32_t n_id = carrier->pci; uint32_t n_scid = (grant->n_scid) ? 1 : 0; if (!grant->n_scid && dmrs_cfg->scrambling_id0_present) { // n_scid = 0 and ID0 present @@ -649,7 +649,7 @@ int srsran_dmrs_sch_put_sf(srsran_dmrs_sch_t* q, // Iterate symbols for (uint32_t i = 0; i < nof_symbols; i++) { uint32_t l = symbols[i]; // Symbol index inside the slot - uint32_t slot_idx = SRSRAN_SLOT_NR_MOD(q->carrier.numerology, slot_cfg->idx); // Slot index in the frame + uint32_t slot_idx = SRSRAN_SLOT_NR_MOD(q->carrier.scs, slot_cfg->idx); // Slot index in the frame uint32_t cinit = srsran_dmrs_sch_seed(&q->carrier, pdsch_cfg, grant, slot_idx, l); srsran_dmrs_sch_put_symbol(q, pdsch_cfg, grant, cinit, delta, &sf_symbols[symbol_sz * l]); @@ -780,7 +780,7 @@ int srsran_dmrs_sch_estimate(srsran_dmrs_sch_t* q, uint32_t l = symbols[i]; // Symbol index inside the slot uint32_t cinit = - srsran_dmrs_sch_seed(&q->carrier, cfg, grant, SRSRAN_SLOT_NR_MOD(q->carrier.numerology, slot->idx), l); + srsran_dmrs_sch_seed(&q->carrier, cfg, grant, SRSRAN_SLOT_NR_MOD(q->carrier.scs, slot->idx), l); nof_pilots_x_symbol = srsran_dmrs_sch_get_symbol( q, cfg, grant, cinit, delta, &sf_symbols[symbol_sz * l], &q->pilot_estimates[nof_pilots_x_symbol * i]); @@ -798,7 +798,7 @@ int srsran_dmrs_sch_estimate(srsran_dmrs_sch_t* q, sync_err += srsran_vec_estimate_frequency(&q->pilot_estimates[nof_pilots_x_symbol * i], nof_pilots_x_symbol); } sync_err /= (float)nof_symbols; - chest_res->sync_error = sync_err / (dmrs_stride * SRSRAN_SUBC_SPACING_NR(q->carrier.numerology)); + chest_res->sync_error = sync_err / (dmrs_stride * SRSRAN_SUBC_SPACING_NR(q->carrier.scs)); #if DMRS_SCH_SYNC_PRECOMPENSATE // Pre-compensate synchronization error @@ -837,7 +837,7 @@ int srsran_dmrs_sch_estimate(srsran_dmrs_sch_t* q, // Measure CFO if more than one symbol is used float cfo_avg = 0.0; for (uint32_t i = 0; i < nof_symbols - 1; i++) { - float time_diff = srsran_symbol_distance_s(symbols[i], symbols[i + 1], q->carrier.numerology); + float time_diff = srsran_symbol_distance_s(symbols[i], symbols[i + 1], q->carrier.scs); float phase_diff = cargf(corr[i + 1] * conjf(corr[i])); if (isnormal(time_diff)) { @@ -852,11 +852,11 @@ int srsran_dmrs_sch_estimate(srsran_dmrs_sch_t* q, if (isnormal(cfo_avg)) { // Calculate phase of the first OFDM symbol (l = 0) float arg0 = - cargf(corr[0]) - 2.0f * M_PI * srsran_symbol_distance_s(0, symbols[0], q->carrier.numerology) * cfo_avg; + cargf(corr[0]) - 2.0f * M_PI * srsran_symbol_distance_s(0, symbols[0], q->carrier.scs) * cfo_avg; // Calculate CFO corrections for (uint32_t l = 0; l < SRSRAN_NSYMB_PER_SLOT_NR; l++) { - float arg = arg0 + 2.0f * M_PI * cfo_avg * srsran_symbol_distance_s(0, l, q->carrier.numerology); + float arg = arg0 + 2.0f * M_PI * cfo_avg * srsran_symbol_distance_s(0, l, q->carrier.scs); cfo_correction[l] = cexpf(I * arg); } diff --git a/lib/src/phy/ch_estimation/test/csi_rs_test.c b/lib/src/phy/ch_estimation/test/csi_rs_test.c index 8d43b8ec2..afaa2d207 100644 --- a/lib/src/phy/ch_estimation/test/csi_rs_test.c +++ b/lib/src/phy/ch_estimation/test/csi_rs_test.c @@ -27,11 +27,13 @@ #include static srsran_carrier_nr_t carrier = { - 0, // cell_id - 0, // numerology - 50, // nof_prb - 0, // start - 1 // max_mimo_layers + 1, // pci + 0, // absolute_frequency_ssb + 0, // absolute_frequency_point_a + srsran_subcarrier_spacing_15kHz, // scs + 50, // nof_prb + 0, // start + 1 // max_mimo_layers }; static float snr_dB = 20.0; @@ -79,7 +81,7 @@ static void usage(char* prog) { printf("Usage: %s [recov]\n", prog); printf("\t-p nof_prb [Default %d]\n", carrier.nof_prb); - printf("\t-c cell_id [Default %d]\n", carrier.id); + printf("\t-c cell_id [Default %d]\n", carrier.pci); printf("\t-s SNR in dB [Default %.2f]\n", snr_dB); printf("\t-S Start RB index [Default %d]\n", start_rb); printf("\t-L Number of RB [Default %d]\n", nof_rb); @@ -97,7 +99,7 @@ static void parse_args(int argc, char** argv) carrier.nof_prb = (uint32_t)strtol(argv[optind], NULL, 10); break; case 'c': - carrier.id = (uint32_t)strtol(argv[optind], NULL, 10); + carrier.pci = (uint32_t)strtol(argv[optind], NULL, 10); break; case 'o': power_control_offset = strtof(argv[optind], NULL); @@ -178,7 +180,7 @@ int main(int argc, char** argv) resource.resource_mapping.freq_band.nof_rb <= nof_rb_end; resource.resource_mapping.freq_band.nof_rb += 4) { // Iterate for all slot numbers - for (slot_cfg.idx = 0; slot_cfg.idx < SRSRAN_NSLOTS_PER_FRAME_NR(carrier.numerology); slot_cfg.idx++) { + for (slot_cfg.idx = 0; slot_cfg.idx < SRSRAN_NSLOTS_PER_FRAME_NR(carrier.scs); slot_cfg.idx++) { // Steer Frequency allocation for (uint32_t freq_dom_alloc = 0; freq_dom_alloc < nof_freq_dom_alloc; freq_dom_alloc++) { for (uint32_t i = 0; i < nof_freq_dom_alloc; i++) { diff --git a/lib/src/phy/ch_estimation/test/dmrs_pdcch_test.c b/lib/src/phy/ch_estimation/test/dmrs_pdcch_test.c index 975a93582..7850db9dd 100644 --- a/lib/src/phy/ch_estimation/test/dmrs_pdcch_test.c +++ b/lib/src/phy/ch_estimation/test/dmrs_pdcch_test.c @@ -39,7 +39,7 @@ void usage(char* prog) printf("\t-r nof_prb [Default %d]\n", carrier.nof_prb); printf("\t-e extended cyclic prefix [Default normal]\n"); - printf("\t-c cell_id [Default %d]\n", carrier.id); + printf("\t-c cell_id [Default %d]\n", carrier.pci); printf("\t-v increase verbosity\n"); } @@ -53,7 +53,7 @@ static void parse_args(int argc, char** argv) carrier.nof_prb = (uint32_t)strtol(argv[optind], NULL, 10); break; case 'c': - carrier.id = (uint32_t)strtol(argv[optind], NULL, 10); + carrier.pci = (uint32_t)strtol(argv[optind], NULL, 10); break; case 'v': srsran_verbose++; @@ -77,7 +77,7 @@ static int run_test(srsran_dmrs_pdcch_estimator_t* estimator, srsran_dci_location_t dci_location = {}; dci_location.L = aggregation_level; - for (slot_cfg.idx = 0; slot_cfg.idx < SRSRAN_NSLOTS_PER_FRAME_NR(carrier.numerology); slot_cfg.idx++) { + for (slot_cfg.idx = 0; slot_cfg.idx < SRSRAN_NSLOTS_PER_FRAME_NR(carrier.scs); slot_cfg.idx++) { uint32_t locations[SRSRAN_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR] = {}; int nof_locations = diff --git a/lib/src/phy/ch_estimation/test/dmrs_pdsch_test.c b/lib/src/phy/ch_estimation/test/dmrs_pdsch_test.c index a21e72c0e..3c3d6e988 100644 --- a/lib/src/phy/ch_estimation/test/dmrs_pdsch_test.c +++ b/lib/src/phy/ch_estimation/test/dmrs_pdsch_test.c @@ -29,12 +29,15 @@ #include #include + static srsran_carrier_nr_t carrier = { - 0, // cell_id - 0, // numerology - 50, // nof_prb - 0, // start - 1 // max_mimo_layers + 1, // pci + 0, // absolute_frequency_ssb + 0, // absolute_frequency_point_a + srsran_subcarrier_spacing_15kHz, // scs + 50, // nof_prb + 0, // start + 1 // max_mimo_layers }; typedef struct { @@ -139,7 +142,7 @@ static void usage(char* prog) printf("\t-r nof_prb [Default %d]\n", carrier.nof_prb); - printf("\t-c cell_id [Default %d]\n", carrier.id); + printf("\t-c cell_id [Default %d]\n", carrier.pci); printf("\t-v increase verbosity\n"); } @@ -153,7 +156,7 @@ static void parse_args(int argc, char** argv) carrier.nof_prb = (uint32_t)strtol(argv[optind], NULL, 10); break; case 'c': - carrier.id = (uint32_t)strtol(argv[optind], NULL, 10); + carrier.pci = (uint32_t)strtol(argv[optind], NULL, 10); break; case 'v': srsran_verbose++; @@ -227,7 +230,7 @@ static int run_test(srsran_dmrs_sch_t* dmrs_pdsch, TESTASSERT(assert_cfg(pdsch_cfg, grant) == SRSRAN_SUCCESS); srsran_slot_cfg_t slot_cfg = {}; - for (slot_cfg.idx = 0; slot_cfg.idx < SRSRAN_NSLOTS_PER_FRAME_NR(dmrs_pdsch->carrier.numerology); slot_cfg.idx++) { + for (slot_cfg.idx = 0; slot_cfg.idx < SRSRAN_NSLOTS_PER_FRAME_NR(dmrs_pdsch->carrier.scs); slot_cfg.idx++) { TESTASSERT(srsran_dmrs_sch_put_sf(dmrs_pdsch, &slot_cfg, pdsch_cfg, grant, sf_symbols) == SRSRAN_SUCCESS); TESTASSERT(srsran_dmrs_sch_estimate(dmrs_pdsch, &slot_cfg, pdsch_cfg, grant, sf_symbols, chest_res) == diff --git a/lib/src/phy/modem/demod_soft.c b/lib/src/phy/modem/demod_soft.c index d9e82169b..26517cb9c 100644 --- a/lib/src/phy/modem/demod_soft.c +++ b/lib/src/phy/modem/demod_soft.c @@ -892,9 +892,6 @@ int srsran_demod_soft_demodulate(srsran_mod_t modulation, const cf_t* symbols, f int srsran_demod_soft_demodulate_s(srsran_mod_t modulation, const cf_t* symbols, short* llr, int nsymbols) { - if (symbols == NULL || llr == NULL) { - return SRSRAN_ERROR_INVALID_INPUTS; - } switch (modulation) { case SRSRAN_MOD_BPSK: demod_bpsk_lte_s(symbols, llr, nsymbols); @@ -920,9 +917,6 @@ int srsran_demod_soft_demodulate_s(srsran_mod_t modulation, const cf_t* symbols, int srsran_demod_soft_demodulate_b(srsran_mod_t modulation, const cf_t* symbols, int8_t* llr, int nsymbols) { - if (symbols == NULL || llr == NULL) { - return SRSRAN_ERROR_INVALID_INPUTS; - } switch (modulation) { case SRSRAN_MOD_BPSK: demod_bpsk_lte_b(symbols, llr, nsymbols); @@ -941,34 +935,7 @@ int srsran_demod_soft_demodulate_b(srsran_mod_t modulation, const cf_t* symbols, break; default: ERROR("Invalid modulation %d", modulation); - return SRSRAN_ERROR; + return -1; } - return SRSRAN_SUCCESS; + return 0; } - -int srsran_demod_soft_demodulate2_b(srsran_mod_t modulation, const cf_t* symbols, int8_t* llr, int nsymbols) -{ - if (symbols == NULL || llr == NULL) { - return SRSRAN_ERROR_INVALID_INPUTS; - } - if (srsran_demod_soft_demodulate_b(modulation, symbols, llr, nsymbols) < SRSRAN_SUCCESS) { - return SRSRAN_ERROR; - } - - // If the number of bits is 2 or less, this is unnecessary - if (modulation < SRSRAN_MOD_16QAM) { - return SRSRAN_SUCCESS; - } - - // Iterate all symbols seeking for zero LLR - uint32_t nof_bits_x_symbol = srsran_mod_bits_x_symbol(modulation); - for (uint32_t i = 0; i < nsymbols; i++) { - if (symbols[i] == 0.0f) { - for (uint32_t j = 0; j < nof_bits_x_symbol; j++) { - llr[i * nof_bits_x_symbol + j] = 0; - } - } - } - - return SRSRAN_SUCCESS; -} \ No newline at end of file diff --git a/lib/src/phy/modem/test/soft_demod_test.c b/lib/src/phy/modem/test/soft_demod_test.c index 730532fc1..2b4b6349e 100644 --- a/lib/src/phy/modem/test/soft_demod_test.c +++ b/lib/src/phy/modem/test/soft_demod_test.c @@ -19,8 +19,11 @@ * */ +#include +#include #include #include +#include #include #include #include @@ -31,7 +34,7 @@ static uint32_t nof_frames = 10; static uint32_t num_bits = 1000; static srsran_mod_t modulation = SRSRAN_MOD_NITEMS; -static void usage(char* prog) +void usage(char* prog) { printf("Usage: %s [nfv] -m modulation (1: BPSK, 2: QPSK, 4: QAM16, 6: QAM64)\n", prog); printf("\t-n num_bits [Default %d]\n", num_bits); @@ -39,7 +42,7 @@ static void usage(char* prog) printf("\t-v srsran_verbose [Default None]\n"); } -static void parse_args(int argc, char** argv) +void parse_args(int argc, char** argv) { int opt; while ((opt = getopt(argc, argv, "nmvf")) != -1) { @@ -88,16 +91,33 @@ static void parse_args(int argc, char** argv) } } +float mse_threshold() +{ + switch (modulation) { + case SRSRAN_MOD_BPSK: + return 1.0e-6; + case SRSRAN_MOD_QPSK: + return 1.0e-6; + case SRSRAN_MOD_16QAM: + return 0.11; + case SRSRAN_MOD_64QAM: + return 0.19; + case SRSRAN_MOD_256QAM: + return 0.3; + default: + return -1.0f; + } +} + int main(int argc, char** argv) { + int i; srsran_modem_table_t mod; - uint8_t* input = NULL; - cf_t* symbols = NULL; - float* llr = NULL; - short* llr_s = NULL; - int8_t* llr_b = NULL; - int8_t* llr_b2 = NULL; - srsran_random_t random_gen = srsran_random_init(0); + uint8_t * input, *output; + cf_t* symbols; + float* llr; + short* llr_s; + int8_t* llr_b; parse_args(argc, argv); @@ -116,6 +136,11 @@ int main(int argc, char** argv) perror("malloc"); exit(-1); } + output = srsran_vec_u8_malloc(num_bits); + if (!output) { + perror("malloc"); + exit(-1); + } symbols = srsran_vec_cf_malloc(num_bits / mod.nbits_x_symbol); if (!symbols) { perror("malloc"); @@ -140,21 +165,17 @@ int main(int argc, char** argv) exit(-1); } - llr_b2 = srsran_vec_i8_malloc(num_bits); - if (!llr_b2) { - perror("malloc"); - exit(-1); - } + /* generate random data */ + srand(0); int ret = -1; struct timeval t[3]; - float mean_texec = 0.0f; - float mean_texec_s = 0.0f; - float mean_texec_b = 0.0f; - float mean_texec_b2 = 0.0f; + float mean_texec = 0.0; + float mean_texec_s = 0.0; + float mean_texec_b = 0.0; for (int n = 0; n < nof_frames; n++) { - for (int i = 0; i < num_bits; i++) { - input[i] = srsran_random_uniform_int_dist(random_gen, 0, 1); + for (i = 0; i < num_bits; i++) { + input[i] = rand() % 2; } /* modulate */ @@ -188,15 +209,6 @@ int main(int argc, char** argv) mean_texec_b = SRSRAN_VEC_CMA((float)t[0].tv_usec, mean_texec_b, n - 1); } - gettimeofday(&t[1], NULL); - srsran_demod_soft_demodulate2_b(modulation, symbols, llr_b2, num_bits / mod.nbits_x_symbol); - gettimeofday(&t[2], NULL); - get_time_interval(t); - - if (n > 0) { - mean_texec_b2 = SRSRAN_VEC_CMA((float)t[0].tv_usec, mean_texec_b2, n - 1); - } - if (SRSRAN_VERBOSE_ISDEBUG()) { printf("bits="); srsran_vec_fprint_b(stdout, input, num_bits); @@ -212,27 +224,12 @@ int main(int argc, char** argv) printf("llr_b="); srsran_vec_fprint_bs(stdout, llr_b, num_bits); - - printf("llr_b2="); - srsran_vec_fprint_bs(stdout, llr_b2, num_bits); } // Check demodulation errors - for (int j = 0; j < num_bits; j++) { - if (input[j] != (llr[j] > 0 ? 1 : 0)) { - ERROR("Error in bit %d\n", j); - goto clean_exit; - } - if (input[j] != (llr_s[j] > 0 ? 1 : 0)) { - ERROR("Error in bit %d\n", j); - goto clean_exit; - } - if (input[j] != (llr_b[j] > 0 ? 1 : 0)) { - ERROR("Error in bit %d\n", j); - goto clean_exit; - } - if (input[j] != (llr_b2[j] > 0 ? 1 : 0)) { - ERROR("Error in bit %d\n", j); + for (int i = 0; i < num_bits; i++) { + if (input[i] != (llr[i] > 0 ? 1 : 0)) { + printf("Error in bit %d\n", i); goto clean_exit; } } @@ -240,23 +237,21 @@ int main(int argc, char** argv) ret = 0; clean_exit: - srsran_random_free(random_gen); free(llr_b); free(llr_s); free(llr); free(symbols); + free(output); free(input); srsran_modem_table_free(&mod); - printf("Mean Throughput: %.2f/%.2f/%.2f/%.2f. Mbps ExTime: %.2f/%.2f/%.2f/%.2f us\n", + printf("Mean Throughput: %.2f/%.2f/%.2f. Mbps ExTime: %.2f/%.2f/%.2f us\n", num_bits / mean_texec, num_bits / mean_texec_s, num_bits / mean_texec_b, - num_bits / mean_texec_b2, mean_texec, mean_texec_s, - mean_texec_b, - mean_texec_b2); + mean_texec_b); exit(ret); } diff --git a/lib/src/phy/phch/csi.c b/lib/src/phy/phch/csi.c index f022f4019..a598bd426 100644 --- a/lib/src/phy/phch/csi.c +++ b/lib/src/phy/phch/csi.c @@ -316,11 +316,11 @@ uint32_t srsran_csi_str(const srsran_csi_report_cfg_t* report_cfg, for (uint32_t i = 0; i < nof_reports; i++) { if (report_cfg[i].freq_cfg == SRSRAN_CSI_REPORT_FREQ_WIDEBAND && report_cfg[i].quantity == SRSRAN_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI) { - len = srsran_print_check(str, str_len, len, ", cqi=%d", report_value[i].wideband_cri_ri_pmi_cqi.cqi); + len = srsran_print_check(str, str_len, len, "cqi=%d ", report_value[i].wideband_cri_ri_pmi_cqi.cqi); } else if (report_cfg[i].quantity == SRSRAN_CSI_REPORT_QUANTITY_NONE) { char tmp[20] = {}; srsran_vec_sprint_bin(tmp, sizeof(tmp), report_value[i].none, report_cfg->K_csi_rs); - len = srsran_print_check(str, str_len, len, ", csi=%s", tmp); + len = srsran_print_check(str, str_len, len, "csi=%s ", tmp); } } return len; diff --git a/lib/src/phy/phch/pdcch_nr.c b/lib/src/phy/phch/pdcch_nr.c index c83bea69b..7c8b722ad 100644 --- a/lib/src/phy/phch/pdcch_nr.c +++ b/lib/src/phy/phch/pdcch_nr.c @@ -336,7 +336,7 @@ static uint32_t pdcch_nr_c_init(const srsran_pdcch_nr_t* q, const srsran_dci_msg { uint32_t n_id = (dci_msg->ctx.ss_type == srsran_search_space_type_ue && q->coreset.dmrs_scrambling_id_present) ? q->coreset.dmrs_scrambling_id - : q->carrier.id; + : q->carrier.pci; uint32_t n_rnti = (dci_msg->ctx.ss_type == srsran_search_space_type_ue && q->coreset.dmrs_scrambling_id_present) ? dci_msg->ctx.rnti : 0U; diff --git a/lib/src/phy/phch/pdsch_nr.c b/lib/src/phy/phch/pdsch_nr.c index a98620ce6..e62e29946 100644 --- a/lib/src/phy/phch/pdsch_nr.c +++ b/lib/src/phy/phch/pdsch_nr.c @@ -26,9 +26,6 @@ #include "srsran/phy/mimo/precoding.h" #include "srsran/phy/modem/demod_soft.h" -///@brief Default number of zero RE around DC -#define PDSCH_NR_DEFAULT_NOF_ZERO_RE_AROUND_DC 3 - int pdsch_nr_init_common(srsran_pdsch_nr_t* q, const srsran_pdsch_nr_args_t* args) { SRSRAN_MEM_ZERO(q, srsran_pdsch_nr_t, 1); @@ -43,14 +40,6 @@ int pdsch_nr_init_common(srsran_pdsch_nr_t* q, const srsran_pdsch_nr_args_t* arg } } - if (!args->disable_zero_re_around_dc) { - if (args->nof_zero_re_around_dc == 0) { - q->nof_zero_re_around_dc = PDSCH_NR_DEFAULT_NOF_ZERO_RE_AROUND_DC; - } else { - q->nof_zero_re_around_dc = args->nof_zero_re_around_dc; - } - } - return SRSRAN_SUCCESS; } @@ -194,6 +183,8 @@ void srsran_pdsch_nr_free(srsran_pdsch_nr_t* q) if (q->evm_buffer != NULL) { srsran_evm_free(q->evm_buffer); } + + SRSRAN_MEM_ZERO(q, srsran_pdsch_nr_t, 1); } static inline uint32_t pdsch_nr_put_rb(cf_t* dst, cf_t* src, bool* rvd_mask) @@ -257,23 +248,7 @@ static int srsran_pdsch_nr_cp(const srsran_pdsch_nr_t* q, if (put) { count += pdsch_nr_put_rb(&sf_symbols[re_idx], &symbols[count], &rvd_mask[rb * SRSRAN_NRE]); } else { - uint32_t k_begin = rb * SRSRAN_NRE; - uint32_t k_end = (rb + 1) * SRSRAN_NRE; - uint32_t k_dc_begin = q->carrier.nof_prb * SRSRAN_NRE / 2 - q->nof_zero_re_around_dc / 2; - uint32_t k_dc_end = q->carrier.nof_prb * SRSRAN_NRE / 2 + SRSRAN_CEIL(q->nof_zero_re_around_dc, 2); - if (k_begin <= k_dc_end && k_end >= k_dc_begin && q->nof_zero_re_around_dc > 0) { - for (uint32_t k = k_begin; k < k_end; k++) { - if (!rvd_mask[k]) { - if (k >= k_dc_begin && k < k_dc_end) { - symbols[count++] = 0.0f; - } else { - symbols[count++] = sf_symbols[q->carrier.nof_prb * l * SRSRAN_NRE + k]; - } - } - } - } else { - count += pdsch_nr_get_rb(&symbols[count], &sf_symbols[re_idx], &rvd_mask[rb * SRSRAN_NRE]); - } + count += pdsch_nr_get_rb(&symbols[count], &sf_symbols[re_idx], &rvd_mask[rb * SRSRAN_NRE]); } } } @@ -302,7 +277,7 @@ static int srsran_pdsch_nr_get(const srsran_pdsch_nr_t* q, static uint32_t pdsch_nr_cinit(const srsran_carrier_nr_t* carrier, const srsran_sch_cfg_nr_t* cfg, uint16_t rnti, uint32_t cw_idx) { - uint32_t n_id = carrier->id; + uint32_t n_id = carrier->pci; if (cfg->scrambling_id_present && SRSRAN_RNTI_ISUSER(rnti)) { n_id = cfg->scambling_id; } @@ -465,7 +440,7 @@ static inline int pdsch_nr_decode_codeword(srsran_pdsch_nr_t* q, // Demodulation int8_t* llr = (int8_t*)q->b[tb->cw_idx]; - if (srsran_demod_soft_demodulate2_b(tb->mod, q->d[tb->cw_idx], llr, tb->nof_re)) { + if (srsran_demod_soft_demodulate_b(tb->mod, q->d[tb->cw_idx], llr, tb->nof_re)) { return SRSRAN_ERROR; } @@ -584,7 +559,6 @@ static uint32_t pdsch_nr_grant_info(const srsran_pdsch_nr_t* q, uint32_t str_len) { uint32_t len = 0; - len = srsran_print_check(str, str_len, len, "rnti=0x%x ", grant->rnti); uint32_t first_prb = SRSRAN_MAX_PRB_NR; for (uint32_t i = 0; i < SRSRAN_MAX_PRB_NR && first_prb == SRSRAN_MAX_PRB_NR; i++) { @@ -594,27 +568,8 @@ static uint32_t pdsch_nr_grant_info(const srsran_pdsch_nr_t* q, } // Append time-domain resource mapping - len = srsran_print_check(str, - str_len, - len, - "beta_dmrs=%.3f CDM-grp=%d k0=%d prb=%d:%d symb=%d:%d mapping=%s ", - isnormal(grant->beta_dmrs) ? grant->beta_dmrs : 1.0f, - grant->nof_dmrs_cdm_groups_without_data, - grant->k, - first_prb, - grant->nof_prb, - grant->S, - grant->L, - srsran_sch_mapping_type_to_str(grant->mapping)); - - // Skip frequency domain resources... - // ... - - // Append spatial resources - len = srsran_print_check(str, str_len, len, "Nl=%d ", grant->nof_layers); - - // Append scrambling ID - len = srsran_print_check(str, str_len, len, "n_scid=%d ", grant->n_scid); + len = srsran_print_check( + str, str_len, len, "rnti=0x%x prb=%d:%d symb=%d:%d ", grant->rnti, first_prb, grant->nof_prb, grant->S, grant->L); // Append TB info for (uint32_t i = 0; i < SRSRAN_MAX_TB; i++) { @@ -643,13 +598,8 @@ uint32_t srsran_pdsch_nr_rx_info(const srsran_pdsch_nr_t* q, len += pdsch_nr_grant_info(q, cfg, grant, res, &str[len], str_len - len); - if (cfg->rvd_re.count != 0) { - len = srsran_print_check(str, str_len, len, "Reserved: "); - len += srsran_re_pattern_list_info(&cfg->rvd_re, &str[len], str_len - len); - } - if (q->meas_time_en) { - len = srsran_print_check(str, str_len, len, " t=%d us", q->meas_time_us); + len = srsran_print_check(str, str_len, len, "t_us=%d ", q->meas_time_us); } return len; diff --git a/lib/src/phy/phch/phch_cfg_nr.c b/lib/src/phy/phch/phch_cfg_nr.c new file mode 100644 index 000000000..246367aa1 --- /dev/null +++ b/lib/src/phy/phch/phch_cfg_nr.c @@ -0,0 +1,261 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2021 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ +#include "srsran/phy/phch/phch_cfg_nr.h" +#include "srsran/phy/ch_estimation/dmrs_sch.h" +#include "srsran/phy/phch/csi.h" +#include "srsran/phy/phch/uci_nr.h" + +static const char* dmrs_sch_type_to_str(srsran_dmrs_sch_type_t type) +{ + switch (type) { + case srsran_dmrs_sch_type_1: + return "1"; + case srsran_dmrs_sch_type_2: + return "2"; + default:; // Do nothing + } + return "invalid"; +} + +static const char* dmrs_sch_add_pos_to_str(srsran_dmrs_sch_add_pos_t add_pos) +{ + switch (add_pos) { + case srsran_dmrs_sch_add_pos_2: + return "2"; + case srsran_dmrs_sch_add_pos_0: + return "0"; + case srsran_dmrs_sch_add_pos_1: + return "1"; + case srsran_dmrs_sch_add_pos_3: + return "3"; + default:; // Do nothing + } + return "invalid"; +} + +static const char* dmrs_sch_len_to_str(srsran_dmrs_sch_len_t len) +{ + switch (len) { + case srsran_dmrs_sch_len_1: + return "single"; + case srsran_dmrs_sch_len_2: + return "double"; + default:; // Do nothing + } + return "invalid"; +} + +static const char* dmrs_sch_typeApos_to_str(srsran_dmrs_sch_typeA_pos_t typeA_pos) +{ + switch (typeA_pos) { + case srsran_dmrs_sch_typeA_pos_2: + return "2"; + case srsran_dmrs_sch_typeA_pos_3: + return "3"; + default:; // Do nothing + } + return "invalid"; +} + +static uint32_t phch_cfg_nr_dmrs_to_str(const srsran_dmrs_sch_cfg_t* dmrs, + const srsran_sch_grant_nr_t* grant, + char* str, + uint32_t str_len) +{ + uint32_t len = 0; + + len = srsran_print_check(str, str_len, len, " DMRS:\n"); + len = srsran_print_check(str, str_len, len, " type=%s\n", dmrs_sch_type_to_str(dmrs->type)); + len = srsran_print_check(str, str_len, len, " add_pos=%s\n", dmrs_sch_add_pos_to_str(dmrs->additional_pos)); + len = srsran_print_check(str, str_len, len, " len=%s\n", dmrs_sch_len_to_str(dmrs->length)); + len = srsran_print_check(str, str_len, len, " typeA_pos=%s\n", dmrs_sch_typeApos_to_str(dmrs->typeA_pos)); + + if (dmrs->scrambling_id0_present) { + len = srsran_print_check(str, str_len, len, " scrambling_id_0=%03x\n", dmrs->scrambling_id0); + } + + if (dmrs->scrambling_id1_present) { + len = srsran_print_check(str, str_len, len, " scrambling_id_1=%03x\n", dmrs->scrambling_id1); + } + + if (dmrs->lte_CRS_to_match_around) { + len = srsran_print_check(str, str_len, len, " lte_CRS_to_match_around=y\n"); + } + + if (dmrs->additional_DMRS_DL_Alt) { + len = srsran_print_check(str, str_len, len, " additional_DMRS_DL_Alt=y\n"); + } + + srsran_re_pattern_t pattern = {}; + if (srsran_dmrs_sch_rvd_re_pattern(dmrs, grant, &pattern) == SRSRAN_SUCCESS) { + len = srsran_print_check(str, str_len, len, " rvd_pattern: "); + len += srsran_re_pattern_info(&pattern, &str[len], str_len - len); + len = srsran_print_check(str, str_len, len, "\n"); + } + + return len; +} + +static const char* sch_mapping_to_str(srsran_sch_mapping_type_t mapping) +{ + switch (mapping) { + case srsran_sch_mapping_type_A: + return "A"; + case srsran_sch_mapping_type_B: + return "B"; + default:; // Do nothing + } + return "invalid"; +} + +static const char* sch_xoverhead_to_str(srsran_xoverhead_t xoverhead) +{ + switch (xoverhead) { + case srsran_xoverhead_0: + return "0"; + case srsran_xoverhead_6: + return "6"; + case srsran_xoverhead_12: + return "12"; + case srsran_xoverhead_18: + return "18"; + default:; // Do nothing + } + return "invalid"; +} + +static uint32_t phch_cfg_tb_to_str(const srsran_sch_tb_t* tb, char* str, uint32_t str_len) +{ + uint32_t len = 0; + + if (!tb->enabled) { + return len; + } + + len = srsran_print_check(str, str_len, len, " CW%d:\n", tb->cw_idx); + len = srsran_print_check(str, str_len, len, " mod=%s\n", srsran_mod_string(tb->mod)); + len = srsran_print_check(str, str_len, len, " nof_layers=%d\n", tb->N_L); + len = srsran_print_check(str, str_len, len, " mcs=%d\n", tb->mcs); + len = srsran_print_check(str, str_len, len, " tbs=%d\n", tb->tbs); + len = srsran_print_check(str, str_len, len, " R=%.3f\n", tb->R); + len = srsran_print_check(str, str_len, len, " rv=%d\n", tb->rv); + len = srsran_print_check(str, str_len, len, " ndi=%d\n", tb->ndi); + len = srsran_print_check(str, str_len, len, " nof_re=%d\n", tb->nof_re); + len = srsran_print_check(str, str_len, len, " nof_bits=%d\n", tb->nof_bits); + + return len; +} + +static uint32_t phch_cfg_grant_to_str(const srsran_sch_grant_nr_t* grant, char* str, uint32_t str_len) +{ + uint32_t len = 0; + + uint32_t first_prb = SRSRAN_MAX_PRB_NR; + for (uint32_t i = 0; i < SRSRAN_MAX_PRB_NR && first_prb == SRSRAN_MAX_PRB_NR; i++) { + if (grant->prb_idx[i]) { + first_prb = i; + } + } + + len = srsran_print_check(str, str_len, len, " Grant:\n"); + len = srsran_print_check(str, str_len, len, " rnti=0x%x\n", grant->rnti); + len = srsran_print_check(str, str_len, len, " rnti_type=%s\n", srsran_rnti_type_str(grant->rnti_type)); + len = srsran_print_check(str, str_len, len, " k=%d\n", grant->k); + len = srsran_print_check(str, str_len, len, " mapping=%s\n", sch_mapping_to_str(grant->mapping)); + len = srsran_print_check(str, str_len, len, " t_alloc=%d:%d\n", grant->S, grant->L); + len = srsran_print_check(str, str_len, len, " f_alloc=%d:%d\n", first_prb, grant->nof_prb); + len = srsran_print_check(str, str_len, len, " nof_dmrs_cdm_grps=%d\n", grant->nof_dmrs_cdm_groups_without_data); + len = srsran_print_check(str, str_len, len, " beta_dmrs=%f\n", grant->beta_dmrs); + len = srsran_print_check(str, str_len, len, " nof_layers=%d\n", grant->nof_layers); + len = srsran_print_check(str, str_len, len, " n_scid=%d\n", grant->n_scid); + len = srsran_print_check(str, str_len, len, " tb_scaling_field=%d\n", grant->tb_scaling_field); + + for (uint32_t i = 0; i < SRSRAN_MAX_TB; i++) { + len += phch_cfg_tb_to_str(&grant->tb[i], &str[len], str_len - len); + } + + return len; +} + +static uint32_t phch_cfg_sch_to_str(const srsran_sch_cfg_t* sch, char* str, uint32_t str_len) +{ + uint32_t len = 0; + + len = srsran_print_check(str, str_len, len, " SCH:\n"); + len = srsran_print_check(str, str_len, len, " mcs_table=%s\n", srsran_mcs_table_to_str(sch->mcs_table)); + len = srsran_print_check(str, str_len, len, " xoverhead=%s\n", sch_xoverhead_to_str(sch->xoverhead)); + + return len; +} + +static uint32_t phch_cfg_rvd_to_str(const srsran_re_pattern_list_t* pattern_list, char* str, uint32_t str_len) +{ + uint32_t len = 0; + + if (pattern_list->count == 0) { + return len; + } + + len = srsran_print_check(str, str_len, len, " Reserved:\n"); + for (uint32_t i = 0; i < pattern_list->count; i++) { + len = srsran_print_check(str, str_len, len, " %d: ", i); + len += srsran_re_pattern_info(&pattern_list->data[i], &str[len], str_len - len); + len = srsran_print_check(str, str_len, len, "\n"); + } + + return len; +} + +static uint32_t phch_cfg_uci_to_str(const srsran_uci_cfg_nr_t* uci, char* str, uint32_t str_len) +{ + uint32_t len = 0; + + if (srsran_uci_nr_total_bits(uci) == 0) { + return len; + } + + len = srsran_print_check(str, str_len, len, " UCI:\n"); + len = srsran_print_check(str, str_len, len, " alpha=%.2f\n", uci->pusch.alpha); + len = srsran_print_check(str, str_len, len, " beta_harq_ack_offset=%.2f\n", uci->pusch.beta_harq_ack_offset); + len = srsran_print_check(str, str_len, len, " beta_csi_part1_offset=%.2f\n", uci->pusch.beta_csi1_offset); + len = srsran_print_check(str, str_len, len, " beta_csi_part2_offset=%.2f\n", uci->pusch.beta_csi1_offset); + len = srsran_print_check(str, str_len, len, " o_csi1=%d\n", srsran_csi_part1_nof_bits(uci->csi, uci->nof_csi)); + len = srsran_print_check(str, str_len, len, " o_ack=%d\n", uci->o_ack); + + return len; +} + +uint32_t srsran_sch_cfg_nr_info(const srsran_sch_cfg_nr_t* sch_cfg, char* str, uint32_t str_len) +{ + uint32_t len = 0; + + if (sch_cfg->scambling_id) { + len = srsran_print_check(str, str_len, len, " scrambling_id=0x%03x\n", sch_cfg->scrambling_id_present); + } + + // Append DMRS information + len += phch_cfg_nr_dmrs_to_str(&sch_cfg->dmrs, &sch_cfg->grant, &str[len], str_len - len); + + // Append grant information + len += phch_cfg_grant_to_str(&sch_cfg->grant, &str[len], str_len - len); + + // Append SCH information + len += phch_cfg_sch_to_str(&sch_cfg->sch_cfg, &str[len], str_len - len); + + // Append SCH information + len += phch_cfg_rvd_to_str(&sch_cfg->rvd_re, &str[len], str_len - len); + + // UCI configuration + len += phch_cfg_uci_to_str(&sch_cfg->uci, &str[len], str_len - len); + + return len; +} diff --git a/lib/src/phy/phch/pucch_nr.c b/lib/src/phy/phch/pucch_nr.c index 359ce6d5c..83e0ed9c2 100644 --- a/lib/src/phy/phch/pucch_nr.c +++ b/lib/src/phy/phch/pucch_nr.c @@ -37,7 +37,7 @@ int srsran_pucch_nr_group_sequence(const srsran_carrier_nr_t* carrier, { uint32_t f_gh = 0; uint32_t f_ss = 0; - uint32_t n_id = cfg->hopping_id_present ? cfg->hopping_id : carrier->id; + uint32_t n_id = cfg->hopping_id_present ? cfg->hopping_id : carrier->pci; switch (cfg->group_hopping) { case SRSRAN_PUCCH_NR_GROUP_HOPPING_NEITHER: @@ -80,13 +80,13 @@ int srsran_pucch_nr_alpha_idx(const srsran_carrier_nr_t* carrier, } // Compute number of slot - uint32_t n_slot = SRSRAN_SLOT_NR_MOD(carrier->numerology, slot->idx); + uint32_t n_slot = SRSRAN_SLOT_NR_MOD(carrier->scs, slot->idx); // Generate pseudo-random sequence - uint32_t cinit = cfg->hopping_id_present ? cfg->hopping_id : carrier->id; + uint32_t cinit = cfg->hopping_id_present ? cfg->hopping_id : carrier->pci; uint8_t cs[SRSRAN_NSYMB_PER_SLOT_NR * SRSRAN_NSLOTS_PER_FRAME_NR(SRSRAN_NR_MAX_NUMEROLOGY) * 8U] = {}; srsran_sequence_apply_bit( - cs, cs, SRSRAN_NSYMB_PER_SLOT_NR * SRSRAN_NSLOTS_PER_FRAME_NR(carrier->numerology) * 8, cinit); + cs, cs, SRSRAN_NSYMB_PER_SLOT_NR * SRSRAN_NSLOTS_PER_FRAME_NR(carrier->scs) * 8, cinit); // Create n_cs parameter uint32_t n_cs = 0; @@ -545,7 +545,7 @@ static uint32_t pucch_nr_format2_cinit(const srsran_carrier_nr_t* carri const srsran_pucch_nr_common_cfg_t* pucch_cfg, const srsran_uci_cfg_nr_t* uci_cfg) { - uint32_t n_id = (pucch_cfg->scrambling_id_present) ? pucch_cfg->scrambling_id_present : carrier->id; + uint32_t n_id = (pucch_cfg->scrambling_id_present) ? pucch_cfg->scrambling_id_present : carrier->pci; return ((uint32_t)uci_cfg->pucch.rnti << 15U) + n_id; } diff --git a/lib/src/phy/phch/pusch_nr.c b/lib/src/phy/phch/pusch_nr.c index ef57db062..8733e6a9c 100644 --- a/lib/src/phy/phch/pusch_nr.c +++ b/lib/src/phy/phch/pusch_nr.c @@ -236,171 +236,25 @@ void srsran_pusch_nr_free(srsran_pusch_nr_t* q) SRSRAN_MEM_ZERO(q, srsran_pusch_nr_t, 1); } -/** - * @brief copies a number of countiguous Resource Elements - * @param sf_symbols slot symbols in frequency domain - * @param symbols resource elements - * @param count number of resource elements to copy - * @param put Direction, symbols are copied into sf_symbols if put is true, otherwise sf_symbols are copied into symbols - */ -static void srsran_pusch_re_cp(cf_t* sf_symbols, cf_t* symbols, uint32_t count, bool put) -{ - if (put) { - srsran_vec_cf_copy(sf_symbols, symbols, count); - } else { - srsran_vec_cf_copy(symbols, sf_symbols, count); - } -} - -/* - * As a RB is 12 RE wide, positions marked as 1 will be used for the 1st CDM group, and the same with group 2: - * - * +---+---+---+---+---+---+---+---+---+---+---+---+ - * | 1 | 1 | 2 | 2 | 1 | 1 | 2 | 2 | 1 | 1 | 2 | 2 | - * +---+---+---+---+---+---+---+---+---+---+---+---+ - * -- k --> - * - * If the number of DMRS CDM groups without data is set to: - * - 1, data is mapped in RE marked as 2 - * - Otherwise, no data is mapped in this symbol - */ -static uint32_t srsran_pusch_nr_cp_dmrs_type1(const srsran_pusch_nr_t* q, - const srsran_sch_grant_nr_t* grant, - cf_t* symbols, - cf_t* sf_symbols, - bool put) -{ - uint32_t count = 0; - uint32_t delta = 0; - - if (grant->nof_dmrs_cdm_groups_without_data != 1) { - return count; - } - - for (uint32_t i = 0; i < q->carrier.nof_prb; i++) { - if (grant->prb_idx[i]) { - for (uint32_t j = 0; j < SRSRAN_NRE; j += 2) { - if (put) { - sf_symbols[i * SRSRAN_NRE + delta + j + 1] = symbols[count++]; - } else { - symbols[count++] = sf_symbols[i * SRSRAN_NRE + delta + j + 1]; - } - } - } - } - - return count; -} - -/* - * As a RB is 12 RE wide, positions marked as 1 will be used for the 1st CDM group, and the same with groups 2 and 3: - * - * +---+---+---+---+---+---+---+---+---+---+---+---+ - * | 1 | 1 | 2 | 2 | 3 | 3 | 1 | 1 | 2 | 2 | 3 | 3 | - * +---+---+---+---+---+---+---+---+---+---+---+---+ - * -- k --> - * - * If the number of DMRS CDM groups without data is set to: - * - 1, data is mapped in RE marked as 2 and 3 - * - 2, data is mapped in RE marked as 3 - * - otherwise, no data is mapped in this symbol - */ -static uint32_t srsran_pusch_nr_cp_dmrs_type2(const srsran_pusch_nr_t* q, - const srsran_sch_grant_nr_t* grant, - cf_t* symbols, - cf_t* sf_symbols, - bool put) +static inline uint32_t pusch_nr_put_rb(cf_t* dst, cf_t* src, bool* rvd_mask) { uint32_t count = 0; - - if (grant->nof_dmrs_cdm_groups_without_data != 1 && grant->nof_dmrs_cdm_groups_without_data != 2) { - return count; - } - - uint32_t re_offset = (grant->nof_dmrs_cdm_groups_without_data == 1) ? 2 : 4; - uint32_t re_count = (grant->nof_dmrs_cdm_groups_without_data == 1) ? 4 : 2; - - for (uint32_t i = 0; i < q->carrier.nof_prb; i++) { - if (grant->prb_idx[i]) { - // Copy RE between pilot pairs - srsran_pusch_re_cp(&sf_symbols[i * SRSRAN_NRE + re_offset], &symbols[count], re_count, put); - count += re_count; - - // Copy RE after second pilot - srsran_pusch_re_cp(&sf_symbols[(i + 1) * SRSRAN_NRE - re_count], &symbols[count], re_count, put); - count += re_count; + for (uint32_t i = 0; i < SRSRAN_NRE; i++) { + if (!rvd_mask[i]) { + dst[i] = src[count++]; } } - return count; } -static uint32_t srsran_pusch_nr_cp_dmrs(const srsran_pusch_nr_t* q, - const srsran_sch_cfg_nr_t* cfg, - const srsran_sch_grant_nr_t* grant, - cf_t* symbols, - cf_t* sf_symbols, - bool put) +static inline uint32_t pusch_nr_get_rb(cf_t* dst, cf_t* src, bool* rvd_mask) { uint32_t count = 0; - - const srsran_dmrs_sch_cfg_t* dmrs_cfg = &cfg->dmrs; - - switch (dmrs_cfg->type) { - case srsran_dmrs_sch_type_1: - count = srsran_pusch_nr_cp_dmrs_type1(q, grant, symbols, sf_symbols, put); - break; - case srsran_dmrs_sch_type_2: - count = srsran_pusch_nr_cp_dmrs_type2(q, grant, symbols, sf_symbols, put); - break; - } - - return count; -} - -static uint32_t srsran_pusch_nr_cp_clean(const srsran_pusch_nr_t* q, - const srsran_sch_grant_nr_t* grant, - cf_t* symbols, - cf_t* sf_symbols, - bool put) -{ - uint32_t count = 0; - uint32_t start = 0; // Index of the start of continuous data - uint32_t length = 0; // End of continuous RE - - for (uint32_t i = 0; i < q->carrier.nof_prb; i++) { - if (grant->prb_idx[i]) { - // If fist continuous block, save start - if (length == 0) { - start = i * SRSRAN_NRE; - } - length += SRSRAN_NRE; - } else { - // Consecutive block is finished - if (put) { - srsran_vec_cf_copy(&sf_symbols[start], &symbols[count], length); - } else { - srsran_vec_cf_copy(&symbols[count], &sf_symbols[start], length); - } - - // Increase RE count - count += length; - - // Reset consecutive block - length = 0; + for (uint32_t i = 0; i < SRSRAN_NRE; i++) { + if (!rvd_mask[i]) { + dst[count++] = src[i]; } } - - // Copy last contiguous block - if (length > 0) { - if (put) { - srsran_vec_cf_copy(&sf_symbols[start], &symbols[count], length); - } else { - srsran_vec_cf_copy(&symbols[count], &sf_symbols[start], length); - } - count += length; - } - return count; } @@ -411,55 +265,60 @@ static int srsran_pusch_nr_cp(const srsran_pusch_nr_t* q, cf_t* sf_symbols, bool put) { - uint32_t count = 0; - uint32_t dmrs_l_idx[SRSRAN_DMRS_SCH_MAX_SYMBOLS] = {}; - uint32_t dmrs_l_count = 0; + uint32_t count = 0; - // Get symbol indexes carrying DMRS - int32_t nof_dmrs_symbols = srsran_dmrs_sch_get_symbols_idx(&cfg->dmrs, grant, dmrs_l_idx); - if (nof_dmrs_symbols < SRSRAN_SUCCESS) { - return SRSRAN_ERROR; - } + for (uint32_t l = grant->S; l < grant->S + grant->L; l++) { + // Initialise reserved RE mask to all false + bool rvd_mask[SRSRAN_NRE * SRSRAN_MAX_PRB_NR] = {}; - if (SRSRAN_DEBUG_ENABLED && srsran_verbose >= SRSRAN_VERBOSE_DEBUG && !handler_registered) { - DEBUG("dmrs_l_idx="); - srsran_vec_fprint_i(stdout, (int32_t*)dmrs_l_idx, nof_dmrs_symbols); - } + // Reserve DMRS + if (srsran_re_pattern_to_symbol_mask(&q->dmrs_re_pattern, l, rvd_mask) < SRSRAN_SUCCESS) { + ERROR("Error generating DMRS reserved RE mask"); + return SRSRAN_ERROR; + } - for (uint32_t l = grant->S; l < grant->S + grant->L; l++) { - // Advance DMRS symbol counter until: - // - the current DMRS symbol index is greater or equal than current symbol l - // - no more DMRS symbols - while (dmrs_l_idx[dmrs_l_count] < l && dmrs_l_count < nof_dmrs_symbols) { - dmrs_l_count++; + // Reserve RE from configuration + if (srsran_re_pattern_list_to_symbol_mask(&cfg->rvd_re, l, rvd_mask) < SRSRAN_SUCCESS) { + ERROR("Error generating reserved RE mask"); + return SRSRAN_ERROR; } - if (l == dmrs_l_idx[dmrs_l_count]) { - count += srsran_pusch_nr_cp_dmrs( - q, cfg, grant, &symbols[count], &sf_symbols[l * q->carrier.nof_prb * SRSRAN_NRE], put); - } else { - count += - srsran_pusch_nr_cp_clean(q, grant, &symbols[count], &sf_symbols[l * q->carrier.nof_prb * SRSRAN_NRE], put); + // Actual copy + for (uint32_t rb = 0; rb < q->carrier.nof_prb; rb++) { + // Skip PRB if not available in grant + if (!grant->prb_idx[rb]) { + continue; + } + + // Calculate RE index at the begin of the symbol + uint32_t re_idx = (q->carrier.nof_prb * l + rb) * SRSRAN_NRE; + + // Put or get + if (put) { + count += pusch_nr_put_rb(&sf_symbols[re_idx], &symbols[count], &rvd_mask[rb * SRSRAN_NRE]); + } else { + count += pusch_nr_get_rb(&symbols[count], &sf_symbols[re_idx], &rvd_mask[rb * SRSRAN_NRE]); + } } } return count; } -static int srsran_pusch_nr_put(const srsran_pusch_nr_t* q, - const srsran_sch_cfg_nr_t* cfg, - const srsran_sch_grant_nr_t* grant, - cf_t* symbols, - cf_t* sf_symbols) +static int pusch_nr_put(const srsran_pusch_nr_t* q, + const srsran_sch_cfg_nr_t* cfg, + const srsran_sch_grant_nr_t* grant, + cf_t* symbols, + cf_t* sf_symbols) { return srsran_pusch_nr_cp(q, cfg, grant, symbols, sf_symbols, true); } -static int srsran_pusch_nr_get(const srsran_pusch_nr_t* q, - const srsran_sch_cfg_nr_t* cfg, - const srsran_sch_grant_nr_t* grant, - cf_t* symbols, - cf_t* sf_symbols) +static int pusch_nr_get(const srsran_pusch_nr_t* q, + const srsran_sch_cfg_nr_t* cfg, + const srsran_sch_grant_nr_t* grant, + cf_t* symbols, + cf_t* sf_symbols) { return srsran_pusch_nr_cp(q, cfg, grant, symbols, sf_symbols, false); } @@ -467,7 +326,7 @@ static int srsran_pusch_nr_get(const srsran_pusch_nr_t* q, static uint32_t pusch_nr_cinit(const srsran_carrier_nr_t* carrier, const srsran_sch_cfg_nr_t* cfg, uint16_t rnti, uint32_t cw_idx) { - uint32_t n_id = carrier->id; + uint32_t n_id = carrier->pci; if (cfg->scrambling_id_present && SRSRAN_RNTI_ISUSER(rnti)) { n_id = cfg->scambling_id; } @@ -478,121 +337,6 @@ pusch_nr_cinit(const srsran_carrier_nr_t* carrier, const srsran_sch_cfg_nr_t* cf return cinit; } -static inline int pusch_nr_fill_uci_cfg(srsran_pusch_nr_t* q, const srsran_sch_cfg_nr_t* cfg) -{ - if (cfg->grant.nof_prb == 0) { - ERROR("Invalid number of PRB (%d)", cfg->grant.nof_prb); - return SRSRAN_ERROR; - } - - // Initially, copy all fields - q->uci_cfg = cfg->uci; - - // Reset UCI PUSCH configuration - SRSRAN_MEM_ZERO(&q->uci_cfg.pusch, srsran_uci_nr_pusch_cfg_t, 1); - - // Get DMRS symbol indexes - uint32_t nof_dmrs_l = 0; - uint32_t dmrs_l[SRSRAN_DMRS_SCH_MAX_SYMBOLS] = {}; - int n = srsran_dmrs_sch_get_symbols_idx(&cfg->dmrs, &cfg->grant, dmrs_l); - if (n < SRSRAN_SUCCESS) { - return SRSRAN_ERROR; - } - nof_dmrs_l = (uint32_t)n; - - // Find OFDM symbol index of the first OFDM symbol after the first set of consecutive OFDM symbol(s) carrying DMRS - // Starts at first OFDM symbol carrying DMRS - for (uint32_t l = dmrs_l[0], dmrs_l_idx = 0; l < cfg->grant.S + cfg->grant.L; l++) { - // Check if it is not carrying DMRS... - if (l != dmrs_l[dmrs_l_idx]) { - // Set value and stop iterating - q->uci_cfg.pusch.l0 = l; - break; - } - - // Move to the next DMRS OFDM symbol index - if (dmrs_l_idx < nof_dmrs_l) { - dmrs_l_idx++; - } - } - - // Find OFDM symbol index of the first OFDM symbol that does not carry DMRS - // Starts at first OFDM symbol of the PUSCH transmission - for (uint32_t l = cfg->grant.S, dmrs_l_idx = 0; l < cfg->grant.S + cfg->grant.L; l++) { - // Check if it is not carrying DMRS... - if (l != dmrs_l[dmrs_l_idx]) { - q->uci_cfg.pusch.l1 = l; - break; - } - - // Move to the next DMRS OFDM symbol index - if (dmrs_l_idx < nof_dmrs_l) { - dmrs_l_idx++; - } - } - - // Number of DMRS per PRB - uint32_t n_sc_dmrs = SRSRAN_DMRS_SCH_SC(cfg->grant.nof_dmrs_cdm_groups_without_data, cfg->dmrs.type); - - // Set UCI RE number of candidates per OFDM symbol according to TS 38.312 6.3.2.4.2.1 - for (uint32_t l = 0, dmrs_l_idx = 0; l < SRSRAN_NSYMB_PER_SLOT_NR; l++) { - // Skip if OFDM symbol is outside of the PUSCH transmission - if (l < cfg->grant.S || l >= (cfg->grant.S + cfg->grant.L)) { - q->uci_cfg.pusch.M_pusch_sc[l] = 0; - q->uci_cfg.pusch.M_uci_sc[l] = 0; - continue; - } - - // OFDM symbol carries DMRS - if (l == dmrs_l[dmrs_l_idx]) { - // Calculate PUSCH RE candidates - q->uci_cfg.pusch.M_pusch_sc[l] = cfg->grant.nof_prb * (SRSRAN_NRE - n_sc_dmrs); - - // The Number of RE candidates for UCI are 0 - q->uci_cfg.pusch.M_uci_sc[l] = 0; - - // Advance DMRS symbol index - dmrs_l_idx++; - - // Skip to next symbol - continue; - } - - // Number of RE for Phase Tracking Reference Signals (PT-RS) - uint32_t M_ptrs_sc = 0; // Not implemented yet - - // Number of RE given by the grant - q->uci_cfg.pusch.M_pusch_sc[l] = cfg->grant.nof_prb * SRSRAN_NRE; - - // Calculate the number of UCI candidates - q->uci_cfg.pusch.M_uci_sc[l] = q->uci_cfg.pusch.M_pusch_sc[l] - M_ptrs_sc; - } - - // Generate SCH Transport block information - srsran_sch_nr_tb_info_t sch_tb_info = {}; - if (srsran_sch_nr_fill_tb_info(&q->carrier, &cfg->sch_cfg, &cfg->grant.tb[0], &sch_tb_info) < SRSRAN_SUCCESS) { - ERROR("Generating TB info"); - return SRSRAN_ERROR; - } - - // Calculate the sum of codeblock sizes - for (uint32_t i = 0; i < sch_tb_info.C; i++) { - // Accumulate codeblock size if mask is enabled - q->uci_cfg.pusch.K_sum += (sch_tb_info.mask[i]) ? sch_tb_info.Kr : 0; - } - - // Set other PUSCH parameters - q->uci_cfg.pusch.modulation = cfg->grant.tb[0].mod; - q->uci_cfg.pusch.nof_layers = cfg->grant.nof_layers; - q->uci_cfg.pusch.R = (float)cfg->grant.tb[0].R; - q->uci_cfg.pusch.alpha = cfg->scaling; - q->uci_cfg.pusch.beta_harq_ack_offset = cfg->beta_harq_ack_offset; - q->uci_cfg.pusch.beta_csi1_offset = cfg->beta_csi_part1_offset; - q->uci_cfg.pusch.nof_re = cfg->grant.tb[0].nof_re; - - return SRSRAN_SUCCESS; -} - // Implements TS 38.212 6.2.7 Data and control multiplexing (for NR-PUSCH) static int pusch_nr_gen_mux_uci(srsran_pusch_nr_t* q, const srsran_uci_cfg_nr_t* cfg) { @@ -629,7 +373,7 @@ static int pusch_nr_gen_mux_uci(srsran_pusch_nr_t* q, const srsran_uci_cfg_nr_t* if (cfg->o_ack <= 2) { // the number of reserved resource elements for potential HARQ-ACK transmission is calculated according to Clause // 6.3.2.4.2.1, by setting O_ACK = 2 ; - G_ack_rvd = srsran_uci_nr_pusch_ack_nof_bits(&q->uci_cfg.pusch, 2); + G_ack_rvd = srsran_uci_nr_pusch_ack_nof_bits(&cfg->pusch, 2); // Disable non reserved HARQ-ACK bits G_ack = 0; @@ -845,7 +589,7 @@ static inline int pusch_nr_encode_codeword(srsran_pusch_nr_t* q, } // Encode HARQ-ACK bits - int E_uci_ack = srsran_uci_nr_encode_pusch_ack(&q->uci, &q->uci_cfg, uci, q->g_ack); + int E_uci_ack = srsran_uci_nr_encode_pusch_ack(&q->uci, &cfg->uci, uci, q->g_ack); if (E_uci_ack < SRSRAN_SUCCESS) { ERROR("Error encoding HARQ-ACK bits"); return SRSRAN_ERROR; @@ -853,7 +597,7 @@ static inline int pusch_nr_encode_codeword(srsran_pusch_nr_t* q, q->G_ack = (uint32_t)E_uci_ack; // Encode CSI part 1 - int E_uci_csi1 = srsran_uci_nr_encode_pusch_csi1(&q->uci, &q->uci_cfg, uci, q->g_csi1); + int E_uci_csi1 = srsran_uci_nr_encode_pusch_csi1(&q->uci, &cfg->uci, uci, q->g_csi1); if (E_uci_csi1 < SRSRAN_SUCCESS) { ERROR("Error encoding HARQ-ACK bits"); return SRSRAN_ERROR; @@ -865,7 +609,7 @@ static inline int pusch_nr_encode_codeword(srsran_pusch_nr_t* q, q->G_csi2 = 0; // Generate PUSCH UCI/UL-SCH multiplexing - if (pusch_nr_gen_mux_uci(q, &q->uci_cfg) < SRSRAN_SUCCESS) { + if (pusch_nr_gen_mux_uci(q, &cfg->uci) < SRSRAN_SUCCESS) { ERROR("Error generating PUSCH mux tables"); return SRSRAN_ERROR; } @@ -877,7 +621,8 @@ static inline int pusch_nr_encode_codeword(srsran_pusch_nr_t* q, } // Multiplex UL-SCH with UCI only if it is necessary - uint8_t* b = q->g_ulsch; + uint32_t nof_bits = tb->nof_re * srsran_mod_bits_x_symbol(tb->mod); + uint8_t* b = q->g_ulsch; if (q->uci_mux) { // Change b location b = q->b[tb->cw_idx]; @@ -905,15 +650,15 @@ static inline int pusch_nr_encode_codeword(srsran_pusch_nr_t* q, if (SRSRAN_DEBUG_ENABLED && srsran_verbose >= SRSRAN_VERBOSE_DEBUG && !handler_registered) { DEBUG("b="); - srsran_vec_fprint_b(stdout, b, tb->nof_bits); + srsran_vec_fprint_b(stdout, b, nof_bits); } // 7.3.1.1 Scrambling uint32_t cinit = pusch_nr_cinit(&q->carrier, cfg, rnti, tb->cw_idx); - srsran_sequence_apply_bit(b, q->b[tb->cw_idx], tb->nof_bits, cinit); + srsran_sequence_apply_bit(b, q->b[tb->cw_idx], nof_bits, cinit); // Special Scrambling condition - if (q->uci_cfg.o_ack <= 2) { + if (cfg->uci.o_ack <= 2) { for (uint32_t i = 0; i < q->G_ack; i++) { uint32_t idx = q->pos_ack[i]; if (q->g_ack[i] == (uint8_t)UCI_BIT_REPETITION) { @@ -927,7 +672,7 @@ static inline int pusch_nr_encode_codeword(srsran_pusch_nr_t* q, } // 7.3.1.2 Modulation - srsran_mod_modulate(&q->modem_tables[tb->mod], q->b[tb->cw_idx], q->d[tb->cw_idx], tb->nof_bits); + srsran_mod_modulate(&q->modem_tables[tb->mod], q->b[tb->cw_idx], q->d[tb->cw_idx], nof_bits); if (SRSRAN_DEBUG_ENABLED && srsran_verbose >= SRSRAN_VERBOSE_DEBUG && !handler_registered) { DEBUG("d="); @@ -945,6 +690,7 @@ int srsran_pusch_nr_encode(srsran_pusch_nr_t* q, { // Check input pointers if (!q || !cfg || !grant || !data || !sf_symbols) { + ERROR("Invalid inputs"); return SRSRAN_ERROR_INVALID_INPUTS; } @@ -959,9 +705,9 @@ int srsran_pusch_nr_encode(srsran_pusch_nr_t* q, return SRSRAN_ERROR; } - // Fill UCI configuration for PUSCH configuration - if (pusch_nr_fill_uci_cfg(q, cfg) < SRSRAN_SUCCESS) { - ERROR("Error filling UCI configuration for PUSCH"); + // Compute DMRS pattern + if (srsran_dmrs_sch_rvd_re_pattern(&cfg->dmrs, grant, &q->dmrs_re_pattern) < SRSRAN_SUCCESS) { + ERROR("Error computing DMRS pattern"); return SRSRAN_ERROR; } @@ -991,7 +737,7 @@ int srsran_pusch_nr_encode(srsran_pusch_nr_t* q, // ... Not implemented // 7.3.1.6 Mapping from virtual to physical resource blocks - int n = srsran_pusch_nr_put(q, cfg, grant, x[0], sf_symbols[0]); + int n = pusch_nr_put(q, cfg, grant, x[0], sf_symbols[0]); if (n < SRSRAN_SUCCESS) { ERROR("Putting NR PUSCH resources"); return SRSRAN_ERROR; @@ -1039,8 +785,11 @@ static inline int pusch_nr_decode_codeword(srsran_pusch_nr_t* q, srsran_vec_fprint_c(stdout, q->d[tb->cw_idx], tb->nof_re); } + // Total number of bits + uint32_t nof_bits = tb->nof_re * srsran_mod_bits_x_symbol(tb->mod); + // Calculate HARQ-ACK bits - int n = srsran_uci_nr_pusch_ack_nof_bits(&q->uci_cfg.pusch, q->uci_cfg.o_ack); + int n = srsran_uci_nr_pusch_ack_nof_bits(&cfg->uci.pusch, cfg->uci.o_ack); if (n < SRSRAN_SUCCESS) { ERROR("Calculating G_ack"); return SRSRAN_ERROR; @@ -1048,7 +797,7 @@ static inline int pusch_nr_decode_codeword(srsran_pusch_nr_t* q, q->G_ack = (uint32_t)n; // Calculate CSI part 1 bits - n = srsran_uci_nr_pusch_csi1_nof_bits(&q->uci_cfg); + n = srsran_uci_nr_pusch_csi1_nof_bits(&cfg->uci); if (n < SRSRAN_SUCCESS) { ERROR("Calculating G_csi1"); return SRSRAN_ERROR; @@ -1060,7 +809,7 @@ static inline int pusch_nr_decode_codeword(srsran_pusch_nr_t* q, q->G_csi2 = 0; // Generate PUSCH UCI/UL-SCH multiplexing - if (pusch_nr_gen_mux_uci(q, &q->uci_cfg) < SRSRAN_SUCCESS) { + if (pusch_nr_gen_mux_uci(q, &cfg->uci) < SRSRAN_SUCCESS) { ERROR("Error generating PUSCH mux tables"); return SRSRAN_ERROR; } @@ -1073,16 +822,15 @@ static inline int pusch_nr_decode_codeword(srsran_pusch_nr_t* q, // EVM if (q->evm_buffer != NULL) { - res->evm[tb->cw_idx] = - srsran_evm_run_b(q->evm_buffer, &q->modem_tables[tb->mod], q->d[tb->cw_idx], llr, tb->nof_bits); + res->evm[tb->cw_idx] = srsran_evm_run_b(q->evm_buffer, &q->modem_tables[tb->mod], q->d[tb->cw_idx], llr, nof_bits); } // Descrambling - srsran_sequence_apply_c(llr, llr, tb->nof_bits, pusch_nr_cinit(&q->carrier, cfg, rnti, tb->cw_idx)); + srsran_sequence_apply_c(llr, llr, nof_bits, pusch_nr_cinit(&q->carrier, cfg, rnti, tb->cw_idx)); if (SRSRAN_DEBUG_ENABLED && srsran_verbose >= SRSRAN_VERBOSE_DEBUG && !handler_registered) { DEBUG("b="); - srsran_vec_fprint_bs(stdout, llr, tb->nof_bits); + srsran_vec_fprint_bs(stdout, llr, nof_bits); } // Demultiplex UCI only if necessary @@ -1092,7 +840,7 @@ static inline int pusch_nr_decode_codeword(srsran_pusch_nr_t* q, for (uint32_t i = 0; i < q->G_ulsch; i++) { g_ulsch[i] = -llr[q->pos_ulsch[i]]; } - for (uint32_t i = q->G_ulsch; i < tb->nof_bits; i++) { + for (uint32_t i = q->G_ulsch; i < nof_bits; i++) { g_ulsch[i] = 0; } @@ -1116,7 +864,7 @@ static inline int pusch_nr_decode_codeword(srsran_pusch_nr_t* q, // Decode HARQ-ACK if (q->G_ack) { - if (srsran_uci_nr_decode_pusch_ack(&q->uci, &q->uci_cfg, g_ack, &res->uci)) { + if (srsran_uci_nr_decode_pusch_ack(&q->uci, &cfg->uci, g_ack, &res->uci)) { ERROR("Error in UCI decoding"); return SRSRAN_ERROR; } @@ -1124,7 +872,7 @@ static inline int pusch_nr_decode_codeword(srsran_pusch_nr_t* q, // Decode CSI part 1 if (q->G_csi1) { - if (srsran_uci_nr_decode_pusch_csi1(&q->uci, &q->uci_cfg, g_csi1, &res->uci)) { + if (srsran_uci_nr_decode_pusch_csi1(&q->uci, &cfg->uci, g_csi1, &res->uci)) { ERROR("Error in UCI decoding"); return SRSRAN_ERROR; } @@ -1136,13 +884,13 @@ static inline int pusch_nr_decode_codeword(srsran_pusch_nr_t* q, // Change LLR pointer llr = g_ulsch; } else { - for (uint32_t i = 0; i < tb->nof_bits; i++) { + for (uint32_t i = 0; i < nof_bits; i++) { llr[i] *= -1; } } // Decode Ul-SCH - if (tb->nof_bits != 0) { + if (nof_bits != 0) { if (srsran_ulsch_nr_decode(&q->sch, &cfg->sch_cfg, tb, llr, &res->tb[tb->cw_idx]) < SRSRAN_SUCCESS) { ERROR("Error in SCH decoding"); return SRSRAN_ERROR; @@ -1175,9 +923,9 @@ int srsran_pusch_nr_decode(srsran_pusch_nr_t* q, return SRSRAN_ERROR; } - // Fill UCI configuration for PUSCH configuration - if (pusch_nr_fill_uci_cfg(q, cfg) < SRSRAN_SUCCESS) { - ERROR("Error filling UCI configuration for PUSCH"); + // Compute DMRS pattern + if (srsran_dmrs_sch_rvd_re_pattern(&cfg->dmrs, grant, &q->dmrs_re_pattern) < SRSRAN_SUCCESS) { + ERROR("Error computing DMRS pattern"); return SRSRAN_ERROR; } @@ -1194,7 +942,7 @@ int srsran_pusch_nr_decode(srsran_pusch_nr_t* q, } // Demapping from virtual to physical resource blocks - uint32_t nof_re_get = srsran_pusch_nr_get(q, cfg, grant, q->x[0], sf_symbols[0]); + uint32_t nof_re_get = pusch_nr_get(q, cfg, grant, q->x[0], sf_symbols[0]); if (nof_re_get != nof_re) { ERROR("Inconsistent number of RE (%d!=%d)", nof_re_get, nof_re); return SRSRAN_ERROR; @@ -1239,14 +987,14 @@ int srsran_pusch_nr_decode(srsran_pusch_nr_t* q, return SRSRAN_SUCCESS; } -static uint32_t srsran_pusch_nr_grant_info(const srsran_sch_cfg_nr_t* cfg, - const srsran_sch_grant_nr_t* grant, - const srsran_pusch_res_nr_t* res, - char* str, - uint32_t str_len) +static uint32_t pusch_nr_grant_info(const srsran_pusch_nr_t* q, + const srsran_sch_cfg_nr_t* cfg, + const srsran_sch_grant_nr_t* grant, + const srsran_pusch_res_nr_t* res, + char* str, + uint32_t str_len) { uint32_t len = 0; - len = srsran_print_check(str, str_len, len, "rnti=0x%x", grant->rnti); uint32_t first_prb = SRSRAN_MAX_PRB_NR; for (uint32_t i = 0; i < SRSRAN_MAX_PRB_NR && first_prb == SRSRAN_MAX_PRB_NR; i++) { @@ -1256,29 +1004,20 @@ static uint32_t srsran_pusch_nr_grant_info(const srsran_sch_cfg_nr_t* cfg, } // Append time-domain resource mapping - len = srsran_print_check(str, - str_len, - len, - ",k2=%d,prb=%d:%d,S=%d,L=%d,mapping=%s", - grant->k, - first_prb, - grant->nof_prb, - grant->S, - grant->L, - srsran_sch_mapping_type_to_str(grant->mapping)); - - // Skip frequency domain resources... - // ... - - // Append spatial resources - len = srsran_print_check(str, str_len, len, ",Nl=%d", grant->nof_layers); - - // Append scrambling ID - len = srsran_print_check(str, str_len, len, ",n_scid=%d,", grant->n_scid); + len = srsran_print_check( + str, str_len, len, "rnti=0x%x prb=%d:%d symb=%d:%d ", grant->rnti, first_prb, grant->nof_prb, grant->S, grant->L); // Append TB info for (uint32_t i = 0; i < SRSRAN_MAX_TB; i++) { len += srsran_sch_nr_tb_info(&grant->tb[i], &res->tb[i], &str[len], str_len - len); + + if (res != NULL) { + if (grant->tb[i].enabled && !isnan(res->evm[i])) { + len = srsran_print_check(str, str_len, len, "evm=%.2f ", res->evm[i]); + if (i < SRSRAN_MAX_CODEWORDS - 1) { + } + } + } } return len; @@ -1297,45 +1036,18 @@ uint32_t srsran_pusch_nr_rx_info(const srsran_pusch_nr_t* q, return 0; } - len += srsran_pusch_nr_grant_info(cfg, grant, res, &str[len], str_len - len); + len += pusch_nr_grant_info(q, cfg, grant, res, &str[len], str_len - len); - if (q->evm_buffer != NULL) { - len = srsran_print_check(str, str_len, len, ",evm={", 0); - for (uint32_t i = 0; i < SRSRAN_MAX_CODEWORDS; i++) { - if (grant->tb[i].enabled && !isnan(res->evm[i])) { - len = srsran_print_check(str, str_len, len, "%.2f", res[i].evm); - if (i < SRSRAN_MAX_CODEWORDS - 1) { - if (grant->tb[i + 1].enabled) { - len = srsran_print_check(str, str_len, len, ",", 0); - } - } - } - } - len = srsran_print_check(str, str_len, len, "}", 0); - } - - if (res != NULL) { + if (res != NULL && srsran_uci_nr_total_bits(&cfg->uci) > 0) { + len = srsran_print_check(str, str_len, len, "UCI: "); srsran_uci_data_nr_t uci_data = {}; uci_data.cfg = cfg->uci; - uci_data.value = res[0].uci; + uci_data.value = res->uci; len += srsran_uci_nr_info(&uci_data, &str[len], str_len - len); - - len = srsran_print_check(str, str_len, len, ",crc={", 0); - for (uint32_t i = 0; i < SRSRAN_MAX_CODEWORDS; i++) { - if (grant->tb[i].enabled) { - len = srsran_print_check(str, str_len, len, "%s", res->tb[i].crc ? "OK" : "KO"); - if (i < SRSRAN_MAX_CODEWORDS - 1) { - if (grant->tb[i + 1].enabled) { - len = srsran_print_check(str, str_len, len, ",", 0); - } - } - } - } - len = srsran_print_check(str, str_len, len, "}", 0); } if (q->meas_time_en) { - len = srsran_print_check(str, str_len, len, ", t=%d us", q->meas_time_us); + len = srsran_print_check(str, str_len, len, "t_us=%d ", q->meas_time_us); } return len; @@ -1354,7 +1066,7 @@ uint32_t srsran_pusch_nr_tx_info(const srsran_pusch_nr_t* q, return 0; } - len += srsran_pusch_nr_grant_info(cfg, grant, NULL, &str[len], str_len - len); + len += pusch_nr_grant_info(q, cfg, grant, NULL, &str[len], str_len - len); if (uci_value != NULL) { srsran_uci_data_nr_t uci_data = {}; @@ -1364,7 +1076,7 @@ uint32_t srsran_pusch_nr_tx_info(const srsran_pusch_nr_t* q, } if (q->meas_time_en) { - len = srsran_print_check(str, str_len, len, ", t=%d us", q->meas_time_us); + len = srsran_print_check(str, str_len, len, " t=%d us", q->meas_time_us); } return len; diff --git a/lib/src/phy/phch/ra_nr.c b/lib/src/phy/phch/ra_nr.c index 6bac2fce9..dbaec02d7 100644 --- a/lib/src/phy/phch/ra_nr.c +++ b/lib/src/phy/phch/ra_nr.c @@ -25,6 +25,7 @@ #include "srsran/phy/phch/pdsch_nr.h" #include "srsran/phy/phch/ra_dl_nr.h" #include "srsran/phy/phch/ra_ul_nr.h" +#include "srsran/phy/phch/uci_nr.h" #include "srsran/phy/utils/debug.h" typedef struct { @@ -686,6 +687,7 @@ int srsran_ra_dl_dci_to_grant_nr(const srsran_carrier_nr_t* carrier, pdsch_grant->rnti_type = dci_dl->ctx.rnti_type; pdsch_grant->tb[0].rv = dci_dl->rv; pdsch_grant->tb[0].mcs = dci_dl->mcs; + pdsch_grant->tb[0].ndi = dci_dl->ndi; // 5.1.4 PDSCH resource mapping if (ra_dl_resource_mapping(carrier, slot, pdsch_hl_cfg, pdsch_cfg) < SRSRAN_SUCCESS) { @@ -797,7 +799,6 @@ int srsran_ra_ul_dci_to_grant_nr(const srsran_carrier_nr_t* carrier, pusch_grant->tb[0].rv = dci_ul->rv; pusch_grant->tb[0].mcs = dci_ul->mcs; pusch_grant->tb[0].ndi = dci_ul->ndi; - pusch_grant->tb[0].pid = dci_ul->pid; // 5.1.6.2 DM-RS reception procedure if (ra_ul_dmrs(pusch_hl_cfg, pusch_grant, pusch_cfg) < SRSRAN_SUCCESS) { @@ -821,12 +822,16 @@ int srsran_ra_ul_dci_to_grant_nr(const srsran_carrier_nr_t* carrier, static float ra_ul_beta_offset_ack_semistatic(const srsran_beta_offsets_t* beta_offsets, const srsran_uci_cfg_nr_t* uci_cfg) { + if (isnormal(beta_offsets->fix_ack)) { + return beta_offsets->fix_ack; + } + // Select Beta Offset index from the number of HARQ-ACK bits uint32_t beta_offset_index = beta_offsets->ack_index1; if (uci_cfg->o_ack > 11) { beta_offset_index = beta_offsets->ack_index3; } else if (uci_cfg->o_ack > 2) { - beta_offset_index = beta_offsets->ack_index1; + beta_offset_index = beta_offsets->ack_index2; } // Protect table boundary @@ -850,6 +855,11 @@ static float ra_ul_beta_offset_csi_semistatic(const srsran_beta_offsets_t* beta_ const srsran_uci_cfg_nr_t* uci_cfg, bool part2) { + float fix_beta_offset = part2 ? beta_offsets->fix_csi2 : beta_offsets->fix_csi1; + if (isnormal(fix_beta_offset)) { + return fix_beta_offset; + } + // Calculate number of CSI bits; CSI part 2 is not supported. uint32_t O_csi = part2 ? 0 : srsran_csi_part1_nof_bits(uci_cfg->csi, uci_cfg->nof_csi); @@ -872,35 +882,162 @@ static float ra_ul_beta_offset_csi_semistatic(const srsran_beta_offsets_t* beta_ return ra_nr_beta_offset_csi_table[beta_offset_index]; } -int srsran_ra_ul_set_grant_uci_nr(const srsran_sch_hl_cfg_nr_t* pusch_hl_cfg, +int srsran_ra_ul_set_grant_uci_nr(const srsran_carrier_nr_t* carrier, + const srsran_sch_hl_cfg_nr_t* pusch_hl_cfg, const srsran_uci_cfg_nr_t* uci_cfg, srsran_sch_cfg_nr_t* pusch_cfg) { + if (pusch_cfg->grant.nof_prb == 0) { + ERROR("Invalid number of PRB (%d)", pusch_cfg->grant.nof_prb); + return SRSRAN_ERROR; + } + + // Initially, copy all fields + pusch_cfg->uci = *uci_cfg; + + // Reset UCI PUSCH configuration + SRSRAN_MEM_ZERO(&pusch_cfg->uci.pusch, srsran_uci_nr_pusch_cfg_t, 1); + + // Get DMRS symbol indexes + uint32_t nof_dmrs_l = 0; + uint32_t dmrs_l[SRSRAN_DMRS_SCH_MAX_SYMBOLS] = {}; + int n = srsran_dmrs_sch_get_symbols_idx(&pusch_cfg->dmrs, &pusch_cfg->grant, dmrs_l); + if (n < SRSRAN_SUCCESS) { + return SRSRAN_ERROR; + } + nof_dmrs_l = (uint32_t)n; + + // Find OFDM symbol index of the first OFDM symbol after the first set of consecutive OFDM symbol(s) carrying DMRS + // Starts at first OFDM symbol carrying DMRS + for (uint32_t l = dmrs_l[0], dmrs_l_idx = 0; l < pusch_cfg->grant.S + pusch_cfg->grant.L; l++) { + // Check if it is not carrying DMRS... + if (l != dmrs_l[dmrs_l_idx]) { + // Set value and stop iterating + pusch_cfg->uci.pusch.l0 = l; + break; + } + + // Move to the next DMRS OFDM symbol index + if (dmrs_l_idx < nof_dmrs_l) { + dmrs_l_idx++; + } + } + + // Find OFDM symbol index of the first OFDM symbol that does not carry DMRS + // Starts at first OFDM symbol of the PUSCH transmission + for (uint32_t l = pusch_cfg->grant.S, dmrs_l_idx = 0; l < pusch_cfg->grant.S + pusch_cfg->grant.L; l++) { + // Check if it is not carrying DMRS... + if (l != dmrs_l[dmrs_l_idx]) { + pusch_cfg->uci.pusch.l1 = l; + break; + } + + // Move to the next DMRS OFDM symbol index + if (dmrs_l_idx < nof_dmrs_l) { + dmrs_l_idx++; + } + } + + // Number of DMRS per PRB + uint32_t n_sc_dmrs = SRSRAN_DMRS_SCH_SC(pusch_cfg->grant.nof_dmrs_cdm_groups_without_data, pusch_cfg->dmrs.type); + + // Set UCI RE number of candidates per OFDM symbol according to TS 38.312 6.3.2.4.2.1 + for (uint32_t l = 0, dmrs_l_idx = 0; l < SRSRAN_NSYMB_PER_SLOT_NR; l++) { + // Skip if OFDM symbol is outside of the PUSCH transmission + if (l < pusch_cfg->grant.S || l >= (pusch_cfg->grant.S + pusch_cfg->grant.L)) { + pusch_cfg->uci.pusch.M_pusch_sc[l] = 0; + pusch_cfg->uci.pusch.M_uci_sc[l] = 0; + continue; + } + + // OFDM symbol carries DMRS + if (l == dmrs_l[dmrs_l_idx]) { + // Calculate PUSCH RE candidates + pusch_cfg->uci.pusch.M_pusch_sc[l] = pusch_cfg->grant.nof_prb * (SRSRAN_NRE - n_sc_dmrs); + + // The Number of RE candidates for UCI are 0 + pusch_cfg->uci.pusch.M_uci_sc[l] = 0; + + // Advance DMRS symbol index + dmrs_l_idx++; + + // Skip to next symbol + continue; + } + + // Number of RE for Phase Tracking Reference Signals (PT-RS) + uint32_t M_ptrs_sc = 0; // Not implemented yet + + // Number of RE given by the grant + pusch_cfg->uci.pusch.M_pusch_sc[l] = pusch_cfg->grant.nof_prb * SRSRAN_NRE; + + // Calculate the number of UCI candidates + pusch_cfg->uci.pusch.M_uci_sc[l] = pusch_cfg->uci.pusch.M_pusch_sc[l] - M_ptrs_sc; + } + + // Generate SCH Transport block information + srsran_sch_nr_tb_info_t sch_tb_info = {}; + if (srsran_sch_nr_fill_tb_info(carrier, &pusch_cfg->sch_cfg, &pusch_cfg->grant.tb[0], &sch_tb_info) < + SRSRAN_SUCCESS) { + ERROR("Generating TB info"); + return SRSRAN_ERROR; + } + + // Calculate the sum of codeblock sizes + for (uint32_t i = 0; i < sch_tb_info.C; i++) { + // Accumulate codeblock size if mask is enabled + pusch_cfg->uci.pusch.K_sum += (sch_tb_info.mask[i]) ? sch_tb_info.Kr : 0; + } + + // Set other PUSCH parameters + pusch_cfg->uci.pusch.modulation = pusch_cfg->grant.tb[0].mod; + pusch_cfg->uci.pusch.nof_layers = pusch_cfg->grant.nof_layers; + pusch_cfg->uci.pusch.R = (float)pusch_cfg->grant.tb[0].R; + pusch_cfg->uci.pusch.nof_re = pusch_cfg->grant.tb[0].nof_re; + // Select beta offsets - pusch_cfg->beta_harq_ack_offset = ra_ul_beta_offset_ack_semistatic(&pusch_hl_cfg->beta_offsets, uci_cfg); - if (!isnormal(pusch_cfg->beta_harq_ack_offset)) { + pusch_cfg->uci.pusch.beta_harq_ack_offset = ra_ul_beta_offset_ack_semistatic(&pusch_hl_cfg->beta_offsets, uci_cfg); + if (!isnormal(pusch_cfg->uci.pusch.beta_harq_ack_offset)) { return SRSRAN_ERROR; } - pusch_cfg->beta_csi_part1_offset = ra_ul_beta_offset_csi_semistatic(&pusch_hl_cfg->beta_offsets, uci_cfg, false); - if (!isnormal(pusch_cfg->beta_csi_part1_offset)) { + pusch_cfg->uci.pusch.beta_csi1_offset = ra_ul_beta_offset_csi_semistatic(&pusch_hl_cfg->beta_offsets, uci_cfg, false); + if (!isnormal(pusch_cfg->uci.pusch.beta_csi1_offset)) { return SRSRAN_ERROR; } - pusch_cfg->beta_csi_part2_offset = ra_ul_beta_offset_csi_semistatic(&pusch_hl_cfg->beta_offsets, uci_cfg, true); - if (!isnormal(pusch_cfg->beta_csi_part2_offset)) { + pusch_cfg->uci.pusch.beta_csi2_offset = ra_ul_beta_offset_csi_semistatic(&pusch_hl_cfg->beta_offsets, uci_cfg, true); + if (!isnormal(pusch_cfg->uci.pusch.beta_csi2_offset)) { return SRSRAN_ERROR; } - // pusch_cfg->beta_csi_part2_offset = pusch_hl_cfg->beta_offset_csi2; - pusch_cfg->scaling = pusch_hl_cfg->scaling; - if (!isnormal(pusch_cfg->scaling)) { - ERROR("Invalid Scaling (%f)", pusch_cfg->scaling); + pusch_cfg->uci.pusch.alpha = pusch_hl_cfg->scaling; + if (!isnormal(pusch_cfg->uci.pusch.alpha)) { + ERROR("Invalid Scaling (%f)", pusch_cfg->uci.pusch.alpha); return SRSRAN_ERROR; } - // Copy UCI configuration - pusch_cfg->uci = *uci_cfg; + // Calculate number of UCI encoded bits + int Gack = 0; + if (pusch_cfg->uci.o_ack > 2) { + Gack = srsran_uci_nr_pusch_ack_nof_bits(&pusch_cfg->uci.pusch, pusch_cfg->uci.o_ack); + if (Gack < SRSRAN_SUCCESS) { + ERROR("Error calculating Qdack"); + return SRSRAN_ERROR; + } + } + int Gcsi1 = srsran_uci_nr_pusch_csi1_nof_bits(&pusch_cfg->uci); + if (Gcsi1 < SRSRAN_SUCCESS) { + ERROR("Error calculating Qdack"); + return SRSRAN_ERROR; + } + int Gcsi2 = 0; // NOT supported + + // Update Number of TB encoded bits + for (uint32_t i = 0; i < SRSRAN_MAX_TB; i++) { + pusch_cfg->grant.tb[i].nof_bits = + pusch_cfg->grant.tb[i].nof_re * srsran_mod_bits_x_symbol(pusch_cfg->grant.tb[i].mod) - Gack - Gcsi1 - Gcsi2; + } return SRSRAN_SUCCESS; } diff --git a/lib/src/phy/phch/sch_nr.c b/lib/src/phy/phch/sch_nr.c index 5d624dc08..962a15b5b 100644 --- a/lib/src/phy/phch/sch_nr.c +++ b/lib/src/phy/phch/sch_nr.c @@ -743,15 +743,12 @@ int srsran_sch_nr_tb_info(const srsran_sch_tb_t* tb, const srsran_sch_tb_res_nr_ len = srsran_print_check(str, str_len, len, - "CW%d: mod=%s Nl=%d tbs=%d R=%.3f rv=%d Nre=%d Nbit=%d ", + "CW%d: mod=%s tbs=%d R=%.3f rv=%d ", tb->cw_idx, srsran_mod_string(tb->mod), - tb->N_L, tb->tbs / 8, tb->R, - tb->rv, - tb->nof_re, - tb->nof_bits); + tb->rv); if (res != NULL) { len = srsran_print_check(str, str_len, len, "CRC=%s iter=%.1f ", res->crc ? "OK" : "KO", res->avg_iter); diff --git a/lib/src/phy/phch/test/pdcch_nr_test.c b/lib/src/phy/phch/test/pdcch_nr_test.c index 159407907..09580720a 100644 --- a/lib/src/phy/phch/test/pdcch_nr_test.c +++ b/lib/src/phy/phch/test/pdcch_nr_test.c @@ -25,11 +25,13 @@ #include static srsran_carrier_nr_t carrier = { - 0, // cell_id - 0, // numerology - 50, // nof_prb - 0, // start - 1 // max_mimo_layers + 1, // pci + 0, // absolute_frequency_ssb + 0, // absolute_frequency_point_a + srsran_subcarrier_spacing_15kHz, // scs + 50, // nof_prb + 0, // start + 1 // max_mimo_layers }; static uint16_t rnti = 0x1234; @@ -194,7 +196,7 @@ int main(int argc, char** argv) aggregation_level++) { uint32_t L = 1U << aggregation_level; - for (uint32_t slot_idx = 0; slot_idx < SRSRAN_NSLOTS_PER_FRAME_NR(carrier.numerology); slot_idx++) { + for (uint32_t slot_idx = 0; slot_idx < SRSRAN_NSLOTS_PER_FRAME_NR(carrier.scs); slot_idx++) { uint32_t dci_locations[SRSRAN_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR] = {}; // Calculate candidate locations diff --git a/lib/src/phy/phch/test/pdsch_nr_test.c b/lib/src/phy/phch/test/pdsch_nr_test.c index 8c45d1a96..f922e3b20 100644 --- a/lib/src/phy/phch/test/pdsch_nr_test.c +++ b/lib/src/phy/phch/test/pdsch_nr_test.c @@ -30,13 +30,16 @@ #include static srsran_carrier_nr_t carrier = { - 1, // cell_id - 0, // numerology - SRSRAN_MAX_PRB_NR, // nof_prb - 0, // start - 1 // max_mimo_layers + 1, // pci + 0, // absolute_frequency_ssb + 0, // absolute_frequency_point_a + srsran_subcarrier_spacing_15kHz, // scs + SRSRAN_MAX_PRB_NR, // nof_prb + 0, // start + 1 // max_mimo_layers }; + static uint32_t n_prb = 0; // Set to 0 for steering static uint32_t mcs = 30; // Set to 30 for steering static srsran_sch_cfg_nr_t pdsch_cfg = {}; diff --git a/lib/src/phy/phch/test/pucch_nr_test.c b/lib/src/phy/phch/test/pucch_nr_test.c index 01cd47fe2..d9365dd9d 100644 --- a/lib/src/phy/phch/test/pucch_nr_test.c +++ b/lib/src/phy/phch/test/pucch_nr_test.c @@ -32,11 +32,13 @@ #include static srsran_carrier_nr_t carrier = { - 0, // cell_id - 0, // numerology - 6, // nof_prb - 0, // start - 1 // max_mimo_layers + 1, // pci + 0, // absolute_frequency_ssb + 0, // absolute_frequency_point_a + srsran_subcarrier_spacing_15kHz, // scs + 6, // nof_prb + 0, // start + 1 // max_mimo_layers }; static uint32_t starting_prb_stride = 4; @@ -52,7 +54,7 @@ static int test_pucch_format0(srsran_pucch_nr_t* pucch, const srsran_pucch_nr_co srsran_pucch_nr_resource_t resource = {}; resource.format = SRSRAN_PUCCH_NR_FORMAT_0; - for (slot.idx = 0; slot.idx < SRSRAN_NSLOTS_PER_FRAME_NR(carrier.numerology); slot.idx++) { + for (slot.idx = 0; slot.idx < SRSRAN_NSLOTS_PER_FRAME_NR(carrier.scs); slot.idx++) { for (resource.starting_prb = 0; resource.starting_prb < carrier.nof_prb; resource.starting_prb += starting_prb_stride) { for (resource.nof_symbols = 1; resource.nof_symbols <= 2; resource.nof_symbols++) { @@ -100,7 +102,7 @@ static int test_pucch_format1(srsran_pucch_nr_t* pucch, srsran_pucch_nr_resource_t resource = {}; resource.format = SRSRAN_PUCCH_NR_FORMAT_1; - for (slot.idx = 0; slot.idx < SRSRAN_NSLOTS_PER_FRAME_NR(carrier.numerology); slot.idx++) { + for (slot.idx = 0; slot.idx < SRSRAN_NSLOTS_PER_FRAME_NR(carrier.scs); slot.idx++) { for (resource.starting_prb = 0; resource.starting_prb < carrier.nof_prb; resource.starting_prb += starting_prb_stride) { for (resource.nof_symbols = SRSRAN_PUCCH_NR_FORMAT1_MIN_NSYMB; @@ -173,7 +175,7 @@ static int test_pucch_format2(srsran_pucch_nr_t* pucch, srsran_pucch_nr_resource_t resource = {}; resource.format = SRSRAN_PUCCH_NR_FORMAT_2; - for (slot.idx = 0; slot.idx < SRSRAN_NSLOTS_PER_FRAME_NR(carrier.numerology); slot.idx++) { + for (slot.idx = 0; slot.idx < SRSRAN_NSLOTS_PER_FRAME_NR(carrier.scs); slot.idx++) { for (resource.nof_symbols = SRSRAN_PUCCH_NR_FORMAT2_MIN_NSYMB; resource.nof_symbols <= SRSRAN_PUCCH_NR_FORMAT2_MAX_NSYMB; resource.nof_symbols++) { @@ -256,7 +258,7 @@ static int test_pucch_format2(srsran_pucch_nr_t* pucch, static void usage(char* prog) { printf("Usage: %s [csNnv]\n", prog); - printf("\t-c cell id [Default %d]\n", carrier.id); + printf("\t-c cell id [Default %d]\n", carrier.pci); printf("\t-n nof_prb [Default %d]\n", carrier.nof_prb); printf("\t-f format [Default %d]\n", format); printf("\t-s SNR in dB [Default %.2f]\n", snr_db); @@ -269,7 +271,7 @@ static void parse_args(int argc, char** argv) while ((opt = getopt(argc, argv, "cnfsv")) != -1) { switch (opt) { case 'c': - carrier.id = (uint32_t)strtol(argv[optind], NULL, 10); + carrier.pci = (uint32_t)strtol(argv[optind], NULL, 10); break; case 'n': carrier.nof_prb = (uint32_t)strtol(argv[optind], NULL, 10); diff --git a/lib/src/phy/phch/test/pusch_nr_test.c b/lib/src/phy/phch/test/pusch_nr_test.c index 0d950e3b9..5cde5c4eb 100644 --- a/lib/src/phy/phch/test/pusch_nr_test.c +++ b/lib/src/phy/phch/test/pusch_nr_test.c @@ -29,11 +29,13 @@ #include static srsran_carrier_nr_t carrier = { - 1, // cell_id - 0, // numerology - SRSRAN_MAX_PRB_NR, // nof_prb - 0, // start - 1 // max_mimo_layers + 1, // pci + 0, // absolute_frequency_ssb + 0, // absolute_frequency_point_a + srsran_subcarrier_spacing_15kHz, // scs + SRSRAN_MAX_PRB_NR, // nof_prb + 0, // start + 1 // max_mimo_layers }; static uint32_t n_prb = 0; // Set to 0 for steering @@ -167,7 +169,7 @@ int main(int argc, char** argv) } // Use grant default A time resources with m=0 - if (srsran_ra_ul_nr_pusch_time_resource_default_A(carrier.numerology, 0, &pusch_cfg.grant) < SRSRAN_SUCCESS) { + if (srsran_ra_ul_nr_pusch_time_resource_default_A(carrier.scs, 0, &pusch_cfg.grant) < SRSRAN_SUCCESS) { ERROR("Error loading default grant"); goto clean_exit; } @@ -196,9 +198,11 @@ int main(int argc, char** argv) mcs_end = SRSRAN_MIN(mcs + 1, mcs_end); } - pusch_cfg.scaling = 0.5f; - pusch_cfg.beta_harq_ack_offset = 2.0f; - pusch_cfg.beta_csi_part1_offset = 2.0f; + srsran_sch_hl_cfg_nr_t sch_hl_cfg = {}; + sch_hl_cfg.scaling = 1.0f; + sch_hl_cfg.beta_offsets.fix_ack = 12.625f; + sch_hl_cfg.beta_offsets.fix_csi1 = 2.25f; + sch_hl_cfg.beta_offsets.fix_csi2 = 2.25f; if (srsran_chest_dl_res_init(&chest, carrier.nof_prb) < SRSRAN_SUCCESS) { ERROR("Initiating chest"); @@ -254,6 +258,11 @@ int main(int argc, char** argv) data_rx.uci.csi[0].none = csi_report_rx; } + if (srsran_ra_ul_set_grant_uci_nr(&carrier, &sch_hl_cfg, &pusch_cfg.uci, &pusch_cfg) < SRSRAN_SUCCESS) { + ERROR("Setting UCI"); + goto clean_exit; + } + if (srsran_pusch_nr_encode(&pusch_tx, &pusch_cfg, &pusch_cfg.grant, &data_tx, sf_symbols) < SRSRAN_SUCCESS) { ERROR("Error encoding"); goto clean_exit; @@ -349,6 +358,15 @@ int main(int argc, char** argv) } } + if (srsran_verbose >= SRSRAN_VERBOSE_INFO) { + char str[512]; + srsran_pusch_nr_rx_info(&pusch_rx, &pusch_cfg, &pusch_cfg.grant, &data_rx, str, (uint32_t)sizeof(str)); + + char str_extra[2048]; + srsran_sch_cfg_nr_info(&pusch_cfg, str_extra, (uint32_t)sizeof(str_extra)); + INFO("PUSCH: %s\n%s", str, str_extra); + } + printf("n_prb=%d; mcs=%d; TBS=%d; EVM=%f; PASSED!\n", n_prb, mcs, pusch_cfg.grant.tb[0].tbs, data_rx.evm[0]); } } diff --git a/lib/src/phy/phch/test/sch_nr_test.c b/lib/src/phy/phch/test/sch_nr_test.c index 4ac4ed2c4..c5eb83382 100644 --- a/lib/src/phy/phch/test/sch_nr_test.c +++ b/lib/src/phy/phch/test/sch_nr_test.c @@ -28,11 +28,13 @@ #include static srsran_carrier_nr_t carrier = { - 0, // cell_id - 0, // numerology - SRSRAN_MAX_PRB_NR, // nof_prb - 0, // start - 1 // max_mimo_layers + 1, // pci + 0, // absolute_frequency_ssb + 0, // absolute_frequency_point_a + srsran_subcarrier_spacing_15kHz, // scs + SRSRAN_MAX_PRB_NR, // nof_prb + 0, // start + 1 // max_mimo_layers }; static uint32_t n_prb = 0; // Set to 0 for steering diff --git a/lib/src/phy/phch/uci_nr.c b/lib/src/phy/phch/uci_nr.c index 2c66f5344..319a6daca 100644 --- a/lib/src/phy/phch/uci_nr.c +++ b/lib/src/phy/phch/uci_nr.c @@ -392,16 +392,18 @@ static int uci_nr_decode_1_bit(srsran_uci_nr_t* q, } // Correlate LLR - float corr = 0.0f; - float pwr = 0.0f; + float corr = 0.0f; + float pwr = 0.0f; + uint32_t count = 0; for (uint32_t i = 0; i < E; i += Qm) { float t = (float)llr[i]; corr += t; pwr += t * t; + count++; } // Normalise correlation - float norm_corr = Qm * corr / (E * sqrtf(pwr)); + float norm_corr = fabsf(corr) / sqrtf(pwr * count); // Take decoded decision with threshold *decoded_ok = (norm_corr > q->one_bit_threshold); @@ -995,9 +997,9 @@ uint32_t srsran_uci_nr_info(const srsran_uci_data_nr_t* uci_data, char* str, uin uint32_t len = 0; if (uci_data->cfg.o_ack > 0) { - char str2[10]; - srsran_vec_sprint_bin(str2, 10, uci_data->value.ack, uci_data->cfg.o_ack); - len = srsran_print_check(str, str_len, len, ", ack=%s", str2); + char str_ack[10]; + srsran_vec_sprint_bin(str_ack, (uint32_t)sizeof(str_ack), uci_data->value.ack, uci_data->cfg.o_ack); + len = srsran_print_check(str, str_len, len, "ack=%s ", str_ack); } if (uci_data->cfg.nof_csi > 0) { @@ -1005,7 +1007,7 @@ uint32_t srsran_uci_nr_info(const srsran_uci_data_nr_t* uci_data, char* str, uin } if (uci_data->cfg.o_sr > 0) { - len = srsran_print_check(str, str_len, len, ", sr=%d", uci_data->value.sr); + len = srsran_print_check(str, str_len, len, "sr=%d ", uci_data->value.sr); } return len; diff --git a/lib/src/phy/rf/rf_uhd_generic.h b/lib/src/phy/rf/rf_uhd_generic.h index 57488918c..c78d33bda 100644 --- a/lib/src/phy/rf/rf_uhd_generic.h +++ b/lib/src/phy/rf/rf_uhd_generic.h @@ -33,6 +33,7 @@ private: uhd::stream_args_t stream_args = {}; double lo_freq_tx_hz = 0.0; double lo_freq_rx_hz = 0.0; + double lo_freq_offset_hz = 0.0; uhd_error usrp_make_internal(const uhd::device_addr_t& dev_addr) override { @@ -170,6 +171,20 @@ public: dev_addr.pop("lo_freq_rx_hz"); } + // LO Frequency offset automatic + if (dev_addr.has_key("lo_freq_offset_hz")) { + lo_freq_offset_hz = dev_addr.cast("lo_freq_offset_hz", lo_freq_offset_hz); + dev_addr.pop("lo_freq_offset_hz"); + + if (std::isnormal(lo_freq_tx_hz)) { + Warning("'lo_freq_offset_hz' overrides 'lo_freq_tx_hz' (" << lo_freq_tx_hz / 1e6 << " MHz)"); + } + + if (std::isnormal(lo_freq_rx_hz)) { + Warning("'lo_freq_offset_hz' overrides 'lo_freq_rx_hz' (" << lo_freq_rx_hz / 1e6 << " MHz)"); + } + } + // Make USRP uhd_error err = usrp_multi_make(dev_addr); if (err != UHD_ERROR_NONE) { @@ -348,6 +363,10 @@ public: // Create Tune request uhd::tune_request_t tune_request(target_freq); + if (std::isnormal(lo_freq_offset_hz)) { + lo_freq_tx_hz = target_freq + lo_freq_offset_hz; + } + // If the LO frequency is defined, force a LO frequency and use the if (std::isnormal(lo_freq_tx_hz)) { tune_request.rf_freq = lo_freq_tx_hz; @@ -365,6 +384,10 @@ public: // Create Tune request uhd::tune_request_t tune_request(target_freq); + if (std::isnormal(lo_freq_offset_hz)) { + lo_freq_rx_hz = target_freq + lo_freq_offset_hz; + } + // If the LO frequency is defined, force a LO frequency and use the if (std::isnormal(lo_freq_rx_hz)) { tune_request.rf_freq = lo_freq_rx_hz; diff --git a/lib/src/phy/ue/ue_dl_nr.c b/lib/src/phy/ue/ue_dl_nr.c index 2e0363f94..d84b5137a 100644 --- a/lib/src/phy/ue/ue_dl_nr.c +++ b/lib/src/phy/ue/ue_dl_nr.c @@ -382,7 +382,7 @@ static int ue_dl_nr_find_dci_ss(srsran_ue_dl_nr_t* q, // Calculate possible PDCCH DCI candidates uint32_t candidates[SRSRAN_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR] = {}; int nof_candidates = srsran_pdcch_nr_locations_coreset( - coreset, search_space, rnti, L, SRSRAN_SLOT_NR_MOD(q->carrier.numerology, slot_cfg->idx), candidates); + coreset, search_space, rnti, L, SRSRAN_SLOT_NR_MOD(q->carrier.scs, slot_cfg->idx), candidates); if (nof_candidates < SRSRAN_SUCCESS) { ERROR("Error calculating DCI candidate location"); return SRSRAN_ERROR; diff --git a/lib/src/phy/ue/ue_ul_nr.c b/lib/src/phy/ue/ue_ul_nr.c index 0130f464b..00f75e91c 100644 --- a/lib/src/phy/ue/ue_ul_nr.c +++ b/lib/src/phy/ue/ue_ul_nr.c @@ -132,6 +132,13 @@ int srsran_ue_ul_nr_encode_pusch(srsran_ue_ul_nr_t* q, // Generate signal srsran_ofdm_tx_sf(&q->ifft); + // Normalise to peak + uint32_t max_idx = srsran_vec_max_abs_ci(q->ifft.cfg.out_buffer, q->ifft.sf_sz); + float max_peak = cabsf(q->ifft.cfg.out_buffer[max_idx]); + if (isnormal(max_peak)) { + srsran_vec_sc_prod_cfc(q->ifft.cfg.out_buffer, 0.99f / max_peak, q->ifft.cfg.out_buffer, q->ifft.sf_sz); + } + return SRSRAN_SUCCESS; } diff --git a/lib/src/upper/pdcp.cc b/lib/src/upper/pdcp.cc index 2b56aa381..c43bc5c85 100644 --- a/lib/src/upper/pdcp.cc +++ b/lib/src/upper/pdcp.cc @@ -39,6 +39,15 @@ pdcp::~pdcp() pdcp_array_mrb.clear(); } +void pdcp::init(srsue::rlc_interface_pdcp* rlc_, + srsue::rrc_interface_pdcp* rrc_, + srsue::rrc_interface_pdcp* rrc_nr_, + srsue::gw_interface_pdcp* gw_) +{ + init(rlc_, rrc_, gw_); + rrc_nr = rrc_nr_; +} + void pdcp::init(srsue::rlc_interface_pdcp* rlc_, srsue::rrc_interface_pdcp* rrc_, srsue::gw_interface_pdcp* gw_) { rlc = rlc_; @@ -104,7 +113,16 @@ void pdcp::add_bearer(uint32_t lcid, pdcp_config_t cfg) if (not valid_lcid(lcid)) { std::unique_ptr entity; // For now we create an pdcp entity lte for nr due to it's maturity - entity.reset(new pdcp_entity_lte{rlc, rrc, gw, task_sched, logger, lcid}); + if (cfg.rat == srsran::srsran_rat_t::lte) { + entity.reset(new pdcp_entity_lte{rlc, rrc, gw, task_sched, logger, lcid}); + } else if (cfg.rat == srsran::srsran_rat_t::nr) { + if (rrc_nr == nullptr) { + logger.warning("Cannot add PDCP entity - missing rrc_nr parent pointer"); + return; + } + entity.reset(new pdcp_entity_lte{rlc, rrc_nr, gw, task_sched, logger, lcid}); + } + if (not entity->configure(cfg)) { logger.error("Can not configure PDCP entity"); return; diff --git a/lib/src/upper/pdcp_entity_lte.cc b/lib/src/upper/pdcp_entity_lte.cc index fd73ad056..b98e5faed 100644 --- a/lib/src/upper/pdcp_entity_lte.cc +++ b/lib/src/upper/pdcp_entity_lte.cc @@ -728,7 +728,7 @@ void pdcp_entity_lte::notify_delivery(const pdcp_sn_vector_t& pdcp_sns) } // Find undelivered PDU info if (not undelivered_sdus->has_sdu(sn)) { - logger.warning("Could not find PDU for delivery notification. Notified SN=%d", sn); + logger.info("Could not find PDU for delivery notification. Notified SN=%d", sn); } else { // Metrics auto& sdu = (*undelivered_sdus)[sn]; diff --git a/lib/src/upper/rlc.cc b/lib/src/upper/rlc.cc index 8fd146474..baacddc72 100644 --- a/lib/src/upper/rlc.cc +++ b/lib/src/upper/rlc.cc @@ -54,6 +54,16 @@ rlc::~rlc() pthread_rwlock_destroy(&rwlock); } +void rlc::init(srsue::pdcp_interface_rlc* pdcp_, + srsue::rrc_interface_rlc* rrc_, + srsue::rrc_interface_rlc* rrc_nr_, + srsran::timer_handler* timers_, + uint32_t lcid_) +{ + init(pdcp_, rrc_, timers_, lcid_); + rrc_nr = rrc_nr_; +} + void rlc::init(srsue::pdcp_interface_rlc* pdcp_, srsue::rrc_interface_rlc* rrc_, srsran::timer_handler* timers_, @@ -157,7 +167,7 @@ void rlc::reestablish() void rlc::reestablish(uint32_t lcid) { if (valid_lcid(lcid)) { - logger.info("Reestablishing %s", rrc->get_rb_name(lcid)); + logger.info("Reestablishing LCID %d", lcid); rlc_array.at(lcid)->reestablish(); } else { logger.warning("RLC LCID %d doesn't exist.", lcid); @@ -404,6 +414,12 @@ void rlc::add_bearer(uint32_t lcid, const rlc_config_t& cnfg) rlc_common* rlc_entity = nullptr; + // Check this for later rrc_nr pointer access + if (cnfg.rat == srsran::srsran_rat_t::nr && rrc_nr == nullptr) { + logger.error("Cannot add/modify RLC entity - missing rrc_nr parent pointer for rat type nr"); + return; + } + if (cnfg.rlc_mode != rlc_mode_t::tm and rlc_array.find(lcid) != rlc_array.end()) { if (rlc_array[lcid]->get_mode() != cnfg.rlc_mode) { logger.info("Switching RLC entity type. Recreating it."); @@ -412,46 +428,51 @@ void rlc::add_bearer(uint32_t lcid, const rlc_config_t& cnfg) } if (not valid_lcid(lcid)) { - if (cnfg.rat == srsran_rat_t::lte) { - switch (cnfg.rlc_mode) { - case rlc_mode_t::tm: - rlc_entity = new rlc_tm(logger, lcid, pdcp, rrc); - break; - case rlc_mode_t::am: - rlc_entity = new rlc_am_lte(logger, lcid, pdcp, rrc, timers); - break; - case rlc_mode_t::um: - rlc_entity = new rlc_um_lte(logger, lcid, pdcp, rrc, timers); - break; - default: - logger.error("Cannot add RLC entity - invalid mode"); - return; - } - if (rlc_entity != nullptr) { - rlc_entity->set_bsr_callback(bsr_callback); - } - } else if (cnfg.rat == srsran_rat_t::nr) { - switch (cnfg.rlc_mode) { - case rlc_mode_t::tm: - rlc_entity = new rlc_tm(logger, lcid, pdcp, rrc); - break; - case rlc_mode_t::um: - rlc_entity = new rlc_um_nr(logger, lcid, pdcp, rrc, timers); - break; - default: - logger.error("Cannot add RLC entity - invalid mode"); - return; - } - } else { - logger.error("RAT not supported"); - return; + switch (cnfg.rat) { + case srsran_rat_t::lte: + switch (cnfg.rlc_mode) { + case rlc_mode_t::tm: + rlc_entity = new rlc_tm(logger, lcid, pdcp, rrc); + break; + case rlc_mode_t::am: + rlc_entity = new rlc_am_lte(logger, lcid, pdcp, rrc, timers); + break; + case rlc_mode_t::um: + rlc_entity = new rlc_um_lte(logger, lcid, pdcp, rrc, timers); + break; + default: + logger.error("Cannot add RLC entity - invalid mode"); + return; + } + if (rlc_entity != nullptr) { + rlc_entity->set_bsr_callback(bsr_callback); + } + break; + case srsran_rat_t::nr: + switch (cnfg.rlc_mode) { + case rlc_mode_t::tm: + rlc_entity = new rlc_tm(logger, lcid, pdcp, rrc_nr); + break; + case rlc_mode_t::um: + rlc_entity = new rlc_um_nr(logger, lcid, pdcp, rrc_nr, timers); + break; + default: + logger.error("Cannot add RLC entity - invalid mode"); + return; + } + break; + default: + logger.error("RAT not supported"); + return; } if (not rlc_array.insert(rlc_map_pair_t(lcid, rlc_entity)).second) { logger.error("Error inserting RLC entity in to array."); goto delete_and_exit; } - logger.info("Added radio bearer %s in %s", rrc->get_rb_name(lcid), to_string(cnfg.rlc_mode).c_str()); + + logger.info( + "Added %s radio bearer with LCID %d in %s", to_string(cnfg.rat), lcid, to_string(cnfg.rlc_mode).c_str()); rlc_entity = NULL; } @@ -463,7 +484,8 @@ void rlc::add_bearer(uint32_t lcid, const rlc_config_t& cnfg) } } - logger.info("Configured radio bearer %s in %s", rrc->get_rb_name(lcid), to_string(cnfg.rlc_mode).c_str()); + logger.info( + "Configured %s radio bearer with LCID %d in %s", to_string(cnfg.rat), lcid, to_string(cnfg.rlc_mode).c_str()); delete_and_exit: if (rlc_entity) { @@ -510,9 +532,9 @@ void rlc::del_bearer(uint32_t lcid) it->second->stop(); delete (it->second); rlc_array.erase(it); - logger.warning("Deleted RLC bearer %s", rrc->get_rb_name(lcid)); + logger.info("Deleted RLC bearer with LCID %d", lcid); } else { - logger.error("Can't delete bearer %s. Bearer doesn't exist.", rrc->get_rb_name(lcid)); + logger.error("Can't delete bearer with LCID %d. Bearer doesn't exist.", lcid); } } @@ -525,9 +547,9 @@ void rlc::del_bearer_mrb(uint32_t lcid) it->second->stop(); delete (it->second); rlc_array_mrb.erase(it); - logger.warning("Deleted RLC MRB bearer %s", rrc->get_rb_name(lcid)); + logger.warning("Deleted RLC MRB bearer with LCID %d", lcid); } else { - logger.error("Can't delete bearer %s. Bearer doesn't exist.", rrc->get_rb_name(lcid)); + logger.error("Can't delete bearer with LCID %d. Bearer doesn't exist.", lcid); } } @@ -553,8 +575,7 @@ void rlc::change_lcid(uint32_t old_lcid, uint32_t new_lcid) logger.error("Error during LCID change of RLC bearer from %d to %d", old_lcid, new_lcid); } } else { - logger.error("Can't change LCID of bearer %s from %d to %d. Bearer doesn't exist or new LCID already occupied.", - rrc->get_rb_name(old_lcid), + logger.error("Can't change LCID of bearer LCID %d to %d. Bearer doesn't exist or new LCID already occupied.", old_lcid, new_lcid); } @@ -565,26 +586,26 @@ void rlc::suspend_bearer(uint32_t lcid) { if (valid_lcid(lcid)) { if (rlc_array.at(lcid)->suspend()) { - logger.info("Suspended radio bearer %s", rrc->get_rb_name(lcid)); + logger.info("Suspended radio bearer with LCID %d", lcid); } else { logger.error("Error suspending RLC entity: bearer already suspended."); } } else { - logger.error("Suspending bearer: bearer %s not configured.", rrc->get_rb_name(lcid)); + logger.error("Suspending bearer: bearer with LCID %d not configured.", lcid); } } void rlc::resume_bearer(uint32_t lcid) { - logger.info("Resuming radio bearer %s", rrc->get_rb_name(lcid)); + logger.info("Resuming radio LCID %d", lcid); if (valid_lcid(lcid)) { if (rlc_array.at(lcid)->resume()) { - logger.info("Resumed radio bearer %s", rrc->get_rb_name(lcid)); + logger.info("Resumed radio LCID %d", lcid); } else { logger.error("Error resuming RLC entity: bearer not suspended."); } } else { - logger.error("Resuming bearer: bearer %s not configured.", rrc->get_rb_name(lcid)); + logger.error("Resuming bearer: bearer with LCID %d not configured.", lcid); } } diff --git a/lib/src/upper/rlc_am_lte.cc b/lib/src/upper/rlc_am_lte.cc index 0e31db352..72f2efd14 100644 --- a/lib/src/upper/rlc_am_lte.cc +++ b/lib/src/upper/rlc_am_lte.cc @@ -66,6 +66,70 @@ void log_rlc_am_status_pdu_to_string(srslog::log_channel& log_ch, log_ch(fmt_str, std::forward(args)..., to_c_str(buffer)); } +/******************************* + * RLC AM Segments + ******************************/ + +int rlc_am_pdu_segment_pool::segment_resource::id() const +{ + return std::distance(parent_pool->segments.cbegin(), this); +} + +void rlc_am_pdu_segment_pool::segment_resource::release_pdcp_sn() +{ + pdcp_sn_ = invalid_pdcp_sn; + if (empty()) { + parent_pool->free_list.push_front(this); + } +} + +void rlc_am_pdu_segment_pool::segment_resource::release_rlc_sn() +{ + rlc_sn_ = invalid_rlc_sn; + if (empty()) { + parent_pool->free_list.push_front(this); + } +} + +rlc_am_pdu_segment_pool::rlc_am_pdu_segment_pool() +{ + for (segment_resource& s : segments) { + s.parent_pool = this; + free_list.push_front(&s); + } +} + +bool rlc_am_pdu_segment_pool::make_segment(rlc_amd_tx_pdu& rlc_list, pdcp_pdu_info& pdcp_list) +{ + if (not has_segments()) { + return false; + } + segment_resource* segment = free_list.pop_front(); + segment->rlc_sn_ = rlc_list.rlc_sn; + segment->pdcp_sn_ = pdcp_list.sn; + rlc_list.add_segment(*segment); + pdcp_list.add_segment(*segment); + return true; +} + +void pdcp_pdu_info::ack_segment(rlc_am_pdu_segment& segment) +{ + // remove from list + list.pop(&segment); + // signal pool that the pdcp handle is released + segment.release_pdcp_sn(); +} + +rlc_amd_tx_pdu::~rlc_amd_tx_pdu() +{ + while (not list.empty()) { + // remove from list + rlc_am_pdu_segment* segment = list.pop_front(); + // deallocate if also removed from PDCP + segment->release_rlc_sn(); + } +} + /******************************* * rlc_am_lte class ******************************/ @@ -325,7 +389,7 @@ bool rlc_am_lte::rlc_am_lte_tx::has_data() { return (((do_status() && not status_prohibit_timer.is_running())) || // if we have a status PDU to transmit (not retx_queue.empty()) || // if we have a retransmission - (tx_sdu != NULL) || // if we are currently transmitting a SDU + (tx_sdu != nullptr) || // if we are currently transmitting a SDU (tx_sdu_queue.get_n_sdus() != 0)); // or if there is a SDU queued up for transmission } @@ -341,9 +405,13 @@ bool rlc_am_lte::rlc_am_lte_tx::has_data() void rlc_am_lte::rlc_am_lte_tx::check_sn_reached_max_retx(uint32_t sn) { if (tx_window[sn].retx_count == cfg.max_retx_thresh) { - logger.warning("%s Signaling max number of reTx=%d for for SN=%d", RB_NAME, tx_window[sn].retx_count, sn); + logger.warning("%s Signaling max number of reTx=%d for SN=%d", RB_NAME, tx_window[sn].retx_count, sn); parent->rrc->max_retx_attempted(); - parent->pdcp->notify_failure(parent->lcid, tx_window[sn].pdcp_sns); + srsran::pdcp_sn_vector_t pdcp_sns; + for (const rlc_am_pdu_segment& segment : tx_window[sn]) { + pdcp_sns.push_back(segment.pdcp_sn()); + } + parent->pdcp->notify_failure(parent->lcid, pdcp_sns); parent->metrics.num_lost_pdus++; } } @@ -560,7 +628,7 @@ void rlc_am_lte::rlc_am_lte_tx::retransmit_pdu() } // select first PDU in tx window for retransmission - rlc_amd_tx_pdu_t& pdu = tx_window[vt_a]; + rlc_amd_tx_pdu& pdu = tx_window[vt_a]; logger.info("%s Schedule SN=%d for reTx.", RB_NAME, pdu.rlc_sn); rlc_amd_retx_t& retx = retx_queue.push(); retx.is_segment = false; @@ -921,7 +989,7 @@ int rlc_am_lte::rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_byt srsran::console("tx_window size: %zd PDUs\n", tx_window.size()); srsran::console("vt_a = %d, vt_ms = %d, vt_s = %d, poll_sn = %d\n", vt_a, vt_ms, vt_s, poll_sn); srsran::console("retx_queue size: %zd PDUs\n", retx_queue.size()); - std::map::iterator txit; + std::map::iterator txit; for (txit = tx_window.begin(); txit != tx_window.end(); txit++) { srsran::console("tx_window - SN=%d\n", txit->first); } @@ -936,10 +1004,14 @@ int rlc_am_lte::rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_byt header.fi = RLC_FI_FIELD_START_AND_END_ALIGNED; header.sn = vt_s; + if (not segment_pool.has_segments()) { + logger.info("Can't build a PDU - No segments available"); + return 0; + } + // insert newly assigned SN into window and use reference for in-place operations // NOTE: from now on, we can't return from this function anymore before increasing vt_s - rlc_amd_tx_pdu_t& tx_pdu = tx_window.add_pdu(header.sn); - tx_pdu.pdcp_sns.clear(); + rlc_amd_tx_pdu& tx_pdu = tx_window.add_pdu(header.sn); uint32_t head_len = rlc_am_packed_length(&header); uint32_t to_move = 0; @@ -959,15 +1031,10 @@ int rlc_am_lte::rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_byt tx_sdu->N_bytes -= to_move; tx_sdu->msg += to_move; if (undelivered_sdu_info_queue.has_pdcp_sn(tx_sdu->md.pdcp_sn)) { - pdcp_sdu_info_t& pdcp_sdu = undelivered_sdu_info_queue[tx_sdu->md.pdcp_sn]; - pdcp_sdu.rlc_sn_info_list.push_back({header.sn, false}); - if (not tx_pdu.pdcp_sns.full()) { - tx_pdu.pdcp_sns.push_back(tx_sdu->md.pdcp_sn); - } else { - logger.warning("Cant't store PDCP_SN=%d for delivery notification.", tx_sdu->md.pdcp_sn); - } + pdcp_pdu_info& pdcp_pdu = undelivered_sdu_info_queue[tx_sdu->md.pdcp_sn]; + segment_pool.make_segment(tx_pdu, pdcp_pdu); if (tx_sdu->N_bytes == 0) { - pdcp_sdu.fully_txed = true; + pdcp_pdu.fully_txed = true; } } else { // PDCP SNs for the RLC SDU has been removed from the queue @@ -996,6 +1063,14 @@ int rlc_am_lte::rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_byt // Pull SDUs from queue while (pdu_space > head_len && tx_sdu_queue.get_n_sdus() > 0 && header.N_li < RLC_AM_WINDOW_SIZE) { + if (not segment_pool.has_segments()) { + logger.info("Can't build a PDU segment - No segment resources available"); + if (pdu_ptr != pdu->msg) { + break; // continue with the segments created up to this point + } + tx_window.remove_pdu(tx_pdu.rlc_sn); + return 0; + } if (last_li > 0) { header.li[header.N_li] = last_li; header.N_li++; @@ -1027,15 +1102,10 @@ int rlc_am_lte::rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_byt tx_sdu->N_bytes -= to_move; tx_sdu->msg += to_move; if (undelivered_sdu_info_queue.has_pdcp_sn(tx_sdu->md.pdcp_sn)) { - pdcp_sdu_info_t& pdcp_sdu = undelivered_sdu_info_queue[tx_sdu->md.pdcp_sn]; - pdcp_sdu.rlc_sn_info_list.push_back({header.sn, false}); - if (not tx_pdu.pdcp_sns.full()) { - tx_pdu.pdcp_sns.push_back(tx_sdu->md.pdcp_sn); - } else { - logger.warning("Cant't store PDCP_SN=%d for delivery notification.", tx_sdu->md.pdcp_sn); - } + pdcp_pdu_info& pdcp_pdu = undelivered_sdu_info_queue[tx_sdu->md.pdcp_sn]; + segment_pool.make_segment(tx_pdu, pdcp_pdu); if (tx_sdu->N_bytes == 0) { - pdcp_sdu.fully_txed = true; + pdcp_pdu.fully_txed = true; } } else { // PDCP SNs for the RLC SDU has been removed from the queue @@ -1090,9 +1160,6 @@ int rlc_am_lte::rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_byt // Write final header and TX tx_pdu.buf = std::move(pdu); tx_pdu.header = header; - tx_pdu.is_acked = false; - tx_pdu.retx_count = 0; - tx_pdu.rlc_sn = header.sn; const byte_buffer_t* buffer_ptr = tx_pdu.buf.get(); uint8_t* ptr = payload; @@ -1193,8 +1260,8 @@ void rlc_am_lte::rlc_am_lte_tx::handle_control_pdu(uint8_t* payload, uint32_t no if (!nack) { // ACKed SNs get marked and removed from tx_window so PDCP get's only notified once if (tx_window.has_sn(i)) { - auto& pdu = tx_window[i]; - update_notification_ack_info(pdu); + update_notification_ack_info(i); + logger.debug("Tx PDU SN=%zd being removed from tx window", i); tx_window.remove_pdu(i); } // Advance window if possible @@ -1211,17 +1278,6 @@ void rlc_am_lte::rlc_am_lte_tx::handle_control_pdu(uint8_t* payload, uint32_t no logger.error("%s vt_a=%d points to invalid position in Tx window", RB_NAME, vt_a); } - if (not notify_info_vec.empty()) { - // Remove all SDUs that were fully acked - for (uint32_t acked_pdcp_sn : notify_info_vec) { - logger.debug("Erasing SDU info: PDCP_SN=%d", acked_pdcp_sn); - if (not undelivered_sdu_info_queue.has_pdcp_sn(acked_pdcp_sn)) { - logger.error("Could not find info to erase: SN=%d", acked_pdcp_sn); - } - undelivered_sdu_info_queue.clear_pdcp_sdu(acked_pdcp_sn); - } - } - debug_state(); lock.unlock(); @@ -1238,42 +1294,37 @@ void rlc_am_lte::rlc_am_lte_tx::handle_control_pdu(uint8_t* payload, uint32_t no * @tx_pdu: RLC PDU that was ack'ed. * @notify_info_vec: Vector which will keep track of the PDCP PDU SNs that have been fully ack'ed. */ -void rlc_am_lte::rlc_am_lte_tx::update_notification_ack_info(const rlc_amd_tx_pdu_t& tx_pdu) +void rlc_am_lte::rlc_am_lte_tx::update_notification_ack_info(uint32_t rlc_sn) { logger.debug("Updating ACK info: RLC SN=%d, number of notified SDU=%ld, number of undelivered SDUs=%ld", - tx_pdu.header.sn, + rlc_sn, notify_info_vec.size(), undelivered_sdu_info_queue.nof_sdus()); // Iterate over all undelivered SDUs - if (not tx_window.has_sn(tx_pdu.header.sn)) { + if (not tx_window.has_sn(rlc_sn)) { return; } - pdcp_sn_vector_t& pdcp_sns = tx_window[tx_pdu.header.sn].pdcp_sns; - for (uint32_t pdcp_sn : pdcp_sns) { - // Iterate over all SNs that were TX'ed - auto& info = undelivered_sdu_info_queue[pdcp_sn]; - for (auto& rlc_sn_info : info.rlc_sn_info_list) { - // Mark this SN as acked, if necessary - if (rlc_sn_info.is_acked == false && rlc_sn_info.sn == tx_pdu.header.sn) { - rlc_sn_info.is_acked = true; - } - } - // Check wether the SDU was fully acked - if (info.fully_txed and not info.fully_acked) { + auto& acked_pdu = tx_window[rlc_sn]; + // Iterate over all PDCP SNs of the same RLC PDU that were TX'ed + for (rlc_am_pdu_segment& acked_segment : acked_pdu) { + uint32_t pdcp_sn = acked_segment.pdcp_sn(); + pdcp_pdu_info& info = undelivered_sdu_info_queue[pdcp_sn]; + + // Remove RLC SN from PDCP PDU undelivered list + info.ack_segment(acked_segment); + + // Check whether the SDU was fully acked + if (info.fully_acked()) { // Check if all SNs were ACK'ed - info.fully_acked = std::all_of(info.rlc_sn_info_list.begin(), - info.rlc_sn_info_list.end(), - [](rlc_sn_info_t rlc_sn_info) { return rlc_sn_info.is_acked; }); - if (info.fully_acked) { - if (not notify_info_vec.full()) { - notify_info_vec.push_back(pdcp_sn); - } else { - logger.warning("Can't notify delivery of PDCP_SN=%d.", pdcp_sn); - } + if (not notify_info_vec.full()) { + notify_info_vec.push_back(pdcp_sn); + } else { + logger.warning("Can't notify delivery of PDCP_SN=%d.", pdcp_sn); } + logger.debug("Erasing SDU info: PDCP_SN=%d", pdcp_sn); + undelivered_sdu_info_queue.clear_pdcp_sdu(pdcp_sn); } } - pdcp_sns.clear(); } void rlc_am_lte::rlc_am_lte_tx::debug_state() @@ -1425,7 +1476,7 @@ void rlc_am_lte::rlc_am_lte_rx::stop() */ void rlc_am_lte::rlc_am_lte_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_bytes, rlc_amd_pdu_header_t& header) { - std::map::iterator it; + std::map::iterator it; logger.info(payload, nof_bytes, "%s Rx data PDU SN=%d (%d B)", RB_NAME, header.sn, nof_bytes); log_rlc_amd_pdu_header_to_string(logger.debug, header); @@ -1461,8 +1512,8 @@ void rlc_am_lte::rlc_am_lte_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_b } // Write to rx window - rlc_amd_rx_pdu_t& pdu = rx_window.add_pdu(header.sn); - pdu.buf = srsran::make_byte_buffer(); + rlc_amd_rx_pdu& pdu = rx_window.add_pdu(header.sn); + pdu.buf = srsran::make_byte_buffer(); if (pdu.buf == NULL) { #ifdef RLC_AM_BUFFER_DEBUG srsran::console("Fatal Error: Couldn't allocate PDU in handle_data_pdu().\n"); @@ -1566,7 +1617,7 @@ void rlc_am_lte::rlc_am_lte_rx::handle_data_pdu_segment(uint8_t* pa return; } - rlc_amd_rx_pdu_t segment; + rlc_amd_rx_pdu segment; segment.buf = srsran::make_byte_buffer(); if (segment.buf == NULL) { #ifdef RLC_AM_BUFFER_DEBUG @@ -1759,7 +1810,7 @@ void rlc_am_lte::rlc_am_lte_rx::reassemble_rx_sdus() it = rx_segments.find(vr_r); if (rx_segments.end() != it) { logger.debug("Erasing segments of SN=%d", vr_r); - std::list::iterator segit; + std::list::iterator segit; for (segit = it->second.segments.begin(); segit != it->second.segments.end(); ++segit) { logger.debug(" Erasing segment of SN=%d SO=%d Len=%d N_li=%d", segit->header.sn, @@ -1921,7 +1972,7 @@ void rlc_am_lte::rlc_am_lte_rx::print_rx_segments() std::stringstream ss; ss << "rx_segments:" << std::endl; for (it = rx_segments.begin(); it != rx_segments.end(); it++) { - std::list::iterator segit; + std::list::iterator segit; for (segit = it->second.segments.begin(); segit != it->second.segments.end(); segit++) { ss << " SN=" << segit->header.sn << " SO:" << segit->header.so << " N:" << segit->buf->N_bytes << " N_li: " << segit->header.N_li << std::endl; @@ -1931,7 +1982,7 @@ void rlc_am_lte::rlc_am_lte_rx::print_rx_segments() } // NOTE: Preference would be to capture by value, and then move; but header is stack allocated -bool rlc_am_lte::rlc_am_lte_rx::add_segment_and_check(rlc_amd_rx_pdu_segments_t* pdu, rlc_amd_rx_pdu_t* segment) +bool rlc_am_lte::rlc_am_lte_rx::add_segment_and_check(rlc_amd_rx_pdu_segments_t* pdu, rlc_amd_rx_pdu* segment) { // Find segment insertion point in the list of segments auto it1 = pdu->segments.begin(); @@ -1943,7 +1994,7 @@ bool rlc_am_lte::rlc_am_lte_rx::add_segment_and_check(rlc_amd_rx_pdu_segments_t* // Check if the insertion point was found if (it1 != pdu->segments.end()) { // Found insertion point - rlc_amd_rx_pdu_t& s = *it1; + rlc_amd_rx_pdu& s = *it1; if (s.header.so == segment->header.so) { // Same Segment offset if (segment->buf->N_bytes > s.buf->N_bytes) { @@ -1961,8 +2012,8 @@ bool rlc_am_lte::rlc_am_lte_rx::add_segment_and_check(rlc_amd_rx_pdu_segments_t* } // Check for complete - uint32_t so = 0; - std::list::iterator it, tmpit; + uint32_t so = 0; + std::list::iterator it, tmpit; for (it = pdu->segments.begin(); it != pdu->segments.end(); /* Do not increment */) { // Check that there is no gap between last segment and current; overlap allowed if (so < it->header.so) { @@ -2125,24 +2176,16 @@ void rlc_am_lte::rlc_am_lte_rx::debug_state() logger.debug("%s vr_r = %d, vr_mr = %d, vr_x = %d, vr_ms = %d, vr_h = %d", RB_NAME, vr_r, vr_mr, vr_x, vr_ms, vr_h); } -const size_t buffered_pdcp_pdu_list::max_buffer_idx; - -buffered_pdcp_pdu_list::buffered_pdcp_pdu_list() : buffered_pdus(max_buffer_idx + 1) +buffered_pdcp_pdu_list::buffered_pdcp_pdu_list() : buffered_pdus(buffered_pdcp_pdu_list::buffer_size) { - for (size_t i = 0; i < buffered_pdus.size(); ++i) { - buffered_pdus[i].rlc_sn_info_list.reserve(5); - } clear(); } void buffered_pdcp_pdu_list::clear() { count = 0; - for (auto& b : buffered_pdus) { - b.sn = invalid_sn; - b.fully_acked = false; - b.fully_txed = false; - b.rlc_sn_info_list.clear(); + for (pdcp_pdu_info& b : buffered_pdus) { + b.clear(); } } @@ -2402,26 +2445,16 @@ bool rlc_am_is_pdu_segment(uint8_t* payload) return ((*(payload) >> 6) & 0x01) == 1; } -std::string rlc_am_undelivered_sdu_info_to_string(const std::map& info_queue) +void rlc_am_undelivered_sdu_info_to_string(fmt::memory_buffer& buffer, const std::vector& info_queue) { - std::string str = "\n"; - for (const auto& info_it : info_queue) { - uint32_t pdcp_sn = info_it.first; - auto info = info_it.second; - std::string tmp_str = fmt::format("\tPDCP_SN = {}, RLC_SNs = [", pdcp_sn); - for (auto rlc_sn_info : info.rlc_sn_info_list) { - std::string tmp_str2; - if (rlc_sn_info.is_acked) { - tmp_str2 = fmt::format("ACK={}, ", rlc_sn_info.sn); - } else { - tmp_str2 = fmt::format("NACK={}, ", rlc_sn_info.sn); - } - tmp_str += tmp_str2; + fmt::format_to(buffer, "\n"); + for (const auto& pdcp_pdu : info_queue) { + fmt::format_to(buffer, "\tPDCP_SN = {}, undelivered RLC SNs = [", pdcp_pdu.sn); + for (const auto& nacked_segment : pdcp_pdu) { + fmt::format_to(buffer, "{} ", nacked_segment.rlc_sn()); } - tmp_str += "]\n"; - str += tmp_str; + fmt::format_to(buffer, "]\n"); } - return str; } void log_rlc_amd_pdu_header_to_string(srslog::log_channel& log_ch, const rlc_amd_pdu_header_t& header) diff --git a/lib/src/upper/rlc_tm.cc b/lib/src/upper/rlc_tm.cc index 6ab1e7a50..18353bfb0 100644 --- a/lib/src/upper/rlc_tm.cc +++ b/lib/src/upper/rlc_tm.cc @@ -20,7 +20,7 @@ */ #include "srsran/upper/rlc_tm.h" -#include "srsran/common/lte_common.h" +#include "srsran/common/common_lte.h" #include "srsran/interfaces/ue_pdcp_interfaces.h" #include "srsran/interfaces/ue_rrc_interfaces.h" diff --git a/lib/src/upper/rlc_um_nr.cc b/lib/src/upper/rlc_um_nr.cc index 9d24f027c..8470e53ca 100644 --- a/lib/src/upper/rlc_um_nr.cc +++ b/lib/src/upper/rlc_um_nr.cc @@ -165,10 +165,10 @@ int rlc_um_nr::rlc_um_nr_tx::build_data_pdu(unique_byte_buffer_t pdu, uint8_t* p // Calculate actual header length uint32_t head_len = rlc_um_nr_packed_length(header); if (pdu_space <= head_len + 1) { - logger.warning("%s Cannot build a PDU - %d bytes available, %d bytes required for header", - rb_name.c_str(), - nof_bytes, - head_len); + logger.info("%s Cannot build a PDU - %d bytes available, %d bytes required for header", + rb_name.c_str(), + nof_bytes, + head_len); return 0; } @@ -296,7 +296,7 @@ void rlc_um_nr::rlc_um_nr_rx::timer_expired(uint32_t timeout_id) if (reassembly_timer.id() == timeout_id) { logger.info("%s reassembly timeout expiry - updating RX_Next_Reassembly and reassembling", rb_name.c_str()); - logger.warning("Lost PDU SN: %d", RX_Next_Reassembly); + logger.info("Lost PDU SN=%d", RX_Next_Reassembly); metrics.num_lost_pdus++; if (rx_sdu != nullptr) { @@ -350,8 +350,8 @@ unique_byte_buffer_t rlc_um_nr::rlc_um_nr_rx::rlc_um_nr_strip_pdu_header(const r const uint32_t nof_bytes) { unique_byte_buffer_t sdu = make_byte_buffer(); - if (!sdu) { - logger.error("Discarting packet: no space in buffer pool"); + if (sdu == nullptr) { + logger.error("Couldn't allocate PDU in %s().", __FUNCTION__); return nullptr; } memcpy(sdu->msg, payload, nof_bytes); diff --git a/lib/test/adt/bounded_bitset_test.cc b/lib/test/adt/bounded_bitset_test.cc index 0507bd6f3..8010637fd 100644 --- a/lib/test/adt/bounded_bitset_test.cc +++ b/lib/test/adt/bounded_bitset_test.cc @@ -22,6 +22,39 @@ #include "srsran/adt/bounded_bitset.h" #include "srsran/common/test_common.h" +void test_bit_operations() +{ + TESTASSERT(0 == srsran::mask_lsb_ones(0)); + TESTASSERT(0 == srsran::mask_msb_ones(0)); + TESTASSERT(0 == srsran::mask_lsb_ones(0)); + TESTASSERT(0 == srsran::mask_msb_ones(0)); + TESTASSERT(0b11111111 == srsran::mask_lsb_zeros(0)); + TESTASSERT(0b11111111 == srsran::mask_msb_zeros(0)); + TESTASSERT((uint32_t)-1 == srsran::mask_lsb_zeros(0)); + TESTASSERT((uint32_t)-1 == srsran::mask_msb_zeros(0)); + + TESTASSERT(0b11 == srsran::mask_lsb_ones(2)); + TESTASSERT(0b11000000 == srsran::mask_msb_ones(2)); + TESTASSERT(0b11111100 == srsran::mask_lsb_zeros(2)); + TESTASSERT(0b00111111 == srsran::mask_msb_zeros(2)); + + TESTASSERT(0b11111111 == srsran::mask_lsb_ones(8)); + TESTASSERT(0b1111 == srsran::mask_lsb_ones(4)); + + TESTASSERT(srsran::find_first_lsb_one(0) == std::numeric_limits::digits); + TESTASSERT(srsran::find_first_msb_one(0) == std::numeric_limits::digits); + TESTASSERT(srsran::find_first_lsb_one(1) == 0); + TESTASSERT(srsran::find_first_msb_one(1) == 0); + TESTASSERT(srsran::find_first_lsb_one(0b11) == 0); + TESTASSERT(srsran::find_first_lsb_one(0b10) == 1); + TESTASSERT(srsran::find_first_msb_one(0b11) == 1); + TESTASSERT(srsran::find_first_msb_one(0b10) == 1); + TESTASSERT(srsran::find_first_lsb_one(0b11) == 0); + TESTASSERT(srsran::find_first_lsb_one(0b10) == 1); + TESTASSERT(srsran::find_first_msb_one(0b11) == 1); + TESTASSERT(srsran::find_first_msb_one(0b10) == 1); +} + int test_zero_bitset() { srsran::bounded_bitset<25> mask; @@ -185,14 +218,77 @@ int test_bitset_resize() return SRSRAN_SUCCESS; } +template +void test_bitset_find() +{ + { + srsran::bounded_bitset<25, reversed> bitset(6); + + // 0b000000 + TESTASSERT(bitset.find_lowest(0, bitset.size(), false) == 0); + TESTASSERT(bitset.find_lowest(0, bitset.size(), true) == -1); + + // 0b000100 + bitset.set(2); + TESTASSERT(bitset.find_lowest(0, 6) == 2); + TESTASSERT(bitset.find_lowest(0, 6, false) == 0); + TESTASSERT(bitset.find_lowest(3, 6) == -1); + TESTASSERT(bitset.find_lowest(3, 6, false) == 3); + + // 0b000101 + bitset.set(0); + TESTASSERT(bitset.find_lowest(0, 6) == 0); + TESTASSERT(bitset.find_lowest(0, 6, false) == 1); + TESTASSERT(bitset.find_lowest(3, 6) == -1); + TESTASSERT(bitset.find_lowest(3, 6, false) == 3); + + // 0b100101 + bitset.set(5); + TESTASSERT(bitset.find_lowest(0, 6) == 0); + TESTASSERT(bitset.find_lowest(0, 6, false) == 1); + TESTASSERT(bitset.find_lowest(3, 6) == 5); + + // 0b111111 + bitset.fill(0, 6); + TESTASSERT(bitset.find_lowest(0, 6) == 0); + TESTASSERT(bitset.find_lowest(0, 6, false) == -1); + TESTASSERT(bitset.find_lowest(3, 6, false) == -1); + } + { + srsran::bounded_bitset<100, reversed> bitset(95); + + // 0b0...0 + TESTASSERT(bitset.find_lowest(0, bitset.size()) == -1); + + // 0b1000... + bitset.set(94); + TESTASSERT(bitset.find_lowest(0, 93) == -1); + TESTASSERT(bitset.find_lowest(0, bitset.size()) == 94); + + // 0b1000...010 + bitset.set(1); + TESTASSERT(bitset.find_lowest(0, bitset.size()) == 1); + TESTASSERT(bitset.find_lowest(1, bitset.size()) == 1); + TESTASSERT(bitset.find_lowest(2, bitset.size()) == 94); + + // 0b11..11 + bitset.fill(0, bitset.size()); + TESTASSERT(bitset.find_lowest(0, bitset.size()) == 0); + TESTASSERT(bitset.find_lowest(5, bitset.size()) == 5); + } +} + int main() { + test_bit_operations(); TESTASSERT(test_zero_bitset() == SRSRAN_SUCCESS); TESTASSERT(test_ones_bitset() == SRSRAN_SUCCESS); TESTASSERT(test_bitset_set() == SRSRAN_SUCCESS); TESTASSERT(test_bitset_bitwise_oper() == SRSRAN_SUCCESS); TESTASSERT(test_bitset_print() == SRSRAN_SUCCESS); TESTASSERT(test_bitset_resize() == SRSRAN_SUCCESS); + test_bitset_find(); + test_bitset_find(); printf("Success\n"); return 0; } diff --git a/lib/test/asn1/rrc_nr_utils_test.cc b/lib/test/asn1/rrc_nr_utils_test.cc index a1bab9c1c..895d96c1b 100644 --- a/lib/test/asn1/rrc_nr_utils_test.cc +++ b/lib/test/asn1/rrc_nr_utils_test.cc @@ -135,7 +135,7 @@ int make_phy_coreset_cfg_test() srsran_coreset_t srsran_coreset; TESTASSERT(make_phy_coreset_cfg(ctrl_res_set, &srsran_coreset) == true); - TESTASSERT(srsran_coreset.coreset_id == 1); + TESTASSERT(srsran_coreset.id == 1); TESTASSERT(srsran_coreset.precoder_granularity == srsran_coreset_precoder_granularity_reg_bundle); TESTASSERT(srsran_coreset.duration == 1); TESTASSERT(srsran_coreset.mapping_type == srsran_coreset_mapping_type_non_interleaved); @@ -555,6 +555,127 @@ int make_phy_pusch_scaling_test() return SRSRAN_SUCCESS; } +int make_phy_zp_csi_rs_resource_test() +{ + srsran_csi_rs_zp_resource_t zp_csi_rs_resource0 = {}; + // Item 0 + // ZP-CSI-RS-Resource + // zp-CSI-RS-ResourceId: 0 + // resourceMapping + // frequencyDomainAllocation: row4 (2) + // row4: 80 [bit length 3, 5 LSB pad bits, 100. .... + // decimal value 4] + // nrofPorts: p4 (2) + // firstOFDMSymbolInTimeDomain: 8 + // cdm-Type: fd-CDM2 (1) + // density: one (1) + // one: NULL + // freqBand + // startingRB: 0 + // nrofRBs: 52 + // periodicityAndOffset: slots80 (9) + // slots80: 1 + + asn1::rrc_nr::zp_csi_rs_res_s zp_csi_rs_res0; + zp_csi_rs_res0.res_map.freq_domain_alloc.set_row4(); + zp_csi_rs_res0.res_map.freq_domain_alloc.row4().from_string("100"); + zp_csi_rs_res0.res_map.nrof_ports = csi_rs_res_map_s::nrof_ports_opts::options::p4; + zp_csi_rs_res0.res_map.first_ofdm_symbol_in_time_domain = 8; + zp_csi_rs_res0.res_map.cdm_type = csi_rs_res_map_s::cdm_type_opts::options::fd_cdm2; + zp_csi_rs_res0.res_map.density.set_one(); + zp_csi_rs_res0.res_map.freq_band.start_rb = 0; + zp_csi_rs_res0.res_map.freq_band.nrof_rbs = 52; + zp_csi_rs_res0.periodicity_and_offset_present = true; + zp_csi_rs_res0.periodicity_and_offset.set_slots80() = 1; + + TESTASSERT(make_phy_zp_csi_rs_resource(zp_csi_rs_res0, &zp_csi_rs_resource0) == true); + + TESTASSERT(zp_csi_rs_resource0.resource_mapping.row == srsran_csi_rs_resource_mapping_row_4); + TESTASSERT(zp_csi_rs_resource0.resource_mapping.frequency_domain_alloc[0] == true); + TESTASSERT(zp_csi_rs_resource0.resource_mapping.frequency_domain_alloc[1] == false); + TESTASSERT(zp_csi_rs_resource0.resource_mapping.frequency_domain_alloc[2] == false); + TESTASSERT(zp_csi_rs_resource0.resource_mapping.nof_ports == 4); + TESTASSERT(zp_csi_rs_resource0.resource_mapping.first_symbol_idx == 8); + TESTASSERT(zp_csi_rs_resource0.resource_mapping.cdm == srsran_csi_rs_cdm_fd_cdm2); + TESTASSERT(zp_csi_rs_resource0.resource_mapping.density == srsran_csi_rs_resource_mapping_density_one); + TESTASSERT(zp_csi_rs_resource0.resource_mapping.freq_band.start_rb == 0); + TESTASSERT(zp_csi_rs_resource0.resource_mapping.freq_band.nof_rb == 52); + TESTASSERT(zp_csi_rs_resource0.periodicity.period == 80); + TESTASSERT(zp_csi_rs_resource0.periodicity.offset == 1); + return SRSRAN_SUCCESS; +} + +int make_phy_nzp_csi_rs_resource_test() +{ + // nzp-CSI-RS-ResourceToAddModList: 5 items + // Item 0 + // NZP-CSI-RS-Resource + // nzp-CSI-RS-ResourceId: 0 + // resourceMapping + // frequencyDomainAllocation: row2 (1) + // row2: 8000 [bit length 12, 4 LSB pad bits, 1000 0000 0000 .... decimal value 2048] + // nrofPorts: p1 (0) + // firstOFDMSymbolInTimeDomain: 4 + // cdm-Type: noCDM (0) + // density: one (1) + // one: NULL + // freqBand + // startingRB: 0 + // nrofRBs: 52 + // powerControlOffset: 0dB + // powerControlOffsetSS: db0 (1) + // scramblingID: 0 + // periodicityAndOffset: slots80 (9) + // slots80: 1 + // qcl-InfoPeriodicCSI-RS: 0 + asn1::rrc_nr::nzp_csi_rs_res_s nzp_csi_rs_res; + nzp_csi_rs_res.nzp_csi_rs_res_id = 0; + nzp_csi_rs_res.res_map.freq_domain_alloc.set_row2(); + nzp_csi_rs_res.res_map.freq_domain_alloc.row2().from_string("100000000000"); + nzp_csi_rs_res.res_map.nrof_ports = csi_rs_res_map_s::nrof_ports_opts::options::p1; + nzp_csi_rs_res.res_map.first_ofdm_symbol_in_time_domain = 4; + nzp_csi_rs_res.res_map.cdm_type = csi_rs_res_map_s::cdm_type_opts::options::no_cdm; + nzp_csi_rs_res.res_map.density.set_one(); + nzp_csi_rs_res.res_map.freq_band.start_rb = 0; + nzp_csi_rs_res.res_map.freq_band.nrof_rbs = 52; + nzp_csi_rs_res.pwr_ctrl_offset = 0; + nzp_csi_rs_res.pwr_ctrl_offset_ss_present = true; + nzp_csi_rs_res.pwr_ctrl_offset_ss = nzp_csi_rs_res_s::pwr_ctrl_offset_ss_opts::options::db0; + nzp_csi_rs_res.scrambling_id = 0; + nzp_csi_rs_res.periodicity_and_offset_present = true; + nzp_csi_rs_res.periodicity_and_offset.set_slots80() = 1; + + srsran_csi_rs_nzp_resource_t nzp_resource_0; + TESTASSERT(make_phy_nzp_csi_rs_resource(nzp_csi_rs_res, &nzp_resource_0) == true); + + TESTASSERT(nzp_resource_0.resource_mapping.row == srsran_csi_rs_resource_mapping_row_2); + TESTASSERT(nzp_resource_0.resource_mapping.frequency_domain_alloc[0] == true); + TESTASSERT(nzp_resource_0.resource_mapping.frequency_domain_alloc[1] == false); + TESTASSERT(nzp_resource_0.resource_mapping.frequency_domain_alloc[2] == false); + TESTASSERT(nzp_resource_0.resource_mapping.frequency_domain_alloc[3] == false); + TESTASSERT(nzp_resource_0.resource_mapping.frequency_domain_alloc[4] == false); + TESTASSERT(nzp_resource_0.resource_mapping.frequency_domain_alloc[5] == false); + TESTASSERT(nzp_resource_0.resource_mapping.frequency_domain_alloc[6] == false); + TESTASSERT(nzp_resource_0.resource_mapping.frequency_domain_alloc[7] == false); + TESTASSERT(nzp_resource_0.resource_mapping.frequency_domain_alloc[8] == false); + TESTASSERT(nzp_resource_0.resource_mapping.frequency_domain_alloc[9] == false); + TESTASSERT(nzp_resource_0.resource_mapping.frequency_domain_alloc[10] == false); + TESTASSERT(nzp_resource_0.resource_mapping.frequency_domain_alloc[11] == false); + TESTASSERT(nzp_resource_0.resource_mapping.nof_ports == 1); + TESTASSERT(nzp_resource_0.resource_mapping.first_symbol_idx == 4); + TESTASSERT(nzp_resource_0.resource_mapping.cdm == srsran_csi_rs_cdm_nocdm); + TESTASSERT(nzp_resource_0.resource_mapping.density == srsran_csi_rs_resource_mapping_density_one); + TESTASSERT(nzp_resource_0.resource_mapping.freq_band.start_rb == 0); + TESTASSERT(nzp_resource_0.resource_mapping.freq_band.nof_rb == 52); + TESTASSERT(nzp_resource_0.power_control_offset == 0); + TESTASSERT(nzp_resource_0.power_control_offset_ss == 0); + TESTASSERT(nzp_resource_0.scrambling_id == 0); + TESTASSERT(nzp_resource_0.periodicity.period == 80); + TESTASSERT(nzp_resource_0.periodicity.offset == 1); + + return SRSRAN_SUCCESS; +} + int main() { auto& asn1_logger = srslog::fetch_basic_logger("ASN1", false); @@ -581,7 +702,8 @@ int main() TESTASSERT(make_phy_dmrs_additional_pos_test() == SRSRAN_SUCCESS); TESTASSERT(make_phy_beta_offsets_test() == SRSRAN_SUCCESS); TESTASSERT(make_phy_pusch_scaling_test() == SRSRAN_SUCCESS); - + TESTASSERT(make_phy_zp_csi_rs_resource_test() == SRSRAN_SUCCESS); + TESTASSERT(make_phy_nzp_csi_rs_resource_test() == SRSRAN_SUCCESS); srslog::flush(); printf("Success\n"); diff --git a/lib/test/phy/phy_dl_nr_test.c b/lib/test/phy/phy_dl_nr_test.c index 704d30b46..3154ce56b 100644 --- a/lib/test/phy/phy_dl_nr_test.c +++ b/lib/test/phy/phy_dl_nr_test.c @@ -29,12 +29,13 @@ #include static srsran_carrier_nr_t carrier = { - 501, // cell_id - 0, // numerology - 52, // nof_prb - 0, // start - 1 // max_mimo_layers - + 501, // pci + 0, // absolute_frequency_ssb + 0, // absolute_frequency_point_a + srsran_subcarrier_spacing_15kHz, // scs + 52, // nof_prb + 0, // start + 1 // max_mimo_layers }; static uint32_t n_prb = 0; // Set to 0 for steering @@ -222,7 +223,6 @@ int main(int argc, char** argv) ue_dl_args.pdsch.sch.disable_simd = false; ue_dl_args.pdsch.sch.decoder_use_flooded = false; ue_dl_args.pdsch.measure_evm = true; - ue_dl_args.pdsch.disable_zero_re_around_dc = true; ue_dl_args.pdcch.disable_simd = false; ue_dl_args.pdcch.measure_evm = true; ue_dl_args.nof_max_prb = carrier.nof_prb; @@ -384,7 +384,7 @@ int main(int argc, char** argv) search_space, pdsch_cfg.grant.rnti, L, - SRSRAN_SLOT_NR_MOD(carrier.numerology, slot.idx), + SRSRAN_SLOT_NR_MOD(carrier.scs, slot.idx), ncce_candidates); if (nof_candidates < SRSRAN_SUCCESS) { ERROR("Error getting PDCCH candidates"); @@ -416,7 +416,7 @@ int main(int argc, char** argv) // Emulate channel CFO if (isnormal(cfo_hz) && ue_dl.fft[0].cfg.symbol_sz > 0) { srsran_vec_apply_cfo(buffer_ue[0], - cfo_hz / (ue_dl.fft[0].cfg.symbol_sz * SRSRAN_SUBC_SPACING_NR(carrier.numerology)), + cfo_hz / (ue_dl.fft[0].cfg.symbol_sz * SRSRAN_SUBC_SPACING_NR(carrier.scs)), buffer_ue[0], sf_len); } @@ -457,6 +457,15 @@ int main(int argc, char** argv) } } + if (srsran_verbose >= SRSRAN_VERBOSE_INFO) { + char str[512]; + srsran_ue_dl_nr_pdsch_info(&ue_dl, &pdsch_cfg, &pdsch_res, str, (uint32_t)sizeof(str)); + + char str_extra[2048]; + srsran_sch_cfg_nr_info(&pdsch_cfg, str_extra, (uint32_t)sizeof(str_extra)); + INFO("PDSCH: %s\n%s", str, str_extra); + } + INFO("n_prb=%d; mcs=%d; TBS=%d; EVM=%f; PASSED!", n_prb, mcs, pdsch_cfg.grant.tb[0].tbs, pdsch_res.evm[0]); // Count the Tx/Rx'd number of bits diff --git a/lib/test/upper/pdcp_lte_test.h b/lib/test/upper/pdcp_lte_test.h index 051c1c6f0..f85a268c2 100644 --- a/lib/test/upper/pdcp_lte_test.h +++ b/lib/test/upper/pdcp_lte_test.h @@ -101,7 +101,8 @@ srsran::unique_byte_buffer_t gen_expected_pdu(const srsran::unique_byte_buffer_t pdcp_sn_len, srsran::pdcp_t_reordering_t::ms500, srsran::pdcp_discard_timer_t::infinity, - false}; + false, + srsran::srsran_rat_t::lte}; pdcp_lte_test_helper pdcp_hlp(cfg, sec_cfg, logger); srsran::pdcp_entity_lte* pdcp = &pdcp_hlp.pdcp; diff --git a/lib/test/upper/pdcp_lte_test_discard_sdu.cc b/lib/test/upper/pdcp_lte_test_discard_sdu.cc index 42a650fbf..dbbab6b3f 100644 --- a/lib/test/upper/pdcp_lte_test_discard_sdu.cc +++ b/lib/test/upper/pdcp_lte_test_discard_sdu.cc @@ -35,7 +35,8 @@ int test_tx_sdu_notify(const srsran::pdcp_lte_state_t& init_state, srsran::PDCP_SN_LEN_12, srsran::pdcp_t_reordering_t::ms500, discard_timeout, - false}; + false, + srsran::srsran_rat_t::lte}; pdcp_lte_test_helper pdcp_hlp(cfg, sec_cfg, logger); srsran::pdcp_entity_lte* pdcp = &pdcp_hlp.pdcp; @@ -84,7 +85,8 @@ int test_tx_sdu_discard(const srsran::pdcp_lte_state_t& init_state, srsran::PDCP_SN_LEN_12, srsran::pdcp_t_reordering_t::ms500, discard_timeout, - false}; + false, + srsran::srsran_rat_t::lte}; pdcp_lte_test_helper pdcp_hlp(cfg, sec_cfg, logger); srsran::pdcp_entity_lte* pdcp = &pdcp_hlp.pdcp; diff --git a/lib/test/upper/pdcp_lte_test_rx.cc b/lib/test/upper/pdcp_lte_test_rx.cc index c141a35ff..4daa8d83e 100644 --- a/lib/test/upper/pdcp_lte_test_rx.cc +++ b/lib/test/upper/pdcp_lte_test_rx.cc @@ -40,7 +40,8 @@ int test_rx(std::vector events, pdcp_sn_len, srsran::pdcp_t_reordering_t::ms500, srsran::pdcp_discard_timer_t::infinity, - false}; + false, + srsran::srsran_rat_t::lte}; pdcp_lte_test_helper pdcp_hlp_rx(cfg_rx, sec_cfg, logger); srsran::pdcp_entity_lte* pdcp_rx = &pdcp_hlp_rx.pdcp; diff --git a/lib/test/upper/pdcp_lte_test_status_report.cc b/lib/test/upper/pdcp_lte_test_status_report.cc index f6ba57a64..00290b3b7 100644 --- a/lib/test/upper/pdcp_lte_test_status_report.cc +++ b/lib/test/upper/pdcp_lte_test_status_report.cc @@ -33,7 +33,8 @@ int test_tx_status_report(const srsran::pdcp_lte_state_t& init_state, srslog::ba srsran::PDCP_SN_LEN_12, srsran::pdcp_t_reordering_t::ms500, srsran::pdcp_discard_timer_t::ms500, - true}; + true, + srsran::srsran_rat_t::lte}; srsran::pdcp_config_t cfg_rx = {1, srsran::PDCP_RB_IS_DRB, @@ -42,7 +43,8 @@ int test_tx_status_report(const srsran::pdcp_lte_state_t& init_state, srslog::ba srsran::PDCP_SN_LEN_12, srsran::pdcp_t_reordering_t::ms500, srsran::pdcp_discard_timer_t::ms500, - true}; + true, + srsran::srsran_rat_t::lte}; // Setup TX pdcp_lte_test_helper pdcp_hlp_tx(cfg_tx, sec_cfg, logger); @@ -137,7 +139,8 @@ int test_tx_wraparound_status_report(const srsran::pdcp_lte_state_t& init_state, srsran::PDCP_SN_LEN_12, srsran::pdcp_t_reordering_t::ms500, srsran::pdcp_discard_timer_t::ms500, - true}; + true, + srsran::srsran_rat_t::lte}; srsran::pdcp_config_t cfg_rx = {1, srsran::PDCP_RB_IS_DRB, @@ -146,7 +149,8 @@ int test_tx_wraparound_status_report(const srsran::pdcp_lte_state_t& init_state, srsran::PDCP_SN_LEN_12, srsran::pdcp_t_reordering_t::ms500, srsran::pdcp_discard_timer_t::ms500, - true}; + true, + srsran::srsran_rat_t::lte}; // Setup TX pdcp_lte_test_helper pdcp_hlp_tx(cfg_tx, sec_cfg, logger); @@ -249,7 +253,8 @@ int test_rx_status_report(const srsran::pdcp_lte_state_t& init_state, srslog::ba srsran::PDCP_SN_LEN_12, srsran::pdcp_t_reordering_t::ms500, srsran::pdcp_discard_timer_t::ms500, - true}; + true, + srsran::srsran_rat_t::lte}; pdcp_lte_test_helper pdcp_hlp(cfg, sec_cfg, logger); srsran::pdcp_entity_lte* pdcp = &pdcp_hlp.pdcp; diff --git a/lib/test/upper/pdcp_nr_test.h b/lib/test/upper/pdcp_nr_test.h index eb9aa61ac..8d889fd9a 100644 --- a/lib/test/upper/pdcp_nr_test.h +++ b/lib/test/upper/pdcp_nr_test.h @@ -134,7 +134,8 @@ srsran::unique_byte_buffer_t gen_expected_pdu(const srsran::unique_byte_buffer_t pdcp_sn_len, srsran::pdcp_t_reordering_t::ms500, srsran::pdcp_discard_timer_t::infinity, - false}; + false, + srsran::srsran_rat_t::nr}; pdcp_nr_test_helper pdcp_hlp(cfg, sec_cfg, logger); srsran::pdcp_entity_nr* pdcp = &pdcp_hlp.pdcp; diff --git a/lib/test/upper/pdcp_nr_test_discard_sdu.cc b/lib/test/upper/pdcp_nr_test_discard_sdu.cc index c4a5c89f1..4aced99cd 100644 --- a/lib/test/upper/pdcp_nr_test_discard_sdu.cc +++ b/lib/test/upper/pdcp_nr_test_discard_sdu.cc @@ -36,7 +36,8 @@ int test_tx_sdu_discard(const pdcp_initial_state& init_state, srsran::PDCP_SN_LEN_12, srsran::pdcp_t_reordering_t::ms500, discard_timeout, - false}; + false, + srsran::srsran_rat_t::nr}; pdcp_nr_test_helper pdcp_hlp(cfg, sec_cfg, logger); srsran::pdcp_entity_nr* pdcp = &pdcp_hlp.pdcp; diff --git a/lib/test/upper/pdcp_nr_test_rx.cc b/lib/test/upper/pdcp_nr_test_rx.cc index a3ed4d28e..04ef31890 100644 --- a/lib/test/upper/pdcp_nr_test_rx.cc +++ b/lib/test/upper/pdcp_nr_test_rx.cc @@ -39,7 +39,8 @@ int test_rx(std::vector events, pdcp_sn_len, srsran::pdcp_t_reordering_t::ms500, srsran::pdcp_discard_timer_t::infinity, - false}; + false, + srsran::srsran_rat_t::nr}; pdcp_nr_test_helper pdcp_hlp_rx(cfg_rx, sec_cfg, logger); srsran::pdcp_entity_nr* pdcp_rx = &pdcp_hlp_rx.pdcp; diff --git a/lib/test/upper/pdcp_nr_test_tx.cc b/lib/test/upper/pdcp_nr_test_tx.cc index 41e52cb9a..2b4d43acc 100644 --- a/lib/test/upper/pdcp_nr_test_tx.cc +++ b/lib/test/upper/pdcp_nr_test_tx.cc @@ -38,7 +38,8 @@ int test_tx(uint32_t n_packets, pdcp_sn_len, srsran::pdcp_t_reordering_t::ms500, srsran::pdcp_discard_timer_t::infinity, - false}; + false, + srsran::srsran_rat_t::nr}; pdcp_nr_test_helper pdcp_hlp(cfg, sec_cfg, logger); srsran::pdcp_entity_nr* pdcp = &pdcp_hlp.pdcp; diff --git a/srsenb/hdr/common/common_enb.h b/srsenb/hdr/common/common_enb.h index 8ad528d9c..ddaf16ed4 100644 --- a/srsenb/hdr/common/common_enb.h +++ b/srsenb/hdr/common/common_enb.h @@ -26,7 +26,7 @@ INCLUDES *******************************************************************************/ -#include "srsran/common/lte_common.h" +#include "srsran/common/common_lte.h" #include namespace srsenb { diff --git a/srsenb/hdr/stack/rrc/rrc_nr.h b/srsenb/hdr/stack/rrc/rrc_nr.h index 4e4c4c944..58e637d93 100644 --- a/srsenb/hdr/stack/rrc/rrc_nr.h +++ b/srsenb/hdr/stack/rrc/rrc_nr.h @@ -93,9 +93,9 @@ public: // RLC interface // TODO - void read_pdu_pcch(uint8_t* payload, uint32_t payload_size) {} - void max_retx_attempted(uint16_t rnti) {} - + void read_pdu_pcch(uint8_t* payload, uint32_t payload_size) {} + void max_retx_attempted(uint16_t rnti) {} + const char* get_rb_name(uint32_t lcid) { return "invalid"; } // PDCP interface void write_pdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t pdu) final; diff --git a/srsenb/src/enb_cfg_parser.cc b/srsenb/src/enb_cfg_parser.cc index 9ded45a09..0c2207132 100644 --- a/srsenb/src/enb_cfg_parser.cc +++ b/srsenb/src/enb_cfg_parser.cc @@ -1011,7 +1011,7 @@ int set_derived_args(all_args_t* args_, rrc_cfg_t* rrc_cfg_, phy_cfg_t* phy_cfg_ phy_cell_cfg_nr_t phy_cell_cfg = {}; phy_cell_cfg.carrier.max_mimo_layers = cell_cfg_.nof_ports; phy_cell_cfg.carrier.nof_prb = cell_cfg_.nof_prb; - phy_cell_cfg.carrier.id = cfg.pci; + phy_cell_cfg.carrier.pci = cfg.pci; phy_cell_cfg.cell_id = cfg.cell_id; phy_cell_cfg.root_seq_idx = cfg.root_seq_idx; phy_cell_cfg.rf_port = cfg.rf_port; diff --git a/srsenb/src/stack/mac/sched.cc b/srsenb/src/stack/mac/sched.cc index ca29df352..708a39f02 100644 --- a/srsenb/src/stack/mac/sched.cc +++ b/srsenb/src/stack/mac/sched.cc @@ -277,15 +277,15 @@ std::array sched::get_enb_ue_cc_map(uint16_t rnti) std::array sched::get_scell_activation_mask(uint16_t rnti) { - std::array enb_ue_cc_map = get_enb_ue_cc_map(rnti); - std::array scell_mask = {}; - for (int ue_cc : enb_ue_cc_map) { - if (ue_cc <= 0) { - // inactive or PCell - continue; + std::array scell_mask = {}; + ue_db_access_locked(rnti, [this, &scell_mask](sched_ue& ue) { + for (size_t enb_cc_idx = 0; enb_cc_idx < carrier_schedulers.size(); ++enb_cc_idx) { + const sched_ue_cell* cc_ue = ue.find_ue_carrier(enb_cc_idx); + if (cc_ue != nullptr and (cc_ue->cc_state() == cc_st::active or cc_ue->cc_state() == cc_st::activating)) { + scell_mask[cc_ue->get_ue_cc_idx()] = true; + } } - scell_mask[ue_cc] = true; - } + }); return scell_mask; } diff --git a/srsenb/src/stack/mac/sched_ue.cc b/srsenb/src/stack/mac/sched_ue.cc index ad2bad8c9..17ae6b516 100644 --- a/srsenb/src/stack/mac/sched_ue.cc +++ b/srsenb/src/stack/mac/sched_ue.cc @@ -86,10 +86,12 @@ void sched_ue::set_cfg(const ue_cfg_t& cfg_) scell_activation_state_changed |= c.is_scell() and (c.cc_state() == cc_st::activating or c.cc_state() == cc_st::deactivating); } - if (prev_supported_cc_list.empty() or prev_supported_cc_list[0].enb_cc_idx != cfg.supported_cc_list[0].enb_cc_idx) { + bool is_handover = not prev_supported_cc_list.empty() and + prev_supported_cc_list[0].enb_cc_idx != cfg.supported_cc_list[0].enb_cc_idx; + if (prev_supported_cc_list.empty() or is_handover) { logger.info("SCHED: rnti=0x%x PCell is now enb_cc_idx=%d", rnti, cfg.supported_cc_list[0].enb_cc_idx); } - if (scell_activation_state_changed) { + if (scell_activation_state_changed and not is_handover) { lch_handler.pending_ces.emplace_back(srsran::dl_sch_lcid::SCELL_ACTIVATION); logger.info("SCHED: Enqueueing SCell Activation CMD for rnti=0x%x", rnti); } diff --git a/srsenb/src/stack/mac/schedulers/sched_base.cc b/srsenb/src/stack/mac/schedulers/sched_base.cc index 55b65255b..01ed508ed 100644 --- a/srsenb/src/stack/mac/schedulers/sched_base.cc +++ b/srsenb/src/stack/mac/schedulers/sched_base.cc @@ -32,22 +32,26 @@ template ::value, prb_interval, rbg_interval>::type> RBInterval find_contiguous_interval(const RBMask& in_mask, uint32_t max_size) { - RBInterval interv, max_interv; + RBInterval max_interv; - for (uint32_t n = 0; n < in_mask.size() and interv.length() < max_size; n++) { - if (not in_mask.test(n) and interv.empty()) { - // new interval - interv.set(n, n + 1); - } else if (not in_mask.test(n)) { - // extend current interval - interv.resize_by(1); - } else if (not interv.empty()) { - // reset interval - max_interv = interv.length() > max_interv.length() ? interv : max_interv; - interv = {}; + for (size_t n = 0; n < in_mask.size();) { + int pos = in_mask.find_lowest(n, in_mask.size(), false); + if (pos < 0) { + break; } + + size_t max_pos = std::min(in_mask.size(), (size_t)pos + max_size); + int pos2 = in_mask.find_lowest(pos, max_pos, true); + RBInterval interv(pos, pos2 < 0 ? max_pos : pos2); + if (interv.length() >= max_size) { + return interv; + } + if (interv.length() > max_interv.length()) { + max_interv = interv; + } + n = interv.stop(); } - return interv.length() > max_interv.length() ? interv : max_interv; + return max_interv; } /**************************** diff --git a/srsenb/src/stack/rrc/mac_controller.cc b/srsenb/src/stack/rrc/mac_controller.cc index c8b106007..60ceb983a 100644 --- a/srsenb/src/stack/rrc/mac_controller.cc +++ b/srsenb/src/stack/rrc/mac_controller.cc @@ -136,9 +136,7 @@ int mac_controller::handle_crnti_ce(uint32_t temp_crnti) current_sched_ue_cfg = next_sched_ue_cfg; // Disable SCells, until RRCReconfComplete is received, otherwise the SCell Act MAC CE is sent too early - for (uint32_t i = 1; i < current_sched_ue_cfg.supported_cc_list.size(); ++i) { - current_sched_ue_cfg.supported_cc_list[i].active = false; - } + set_scell_activation({0}); // keep DRBs disabled until RRCReconfComplete is received set_drb_activation(false); diff --git a/srsenb/src/stack/rrc/rrc_mobility.cc b/srsenb/src/stack/rrc/rrc_mobility.cc index 8109fa92e..8b0a5520f 100644 --- a/srsenb/src/stack/rrc/rrc_mobility.cc +++ b/srsenb/src/stack/rrc/rrc_mobility.cc @@ -844,8 +844,8 @@ void rrc::ue::rrc_mobility::handle_ho_requested(idle_st& s, const ho_req_rx_ev& logger.error("Failed to allocate GTPU TEID for E-RAB id=%d", fwd_erab.erab_id); not_admitted_erabs.emplace_back(); not_admitted_erabs.back().erab_id = erab.second.id; - not_admitted_erabs.back().cause.set_radio_network().value = - asn1::s1ap::cause_radio_network_opts::no_radio_res_available_in_target_cell; + not_admitted_erabs.back().cause.set_transport().value = + asn1::s1ap::cause_transport_opts::transport_res_unavailable; admitted_erabs.pop_back(); continue; } @@ -921,8 +921,8 @@ bool rrc::ue::rrc_mobility::apply_ho_prep_cfg(const ho_prep_info_r8_ies_s& if (rrc_ue->bearer_list.add_gtpu_bearer(erab.erab_id) != SRSRAN_SUCCESS) { erabs_failed_to_setup.emplace_back(); erabs_failed_to_setup.back().erab_id = erab.erab_id; - erabs_failed_to_setup.back().cause.set_radio_network().value = - asn1::s1ap::cause_radio_network_opts::no_radio_res_available_in_target_cell; + erabs_failed_to_setup.back().cause.set_transport().value = + asn1::s1ap::cause_transport_opts::transport_res_unavailable; continue; } } diff --git a/srsenb/src/stack/rrc/rrc_nr.cc b/srsenb/src/stack/rrc/rrc_nr.cc index 07e2cfa8d..dd5e547ff 100644 --- a/srsenb/src/stack/rrc/rrc_nr.cc +++ b/srsenb/src/stack/rrc/rrc_nr.cc @@ -19,10 +19,10 @@ * */ +#include "srsran/common/common_nr.h" +#include "srsran/asn1/rrc_nr_utils.h" #include "srsenb/hdr/stack/rrc/rrc_nr.h" #include "srsenb/hdr/common/common_enb.h" -#include "srsran/asn1/rrc_nr_utils.h" -#include "srsran/interfaces/nr_common_interface_types.h" using namespace asn1::rrc_nr; @@ -74,7 +74,8 @@ int rrc_nr::init(const rrc_nr_cfg_t& cfg_, srsran::PDCP_SN_LEN_18, srsran::pdcp_t_reordering_t::ms500, srsran::pdcp_discard_timer_t::infinity, - false}; + false, + srsran::srsran_rat_t::nr}; pdcp->add_bearer(cfg.coreless.rnti, cfg.coreless.drb_lcid, pdcp_cnfg); logger.info("Started"); @@ -320,16 +321,16 @@ void rrc_nr::get_metrics(srsenb::rrc_metrics_t& m) void rrc_nr::handle_pdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t pdu) { if (pdu) { - logger.info(pdu->msg, pdu->N_bytes, "Rx %s PDU", srsran::to_string(static_cast(lcid))); + logger.info(pdu->msg, pdu->N_bytes, "Rx %s PDU", get_rb_name(lcid)); } if (users.count(rnti) == 1) { - switch (static_cast(lcid)) { - case srsran::rb_id_nr_t::NR_SRB0: + switch (static_cast(lcid)) { + case srsran::nr_srb::srb0: // parse_ul_ccch(rnti, std::move(pdu)); break; - case srsran::rb_id_nr_t::NR_SRB1: - case srsran::rb_id_nr_t::NR_SRB2: + case srsran::nr_srb::srb1: + case srsran::nr_srb::srb2: // parse_ul_dcch(p.rnti, p.lcid, std::move(p.pdu)); break; default: @@ -405,7 +406,7 @@ void rrc_nr::ue::send_dl_ccch(dl_ccch_msg_s* dl_ccch_msg) char buf[32] = {}; sprintf(buf, "SRB0 - rnti=0x%x", rnti); parent->log_rrc_message(buf, Tx, pdu.get(), *dl_ccch_msg); - parent->rlc->write_sdu(rnti, srsran::NR_SRB0, std::move(pdu)); + parent->rlc->write_sdu(rnti, (uint32_t)srsran::nr_srb::srb0, std::move(pdu)); } } // namespace srsenb diff --git a/srsenb/src/stack/upper/pdcp_nr.cc b/srsenb/src/stack/upper/pdcp_nr.cc index e47ea8fb5..2ccf32c4c 100644 --- a/srsenb/src/stack/upper/pdcp_nr.cc +++ b/srsenb/src/stack/upper/pdcp_nr.cc @@ -20,7 +20,6 @@ */ #include "srsenb/hdr/stack/upper/pdcp_nr.h" -#include "lib/include/srsran/interfaces/nr_common_interface_types.h" #include "srsenb/hdr/common/common_enb.h" namespace srsenb { diff --git a/srsenb/src/stack/upper/rlc_nr.cc b/srsenb/src/stack/upper/rlc_nr.cc index 791a53e3d..e334956f5 100644 --- a/srsenb/src/stack/upper/rlc_nr.cc +++ b/srsenb/src/stack/upper/rlc_nr.cc @@ -20,8 +20,7 @@ */ #include "srsenb/hdr/stack/upper/rlc_nr.h" -#include "srsran/interfaces/nr_common_interface_types.h" - +#include "srsran/common/common_nr.h" namespace srsenb { rlc_nr::rlc_nr(const char* logname) : logger(srslog::fetch_basic_logger(logname)) {} @@ -55,7 +54,7 @@ void rlc_nr::add_user(uint16_t rnti) user_itf.parent = this; user_itf.m_rlc.reset(new srsran::rlc(logger.id().c_str())); users[rnti] = std::move(user_itf); - users[rnti].m_rlc->init(&users[rnti], &users[rnti], timers, (int)srsran::rb_id_nr_t::NR_SRB0); + users[rnti].m_rlc->init(&users[rnti], &users[rnti], timers, (int)srsran::nr_srb::srb0); } } @@ -189,7 +188,7 @@ void rlc_nr::user_interface::max_retx_attempted() void rlc_nr::user_interface::write_pdu(uint32_t lcid, srsran::unique_byte_buffer_t sdu) { - if (lcid == (int)srsran::rb_id_nr_t::NR_SRB0) { + if (lcid == (int)srsran::nr_srb::srb0) { m_rrc->write_pdu(rnti, lcid, std::move(sdu)); } else { m_pdcp->write_pdu(rnti, lcid, std::move(sdu)); @@ -213,7 +212,7 @@ void rlc_nr::user_interface::write_pdu_pcch(srsran::unique_byte_buffer_t sdu) const char* rlc_nr::user_interface::get_rb_name(uint32_t lcid) { - return srsran::to_string(static_cast(lcid)); + return m_rrc->get_rb_name(lcid); } void rlc_nr::user_interface::notify_delivery(uint32_t lcid, const srsran::pdcp_sn_vector_t& pdcp_sns) diff --git a/srsenb/test/mac/sched_benchmark.cc b/srsenb/test/mac/sched_benchmark.cc index c0b76a46f..dab6eb75b 100644 --- a/srsenb/test/mac/sched_benchmark.cc +++ b/srsenb/test/mac/sched_benchmark.cc @@ -22,7 +22,7 @@ #include "sched_test_common.h" #include "srsenb/hdr/stack/mac/sched.h" #include "srsran/adt/accumulators.h" -#include "srsran/common/lte_common.h" +#include "srsran/common/common_lte.h" #include namespace srsenb { diff --git a/srsenb/test/mac/sched_ca_test.cc b/srsenb/test/mac/sched_ca_test.cc index cce02feea..7dcc07552 100644 --- a/srsenb/test/mac/sched_ca_test.cc +++ b/srsenb/test/mac/sched_ca_test.cc @@ -22,7 +22,7 @@ #include "sched_test_common.h" #include "sched_test_utils.h" #include "srsenb/hdr/stack/mac/sched.h" -#include "srsran/common/lte_common.h" +#include "srsran/common/common_lte.h" #include "srsran/mac/pdu.h" using namespace srsenb; diff --git a/srsenb/test/mac/sched_dci_test.cc b/srsenb/test/mac/sched_dci_test.cc index cef9d6497..95601492f 100644 --- a/srsenb/test/mac/sched_dci_test.cc +++ b/srsenb/test/mac/sched_dci_test.cc @@ -22,7 +22,7 @@ #include "sched_test_utils.h" #include "srsenb/hdr/stack/mac/sched_common.h" #include "srsenb/hdr/stack/mac/sched_phy_ch/sched_dci.h" -#include "srsran/common/lte_common.h" +#include "srsran/common/common_lte.h" #include "srsran/common/test_common.h" namespace srsenb { diff --git a/srsenb/test/mac/sched_grid_test.cc b/srsenb/test/mac/sched_grid_test.cc index fbd4a170c..3320c0d46 100644 --- a/srsenb/test/mac/sched_grid_test.cc +++ b/srsenb/test/mac/sched_grid_test.cc @@ -21,7 +21,7 @@ #include "sched_test_common.h" #include "srsenb/hdr/stack/mac/sched_grid.h" -#include "srsran/common/lte_common.h" +#include "srsran/common/common_lte.h" #include "srsran/common/test_common.h" using namespace srsenb; diff --git a/srsenb/test/mac/sched_test_rand.cc b/srsenb/test/mac/sched_test_rand.cc index 24ea9acbe..3b65d9d4d 100644 --- a/srsenb/test/mac/sched_test_rand.cc +++ b/srsenb/test/mac/sched_test_rand.cc @@ -34,7 +34,7 @@ #include "sched_common_test_suite.h" #include "sched_test_common.h" #include "sched_test_utils.h" -#include "srsran/common/lte_common.h" +#include "srsran/common/common_lte.h" #include "srsran/common/test_common.h" namespace srsenb { diff --git a/srsue/hdr/phy/nr/cc_worker.h b/srsue/hdr/phy/nr/cc_worker.h index 86bb757a0..8710806b5 100644 --- a/srsue/hdr/phy/nr/cc_worker.h +++ b/srsue/hdr/phy/nr/cc_worker.h @@ -48,6 +48,10 @@ public: int read_pdsch_d(cf_t* pdsch_d); private: + // PHY lib temporal logger types + typedef std::array str_info_t; + typedef std::array str_extra_t; + bool configured = false; srsran_slot_cfg_t dl_slot_cfg = {}; srsran_slot_cfg_t ul_slot_cfg = {}; @@ -60,10 +64,7 @@ private: srsran_ue_ul_nr_t ue_ul = {}; srslog::basic_logger& logger; - // Temporal attributes - srsran_softbuffer_rx_t softbuffer_rx = {}; - - // Methods for DL... + // Methods for DCI blind search void decode_pdcch_ul(); void decode_pdcch_dl(); }; diff --git a/srsue/hdr/phy/nr/state.h b/srsue/hdr/phy/nr/state.h index de0fc286b..95373d83c 100644 --- a/srsue/hdr/phy/nr/state.h +++ b/srsue/hdr/phy/nr/state.h @@ -95,11 +95,11 @@ public: state() { - carrier.id = 500; + carrier.pci = 500; carrier.nof_prb = 100; carrier.max_mimo_layers = 1; - info_metrics.pci = carrier.id; + info_metrics.pci = carrier.pci; // Hard-coded values, this should be set when the measurements take place csi_measurements[0].K_csi_rs = 1; @@ -157,8 +157,9 @@ public: return false; } - // Load shared channel configuration + // Load shared channel configuration and PID pusch_cfg = pending_grant.sch_cfg; + pid = pending_grant.pid; // Reset entry pending_grant.enable = false; diff --git a/srsue/hdr/stack/mac_nr/demux_nr.h b/srsue/hdr/stack/mac_nr/demux_nr.h new file mode 100644 index 000000000..d14d24999 --- /dev/null +++ b/srsue/hdr/stack/mac_nr/demux_nr.h @@ -0,0 +1,60 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2021 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#ifndef SRSLTE_DEMUX_NR_H +#define SRSLTE_DEMUX_NR_H + +#include "mac_nr_interfaces.h" +#include "srsran/common/block_queue.h" +#include "srsran/interfaces/ue_rlc_interfaces.h" + +namespace srsue { + +/** + * @brief Logical Channel Demultiplexing and MAC CE dissassemble according to TS 38.321 + * + * Currently only SDU handling for SCH PDU processing is implemented. + * Downlink CE are parsed but not handled. + * + * PDUs can be pushed by multiple HARQ processes in parallel. + * Handling of the PDUs is done from Stack thread which reads the enqueued PDUs + * from the thread-safe queue. + */ +class demux_nr : public demux_interface_harq_nr +{ +public: + demux_nr(srslog::basic_logger& logger_); + ~demux_nr(); + + int32_t init(rlc_interface_mac* rlc_); + + void process_pdus(); /// Called by MAC to process received PDUs + + // HARQ interface + void push_pdu(srsran::unique_byte_buffer_t pdu, uint32_t tti); + +private: + // internal helpers + void handle_pdu(srsran::unique_byte_buffer_t pdu); + + srslog::basic_logger& logger; + rlc_interface_mac* rlc = nullptr; + + ///< currently only DCH PDUs supported (add BCH, PCH, etc) + srsran::block_queue pdu_queue; + + srsran::mac_sch_pdu_nr rx_pdu; +}; + +} // namespace srsue + +#endif // SRSLTE_DEMUX_NR_H diff --git a/srsue/hdr/stack/mac_nr/dl_harq_nr.h b/srsue/hdr/stack/mac_nr/dl_harq_nr.h new file mode 100644 index 000000000..308834842 --- /dev/null +++ b/srsue/hdr/stack/mac_nr/dl_harq_nr.h @@ -0,0 +1,103 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2021 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#ifndef SRSLTE_DL_HARQ_NR_H +#define SRSLTE_DL_HARQ_NR_H + +#include "srsran/interfaces/mac_interface_types.h" +#include "srsran/interfaces/ue_nr_interfaces.h" +#include "srsran/srslog/logger.h" +#include "srsue/hdr/stack/mac_nr/mac_nr_interfaces.h" +#include + +namespace srsue { + +/** + * @brief Downlink HARQ entity as defined in 5.3.2 of 38.321 + * + * The class supports a configurable number of HARQ processes (up to 16). + * + * The class is configured (init and reset) by the MAC class from the + * Stack thread context. Main functionality, however, is carried + * out from a PHY worker context. + * + * Concurrent access from threads is protected through rwlocks. + * + */ +class dl_harq_entity_nr +{ + using mac_nr_grant_dl_t = mac_interface_phy_nr::mac_nr_grant_dl_t; + +public: + dl_harq_entity_nr(uint8_t cc_idx_, mac_interface_harq_nr* mac_, demux_interface_harq_nr* demux_unit_); + ~dl_harq_entity_nr(); + + int32_t set_config(const srsran::dl_harq_cfg_nr_t& cfg_); + void reset(); + + /// PHY->MAC interface for DL processes + void new_grant_dl(const mac_nr_grant_dl_t& grant, mac_interface_phy_nr::tb_action_dl_t* action); + void tb_decoded(const mac_nr_grant_dl_t& grant, mac_interface_phy_nr::tb_action_dl_result_t result); + + float get_average_retx(); + +private: + class dl_harq_process_nr + { + public: + dl_harq_process_nr(dl_harq_entity_nr* parent); + ~dl_harq_process_nr(); + bool init(int pid); + void reset(void); + uint8_t get_ndi(); + + void + new_grant_dl(const mac_nr_grant_dl_t& grant, const bool& ndi_toggled, mac_interface_phy_nr::tb_action_dl_t* action); + void tb_decoded(const mac_nr_grant_dl_t& grant, mac_interface_phy_nr::tb_action_dl_result_t result); + + private: + dl_harq_entity_nr* harq_entity = nullptr; + srslog::basic_logger& logger; + + bool is_first_tb = true; + + bool is_bcch = false; + uint32_t pid = 0; // HARQ Proccess ID + bool acked = false; + uint32_t n_retx = 0; + + mac_nr_grant_dl_t current_grant = {}; + std::unique_ptr softbuffer_rx; + }; + + // Private members of dl_harq_entity_nr + mac_interface_harq_nr* mac = nullptr; + srsran::dl_harq_cfg_nr_t cfg = {}; + std::array, SRSRAN_MAX_HARQ_PROC_DL_NR> harq_procs; + dl_harq_process_nr bcch_proc; + demux_interface_harq_nr* demux_unit = nullptr; + srslog::basic_logger& logger; + uint16_t last_temporal_crnti = SRSRAN_INVALID_RNTI; + + float average_retx = 0.0; + uint64_t nof_pkts = 0; + uint8_t cc_idx = 0; + + pthread_rwlock_t rwlock; +}; + +typedef std::unique_ptr dl_harq_entity_nr_ptr; +typedef std::array dl_harq_entity_nr_vector; + +} // namespace srsue + +#endif // SRSLTE_DL_HARQ_NR_H diff --git a/srsue/hdr/stack/mac_nr/mac_nr.h b/srsue/hdr/stack/mac_nr/mac_nr.h index 034c6b31b..9877f91f5 100644 --- a/srsue/hdr/stack/mac_nr/mac_nr.h +++ b/srsue/hdr/stack/mac_nr/mac_nr.h @@ -22,16 +22,17 @@ #ifndef SRSUE_MAC_NR_H #define SRSUE_MAC_NR_H +#include "dl_harq_nr.h" #include "mac_nr_interfaces.h" #include "proc_bsr_nr.h" #include "proc_ra_nr.h" #include "proc_sr_nr.h" -#include "srsran/common/block_queue.h" #include "srsran/common/mac_pcap.h" #include "srsran/interfaces/mac_interface_types.h" #include "srsran/interfaces/ue_nr_interfaces.h" #include "srsran/srslog/srslog.h" #include "srsue/hdr/stack/mac_common/mac_common.h" +#include "srsue/hdr/stack/mac_nr/demux_nr.h" #include "srsue/hdr/stack/mac_nr/mux_nr.h" #include "srsue/hdr/stack/ue_stack_base.h" #include "ul_harq_nr.h" @@ -53,7 +54,7 @@ public: mac_nr(srsran::ext_task_sched_handle task_sched_); ~mac_nr(); - int init(const mac_nr_args_t& args_, phy_interface_mac_nr* phy, rlc_interface_mac* rlc, rrc_interface_mac* rrc_); + int init(const mac_nr_args_t& args_, phy_interface_mac_nr* phy_, rlc_interface_mac* rlc_, rrc_interface_mac* rrc_); void stop(); void reset(); @@ -68,7 +69,8 @@ public: sched_rnti_t get_ul_sched_rnti_nr(const uint32_t tti); int sf_indication(const uint32_t tti); - void tb_decoded(const uint32_t cc_idx, mac_nr_grant_dl_t& grant); + void tb_decoded(const uint32_t cc_idx, const mac_nr_grant_dl_t& grant, tb_action_dl_result_t result); + void new_grant_dl(const uint32_t cc_idx, const mac_nr_grant_dl_t& grant, tb_action_dl_t* action); void new_grant_ul(const uint32_t cc_idx, const mac_nr_grant_ul_t& grant, tb_action_ul_t* action); void prach_sent(const uint32_t tti, const uint32_t s_id, @@ -86,6 +88,7 @@ public: int set_config(const srsran::bsr_cfg_nr_t& bsr_cfg); int set_config(const srsran::sr_cfg_nr_t& sr_cfg); void set_config(const srsran::rach_nr_cfg_t& rach_cfg); + int set_config(const srsran::dl_harq_cfg_nr_t& dl_hrq_cfg); void set_contention_id(const uint64_t ue_identity); bool set_crnti(const uint16_t crnti); int add_tag_config(const srsran::tag_cfg_nr_t& tag_cfg); @@ -120,7 +123,9 @@ public: static bool is_in_window(uint32_t tti, int* start, int* len); private: - void write_pcap(const uint32_t cc_idx, mac_nr_grant_dl_t& grant); // If PCAPs are enabled for this MAC + void write_pcap(const uint32_t cc_idx, + const mac_nr_grant_dl_t& grant, + tb_action_dl_result_t& tb); // If PCAPs are enabled for this MAC void handle_pdu(srsran::unique_byte_buffer_t pdu); void get_ul_data(const mac_nr_grant_ul_t& grant, srsran::byte_buffer_t* tx_pdu); @@ -154,14 +159,8 @@ private: uint16_t c_rnti = SRSRAN_INVALID_RNTI; uint64_t contention_id = 0; - srsran::block_queue - pdu_queue; ///< currently only DCH PDUs supported (add BCH, PCH, etc) - std::array metrics = {}; - /// Rx buffer - srsran::mac_sch_pdu_nr rx_pdu; - srsran::task_multiqueue::queue_handle stack_task_dispatch_queue; // MAC Uplink-related procedures @@ -169,10 +168,11 @@ private: proc_sr_nr proc_sr; proc_bsr_nr proc_bsr; mux_nr mux; + demux_nr demux; - // UL HARQ + // DL/UL HARQ + dl_harq_entity_nr_vector dl_harq = {}; ul_harq_entity_nr_vector ul_harq = {}; - ul_harq_cfg_t ul_harq_cfg; const uint8_t PCELL_CC_IDX = 0; }; diff --git a/srsue/hdr/stack/mac_nr/mac_nr_interfaces.h b/srsue/hdr/stack/mac_nr/mac_nr_interfaces.h index ca6143d71..b32aa0025 100644 --- a/srsue/hdr/stack/mac_nr/mac_nr_interfaces.h +++ b/srsue/hdr/stack/mac_nr/mac_nr_interfaces.h @@ -86,6 +86,16 @@ public: virtual uint16_t get_csrnti() = 0; }; +/** + * @brief Interface from HARQ class to demux class + */ +class demux_interface_harq_nr +{ +public: + /// Inform demux unit about a newly decoded TB. + virtual void push_pdu(srsran::unique_byte_buffer_t pdu, uint32_t tti) = 0; +}; + } // namespace srsue #endif // SRSUE_MAC_NR_INTERFACES_H \ No newline at end of file diff --git a/srsue/hdr/stack/mac_nr/proc_ra_nr.h b/srsue/hdr/stack/mac_nr/proc_ra_nr.h index c1fa415d5..f3788a560 100644 --- a/srsue/hdr/stack/mac_nr/proc_ra_nr.h +++ b/srsue/hdr/stack/mac_nr/proc_ra_nr.h @@ -52,7 +52,7 @@ public: // PHY interfaces void prach_sent(uint32_t tti, uint32_t s_id, uint32_t t_id, uint32_t f_id, uint32_t ul_carrier_id); - void handle_rar_pdu(mac_interface_phy_nr::mac_nr_grant_dl_t& grant); + void handle_rar_pdu(mac_interface_phy_nr::tb_action_dl_result_t& grant); void pdcch_to_crnti(); void start_by_rrc(); @@ -113,7 +113,7 @@ private: void ra_procedure_initialization(); void ra_resource_selection(); void ra_preamble_transmission(); - void ra_response_reception(const mac_interface_phy_nr::mac_nr_grant_dl_t& grant); + void ra_response_reception(const mac_interface_phy_nr::tb_action_dl_result_t& tb); void ra_contention_resolution(); void ra_contention_resolution(uint64_t rx_contention_id); void ra_completion(); diff --git a/srsue/hdr/stack/rrc/rrc.h b/srsue/hdr/stack/rrc/rrc.h index e1a1cf030..2a82fe9a1 100644 --- a/srsue/hdr/stack/rrc/rrc.h +++ b/srsue/hdr/stack/rrc/rrc.h @@ -30,7 +30,7 @@ #include "srsran/common/block_queue.h" #include "srsran/common/buffer_pool.h" #include "srsran/common/common.h" -#include "srsran/common/lte_common.h" +#include "srsran/common/common_lte.h" #include "srsran/common/security.h" #include "srsran/common/stack_procedure.h" #include "srsran/interfaces/ue_interfaces.h" @@ -58,9 +58,9 @@ typedef struct { #define SRSRAN_UE_CATEGORY_DEFAULT "4" #define SRSRAN_UE_CATEGORY_MIN 1 #define SRSRAN_UE_CATEGORY_MAX 21 -#define SRSRAN_RELEASE_DEFAULT 8 #define SRSRAN_RELEASE_MIN 8 #define SRSRAN_RELEASE_MAX 15 +#define SRSRAN_RELEASE_DEFAULT (SRSRAN_RELEASE_MAX) using srsran::byte_buffer_t; diff --git a/srsue/hdr/stack/rrc/rrc_nr.h b/srsue/hdr/stack/rrc/rrc_nr.h index 3810bfdda..48b3f6934 100644 --- a/srsue/hdr/stack/rrc/rrc_nr.h +++ b/srsue/hdr/stack/rrc/rrc_nr.h @@ -25,12 +25,12 @@ #include "srsran/asn1/rrc_nr.h" #include "srsran/asn1/rrc_nr_utils.h" #include "srsran/common/block_queue.h" +#include "srsran/common/common_nr.h" #include "srsran/common/buffer_pool.h" #include "srsran/common/stack_procedure.h" #include "srsran/common/task_scheduler.h" -#include "srsran/interfaces/nr_common_interface_types.h" -#include "srsran/interfaces/ue_nr_interfaces.h" #include "srsran/interfaces/ue_rrc_interfaces.h" +#include "srsran/interfaces/ue_nr_interfaces.h" #include "srsue/hdr/stack/upper/gw.h" namespace srsue { @@ -49,6 +49,7 @@ struct core_less_args_t { struct rrc_nr_args_t { core_less_args_t coreless; + std::string supported_bands_nr_str; std::vector supported_bands_nr; std::vector supported_bands_eutra; std::string log_level; @@ -181,24 +182,20 @@ private: // RRC constants and timers srsran::timer_handler* timers = nullptr; - const char* get_rb_name(uint32_t lcid) final { return srsran::to_string((srsran::rb_id_nr_t)lcid); } - - typedef enum { Srb = 0, Drb } rb_type_t; - typedef struct { - uint32_t rb_id; - rb_type_t rb_type; - } rb_t; + const char* get_rb_name(uint32_t lcid) final; - bool add_lcid_rb(uint32_t lcid, rb_type_t rb_type, uint32_t rbid); - uint32_t get_lcid_for_rbid(uint32_t rdid); + bool add_lcid_drb(uint32_t lcid, uint32_t drb_id); + uint32_t get_lcid_for_drbid(uint32_t rdid); - std::map lcid_rb; // Map of lcid to radio bearer (type and rb id) + std::map lcid_drb; // Map of lcid to drb std::map drb_eps_bearer_id; // Map of drb id to eps_bearer_id // temporary maps for building the pucch nr resources - std::map res_list; - std::map res_list_present; + std::map res_list; + std::map res_list_present; + std::map csi_rs_zp_res; + std::map csi_rs_nzp_res; bool apply_cell_group_cfg(const asn1::rrc_nr::cell_group_cfg_s& cell_group_cfg); bool apply_radio_bearer_cfg(const asn1::rrc_nr::radio_bearer_cfg_s& radio_bearer_cfg); diff --git a/srsue/hdr/stack/ue_stack_lte.h b/srsue/hdr/stack/ue_stack_lte.h index ef866633f..71dbbe871 100644 --- a/srsue/hdr/stack/ue_stack_lte.h +++ b/srsue/hdr/stack/ue_stack_lte.h @@ -105,7 +105,7 @@ public: mac.new_grant_ul(cc_idx, grant, action); } - void new_grant_dl(uint32_t cc_idx, mac_grant_dl_t grant, tb_action_dl_t* action) final + void new_grant_dl(uint32_t cc_idx, mac_grant_dl_t grant, mac_interface_phy_lte::tb_action_dl_t* action) final { mac.new_grant_dl(cc_idx, grant, action); } @@ -122,7 +122,7 @@ public: void mch_decoded(uint32_t len, bool crc) final { mac.mch_decoded(len, crc); } - void new_mch_dl(const srsran_pdsch_grant_t& phy_grant, tb_action_dl_t* action) final + void new_mch_dl(const srsran_pdsch_grant_t& phy_grant, mac_interface_phy_lte::tb_action_dl_t* action) final { mac.new_mch_dl(phy_grant, action); } @@ -133,8 +133,18 @@ public: // MAC Interface for NR PHY int sf_indication(const uint32_t tti) final { return SRSRAN_SUCCESS; } - void tb_decoded(const uint32_t cc_idx, mac_nr_grant_dl_t& grant) final { mac_nr.tb_decoded(cc_idx, grant); } - + void tb_decoded(const uint32_t cc_idx, + const mac_nr_grant_dl_t& grant, + mac_interface_phy_nr::tb_action_dl_result_t result) final + { + mac_nr.tb_decoded(cc_idx, grant, std::move(result)); + } + void new_grant_dl(const uint32_t cc_idx, + const mac_nr_grant_dl_t& grant, + mac_interface_phy_nr::tb_action_dl_t* action) final + { + mac_nr.new_grant_dl(cc_idx, grant, action); + } void new_grant_ul(const uint32_t cc_idx, const mac_nr_grant_ul_t& grant, mac_interface_phy_nr::tb_action_ul_t* action) final diff --git a/srsue/hdr/stack/ue_stack_nr.h b/srsue/hdr/stack/ue_stack_nr.h index 0c63af17f..ed86e0e82 100644 --- a/srsue/hdr/stack/ue_stack_nr.h +++ b/srsue/hdr/stack/ue_stack_nr.h @@ -89,7 +89,14 @@ public: run_tti(tti); return SRSRAN_SUCCESS; } - void tb_decoded(const uint32_t cc_idx, mac_nr_grant_dl_t& grant) final { mac->tb_decoded(cc_idx, grant); } + void tb_decoded(const uint32_t cc_idx, const mac_nr_grant_dl_t& grant, tb_action_dl_result_t result) final + { + mac->tb_decoded(cc_idx, grant, std::move(result)); + } + void new_grant_dl(const uint32_t cc_idx, const mac_nr_grant_dl_t& grant, tb_action_dl_t* action) final + { + mac->new_grant_dl(cc_idx, grant, action); + } void new_grant_ul(const uint32_t cc_idx, const mac_nr_grant_ul_t& grant, tb_action_ul_t* action) final { mac->new_grant_ul(cc_idx, grant, action); diff --git a/srsue/src/CMakeLists.txt b/srsue/src/CMakeLists.txt index a5027ceec..f0501da58 100644 --- a/srsue/src/CMakeLists.txt +++ b/srsue/src/CMakeLists.txt @@ -60,8 +60,8 @@ endif(NOT SRSGUI_FOUND) # Checks that ue.conf.example is valid and it does not leak memory if RF fails if (ZEROMQ_FOUND) add_test(ue_rf_failure srsue ${CMAKE_SOURCE_DIR}/srsue/ue.conf.example --rf.device_name=zmq) - add_test(ue_rf_failure_max_channels srsue ${CMAKE_SOURCE_DIR}/srsue/ue.conf.example --rf.device_name=zmq --rf.nof_antennas=4 --rf.nof_carriers=5) - add_test(ue_rf_failure_exceeds_channels srsue ${CMAKE_SOURCE_DIR}/srsue/ue.conf.example --rf.device_name=zmq --rf.nof_antennas=5 --rf.nof_carriers=5) + add_test(ue_rf_failure_max_channels srsue ${CMAKE_SOURCE_DIR}/srsue/ue.conf.example --rf.device_name=zmq --rf.nof_antennas=4 --rat.eutra.nof_carriers=5) + add_test(ue_rf_failure_exceeds_channels srsue ${CMAKE_SOURCE_DIR}/srsue/ue.conf.example --rf.device_name=zmq --rf.nof_antennas=5 --rat.eutra.nof_carriers=5) endif(ZEROMQ_FOUND) ######################################################################## diff --git a/srsue/src/main.cc b/srsue/src/main.cc index ebbea34d8..f4c20d9cd 100644 --- a/srsue/src/main.cc +++ b/srsue/src/main.cc @@ -75,13 +75,8 @@ static int parse_args(all_args_t* args, int argc, char* argv[]) ("ue.phy", bpo::value(&args->phy.type)->default_value("lte"), "Type of the PHY [lte]") ("ue.stack", bpo::value(&args->stack.type)->default_value("lte"), "Type of the upper stack [lte, nr]") - ("rf.dl_earfcn", bpo::value(&args->phy.dl_earfcn)->default_value("3400"), "Downlink EARFCN list") - ("rf.ul_earfcn", bpo::value(&args->phy.ul_earfcn), "Uplink EARFCN list. Optional.") - ("rf.dl_nr_arfcn", bpo::value(&args->phy.dl_nr_arfcn)->default_value("632628"), "Downlink NR-ARFCN list") ("rf.srate", bpo::value(&args->rf.srate_hz)->default_value(0.0), "Force Tx and Rx sampling rate in Hz") ("rf.freq_offset", bpo::value(&args->rf.freq_offset)->default_value(0), "(optional) Frequency offset") - ("rf.dl_freq", bpo::value(&args->phy.dl_freq)->default_value(-1), "Downlink Frequency (if positive overrides EARFCN)") - ("rf.ul_freq", bpo::value(&args->phy.ul_freq)->default_value(-1), "Uplink Frequency (if positive overrides EARFCN)") ("rf.rx_gain", bpo::value(&args->rf.rx_gain)->default_value(-1), "Front-end receiver gain") ("rf.tx_gain", bpo::value(&args->rf.tx_gain)->default_value(-1), "Front-end transmitter gain (all channels)") ("rf.tx_gain[0]", bpo::value(&args->rf.tx_gain_ch[0])->default_value(-1), "Front-end transmitter gain CH0") @@ -94,7 +89,6 @@ static int parse_args(all_args_t* args, int argc, char* argv[]) ("rf.rx_gain[2]", bpo::value(&args->rf.rx_gain_ch[2])->default_value(-1), "Front-end receiver gain CH2") ("rf.rx_gain[3]", bpo::value(&args->rf.rx_gain_ch[3])->default_value(-1), "Front-end receiver gain CH3") ("rf.rx_gain[4]", bpo::value(&args->rf.rx_gain_ch[4])->default_value(-1), "Front-end receiver gain CH4") - ("rf.nof_carriers", bpo::value(&args->rf.nof_carriers)->default_value(1), "Number of carriers") ("rf.nof_antennas", bpo::value(&args->rf.nof_antennas)->default_value(1), "Number of antennas per carrier") ("rf.device_name", bpo::value(&args->rf.device_name)->default_value("auto"), "Front-end device name") @@ -124,12 +118,24 @@ static int parse_args(all_args_t* args, int argc, char* argv[]) ("rf.bands.tx[4].min", bpo::value(&args->rf.ch_tx_bands[4].min)->default_value(0), "Lower frequency boundary for CH4-TX") ("rf.bands.tx[4].max", bpo::value(&args->rf.ch_tx_bands[4].max)->default_value(0), "Higher frequency boundary for CH4-TX") + ("rat.eutra.dl_earfcn", bpo::value(&args->phy.dl_earfcn)->default_value("3400"), "Downlink EARFCN list") + ("rat.eutra.ul_earfcn", bpo::value(&args->phy.ul_earfcn), "Uplink EARFCN list. Optional.") + ("rat.eutra.dl_freq", bpo::value(&args->phy.dl_freq)->default_value(-1), "Downlink Frequency (if positive overrides EARFCN)") + ("rat.eutra.ul_freq", bpo::value(&args->phy.ul_freq)->default_value(-1), "Uplink Frequency (if positive overrides EARFCN)") + ("rat.eutra.nof_carriers", bpo::value(&args->phy.nof_lte_carriers)->default_value(1), "Number of carriers") + + ("rat.nr.bands", bpo::value(&args->stack.rrc_nr.supported_bands_nr_str)->default_value("78"), "Supported NR bands") + ("rat.nr.dl_arfcn", bpo::value(&args->phy.dl_nr_arfcn)->default_value("634240"), "Downlink NR-ARFCN list") + ("rat.nr.dl_freq", bpo::value(&args->phy.nr_freq_hz)->default_value(3513.6e6), "NR DL frequency") + ("rat.nr.nof_carriers", bpo::value(&args->phy.nof_nr_carriers)->default_value(0), "Number of NR carriers") + ("rat.nr.nof_prb", bpo::value(&args->phy.nr_nof_prb)->default_value(52), "NR carrier bandwidth") + ("rrc.feature_group", bpo::value(&args->stack.rrc.feature_group)->default_value(0xe6041000), "Hex value of the featureGroupIndicators field in the" "UECapabilityInformation message. Default 0xe6041000") ("rrc.ue_category", bpo::value(&args->stack.rrc.ue_category_str)->default_value(SRSRAN_UE_CATEGORY_DEFAULT), "UE Category (1 to 10)") - ("rrc.ue_category_dl", bpo::value(&args->stack.rrc.ue_category_dl)->default_value(-1), "UE Category DL v12 (valid values: 0, 4, 6, 7, 9 to 16)") - ("rrc.ue_category_ul", bpo::value(&args->stack.rrc.ue_category_ul)->default_value(-1), "UE Category UL v12 (valid values: 0, 3, 5, 7, 8 and 13)") - ("rrc.release", bpo::value(&args->stack.rrc.release)->default_value(SRSRAN_RELEASE_DEFAULT), "UE Release (8 to 12)") + ("rrc.ue_category_dl", bpo::value(&args->stack.rrc.ue_category_dl)->default_value(-1), "UE Category DL v12 (valid values: 0, 4, 6, 7, 9 to 16)") + ("rrc.ue_category_ul", bpo::value(&args->stack.rrc.ue_category_ul)->default_value(-1), "UE Category UL v12 (valid values: 0, 3, 5, 7, 8 and 13)") + ("rrc.release", bpo::value(&args->stack.rrc.release)->default_value(SRSRAN_RELEASE_DEFAULT), "UE Release (8 to 15)") ("rrc.mbms_service_id", bpo::value(&args->stack.rrc.mbms_service_id)->default_value(-1), "MBMS service id for autostart (-1 means disabled)") ("rrc.mbms_service_port", bpo::value(&args->stack.rrc.mbms_service_port)->default_value(4321), "Port of the MBMS service") @@ -447,9 +453,6 @@ static int parse_args(all_args_t* args, int argc, char* argv[]) ("vnf.type", bpo::value(&args->phy.vnf_args.type)->default_value("ue"), "VNF instance type [gnb,ue]") ("vnf.addr", bpo::value(&args->phy.vnf_args.bind_addr)->default_value("localhost"), "Address to bind VNF interface") ("vnf.port", bpo::value(&args->phy.vnf_args.bind_port)->default_value(3334), "Bind port") - ("nr.nof_carriers", bpo::value(&args->phy.nof_nr_carriers)->default_value(0), "Number of NR carriers") - ("nr.nof_prb", bpo::value(&args->phy.nr_nof_prb)->default_value(50), "NR carrier bandwidth") - ("nr.freq", bpo::value(&args->phy.nr_freq_hz)->default_value(2630e6), "NR carrier bandwidth") ; // Positional options - config file location diff --git a/srsue/src/phy/nr/cc_worker.cc b/srsue/src/phy/nr/cc_worker.cc index 2ba043b0a..2c76b4d74 100644 --- a/srsue/src/phy/nr/cc_worker.cc +++ b/srsue/src/phy/nr/cc_worker.cc @@ -47,19 +47,12 @@ cc_worker::cc_worker(uint32_t cc_idx_, srslog::basic_logger& log, state* phy_sta ERROR("Error initiating UE DL NR"); return; } - - if (srsran_softbuffer_rx_init_guru(&softbuffer_rx, SRSRAN_SCH_NR_MAX_NOF_CB_LDPC, SRSRAN_LDPC_MAX_LEN_ENCODED_CB) < - SRSRAN_SUCCESS) { - ERROR("Error init soft-buffer"); - return; - } } cc_worker::~cc_worker() { srsran_ue_dl_nr_free(&ue_dl); srsran_ue_ul_nr_free(&ue_ul); - srsran_softbuffer_rx_free(&softbuffer_rx); for (cf_t* p : rx_buffer) { if (p != nullptr) { free(p); @@ -242,10 +235,20 @@ bool cc_worker::work_dl() srsran_sch_cfg_nr_t pdsch_cfg = {}; srsran_pdsch_ack_resource_nr_t ack_resource = {}; if (phy->get_dl_pending_grant(dl_slot_cfg.idx, pdsch_cfg, ack_resource, pid)) { - // As HARQ processes are not implemented nor LDPC early-stop, retransmissions are disabled for performance reasons - if (pdsch_cfg.grant.tb[0].rv != 0) { - phy->set_pending_ack(dl_slot_cfg.idx, ack_resource, true); - logger.warning("PDSCH Retransmission with rv=%d not supported", pdsch_cfg.grant.tb[0].rv); + // Notify MAC about PDSCH grant + mac_interface_phy_nr::tb_action_dl_t dl_action = {}; + mac_interface_phy_nr::mac_nr_grant_dl_t mac_dl_grant = {}; + mac_dl_grant.rnti = pdsch_cfg.grant.rnti; + mac_dl_grant.pid = pid; + mac_dl_grant.rv = pdsch_cfg.grant.tb[0].rv; + mac_dl_grant.ndi = pdsch_cfg.grant.tb[0].ndi; + mac_dl_grant.tbs = pdsch_cfg.grant.tb[0].tbs / 8; + mac_dl_grant.tti = dl_slot_cfg.idx; + phy->stack->new_grant_dl(0, mac_dl_grant, &dl_action); + + // Early stop if MAC says it doesn't need the TB + if (not dl_action.tb.enabled) { + logger.info("Decoding not required. Skipping PDSCH"); return true; } @@ -257,14 +260,10 @@ bool cc_worker::work_dl() } data->N_bytes = pdsch_cfg.grant.tb[0].tbs / 8U; - // Get soft-buffer from MAC - // ... - srsran_softbuffer_rx_reset(&softbuffer_rx); - // Initialise PDSCH Result srsran_pdsch_res_nr_t pdsch_res = {}; pdsch_res.tb[0].payload = data->msg; - pdsch_cfg.grant.tb[0].softbuffer.rx = &softbuffer_rx; + pdsch_cfg.grant.tb[0].softbuffer.rx = dl_action.tb.softbuffer; // Decode actual PDSCH transmission if (srsran_ue_dl_nr_decode_pdsch(&ue_dl, &dl_slot_cfg, &pdsch_cfg, &pdsch_res) < SRSRAN_SUCCESS) { @@ -274,9 +273,27 @@ bool cc_worker::work_dl() // Logging if (logger.info.enabled()) { - std::array str; - srsran_ue_dl_nr_pdsch_info(&ue_dl, &pdsch_cfg, &pdsch_res, str.data(), str.size()); - logger.info(pdsch_res.tb[0].payload, pdsch_cfg.grant.tb[0].tbs / 8, "PDSCH: cc=%d, %s", cc_idx, str.data()); + str_info_t str; + srsran_ue_dl_nr_pdsch_info(&ue_dl, &pdsch_cfg, &pdsch_res, str.data(), (uint32_t)str.size()); + + if (logger.debug.enabled()) { + str_extra_t str_extra; + srsran_sch_cfg_nr_info(&pdsch_cfg, str_extra.data(), (uint32_t)str_extra.size()); + logger.info(pdsch_res.tb[0].payload, + pdsch_cfg.grant.tb[0].tbs / 8, + "PDSCH: cc=%d pid=%d %s\n%s", + cc_idx, + pid, + str.data(), + str_extra.data()); + } else { + logger.info(pdsch_res.tb[0].payload, + pdsch_cfg.grant.tb[0].tbs / 8, + "PDSCH: cc=%d pid=%d %s", + cc_idx, + pid, + str.data()); + } } // Enqueue PDSCH ACK information only if the RNTI is type C @@ -285,21 +302,16 @@ bool cc_worker::work_dl() } // Notify MAC about PDSCH decoding result - if (pdsch_res.tb[0].crc) { - // Prepare grant - mac_interface_phy_nr::mac_nr_grant_dl_t mac_nr_grant = {}; - mac_nr_grant.tb[0] = std::move(data); - mac_nr_grant.pid = pid; - mac_nr_grant.rnti = pdsch_cfg.grant.rnti; - mac_nr_grant.tti = dl_slot_cfg.idx; - - if (pdsch_cfg.grant.rnti_type == srsran_rnti_type_ra) { - phy->rar_grant_tti = dl_slot_cfg.idx; - } + mac_interface_phy_nr::tb_action_dl_result_t mac_dl_result = {}; + mac_dl_result.ack = pdsch_res.tb[0].crc; + mac_dl_result.payload = mac_dl_result.ack ? std::move(data) : nullptr; // only pass data when successful + phy->stack->tb_decoded(cc_idx, mac_dl_grant, std::move(mac_dl_result)); - // Send data to MAC - phy->stack->tb_decoded(cc_idx, mac_nr_grant); + if (pdsch_cfg.grant.rnti_type == srsran_rnti_type_ra) { + phy->rar_grant_tti = dl_slot_cfg.idx; + } + if (pdsch_res.tb[0].crc) { // Generate DL metrics dl_metrics_t dl_m = {}; dl_m.mcs = pdsch_cfg.grant.tb[0].mcs; @@ -388,7 +400,7 @@ bool cc_worker::work_ul() } // Set UCI configuration following procedures - srsran_ra_ul_set_grant_uci_nr(&phy->cfg.pusch, &uci_data.cfg, &pusch_cfg); + srsran_ra_ul_set_grant_uci_nr(&phy->carrier, &phy->cfg.pusch, &uci_data.cfg, &pusch_cfg); // Assigning MAC provided values to PUSCH config structs pusch_cfg.grant.tb[0].softbuffer.tx = ul_action.tb.softbuffer; @@ -406,14 +418,29 @@ bool cc_worker::work_ul() // PUSCH Logging if (logger.info.enabled()) { - std::array str; + str_info_t str; srsran_ue_ul_nr_pusch_info(&ue_ul, &pusch_cfg, &data.uci, str.data(), str.size()); - logger.info(ul_action.tb.payload->msg, - pusch_cfg.grant.tb[0].tbs / 8, - "PUSCH: cc=%d, %s, tti_tx=%d", - cc_idx, - str.data(), - ul_slot_cfg.idx); + + if (logger.debug.enabled()) { + str_extra_t str_extra; + srsran_sch_cfg_nr_info(&pusch_cfg, str_extra.data(), (uint32_t)str_extra.size()); + logger.info(ul_action.tb.payload->msg, + pusch_cfg.grant.tb[0].tbs / 8, + "PUSCH: cc=%d pid=%d %s tti_tx=%d\n%s", + cc_idx, + pid, + str.data(), + ul_slot_cfg.idx, + str_extra.data()); + } else { + logger.info(ul_action.tb.payload->msg, + pusch_cfg.grant.tb[0].tbs / 8, + "PUSCH: cc=%d pid=%d %s tti_tx=%d", + cc_idx, + pid, + str.data(), + ul_slot_cfg.idx); + } } // Set metrics diff --git a/srsue/src/phy/nr/sf_worker.cc b/srsue/src/phy/nr/sf_worker.cc index c04d4ce19..27292bc4c 100644 --- a/srsue/src/phy/nr/sf_worker.cc +++ b/srsue/src/phy/nr/sf_worker.cc @@ -108,7 +108,7 @@ void sf_worker::work_imp() // Notify MAC about PRACH transmission phy_state->stack->prach_sent(TTI_TX(tti_rx), srsran_prach_nr_start_symbol_fr1_unpaired(phy_state->cfg.prach.config_idx), - SRSRAN_SLOT_NR_MOD(phy_state->carrier.numerology, TTI_TX(tti_rx)), + SRSRAN_SLOT_NR_MOD(phy_state->carrier.scs, TTI_TX(tti_rx)), 0, 0); diff --git a/srsue/src/phy/nr/worker_pool.cc b/srsue/src/phy/nr/worker_pool.cc index f12e9d91f..4bff9d4b3 100644 --- a/srsue/src/phy/nr/worker_pool.cc +++ b/srsue/src/phy/nr/worker_pool.cc @@ -31,7 +31,7 @@ bool worker_pool::init(const phy_args_nr_t& args, phy_common* common, stack_inte phy_state.args = args; // Set carrier attributes - phy_state.carrier.id = 500; + phy_state.carrier.pci = 500; phy_state.carrier.nof_prb = args.nof_prb; // Set NR arguments @@ -58,10 +58,11 @@ bool worker_pool::init(const phy_args_nr_t& args, phy_common* common, stack_inte } } + // Set PHY loglevel + logger.set_level(srslog::str_to_basic_level(args.log.phy_level)); + // Initialise PRACH - auto& prach_log = srslog::fetch_basic_logger("PRACH-NR"); - prach_log.set_level(srslog::str_to_basic_level(args.log.phy_level)); - prach_buffer = std::unique_ptr(new prach(prach_log)); + prach_buffer = std::unique_ptr(new prach(logger)); prach_buffer->init(phy_state.args.dl.nof_max_prb); return true; @@ -81,7 +82,7 @@ sf_worker* worker_pool::wait_worker(uint32_t tti) sf_worker* worker = (sf_worker*)pool.wait_worker(tti); // Generate PRACH if ready - if (prach_buffer->is_ready_to_send(tti, phy_state.carrier.id)) { + if (prach_buffer->is_ready_to_send(tti, phy_state.carrier.pci)) { uint32_t nof_prach_sf = 0; float prach_target_power = 0.0f; cf_t* prach_ptr = prach_buffer->generate(0.0f, &nof_prach_sf, &prach_target_power); @@ -138,7 +139,7 @@ bool worker_pool::set_config(const srsran::phy_cfg_nr_t& cfg) // Set PRACH hard-coded cell srsran_cell_t cell = {}; cell.nof_prb = 50; - cell.id = phy_state.carrier.id; + cell.id = phy_state.carrier.pci; if (not prach_buffer->set_cell(cell, phy_state.cfg.prach)) { logger.error("Error setting PRACH cell"); return false; diff --git a/srsue/src/stack/mac/proc_ra.cc b/srsue/src/stack/mac/proc_ra.cc index cf7c052c2..125ef19b8 100644 --- a/srsue/src/stack/mac/proc_ra.cc +++ b/srsue/src/stack/mac/proc_ra.cc @@ -120,10 +120,6 @@ void ra_proc::read_params() maskIndex = 0; // same } - if (rach_cfg.nof_groupA_preambles == 0) { - rach_cfg.nof_groupA_preambles = rach_cfg.nof_preambles; - } - phy_interface_mac_lte::prach_info_t prach_info = phy_h->prach_get_info(); delta_preamble_db = delta_preamble_db_table[prach_info.preamble_format % 5]; @@ -240,31 +236,43 @@ void ra_proc::initialization() void ra_proc::resource_selection() { ra_group_t sel_group; + uint32_t nof_groupB_preambles = rach_cfg.nof_preambles - rach_cfg.nof_groupA_preambles; - uint32_t nof_groupB_preambles = 0; - if (rach_cfg.nof_groupA_preambles > 0) { - nof_groupB_preambles = rach_cfg.nof_preambles - rach_cfg.nof_groupA_preambles; - } - + // If ra-PreambleIndex (Random Access Preamble) and ra-PRACH-MaskIndex (PRACH Mask Index) have been + // explicitly signalled and ra-PreambleIndex is not 000000: if (preambleIndex > 0) { - // Preamble is chosen by Higher layers (ie Network) + // the Random Access Preamble and the PRACH Mask Index are those explicitly signalled. sel_maskIndex = maskIndex; sel_preamble = (uint32_t)preambleIndex; } else { - // Preamble is chosen by MAC UE + // else the Random Access Preamble shall be selected by the UE as follows: if (!mux_unit->msg3_is_transmitted()) { - if (nof_groupB_preambles && + // If Msg3 has not yet been transmitted, the UE shall: + // if Random Access Preambles group B exists and if the potential message size (data available for transmission + // plus MAC header and, where required, MAC control elements) is greater than messageSizeGroupA and if the + // pathloss is less than P CMAX – preambleInitialReceivedTargetPower – deltaPreambleMsg3 – + // messagePowerOffsetGroupB, then: + if (nof_groupB_preambles > 0 && new_ra_msg_len > rach_cfg.messageSizeGroupA) { // Check also pathloss (Pcmax,deltaPreamble and powerOffset) + // select the Random Access Preambles group B; sel_group = RA_GROUP_B; } else { + // else: + // select the Random Access Preambles group A. sel_group = RA_GROUP_A; } last_msg3_group = sel_group; } else { + // else, if Msg3 is being retransmitted, the UE shall: + // select the same group of Random Access Preambles as was used for the preamble transmission attempt + // corresponding to the first transmission of Msg3. sel_group = last_msg3_group; } + + // randomly select a Random Access Preamble within the selected group. The random function shall be such + // that each of the allowed selections can be chosen with equal probability; if (sel_group == RA_GROUP_A) { - if (rach_cfg.nof_groupA_preambles) { + if (rach_cfg.nof_groupA_preambles > 0) { // randomly choose preamble from [0 nof_groupA_preambles) sel_preamble = rand() % rach_cfg.nof_groupA_preambles; } else { @@ -282,6 +290,8 @@ void ra_proc::resource_selection() return; } } + + // set PRACH Mask Index to 0. sel_maskIndex = 0; } diff --git a/srsue/src/stack/mac_nr/CMakeLists.txt b/srsue/src/stack/mac_nr/CMakeLists.txt index 7ef2f8b86..95cd16b39 100644 --- a/srsue/src/stack/mac_nr/CMakeLists.txt +++ b/srsue/src/stack/mac_nr/CMakeLists.txt @@ -18,8 +18,15 @@ # and at http://www.gnu.org/licenses/. # -set(SOURCES mac_nr.cc proc_ra_nr.cc proc_bsr_nr.cc proc_sr_nr.cc mux_nr.cc ul_harq_nr.cc) +set(SOURCES mac_nr.cc + proc_ra_nr.cc + proc_bsr_nr.cc + proc_sr_nr.cc + mux_nr.cc + demux_nr.cc + dl_harq_nr.cc + ul_harq_nr.cc) add_library(srsue_mac_nr STATIC ${SOURCES}) target_link_libraries(srsue_mac_nr srsue_mac_common srsran_mac) -add_subdirectory(test) \ No newline at end of file +add_subdirectory(test) diff --git a/srsue/src/stack/mac_nr/demux_nr.cc b/srsue/src/stack/mac_nr/demux_nr.cc new file mode 100644 index 000000000..dce9c4e87 --- /dev/null +++ b/srsue/src/stack/mac_nr/demux_nr.cc @@ -0,0 +1,81 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2021 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include "srsue/hdr/stack/mac_nr/demux_nr.h" +#include "srsran/common/buffer_pool.h" +#include "srsran/interfaces/ue_rlc_interfaces.h" + +namespace srsue { + +demux_nr::demux_nr(srslog::basic_logger& logger_) : logger(logger_) {} + +demux_nr::~demux_nr() {} + +int32_t demux_nr::init(rlc_interface_mac* rlc_) +{ + rlc = rlc_; + return SRSRAN_SUCCESS; +} + +// Enqueues PDU and returns quickly +void demux_nr::push_pdu(srsran::unique_byte_buffer_t pdu, uint32_t tti) +{ + pdu_queue.push(std::move(pdu)); +} + +void demux_nr::process_pdus() +{ + while (not pdu_queue.empty()) { + srsran::unique_byte_buffer_t pdu = pdu_queue.wait_pop(); + handle_pdu(std::move(pdu)); + } +} + +/// Handling of DLSCH PDUs only +void demux_nr::handle_pdu(srsran::unique_byte_buffer_t pdu) +{ + logger.info(pdu->msg, pdu->N_bytes, "Handling MAC PDU (%d B)", pdu->N_bytes); + + rx_pdu.init_rx(); + if (rx_pdu.unpack(pdu->msg, pdu->N_bytes) != SRSRAN_SUCCESS) { + return; + } + + for (uint32_t i = 0; i < rx_pdu.get_num_subpdus(); ++i) { + srsran::mac_sch_subpdu_nr subpdu = rx_pdu.get_subpdu(i); + logger.info("Handling subPDU %d/%d: rnti=0x%x lcid=%d, sdu_len=%d", + i + 1, + rx_pdu.get_num_subpdus(), + subpdu.get_c_rnti(), + subpdu.get_lcid(), + subpdu.get_sdu_length()); + + // Handle Timing Advance CE + switch (subpdu.get_lcid()) { + case srsran::mac_sch_subpdu_nr::nr_lcid_sch_t::DRX_CMD: + logger.info("DRX CE not implemented."); + break; + case srsran::mac_sch_subpdu_nr::nr_lcid_sch_t::TA_CMD: + logger.info("Timing Advance CE not implemented."); + break; + case srsran::mac_sch_subpdu_nr::nr_lcid_sch_t::CON_RES_ID: + logger.info("Contention Resolution CE not implemented."); + break; + default: + if (subpdu.is_sdu()) { + rlc->write_pdu(subpdu.get_lcid(), subpdu.get_sdu(), subpdu.get_sdu_length()); + } + } + } +} + +} // namespace srsue diff --git a/srsue/src/stack/mac_nr/dl_harq_nr.cc b/srsue/src/stack/mac_nr/dl_harq_nr.cc new file mode 100644 index 000000000..14a99b9a6 --- /dev/null +++ b/srsue/src/stack/mac_nr/dl_harq_nr.cc @@ -0,0 +1,243 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2021 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include "srsue/hdr/stack/mac_nr/dl_harq_nr.h" +#include "srsran/common/mac_pcap.h" +#include "srsran/common/rwlock_guard.h" +#include "srsran/srslog/logger.h" +#include "srsue/hdr/stack/mac_nr/demux_nr.h" + +namespace srsue { + +dl_harq_entity_nr::dl_harq_entity_nr(uint8_t cc_idx_, + mac_interface_harq_nr* mac_, + demux_interface_harq_nr* demux_unit_) : + logger(srslog::fetch_basic_logger("MAC-NR")), cc_idx(cc_idx_), mac(mac_), demux_unit(demux_unit_), bcch_proc(this) +{ + // Init broadcast HARQ process + bcch_proc.init(-1); + pthread_rwlock_init(&rwlock, NULL); +} + +dl_harq_entity_nr::~dl_harq_entity_nr() +{ + pthread_rwlock_destroy(&rwlock); +} + +// Called from Stack thread through MAC (TODO: add shared::mutex) +int32_t dl_harq_entity_nr::set_config(const srsran::dl_harq_cfg_nr_t& cfg_) +{ + srsran::rwlock_write_guard lock(rwlock); + if (cfg_.nof_procs < 1 || cfg_.nof_procs > SRSRAN_MAX_HARQ_PROC_DL_NR) { + logger.error("Invalid configuration: %d HARQ processes not supported", cfg_.nof_procs); + return SRSRAN_ERROR; + } + + // clear old processees + for (auto& proc : harq_procs) { + proc = nullptr; + } + + // Allocate and init configured HARQ processes + for (uint32_t i = 0; i < cfg.nof_procs; i++) { + harq_procs[i] = std::unique_ptr(new dl_harq_process_nr(this)); + if (!harq_procs.at(i)->init(i)) { + logger.error("Error while initializing DL-HARQ process %d", i); + return SRSRAN_ERROR; + } + } + + cfg = cfg_; + + logger.debug("cc_idx=%d, set number of HARQ processes for DL to %d", cc_idx, cfg.nof_procs); + + return SRSRAN_SUCCESS; +} + +// Called from PHY workers +void dl_harq_entity_nr::new_grant_dl(const mac_nr_grant_dl_t& grant, mac_interface_phy_nr::tb_action_dl_t* action) +{ + srsran::rwlock_read_guard lock(rwlock); + + *action = {}; + + // Fetch HARQ process + dl_harq_process_nr* proc_ptr = nullptr; + if (grant.rnti == SRSRAN_SIRNTI) { + // Set BCCH PID for SI RNTI + proc_ptr = &bcch_proc; + } else { + if (grant.pid >= cfg.nof_procs) { + logger.error("Grant for invalid HARQ PID=%d", grant.pid); + return; + } + proc_ptr = harq_procs.at(grant.pid).get(); + } + + // Check NDI toggled state before forwarding to process + bool ndi_toggled = (grant.ndi != harq_procs.at(grant.pid)->get_ndi()); + + if (grant.rnti == mac->get_temp_crnti() && last_temporal_crnti != mac->get_temp_crnti()) { + // Consider the NDI to have been toggled + last_temporal_crnti = mac->get_temp_crnti(); + logger.info("Considering NDI in pid=%d to be toggled for first Temporal C-RNTI", grant.pid); + ndi_toggled = true; + } + + proc_ptr->new_grant_dl(std::move(grant), ndi_toggled, action); +} + +/// Called from PHY workers +void dl_harq_entity_nr::tb_decoded(const mac_nr_grant_dl_t& grant, mac_interface_phy_nr::tb_action_dl_result_t result) +{ + srsran::rwlock_read_guard lock(rwlock); + + if (grant.rnti == SRSRAN_SIRNTI) { + bcch_proc.tb_decoded(grant, std::move(result)); + } else { + if (grant.pid >= cfg.nof_procs) { + logger.error("Decoded TB for invalid HARQ PID=%d", grant.pid); + return; + } + harq_procs.at(grant.pid)->tb_decoded(grant, std::move(result)); + } +} + +/// Called from MAC (Stack thread after, e.g. time alignment expire) +void dl_harq_entity_nr::reset() +{ + srsran::rwlock_write_guard lock(rwlock); + for (const auto& proc : harq_procs) { + if (proc != nullptr) { + proc->reset(); + } + } + bcch_proc.reset(); +} + +float dl_harq_entity_nr::get_average_retx() +{ + return average_retx; +} + +dl_harq_entity_nr::dl_harq_process_nr::dl_harq_process_nr(dl_harq_entity_nr* parent_) : + harq_entity(parent_), + softbuffer_rx(std::unique_ptr(new srsran_softbuffer_rx_t())), + logger(srslog::fetch_basic_logger("MAC-NR")) +{} + +dl_harq_entity_nr::dl_harq_process_nr::~dl_harq_process_nr() +{ + if (softbuffer_rx != nullptr) { + srsran_softbuffer_rx_free(softbuffer_rx.get()); + } +} + +bool dl_harq_entity_nr::dl_harq_process_nr::init(int pid_) +{ + if (softbuffer_rx == nullptr || srsran_softbuffer_rx_init_guru(softbuffer_rx.get(), + SRSRAN_SCH_NR_MAX_NOF_CB_LDPC, + SRSRAN_LDPC_MAX_LEN_ENCODED_CB) != SRSRAN_SUCCESS) { + logger.error("Couldn't allocate and/or initialize softbuffer"); + return false; + } + + if (pid_ < 0) { + is_bcch = true; + pid = 0; + } else { + pid = (uint32_t)pid_; + is_bcch = false; + } + + return true; +} + +void dl_harq_entity_nr::dl_harq_process_nr::reset(void) +{ + current_grant = {}; + is_first_tb = true; + n_retx = 0; +} + +uint8_t dl_harq_entity_nr::dl_harq_process_nr::get_ndi() +{ + return current_grant.ndi; +} + +void dl_harq_entity_nr::dl_harq_process_nr::new_grant_dl(const mac_nr_grant_dl_t& grant, + const bool& ndi_toggled, + mac_interface_phy_nr::tb_action_dl_t* action) +{ + // Determine if it's a new transmission 5.3.2.2 + if (ndi_toggled || // 1st condition (NDI has changed) + (is_bcch && grant.rv == 0) || // 2nd condition (Broadcast and 1st transmission) + is_first_tb) // 3rd condition (is first tx for this tb) + { + // New transmission + n_retx = 0; + srsran_softbuffer_rx_reset_tbs(softbuffer_rx.get(), grant.tbs * 8); + + action->tb.enabled = true; + action->tb.softbuffer = softbuffer_rx.get(); + + // reset conditions + is_first_tb = false; + } else { + // This is a retransmission + if (not acked) { + // If data has not yet been successfully decoded, instruct the PHY to combine the received data + action->tb.enabled = true; + action->tb.softbuffer = softbuffer_rx.get(); + } else { + logger.info("DL %d: Received duplicate. Discarding and retransmitting ACK (n_retx=%d)", pid, n_retx); + } + } + + // increment counter and store grant + n_retx++; + current_grant = grant; +} + +void dl_harq_entity_nr::dl_harq_process_nr::tb_decoded(const mac_nr_grant_dl_t& grant, + mac_interface_phy_nr::tb_action_dl_result_t result) +{ + acked = result.ack; + + if (acked and result.payload != nullptr) { + if (is_bcch) { + logger.warning("Delivering PDU=%d bytes to Dissassemble and Demux unit (BCCH) not implemented", grant.tbs); + reset(); + } else { + if (grant.rnti == harq_entity->mac->get_temp_crnti()) { + logger.debug("Delivering PDU=%d bytes to Dissassemble and Demux unit (Temporal C-RNTI) not implemented", + grant.tbs); + } else { + logger.debug("Delivering PDU=%d bytes to Dissassemble and Demux unit", grant.tbs); + harq_entity->demux_unit->push_pdu(std::move(result.payload), grant.tti); + + // Compute average number of retransmissions per packet + harq_entity->average_retx = SRSRAN_VEC_CMA((float)n_retx, harq_entity->average_retx, harq_entity->nof_pkts++); + } + } + } + + logger.info("DL %d: %s tbs=%d, rv=%d, ack=%s, ndi=%d", + pid, + grant.rv == 0 ? "newTX" : "reTX ", + grant.tbs, + grant.rv, + acked ? "OK" : "KO", + grant.ndi); +} + +} // namespace srsue diff --git a/srsue/src/stack/mac_nr/mac_nr.cc b/srsue/src/stack/mac_nr/mac_nr.cc index bc96c6b9d..f5e5a74a8 100644 --- a/srsue/src/stack/mac_nr/mac_nr.cc +++ b/srsue/src/stack/mac_nr/mac_nr.cc @@ -33,9 +33,11 @@ mac_nr::mac_nr(srsran::ext_task_sched_handle task_sched_) : proc_sr(logger), proc_bsr(logger), mux(*this, logger), + demux(logger), pcap(nullptr) { // Create PCell HARQ entities + dl_harq.at(PCELL_CC_IDX) = dl_harq_entity_nr_ptr(new dl_harq_entity_nr(PCELL_CC_IDX, this, &demux)); ul_harq.at(PCELL_CC_IDX) = ul_harq_entity_nr_ptr(new ul_harq_entity_nr(PCELL_CC_IDX, this, &proc_ra, &mux)); } @@ -71,6 +73,11 @@ int mac_nr::init(const mac_nr_args_t& args_, return SRSRAN_ERROR; } + if (demux.init(rlc) != SRSRAN_SUCCESS) { + logger.error("Couldn't initialize demux unit."); + return SRSRAN_ERROR; + } + // Configure PCell HARQ entities if (ul_harq.at(PCELL_CC_IDX)->init() != SRSRAN_SUCCESS) { logger.error("Couldn't initialize UL HARQ entity."); @@ -107,6 +114,8 @@ void mac_nr::run_tti(const uint32_t tti) return; } + logger.set_context(tti); + // Step all procedures logger.debug("Running MAC tti=%d", tti); @@ -115,6 +124,9 @@ void mac_nr::run_tti(const uint32_t tti) proc_bsr.step(tti, mac_buffer_states); proc_sr.step(tti); + + // process received PDUs + stack_task_dispatch_queue.push([this]() { process_pdus(); }); } void mac_nr::update_buffer_states() @@ -237,49 +249,80 @@ bool mac_nr::sr_opportunity(uint32_t tti, uint32_t sr_id, bool meas_gap, bool ul } // This function handles all PCAP writing for a decoded DL TB -void mac_nr::write_pcap(const uint32_t cc_idx, mac_nr_grant_dl_t& grant) +void mac_nr::write_pcap(const uint32_t cc_idx, const mac_nr_grant_dl_t& grant, tb_action_dl_result_t& tb) { if (pcap) { - for (uint32_t i = 0; i < SRSRAN_MAX_CODEWORDS; ++i) { - if (grant.tb[i] != nullptr) { - if (proc_ra.has_rar_rnti() && grant.rnti == proc_ra.get_rar_rnti()) { - pcap->write_dl_ra_rnti_nr(grant.tb[i]->msg, grant.tb[i]->N_bytes, grant.rnti, true, grant.tti); - } else if (grant.rnti == SRSRAN_PRNTI) { - pcap->write_dl_pch_nr(grant.tb[i]->msg, grant.tb[i]->N_bytes, grant.rnti, true, grant.tti); - } else { - pcap->write_dl_crnti_nr(grant.tb[i]->msg, grant.tb[i]->N_bytes, grant.rnti, true, grant.tti); - } + if (tb.ack && tb.payload != nullptr) { + if (proc_ra.has_rar_rnti() && grant.rnti == proc_ra.get_rar_rnti()) { + pcap->write_dl_ra_rnti_nr(tb.payload->msg, tb.payload->N_bytes, grant.rnti, true, grant.tti); + } else if (grant.rnti == SRSRAN_PRNTI) { + pcap->write_dl_pch_nr(tb.payload->msg, tb.payload->N_bytes, grant.rnti, true, grant.tti); + } else { + pcap->write_dl_crnti_nr(tb.payload->msg, tb.payload->N_bytes, grant.rnti, true, grant.tti); } } } } /** - * \brief Called from PHY after decoding a TB + * \brief Called from PHY after decoding PDCCH for DL reception * - * The TB can directly be used - * - * @param cc_idx - * @param grant structure + * @param cc_idx The CC index + * @param grant The DL grant + * @param action The DL action to be filled by MAC */ -void mac_nr::tb_decoded(const uint32_t cc_idx, mac_nr_grant_dl_t& grant) +void mac_nr::new_grant_dl(const uint32_t cc_idx, const mac_nr_grant_dl_t& grant, tb_action_dl_t* action) +{ + logger.debug("new_grant_dl(): cc_idx=%d, tti=%d, rnti=%d, pid=%d, tbs=%d, ndi=%d, rv=%d", + cc_idx, + grant.tti, + grant.rnti, + grant.pid, + grant.tbs, + grant.ndi, + grant.rv); + + // Assert HARQ entity + if (dl_harq.at(cc_idx) == nullptr) { + logger.error("HARQ entity %d has not been created", cc_idx); + return; + } + + dl_harq.at(cc_idx)->new_grant_dl(grant, action); +} + +void mac_nr::tb_decoded(const uint32_t cc_idx, const mac_nr_grant_dl_t& grant, tb_action_dl_result_t result) { - write_pcap(cc_idx, grant); - // handle PDU + logger.debug("tb_decoded(): cc_idx=%d, tti=%d, rnti=%d, pid=%d, tbs=%d, ndi=%d, rv=%d, result=%s", + cc_idx, + grant.tti, + grant.rnti, + grant.pid, + grant.tbs, + grant.ndi, + grant.rv, + result.ack ? "OK" : "KO"); + + write_pcap(cc_idx, grant, result); + if (proc_ra.has_rar_rnti() && grant.rnti == proc_ra.get_rar_rnti()) { - proc_ra.handle_rar_pdu(grant); + proc_ra.handle_rar_pdu(result); } else { - // Push DL PDUs to queue for background processing - for (uint32_t i = 0; i < SRSRAN_MAX_CODEWORDS; ++i) { - if (grant.tb[i] != nullptr) { - metrics[cc_idx].rx_pkts++; - metrics[cc_idx].rx_brate += grant.tb[i]->N_bytes * 8; - pdu_queue.push(std::move(grant.tb[i])); - } + // Assert HARQ entity + if (dl_harq.at(cc_idx) == nullptr) { + logger.error("HARQ entity %d has not been created", cc_idx); + return; } + + dl_harq.at(cc_idx)->tb_decoded(grant, std::move(result)); } - stack_task_dispatch_queue.push([this]() { process_pdus(); }); + // do metrics + metrics[cc_idx].rx_brate += grant.tbs * 8; + metrics[cc_idx].rx_pkts++; + if (not result.ack) { + metrics[cc_idx].rx_errors++; + } } void mac_nr::new_grant_ul(const uint32_t cc_idx, const mac_nr_grant_ul_t& grant, tb_action_ul_t* action) @@ -354,19 +397,32 @@ int mac_nr::setup_lcid(const srsran::logical_channel_config_t& config) int mac_nr::add_tag_config(const srsran::tag_cfg_nr_t& tag_cfg) { - logger.warning("Add tag config not supported yet"); + logger.info("Add tag config not supported yet"); return SRSRAN_SUCCESS; } int mac_nr::remove_tag_config(const uint32_t tag_id) { - logger.warning("Remove tag config not supported yet"); + logger.info("Remove tag config not supported yet"); return SRSRAN_SUCCESS; } int mac_nr::set_config(const srsran::phr_cfg_nr_t& phr_cfg) { - logger.warning("Add phr config not supported yet"); + logger.info("Add phr config not supported yet"); + return SRSRAN_SUCCESS; +} + +int mac_nr::set_config(const srsran::dl_harq_cfg_nr_t& dl_hrq_cfg) +{ + for (const auto& cc : dl_harq) { + if (cc != nullptr) { + if (cc->set_config(dl_hrq_cfg) != SRSRAN_SUCCESS) { + logger.error("Couldn't configure DL HARQ entity."); + return SRSRAN_ERROR; + } + } + } return SRSRAN_SUCCESS; } @@ -404,7 +460,7 @@ bool mac_nr::set_crnti(const uint16_t c_rnti_) void mac_nr::start_ra_procedure() { - stack_task_dispatch_queue.push([this]() {proc_ra.start_by_rrc();}); + stack_task_dispatch_queue.push([this]() { proc_ra.start_by_rrc(); }); } bool mac_nr::is_valid_crnti(const uint16_t crnti) @@ -444,48 +500,7 @@ void mac_nr::get_metrics(mac_metrics_t m[SRSRAN_MAX_CARRIERS]) */ void mac_nr::process_pdus() { - while (started and not pdu_queue.empty()) { - srsran::unique_byte_buffer_t pdu = pdu_queue.wait_pop(); - // TODO: delegate to demux class - handle_pdu(std::move(pdu)); - } -} - -void mac_nr::handle_pdu(srsran::unique_byte_buffer_t pdu) -{ - logger.info(pdu->msg, pdu->N_bytes, "Handling MAC PDU (%d B)", pdu->N_bytes); - - rx_pdu.init_rx(); - if (rx_pdu.unpack(pdu->msg, pdu->N_bytes) != SRSRAN_SUCCESS) { - return; - } - - for (uint32_t i = 0; i < rx_pdu.get_num_subpdus(); ++i) { - srsran::mac_sch_subpdu_nr subpdu = rx_pdu.get_subpdu(i); - logger.info("Handling subPDU %d/%d: rnti=0x%x lcid=%d, sdu_len=%d", - i + 1, - rx_pdu.get_num_subpdus(), - subpdu.get_c_rnti(), - subpdu.get_lcid(), - subpdu.get_sdu_length()); - - // Handle Timing Advance CE - switch (subpdu.get_lcid()) { - case srsran::mac_sch_subpdu_nr::nr_lcid_sch_t::DRX_CMD: - logger.info("DRX CE not implemented."); - break; - case srsran::mac_sch_subpdu_nr::nr_lcid_sch_t::TA_CMD: - logger.info("Timing Advance CE not implemented."); - break; - case srsran::mac_sch_subpdu_nr::nr_lcid_sch_t::CON_RES_ID: - logger.info("Contention Resolution CE not implemented."); - break; - default: - if (subpdu.is_sdu()) { - rlc->write_pdu(subpdu.get_lcid(), subpdu.get_sdu(), subpdu.get_sdu_length()); - } - } - } + demux.process_pdus(); } uint64_t mac_nr::get_contention_id() diff --git a/srsue/src/stack/mac_nr/proc_ra_nr.cc b/srsue/src/stack/mac_nr/proc_ra_nr.cc index 7c46c7363..64ecc01b1 100644 --- a/srsue/src/stack/mac_nr/proc_ra_nr.cc +++ b/srsue/src/stack/mac_nr/proc_ra_nr.cc @@ -187,7 +187,7 @@ void proc_ra_nr::ra_preamble_transmission() } // 5.1.4 Random Access Preamble transmission -void proc_ra_nr::ra_response_reception(const mac_interface_phy_nr::mac_nr_grant_dl_t& grant) +void proc_ra_nr::ra_response_reception(const mac_interface_phy_nr::tb_action_dl_result_t& tb) { if (state != WAITING_FOR_RESPONSE_RECEPTION) { logger.warning( @@ -199,34 +199,32 @@ void proc_ra_nr::ra_response_reception(const mac_interface_phy_nr::mac_nr_grant_ // Stop rar timer rar_timeout_timer.stop(); - for (uint32_t i = 0; i < SRSRAN_MAX_CODEWORDS; ++i) { - if (grant.tb[i] != nullptr) { - srsran::mac_rar_pdu_nr pdu; - if (!pdu.unpack(grant.tb[i]->msg, grant.tb[i]->N_bytes)) { - logger.warning("Error unpacking RAR PDU (%d)", i); - return; - } - logger.info("%s", pdu.to_string()); - - for (auto& subpdu : pdu.get_subpdus()) { - if (subpdu.has_rapid() && subpdu.get_rapid() == preamble_index) { - logger.debug("PROC RA NR: Setting UL grant and prepare Msg3"); - temp_crnti = subpdu.get_temp_crnti(); - - // Set Temporary-C-RNTI if provided, otherwise C-RNTI is ok - phy->set_ul_grant(subpdu.get_ul_grant(), temp_crnti, srsran_rnti_type_ra); - - // reset all parameters that are used before rar - rar_rnti = SRSRAN_INVALID_RNTI; - mac.msg3_prepare(); - current_ta = subpdu.get_ta(); - - // Set Backoff parameter - if (subpdu.has_backoff()) { - preamble_backoff = backoff_table_nr[subpdu.get_backoff() % 16]; // TODO multiplied with SCALING_FACTOR_BI. - } else { - preamble_backoff = 0; - } + if (tb.ack && tb.payload != nullptr) { + srsran::mac_rar_pdu_nr pdu; + if (!pdu.unpack(tb.payload->msg, tb.payload->N_bytes)) { + logger.warning("Error unpacking RAR PDU"); + return; + } + logger.info("%s", pdu.to_string()); + + for (auto& subpdu : pdu.get_subpdus()) { + if (subpdu.has_rapid() && subpdu.get_rapid() == preamble_index) { + logger.debug("PROC RA NR: Setting UL grant and prepare Msg3"); + temp_crnti = subpdu.get_temp_crnti(); + + // Set Temporary-C-RNTI if provided, otherwise C-RNTI is ok + phy->set_ul_grant(subpdu.get_ul_grant(), temp_crnti, srsran_rnti_type_ra); + + // reset all parameters that are used before rar + rar_rnti = SRSRAN_INVALID_RNTI; + mac.msg3_prepare(); + current_ta = subpdu.get_ta(); + + // Set Backoff parameter + if (subpdu.has_backoff()) { + preamble_backoff = backoff_table_nr[subpdu.get_backoff() % 16]; // TODO multiplied with SCALING_FACTOR_BI. + } else { + preamble_backoff = 0; } } } @@ -354,11 +352,13 @@ void proc_ra_nr::prach_sent(uint32_t tti, uint32_t s_id, uint32_t t_id, uint32_t } // Called by PHY thread through MAC parent -void proc_ra_nr::handle_rar_pdu(mac_interface_phy_nr::mac_nr_grant_dl_t& grant) +void proc_ra_nr::handle_rar_pdu(mac_interface_phy_nr::tb_action_dl_result_t& result) { // Defer the handling of the grant to main stack thread in ra_response_reception - auto task_handler = [this](const mac_interface_phy_nr::mac_nr_grant_dl_t& t) { ra_response_reception(std::move(t)); }; - task_queue.push(std::bind(task_handler, std::move(grant))); + auto task_handler = [this](const mac_interface_phy_nr::tb_action_dl_result_t& t) { + ra_response_reception(std::move(t)); + }; + task_queue.push(std::bind(task_handler, std::move(result))); } // Called from PHY thread, defer actions therefore. diff --git a/srsue/src/stack/mac_nr/test/proc_ra_nr_test.cc b/srsue/src/stack/mac_nr/test/proc_ra_nr_test.cc index e6b184c73..0030ff380 100644 --- a/srsue/src/stack/mac_nr/test/proc_ra_nr_test.cc +++ b/srsue/src/stack/mac_nr/test/proc_ra_nr_test.cc @@ -81,7 +81,7 @@ public: void rrc_ra_problem() { logger.warning("Dummy MAC RRC ra problem"); } private: - uint16_t crnti = SRSRAN_INVALID_RNTI; + uint16_t crnti = SRSRAN_INVALID_RNTI; srslog::basic_logger& logger; }; @@ -133,12 +133,13 @@ int proc_ra_normal_test() mac_interface_phy_nr::mac_nr_grant_dl_t grant; grant.rnti = 0x16; grant.tti = rach_cfg.ra_responseWindow + tti_start + 3; - grant.pid = 0x0123; + grant.pid = 0x0; uint8_t mac_dl_rar_pdu[] = {0x40, 0x06, 0x68, 0x03, 0x21, 0x46, 0x46, 0x02, 0x00, 0x00, 0x00}; - grant.tb[0] = srsran::make_byte_buffer(); - TESTASSERT(grant.tb[0] != nullptr); - grant.tb[0].get()->append_bytes(mac_dl_rar_pdu, sizeof(mac_dl_rar_pdu)); - proc_ra_nr.handle_rar_pdu(grant); + mac_interface_phy_nr::tb_action_dl_result_t result = {}; + result.payload = srsran::make_byte_buffer(); + TESTASSERT(result.payload != nullptr); + result.payload.get()->append_bytes(mac_dl_rar_pdu, sizeof(mac_dl_rar_pdu)); + proc_ra_nr.handle_rar_pdu(result); task_sched.tic(); task_sched.run_pending_tasks(); diff --git a/srsue/src/stack/mac_nr/ul_harq_nr.cc b/srsue/src/stack/mac_nr/ul_harq_nr.cc index 0185a0315..e99e83df7 100644 --- a/srsue/src/stack/mac_nr/ul_harq_nr.cc +++ b/srsue/src/stack/mac_nr/ul_harq_nr.cc @@ -69,7 +69,7 @@ void ul_harq_entity_nr::new_grant_ul(const mac_interface_phy_nr::mac_nr_grant_ul mac_interface_phy_nr::tb_action_ul_t* action) { if (grant.pid >= harq_procs.size()) { - logger.error("Invalid PID: %d", grant.pid); + logger.error("UL grant for invalid HARQ PID=%d", grant.pid); return; } @@ -108,7 +108,7 @@ void ul_harq_entity_nr::new_grant_ul(const mac_interface_phy_nr::mac_nr_grant_ul int ul_harq_entity_nr::get_current_tbs(uint32_t pid) { if (pid >= harq_procs.size()) { - logger.error("Invalid PID: %d", pid); + logger.error("Invalid HARQ PID=%d", pid); return 0; } return harq_procs.at(pid).get_current_tbs(); diff --git a/srsue/src/stack/rrc/rrc_nr.cc b/srsue/src/stack/rrc/rrc_nr.cc index 8f693aee4..4c0781a75 100644 --- a/srsue/src/stack/rrc/rrc_nr.cc +++ b/srsue/src/stack/rrc/rrc_nr.cc @@ -88,19 +88,32 @@ void rrc_nr::init_core_less() srsran::PDCP_SN_LEN_18, srsran::pdcp_t_reordering_t::ms500, srsran::pdcp_discard_timer_t::ms100, - false}; + false, + srsran_rat_t::nr}; pdcp->add_bearer(args.coreless.drb_lcid, pdcp_cnfg); return; } void rrc_nr::get_metrics(rrc_nr_metrics_t& m) {} +const char* rrc_nr::get_rb_name(uint32_t lcid) +{ + if (is_nr_srb(lcid)) { + return get_srb_name(nr_lcid_to_srb(lcid)); + } + if (lcid_drb.find(lcid) != lcid_drb.end()) { + return get_drb_name(lcid_drb[lcid]); + } + logger.warning("Unable to find lcid: %d. Return invalid LCID"); + return "invalid LCID"; +} + // Timeout callback interface void rrc_nr::timer_expired(uint32_t timeout_id) { - logger.debug("[NR] Handling Timer Expired"); + logger.debug("Handling Timer Expired"); if (timeout_id == fake_measurement_timer.id()) { - logger.debug("[NR] Triggered Fake Measurement"); + logger.debug("Triggered Fake Measurement"); phy_meas_nr_t fake_meas = {}; std::vector phy_meas_nr; @@ -166,27 +179,26 @@ void rrc_nr::log_rrc_message(const std::string& source, } } -bool rrc_nr::add_lcid_rb(uint32_t lcid, rb_type_t rb_type, uint32_t rbid) +bool rrc_nr::add_lcid_drb(uint32_t lcid, uint32_t drb_id) { - if (lcid_rb.find(lcid) != lcid_rb.end()) { - logger.error("Couldn't add RB to LCID. RB %d does exist.", rbid); + if (lcid_drb.find(lcid) != lcid_drb.end()) { + logger.error("Couldn't add DRB to LCID (%d). DRB %d already exists.", lcid, drb_id); return false; } else { - logger.info("Adding lcid %d and radio bearer ID %d with type %s ", lcid, rbid, (rb_type == Srb) ? "SRB" : "DRB"); - lcid_rb[lcid].rb_id = rbid; - lcid_rb[lcid].rb_type = rb_type; + logger.info("Adding lcid %d and radio bearer ID %d", lcid, drb_id); + lcid_drb[lcid] = nr_drb_id_to_drb(drb_id); } return true; } -uint32_t rrc_nr::get_lcid_for_rbid(uint32_t rb_id) +uint32_t rrc_nr::get_lcid_for_drbid(uint32_t drb_id) { - for (auto& rb : lcid_rb) { - if (rb.second.rb_id == rb_id) { + for (auto& rb : lcid_drb) { + if (rb.second == nr_drb_id_to_drb(drb_id)) { return rb.first; } } - logger.error("Couldn't find LCID for rb LCID. RB %d does exist.", rb_id); + logger.error("Couldn't find LCID for DRB. DRB %d does exist.", drb_id); return 0; } @@ -404,13 +416,13 @@ void rrc_nr::phy_meas_stop() { // possbile race condition for fake_measurement timer, which might be set at the same moment as stopped => fix with // phy integration - logger.debug("[NR] Stopping fake measurements"); + logger.debug("Stopping fake measurements"); fake_measurement_timer.stop(); } void rrc_nr::phy_set_cells_to_meas(uint32_t carrier_freq_r15) { - logger.debug("[NR] Measuring phy cell %d ", carrier_freq_r15); + logger.debug("Measuring phy cell %d ", carrier_freq_r15); // Start timer for fake measurements auto timer_expire_func = [this](uint32_t tid) { timer_expired(tid); }; fake_measurement_carrier_freq_r15 = carrier_freq_r15; @@ -420,7 +432,7 @@ void rrc_nr::phy_set_cells_to_meas(uint32_t carrier_freq_r15) bool rrc_nr::configure_sk_counter(uint16_t sk_counter) { - logger.info("[NR] Configure new SK counter %d. Update Key for secondary gnb", sk_counter); + logger.info("Configure new SK counter %d. Update Key for secondary gnb", sk_counter); if (usim->generate_nr_context(sk_counter, &sec_cfg) == false) { return false; } @@ -446,10 +458,7 @@ bool rrc_nr::apply_rlc_add_mod(const rlc_bearer_cfg_s& rlc_bearer_cfg) if (rlc_bearer_cfg.served_radio_bearer_present == true) { if (rlc_bearer_cfg.served_radio_bearer.type() == rlc_bearer_cfg_s::served_radio_bearer_c_::types::drb_id) { drb_id = rlc_bearer_cfg.served_radio_bearer.drb_id(); - add_lcid_rb(lc_ch_id, Drb, drb_id); - } else { - srb_id = rlc_bearer_cfg.served_radio_bearer.srb_id(); - add_lcid_rb(lc_ch_id, Srb, srb_id); + add_lcid_drb(lc_ch_id, drb_id); } } else { logger.warning("In RLC bearer cfg does not contain served radio bearer"); @@ -587,11 +596,61 @@ bool rrc_nr::apply_sp_cell_init_dl_pdcch(const asn1::rrc_nr::pdcch_cfg_s& pdcch_ logger.warning("Option search_spaces_to_add_mod_list not present"); return false; } + if (pdcch_cfg.ctrl_res_set_to_add_mod_list_present) { + for (uint32_t i = 0; i < pdcch_cfg.ctrl_res_set_to_add_mod_list.size(); i++) { + srsran_coreset_t coreset; + if (make_phy_coreset_cfg(pdcch_cfg.ctrl_res_set_to_add_mod_list[i], &coreset) == true) { + phy_cfg.pdcch.coreset[coreset.id] = coreset; + phy_cfg.pdcch.coreset_present[coreset.id] = true; + } else { + logger.warning("Warning while building coreset structure"); + return false; + } + } + } else { + logger.warning("Option ctrl_res_set_to_add_mod_list not present"); + } return true; } bool rrc_nr::apply_sp_cell_init_dl_pdsch(const asn1::rrc_nr::pdsch_cfg_s& pdsch_cfg) { + if (pdsch_cfg.zp_csi_rs_res_to_add_mod_list_present) { + for (uint32_t i = 0; i < pdsch_cfg.zp_csi_rs_res_to_add_mod_list.size(); i++) { + srsran_csi_rs_zp_resource_t zp_csi_rs_resource; + if (make_phy_zp_csi_rs_resource(pdsch_cfg.zp_csi_rs_res_to_add_mod_list[i], &zp_csi_rs_resource) == true) { + // temporally store csi_rs_zp_res + csi_rs_zp_res[zp_csi_rs_resource.id] = zp_csi_rs_resource; + } else { + logger.warning("Warning while building zp_csi_rs resource"); + return false; + } + } + } else { + logger.warning("Option zp_csi_rs_res_to_add_mod_list not present"); + return false; + } + + if (pdsch_cfg.p_zp_csi_rs_res_set_present) { + if (pdsch_cfg.p_zp_csi_rs_res_set.type() == setup_release_c::types_opts::setup) { + for (uint32_t i = 0; i < pdsch_cfg.p_zp_csi_rs_res_set.setup().zp_csi_rs_res_id_list.size(); i++) { + uint8_t res = pdsch_cfg.p_zp_csi_rs_res_set.setup().zp_csi_rs_res_id_list[i]; + // use temporally stored values to assign + if (csi_rs_zp_res.find(res) == csi_rs_zp_res.end()) { + logger.warning("Can not find p_zp_csi_rs_res in temporally stored csi_rs_zp_res"); + return false; + } + phy_cfg.pdsch.p_zp_csi_rs_set.data[i] = csi_rs_zp_res[res]; + phy_cfg.pdsch.p_zp_csi_rs_set.count += 1; + } + } else { + logger.warning("Option p_zp_csi_rs_res_set not of type setup"); + return false; + } + } else { + logger.warning("Option p_zp_csi_rs_res_set not present"); + return false; + } return true; } @@ -636,12 +695,60 @@ bool rrc_nr::apply_csi_meas_cfg(const asn1::rrc_nr::csi_meas_cfg_s& csi_meas_cfg logger.warning("Option csi_report_cfg_to_add_mod_list not present"); return false; } + + if (csi_meas_cfg.nzp_csi_rs_res_to_add_mod_list_present) { + for (uint32_t i = 0; i < csi_meas_cfg.nzp_csi_rs_res_to_add_mod_list.size(); i++) { + srsran_csi_rs_nzp_resource_t csi_rs_nzp_resource; + if (make_phy_nzp_csi_rs_resource(csi_meas_cfg.nzp_csi_rs_res_to_add_mod_list[i], &csi_rs_nzp_resource) == true) { + // temporally store csi_rs_zp_res + csi_rs_nzp_res[csi_rs_nzp_resource.id] = csi_rs_nzp_resource; + } else { + logger.warning("Warning while building phy_nzp_csi_rs resource"); + return false; + } + } + } else { + logger.warning("Option nzp_csi_rs_res_to_add_mod_list not present"); + return false; + } + + if (csi_meas_cfg.nzp_csi_rs_res_set_to_add_mod_list_present) { + for (uint32_t i = 0; i < csi_meas_cfg.nzp_csi_rs_res_set_to_add_mod_list.size(); i++) { + uint8_t set_id = csi_meas_cfg.nzp_csi_rs_res_set_to_add_mod_list[i].nzp_csi_res_set_id; + for (uint32_t j = 0; j < csi_meas_cfg.nzp_csi_rs_res_set_to_add_mod_list[i].nzp_csi_rs_res.size(); j++) { + uint8_t res = csi_meas_cfg.nzp_csi_rs_res_set_to_add_mod_list[i].nzp_csi_rs_res[j]; + // use temporally stored values to assign + if (csi_rs_nzp_res.find(res) == csi_rs_nzp_res.end()) { + logger.warning("Can not find p_zp_csi_rs_res in temporally stored csi_rs_zp_res"); + return false; + } + phy_cfg.pdsch.nzp_csi_rs_sets[set_id].data[j] = csi_rs_nzp_res[res]; + phy_cfg.pdsch.nzp_csi_rs_sets[set_id].count += 1; + } + if (csi_meas_cfg.nzp_csi_rs_res_set_to_add_mod_list[i].trs_info_present) { + phy_cfg.pdsch.nzp_csi_rs_sets[set_id].trs_info = true; + } + } + } else { + logger.warning("Option p_zp_csi_rs_res_set not present"); + return false; + } + return true; } bool rrc_nr::apply_dl_common_cfg(const asn1::rrc_nr::dl_cfg_common_s& dl_cfg_common) { if (dl_cfg_common.init_dl_bwp_present) { + if (dl_cfg_common.freq_info_dl_present) { + if (make_phy_carrier_cfg(dl_cfg_common.freq_info_dl, &phy_cfg.carrier) == false) { + logger.warning("Warning while making carrier phy config"); + return false; + } + } else { + logger.warning("Option freq_info_dl not present"); + return false; + } if (dl_cfg_common.init_dl_bwp.pdsch_cfg_common_present) { if (dl_cfg_common.init_dl_bwp.pdsch_cfg_common.type() == asn1::rrc_nr::setup_release_c::types_opts::setup) { @@ -649,8 +756,8 @@ bool rrc_nr::apply_dl_common_cfg(const asn1::rrc_nr::dl_cfg_common_s& dl_cfg_com if (pdcch_cfg_common.common_ctrl_res_set_present) { srsran_coreset_t coreset; if (make_phy_coreset_cfg(pdcch_cfg_common.common_ctrl_res_set, &coreset) == true) { - phy_cfg.pdcch.coreset[coreset.coreset_id] = coreset; - phy_cfg.pdcch.coreset_present[coreset.coreset_id] = true; + phy_cfg.pdcch.coreset[coreset.id] = coreset; + phy_cfg.pdcch.coreset_present[coreset.id] = true; } else { logger.warning("Warning while building coreset structure"); return false; @@ -951,8 +1058,13 @@ bool rrc_nr::apply_sp_cell_cfg(const sp_cell_cfg_s& sp_cell_cfg) if (sp_cell_cfg.recfg_with_sync_present) { const recfg_with_sync_s& recfg_with_sync = sp_cell_cfg.recfg_with_sync; mac->set_crnti(recfg_with_sync.new_ue_id); - // Common config if (recfg_with_sync.sp_cell_cfg_common_present) { + if (recfg_with_sync.sp_cell_cfg_common.pci_present) { + phy_cfg.carrier.pci = recfg_with_sync.sp_cell_cfg_common.pci; + } else { + logger.warning("Option PCI not present"); + return false; + } if (recfg_with_sync.sp_cell_cfg_common.ul_cfg_common_present) { if (apply_ul_common_cfg(recfg_with_sync.sp_cell_cfg_common.ul_cfg_common) == false) { return false; @@ -1060,6 +1172,23 @@ bool rrc_nr::apply_sp_cell_cfg(const sp_cell_cfg_s& sp_cell_cfg) logger.warning("Option ul_cfg not present"); return false; } + + if (sp_cell_cfg.sp_cell_cfg_ded.pdsch_serving_cell_cfg_present) { + if (sp_cell_cfg.sp_cell_cfg_ded.pdsch_serving_cell_cfg.type() == + setup_release_c::types_opts::setup) { + dl_harq_cfg_nr_t dl_harq_cfg_nr; + if (make_mac_dl_harq_cfg_nr_t(sp_cell_cfg.sp_cell_cfg_ded.pdsch_serving_cell_cfg.setup(), &dl_harq_cfg_nr) == + false) { + logger.warning("Failed to make dl_harq_cfg_nr config"); + return false; + } + mac->set_config(dl_harq_cfg_nr); + } + } else { + logger.warning("Option pdsch_serving_cell_cfg not present"); + return false; + } + if (sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg_present) { if (sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg.type() == setup_release_c::types_opts::setup) { if (apply_csi_meas_cfg(sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg.setup()) == false) { @@ -1124,7 +1253,7 @@ bool rrc_nr::apply_cell_group_cfg(const cell_group_cfg_s& cell_group_cfg) bool rrc_nr::apply_drb_release(const uint8_t drb) { - uint32_t lcid = get_lcid_for_rbid(drb); + uint32_t lcid = get_lcid_for_drbid(drb); if(lcid == 0){ logger.warning("Can not release bearer with lcid %d and drb %d", lcid, drb); return false; @@ -1145,7 +1274,7 @@ bool rrc_nr::apply_drb_add_mod(const drb_to_add_mod_s& drb_cfg) return false; } - uint32_t lcid = get_lcid_for_rbid(drb_cfg.drb_id); + uint32_t lcid = get_lcid_for_drbid(drb_cfg.drb_id); // Setup PDCP if (!(drb_cfg.pdcp_cfg.drb_present == true)) { @@ -1232,7 +1361,7 @@ bool rrc_nr::apply_security_cfg(const security_cfg_s& security_cfg) } // Apply security config for all known NR lcids - for (auto& lcid : lcid_rb) { + for (auto& lcid : lcid_drb) { pdcp->config_security(lcid.first, sec_cfg); pdcp->enable_encryption(lcid.first); } diff --git a/srsue/src/stack/ue_stack_lte.cc b/srsue/src/stack/ue_stack_lte.cc index 83e2787ea..fc552201f 100644 --- a/srsue/src/stack/ue_stack_lte.cc +++ b/srsue/src/stack/ue_stack_lte.cc @@ -43,7 +43,7 @@ ue_stack_lte::ue_stack_lte() : rrc_logger(srslog::fetch_basic_logger("RRC", false)), usim_logger(srslog::fetch_basic_logger("USIM", false)), nas_logger(srslog::fetch_basic_logger("NAS", false)), - mac_nr_logger(srslog::fetch_basic_logger("MAC-NR", false)), + mac_nr_logger(srslog::fetch_basic_logger("MAC-NR")), rrc_nr_logger(srslog::fetch_basic_logger("RRC-NR", false)), mac_pcap(), mac_nr_pcap(), @@ -210,8 +210,8 @@ int ue_stack_lte::init(const stack_args_t& args_) sync_task_queue = task_sched.make_task_queue(args.sync_queue_size); mac.init(phy, &rlc, &rrc); - rlc.init(&pdcp, &rrc, task_sched.get_timer_handler(), 0 /* RB_ID_SRB0 */); - pdcp.init(&rlc, &rrc, gw); + rlc.init(&pdcp, &rrc, &rrc_nr, task_sched.get_timer_handler(), 0 /* RB_ID_SRB0 */); + pdcp.init(&rlc, &rrc, &rrc_nr, gw); nas.init(usim.get(), &rrc, gw, args.nas); mac_nr_args_t mac_nr_args = {}; diff --git a/srsue/src/ue.cc b/srsue/src/ue.cc index 30c4e2ef9..d05e3bd6e 100644 --- a/srsue/src/ue.cc +++ b/srsue/src/ue.cc @@ -205,23 +205,21 @@ int ue::parse_args(const all_args_t& args_) return SRSRAN_ERROR; } - if (args.rf.nof_carriers > SRSRAN_MAX_CARRIERS) { - fprintf(stderr, "Maximum number of carriers exceeded (%d > %d)\n", args.rf.nof_carriers, SRSRAN_MAX_CARRIERS); - return SRSRAN_ERROR; - } + args.rf.nof_carriers = args.phy.nof_lte_carriers + args.phy.nof_nr_carriers; - if (args.rf.nof_carriers <= args.phy.nof_nr_carriers) { + if (args.rf.nof_carriers > SRSRAN_MAX_CARRIERS) { fprintf(stderr, - "Maximum number of carriers enough for NR and LTE (%d <= %d)\n", + "Maximum number of carriers exceeded (%d > %d) (nof_lte_carriers %d + nof_nr_carriers %d)\n", args.rf.nof_carriers, + SRSRAN_MAX_CARRIERS, + args.phy.nof_lte_carriers, args.phy.nof_nr_carriers); return SRSRAN_ERROR; } // replicate some RF parameter to make them available to PHY - args.phy.nof_lte_carriers = args.rf.nof_carriers - args.phy.nof_nr_carriers; - args.phy.nof_rx_ant = args.rf.nof_antennas; - args.phy.agc_enable = args.rf.rx_gain < 0.0f; + args.phy.nof_rx_ant = args.rf.nof_antennas; + args.phy.agc_enable = args.rf.rx_gain < 0.0f; // populate DL EARFCN list if (not args.phy.dl_earfcn.empty()) { @@ -266,25 +264,12 @@ int ue::parse_args(const all_args_t& args_) // populate NR DL ARFCNs if (args.phy.nof_nr_carriers > 0) { - if (not args.phy.dl_nr_arfcn.empty()) { - // Parse list - srsran::string_parse_list(args.phy.dl_nr_arfcn, ',', args.phy.dl_nr_arfcn_list); - + if (not args.stack.rrc_nr.supported_bands_nr_str.empty()) { // Populates supported bands - for (uint32_t& arfcn : args.phy.dl_nr_arfcn_list) { - std::vector bands = bands_helper.get_bands_nr(arfcn); - for (const auto& band : bands) { - // make sure we don't add duplicates - if (std::find(args.stack.rrc_nr.supported_bands_nr.begin(), - args.stack.rrc_nr.supported_bands_nr.end(), - band) == args.stack.rrc_nr.supported_bands_nr.end()) { - args.stack.rrc_nr.supported_bands_nr.push_back(band); - } - } - } + srsran::string_parse_list(args.stack.rrc_nr.supported_bands_nr_str, ',', args.stack.rrc_nr.supported_bands_nr); } else { - logger.error("Error: dl_nr_arfcn list is empty"); - srsran::console("Error: dl_nr_arfcn list is empty\n"); + logger.error("Error: rat.nr.bands list is empty"); + srsran::console("Error: rat.nr.bands list is empty\n"); return SRSRAN_ERROR; } } diff --git a/srsue/ue.conf.example b/srsue/ue.conf.example index b9ac0e85c..3632f9c05 100644 --- a/srsue/ue.conf.example +++ b/srsue/ue.conf.example @@ -5,16 +5,10 @@ ##################################################################### # RF configuration # -# dl_earfcn: Downlink EARFCN code. # freq_offset: Uplink and Downlink optional frequency offset (in Hz) # tx_gain: Transmit gain (dB). # rx_gain: Optional receive gain (dB). If disabled, AGC if enabled # -# Optional parameters: -# dl_nr_arfcn: Downlink NR ARFCN for EN-DC -# dl_freq: Override DL frequency corresponding to dl_earfcn -# ul_freq: Override UL frequency corresponding to dl_earfcn -# nof_carriers: Number of carriers # nof_antennas: Number of antennas per carrier (all carriers have the same number of antennas) # device_name: Device driver family. Supported options: "auto" (uses first found), "UHD" or "bladeRF" # device_args: Arguments for the device driver. Options are "auto" or any string. @@ -29,13 +23,10 @@ # Default is auto (yes for UHD, no for rest) ##################################################################### [rf] -dl_earfcn = 3350 -#dl_nr_arfcn = 632628 freq_offset = 0 tx_gain = 80 #rx_gain = 40 -#nof_carriers = 1 #nof_antennas = 1 # For best performance in 2x2 MIMO and >= 15 MHz use the following device_args settings: @@ -52,6 +43,31 @@ tx_gain = 80 #device_name = zmq #device_args = tx_port=tcp://*:2001,rx_port=tcp://localhost:2000,id=ue,base_srate=23.04e6 +##################################################################### +# EUTRA RAT configuration +# +# dl_earfcn: Downlink EARFCN list. +# +# Optional parameters: +# dl_freq: Override DL frequency corresponding to dl_earfcn +# ul_freq: Override UL frequency corresponding to dl_earfcn +# nof_carriers: Number of carriers +##################################################################### +[rat.eutra] +dl_earfcn = 3350 +#nof_carriers = 1 + +##################################################################### +# NR RAT configuration +# +# Optional parameters: +# bands: List of support NR bands seperated by a comma (default 78) +# nof_carriers: Number of NR carriers (must be at least 1 for NR support) +##################################################################### +[rat.nr] +# bands = 78 +# nof_carriers = 0 + ##################################################################### # Packet capture configuration # @@ -132,7 +148,7 @@ imei = 353490069873319 # RRC configuration # # ue_category: Sets UE category (range 1-5). Default: 4 -# release: UE Release (8 to 10) +# release: UE Release (8 to 15) # feature_group: Hex value of the featureGroupIndicators field in the # UECapabilityInformation message. Default 0xe6041000 # mbms_service_id: MBMS service id for autostarting MBMS reception @@ -141,7 +157,7 @@ imei = 353490069873319 ##################################################################### [rrc] #ue_category = 4 -#release = 8 +#release = 15 #feature_group = 0xe6041000 #mbms_service_id = -1 #mbms_service_port = 4321