Merge branch 'next' into agpl_next

# Conflicts:
#	lib/include/srsran/interfaces/nr_common_interface_types.h
master
Codebot 4 years ago committed by Your Name
commit 1bb31e42ab

@ -1,6 +1,18 @@
Change Log for Releases 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 ## 20.10.1
* Fix bug in srsENB that effectively disabled UL HARQ * Fix bug in srsENB that effectively disabled UL HARQ

@ -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. See the srsRAN project pages (www.srsran.com) for documentation, guides and project news.
It includes: 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 * srsENB - a complete SDR LTE eNodeB application
* srsEPC - a light-weight LTE core network implementation with MME, HSS and S/P-GW * 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. * 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 * 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 * SR support
* Periodic and Aperiodic CQI feedback support * Periodic and Aperiodic CQI feedback support
* Standard S1AP and GTP-U interfaces to the Core Network * Standard S1AP and GTP-U interfaces to the Core Network

@ -18,8 +18,8 @@
# and at http://www.gnu.org/licenses/. # and at http://www.gnu.org/licenses/.
# #
SET(SRSRAN_VERSION_MAJOR 20) SET(SRSRAN_VERSION_MAJOR 21)
SET(SRSRAN_VERSION_MINOR 10) SET(SRSRAN_VERSION_MINOR 04)
SET(SRSRAN_VERSION_PATCH 1) SET(SRSRAN_VERSION_PATCH 0)
SET(SRSRAN_VERSION_STRING "${SRSRAN_VERSION_MAJOR}.${SRSRAN_VERSION_MINOR}.${SRSRAN_VERSION_PATCH}") SET(SRSRAN_VERSION_STRING "${SRSRAN_VERSION_MAJOR}.${SRSRAN_VERSION_MINOR}.${SRSRAN_VERSION_PATCH}")
SET(SRSRAN_SOVERSION 0) SET(SRSRAN_SOVERSION 0)

@ -35,6 +35,116 @@ constexpr uint32_t ceil_div(uint32_t x, uint32_t y)
return (x + y - 1) / y; return (x + y - 1) / y;
} }
template <typename Integer>
Integer mask_msb_zeros(size_t N)
{
static_assert(std::is_unsigned<Integer>::value, "T must be unsigned integer");
return (N == 0) ? static_cast<Integer>(-1) : (N == sizeof(Integer) * 8U) ? 0 : (static_cast<Integer>(-1) >> (N));
}
template <typename Integer>
Integer mask_lsb_ones(size_t N)
{
return mask_msb_zeros<Integer>(sizeof(Integer) * 8U - N);
}
template <typename Integer>
Integer mask_msb_ones(size_t N)
{
return ~mask_msb_zeros<Integer>(N);
}
template <typename Integer>
Integer mask_lsb_zeros(size_t N)
{
return ~mask_lsb_ones<Integer>(N);
}
namespace detail {
template <typename Integer, size_t SizeOf>
struct zerobit_counter {
static Integer msb_count(Integer value)
{
if (value == 0) {
return std::numeric_limits<Integer>::digits;
}
Integer ret = 0;
for (Integer shift = std::numeric_limits<Integer>::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<Integer>::digits;
}
Integer ret = 0;
for (Integer shift = std::numeric_limits<Integer>::digits >> 1, mask = std::numeric_limits<Integer>::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 <typename Integer>
struct zerobit_counter<Integer, sizeof(unsigned)> {
static Integer msb_count(Integer value)
{
return (value) ? __builtin_clz(value) : std::numeric_limits<Integer>::digits;
}
static Integer lsb_count(Integer value)
{
return (value) ? __builtin_ctz(value) : std::numeric_limits<Integer>::digits;
}
};
#endif
#ifdef __GNUC__ // clang and gcc
/// Specializations for unsigned long
template <typename Integer>
struct zerobit_counter<Integer, sizeof(unsigned long)> {
static Integer msb_count(Integer value)
{
return (value) ? __builtin_clzl(value) : std::numeric_limits<Integer>::digits;
}
static Integer lsb_count(Integer value)
{
return (value) ? __builtin_ctzl(value) : std::numeric_limits<Integer>::digits;
}
};
#endif
} // namespace detail
/// uses lsb as zero position
template <typename Integer>
Integer find_first_msb_one(Integer value)
{
return (value) ? (sizeof(Integer) * 8U - 1 - detail::zerobit_counter<Integer, sizeof(Integer)>::msb_count(value))
: std::numeric_limits<Integer>::digits;
}
/// uses lsb as zero position
template <typename Integer>
Integer find_first_lsb_one(Integer value)
{
return detail::zerobit_counter<Integer, sizeof(Integer)>::lsb_count(value);
}
template <size_t N, bool reversed = false> template <size_t N, bool reversed = false>
class bounded_bitset class bounded_bitset
{ {
@ -109,8 +219,7 @@ public:
bounded_bitset<N, reversed>& fill(size_t startpos, size_t endpos, bool value = true) bounded_bitset<N, reversed>& fill(size_t startpos, size_t endpos, bool value = true)
{ {
assert_within_bounds_(startpos, false); assert_range_bounds_(startpos, endpos);
assert_within_bounds_(endpos, false);
// NOTE: can be optimized // NOTE: can be optimized
if (value) { if (value) {
for (size_t i = startpos; i < endpos; ++i) { for (size_t i = startpos; i < endpos; ++i) {
@ -124,6 +233,19 @@ public:
return *this; 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 bool all() const noexcept
{ {
const size_t nw = nof_words_(); 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; bitpos = get_bitidx_(bitpos);
return ((get_word_(pos) & maskbit(pos)) != static_cast<word_t>(0)); return ((get_word_(bitpos) & maskbit(bitpos)) != static_cast<word_t>(0));
} }
void set_(size_t pos) noexcept void set_(size_t bitpos) noexcept
{ {
pos = reversed ? size() - 1 - pos : pos; bitpos = get_bitidx_(bitpos);
get_word_(pos) |= maskbit(pos); get_word_(bitpos) |= maskbit(bitpos);
} }
void reset_(size_t pos) noexcept void reset_(size_t bitpos) noexcept
{ {
pos = reversed ? size() - 1 - pos : pos; bitpos = get_bitidx_(bitpos);
get_word_(pos) &= ~(maskbit(pos)); get_word_(bitpos) &= ~(maskbit(bitpos));
} }
size_t nof_words_() const noexcept { return size() > 0 ? (size() - 1) / bits_per_word + 1 : 0; } 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; } 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()), srsran_assert(pos < size() or (not strict and pos == size()),
"ERROR: index=%zd is out-of-bounds for bitset of size=%zd", "ERROR: index=%zd is out-of-bounds for bitset of size=%zd",
@ -316,9 +440,98 @@ private:
size()); size());
} }
static word_t maskbit(size_t pos) { return (static_cast<word_t>(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<word_t>(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;
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<word_t>(offset) : mask_lsb_zeros<word_t>(offset);
}
if (i == lastword) {
size_t offset = (endpos - 1) % bits_per_word;
w &= (reversed) ? mask_msb_ones<word_t>(offset + 1) : mask_lsb_ones<word_t>(offset + 1);
}
if (w != 0) {
return static_cast<int>(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<word_t>(offset);
}
if (i == lastword) {
size_t offset = (endpos - 1) % bits_per_word;
w &= mask_lsb_ones<word_t>(offset + 1);
}
if (w != 0) {
return static_cast<int>(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;
}
static size_t max_nof_words_() { return (N - 1) / bits_per_word + 1; } if (i == startword) {
size_t offset = startbitpos % bits_per_word;
w &= mask_lsb_ones<word_t>(offset + 1);
}
if (i == lastword) {
size_t offset = lastbitpos % bits_per_word;
w &= mask_lsb_zeros<word_t>(offset);
}
if (w != 0) {
word_t pos = find_first_msb_one(w);
return static_cast<int>(size() - 1 - (pos + i * bits_per_word));
}
}
return -1;
}
}; };
template <size_t N, bool reversed> template <size_t N, bool reversed>

@ -45,15 +45,15 @@ class expected
public: public:
expected() : has_val(true), val(T{}) {} expected() : has_val(true), val(T{}) {}
expected(T&& t) : has_val(true), val(std::forward<T>(t)) {} expected(T&& t) noexcept : has_val(true), val(std::move(t)) {}
expected(const T& t) : has_val(true), val(t) {} expected(const T& t) : has_val(true), val(t) {}
expected(E&& e) : has_val(false), unexpected(std::forward<E>(e)) {} expected(E&& e) noexcept : has_val(false), unexpected(std::move(e)) {}
expected(const E& e) : has_val(false), unexpected(e) {} expected(const E& e) : has_val(false), unexpected(e) {}
template < template <
typename U, typename U,
typename std::enable_if<std::is_convertible<U, T>::value and not is_expected<typename std::decay<U>::type>::value, typename std::enable_if<std::is_convertible<U, T>::value and not is_expected<typename std::decay<U>::type>::value,
int>::type = 0> int>::type = 0>
explicit expected(U&& u) : has_val(true), val(std::forward<U>(u)) explicit expected(U&& u) noexcept : has_val(true), val(std::forward<U>(u))
{} {}
expected(const expected& other) expected(const expected& other)
{ {

@ -57,6 +57,10 @@ struct sched_request_res_cfg_s;
struct dmrs_ul_cfg_s; struct dmrs_ul_cfg_s;
struct beta_offsets_s; struct beta_offsets_s;
struct uci_on_pusch_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 rrc_nr
} // namespace asn1 } // 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, bool make_phy_beta_offsets(const asn1::rrc_nr::beta_offsets_s& beta_offsets,
srsran_beta_offsets_t* srsran_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_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 * 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); 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); 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_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 * RLC Config
**************************/ **************************/

@ -19,8 +19,8 @@
* *
*/ */
#ifndef SRSRAN_LTE_COMMON_H #ifndef SRSRAN_COMMON_LTE_H
#define SRSRAN_LTE_COMMON_H #define SRSRAN_COMMON_LTE_H
#include <array> #include <array>
#include <cstdint> #include <cstdint>
@ -97,4 +97,4 @@ inline const char* get_drb_name(lte_drb drb_id)
} // namespace srsran } // namespace srsran
#endif // SRSRAN_LTE_COMMON_H #endif // SRSRAN_COMMON_LTE_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 <array>
#include <cstdint>
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<uint32_t>(srb_id);
}
constexpr nr_srb nr_lcid_to_srb(uint32_t lcid)
{
return static_cast<nr_srb>(lcid);
}
constexpr nr_drb nr_drb_id_to_drb(uint32_t drb_id)
{
return static_cast<nr_drb>(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

@ -29,13 +29,13 @@
#ifndef SRSRAN_THREAD_POOL_H #ifndef SRSRAN_THREAD_POOL_H
#define SRSRAN_THREAD_POOL_H #define SRSRAN_THREAD_POOL_H
#include "srsran/adt/circular_buffer.h"
#include "srsran/adt/move_callback.h" #include "srsran/adt/move_callback.h"
#include "srsran/srslog/srslog.h" #include "srsran/srslog/srslog.h"
#include <condition_variable> #include <condition_variable>
#include <functional> #include <functional>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <queue>
#include <stack> #include <stack>
#include <stdint.h> #include <stdint.h>
#include <string> #include <string>
@ -99,6 +99,8 @@ private:
class task_thread_pool class task_thread_pool
{ {
using task_t = srsran::move_callback<void(), default_move_callback_buffer_size, true>; using task_t = srsran::move_callback<void(), default_move_callback_buffer_size, true>;
static constexpr uint32_t max_task_shift = 14;
static constexpr uint32_t max_task_num = 1u << max_task_shift;
public: public:
task_thread_pool(uint32_t nof_workers = 1, bool start_deferred = false, int32_t prio_ = -1, uint32_t mask_ = 255); 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; uint32_t mask = 255;
srslog::basic_logger& logger; srslog::basic_logger& logger;
std::queue<task_t> pending_tasks; srsran::dyn_circular_buffer<task_t> pending_tasks;
std::vector<std::unique_ptr<worker_t> > workers; std::vector<std::unique_ptr<worker_t> > workers;
mutable std::mutex queue_mutex; mutable std::mutex queue_mutex;
std::condition_variable cv_empty; std::condition_variable cv_empty;

@ -161,6 +161,7 @@ public:
virtual void read_pdu_pcch(uint8_t* payload, uint32_t payload_size) = 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 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 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 class rrc_interface_pdcp_nr
{ {

@ -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 { struct rach_cfg_t {
bool enabled; bool enabled;
uint32_t nof_preambles; uint32_t nof_preambles;

@ -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

@ -135,7 +135,8 @@ public:
uint8_t sn_len_, uint8_t sn_len_,
pdcp_t_reordering_t t_reordering_, pdcp_t_reordering_t t_reordering_,
pdcp_discard_timer_t discard_timer_, pdcp_discard_timer_t discard_timer_,
bool status_report_required_) : bool status_report_required_,
srsran::srsran_rat_t rat_) :
bearer_id(bearer_id_), bearer_id(bearer_id_),
rb_type(rb_type_), rb_type(rb_type_),
tx_direction(tx_direction_), tx_direction(tx_direction_),
@ -143,7 +144,8 @@ public:
sn_len(sn_len_), sn_len(sn_len_),
t_reordering(t_reordering_), t_reordering(t_reordering_),
discard_timer(discard_timer_), 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); 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_t_reordering_t t_reordering = pdcp_t_reordering_t::ms500;
pdcp_discard_timer_t discard_timer = pdcp_discard_timer_t::infinity; 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; bool status_report_required = false;

@ -41,856 +41,9 @@ struct phy_cfg_nr_t {
srsran_pdcch_cfg_nr_t pdcch = {}; srsran_pdcch_cfg_nr_t pdcch = {};
srsran_ue_dl_nr_harq_ack_cfg_t harq_ack = {}; srsran_ue_dl_nr_harq_ack_cfg_t harq_ack = {};
srsran_csi_hl_cfg_t csi = {}; srsran_csi_hl_cfg_t csi = {};
srsran_carrier_nr_t carrier = {};
phy_cfg_nr_t() 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;
}
/** /**
* @param carrier * @param carrier

@ -42,13 +42,31 @@ public:
class mac_interface_phy_nr class mac_interface_phy_nr
{ {
public: 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 { typedef struct {
srsran::unique_byte_buffer_t tb[SRSRAN_MAX_TB];
uint32_t pid;
uint16_t rnti; uint16_t rnti;
uint32_t tti; 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; } 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 // UL grant as conveyed between PHY and MAC
typedef struct { typedef struct {
uint16_t rnti; 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_dl_sched_rnti_nr(const uint32_t tti) = 0;
virtual sched_rnti_t get_ul_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 * @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 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::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::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 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 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; virtual int set_config(const srsran::phr_cfg_nr_t& phr_cfg) = 0;

@ -103,6 +103,7 @@ typedef struct SRSRAN_API {
* @brief Contains TS 38.331 NZP-CSI-RS-Resource flattened configuration * @brief Contains TS 38.331 NZP-CSI-RS-Resource flattened configuration
*/ */
typedef struct SRSRAN_API { typedef struct SRSRAN_API {
uint32_t id;
srsran_csi_rs_resource_mapping_t resource_mapping; ///< CSI-RS time/frequency mapping srsran_csi_rs_resource_mapping_t resource_mapping; ///< CSI-RS time/frequency mapping
float power_control_offset; ///< -8..15 dB float power_control_offset; ///< -8..15 dB
float power_control_offset_ss; ///< -3, 0, 3, 6 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 * @brief Contains TS 38.331 ZP-CSI-RS-Resource flattened configuration
*/ */
typedef struct { typedef struct {
uint32_t id;
srsran_csi_rs_resource_mapping_t resource_mapping; ///< CSI-RS time/frequency mapping srsran_csi_rs_resource_mapping_t resource_mapping; ///< CSI-RS time/frequency mapping
srsran_csi_rs_period_and_offset_t periodicity; srsran_csi_rs_period_and_offset_t periodicity;
} srsran_csi_rs_zp_resource_t; } srsran_csi_rs_zp_resource_t;

@ -269,12 +269,27 @@ typedef enum SRSRAN_API {
srsran_resource_alloc_dynamic, srsran_resource_alloc_dynamic,
} srsran_resource_alloc_t; } 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) * @brief NR carrier parameters. It is a combination of fixed cell and bandwidth-part (BWP)
*/ */
typedef struct SRSRAN_API { typedef struct SRSRAN_API {
uint32_t id; uint32_t pci;
uint32_t numerology; uint32_t absolute_frequency_ssb;
uint32_t absolute_frequency_point_a;
srsran_subcarrier_spacing_t scs;
uint32_t nof_prb; uint32_t nof_prb;
uint32_t start; 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 uint32_t max_mimo_layers; ///< @brief DL: Indicates the maximum number of MIMO layers to be used for PDSCH in all BWPs
@ -319,7 +334,6 @@ typedef struct SRSRAN_API {
*/ */
typedef struct SRSRAN_API { typedef struct SRSRAN_API {
uint32_t id; uint32_t id;
uint32_t coreset_id;
srsran_coreset_mapping_type_t mapping_type; srsran_coreset_mapping_type_t mapping_type;
uint32_t duration; uint32_t duration;
bool freq_resources[SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE]; bool freq_resources[SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE];

@ -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); 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 #endif // SRSRAN_DEMOD_SOFT_H

@ -46,8 +46,6 @@ typedef struct SRSRAN_API {
srsran_sch_nr_args_t sch; srsran_sch_nr_args_t sch;
bool measure_evm; bool measure_evm;
bool measure_time; 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; } srsran_pdsch_nr_args_t;
/** /**
@ -68,8 +66,6 @@ typedef struct SRSRAN_API {
uint32_t meas_time_us; uint32_t meas_time_us;
srsran_re_pattern_t dmrs_re_pattern; srsran_re_pattern_t dmrs_re_pattern;
uint32_t nof_rvd_re; 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; } srsran_pdsch_nr_t;
/** /**

@ -173,6 +173,11 @@ typedef struct {
uint32_t csi1_index2; ///< Use for more than 11 CSI bits. Set to 13 if absent. 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_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. 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; } srsran_beta_offsets_t;
/** /**
@ -247,11 +252,11 @@ typedef struct SRSRAN_API {
/// PUSCH only parameters /// PUSCH only parameters
srsran_uci_cfg_nr_t uci; ///< Uplink Control Information configuration srsran_uci_cfg_nr_t uci; ///< Uplink Control Information configuration
bool enable_transform_precoder; 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; bool freq_hopping_enabled;
} srsran_sch_cfg_nr_t; } 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 #endif // SRSRAN_PHCH_CFG_NR_H

@ -59,7 +59,7 @@ typedef struct SRSRAN_API {
srsran_evm_buffer_t* evm_buffer; srsran_evm_buffer_t* evm_buffer;
bool meas_time_en; bool meas_time_en;
uint32_t meas_time_us; 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_ulsch; ///< Temporal Encoded UL-SCH data
uint8_t* g_ack; ///< Temporal Encoded HARQ-ACK bits uint8_t* g_ack; ///< Temporal Encoded HARQ-ACK bits
uint8_t* g_csi1; ///< Temporal Encoded CSI part 1 bits uint8_t* g_csi1; ///< Temporal Encoded CSI part 1 bits

@ -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 * @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 pusch_hl_cfg PUSCH configuration provided by higher layers
* @param uci_cfg Uplink Control Information configuration for this PUSCH transmission * @param uci_cfg Uplink Control Information configuration for this PUSCH transmission
* @param pusch_cfg PUSCH configuration after applying the procedure * @param pusch_cfg PUSCH configuration after applying the procedure
* @return SRSRAN_SUCCESS if the procedure is successful, SRSRAN_ERROR code otherwise * @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, const srsran_uci_cfg_nr_t* uci_cfg,
srsran_sch_cfg_nr_t* pusch_cfg); srsran_sch_cfg_nr_t* pusch_cfg);

@ -40,9 +40,8 @@ typedef struct SRSRAN_API {
double R; ///< Target LDPC rate double R; ///< Target LDPC rate
int rv; ///< Redundancy version int rv; ///< Redundancy version
int ndi; ///< New Data Indicator int ndi; ///< New Data Indicator
int pid; ///< HARQ Process ID uint32_t nof_re; ///< Number of available resource elements to transmit ULSCH (data) and UCI (control)
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 ULSCH
uint32_t nof_bits; ///< Number of available bits to send, known as G
uint32_t cw_idx; uint32_t cw_idx;
bool enabled; bool enabled;

@ -71,6 +71,7 @@ typedef struct {
float alpha; ///< Higher layer parameter scaling float alpha; ///< Higher layer parameter scaling
float beta_harq_ack_offset; float beta_harq_ack_offset;
float beta_csi1_offset; float beta_csi1_offset;
float beta_csi2_offset;
uint32_t nof_re; uint32_t nof_re;
bool csi_part2_present; bool csi_part2_present;
} srsran_uci_nr_pusch_cfg_t; } srsran_uci_nr_pusch_cfg_t;

@ -35,6 +35,10 @@ class pdcp : public srsue::pdcp_interface_rlc, public srsue::pdcp_interface_rrc
public: public:
pdcp(srsran::task_sched_handle task_sched_, const char* logname); pdcp(srsran::task_sched_handle task_sched_, const char* logname);
virtual ~pdcp(); 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 init(srsue::rlc_interface_pdcp* rlc_, srsue::rrc_interface_pdcp* rrc_, srsue::gw_interface_pdcp* gw_);
void stop(); void stop();
@ -80,6 +84,7 @@ public:
private: private:
srsue::rlc_interface_pdcp* rlc = nullptr; srsue::rlc_interface_pdcp* rlc = nullptr;
srsue::rrc_interface_pdcp* rrc = nullptr; srsue::rrc_interface_pdcp* rrc = nullptr;
srsue::rrc_interface_pdcp* rrc_nr = nullptr;
srsue::gw_interface_pdcp* gw = nullptr; srsue::gw_interface_pdcp* gw = nullptr;
srsran::task_sched_handle task_sched; srsran::task_sched_handle task_sched;
srslog::basic_logger& logger; srslog::basic_logger& logger;

@ -160,7 +160,8 @@ protected:
PDCP_SN_LEN_12, PDCP_SN_LEN_12,
pdcp_t_reordering_t::ms500, pdcp_t_reordering_t::ms500,
pdcp_discard_timer_t::infinity, pdcp_discard_timer_t::infinity,
false}; false,
srsran_rat_t::lte};
srsran::as_security_config_t sec_cfg = {}; srsran::as_security_config_t sec_cfg = {};

@ -48,6 +48,13 @@ public:
srsue::rrc_interface_rlc* rrc_, srsue::rrc_interface_rlc* rrc_,
srsran::timer_handler* timers_, srsran::timer_handler* timers_,
uint32_t lcid_); 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_, void init(srsue::pdcp_interface_rlc* pdcp_,
srsue::rrc_interface_rlc* rrc_, srsue::rrc_interface_rlc* rrc_,
srsran::timer_handler* timers_, srsran::timer_handler* timers_,
@ -96,10 +103,11 @@ public:
private: private:
void reset_metrics(); void reset_metrics();
byte_buffer_pool* pool = nullptr;
srslog::basic_logger& logger; srslog::basic_logger& logger;
byte_buffer_pool* pool = nullptr;
srsue::pdcp_interface_rlc* pdcp = nullptr; srsue::pdcp_interface_rlc* pdcp = nullptr;
srsue::rrc_interface_rlc* rrc = nullptr; srsue::rrc_interface_rlc* rrc = nullptr;
srsue::rrc_interface_rlc* rrc_nr = nullptr;
srsran::timer_handler* timers = nullptr; srsran::timer_handler* timers = nullptr;
typedef std::map<uint16_t, rlc_common*> rlc_map_t; typedef std::map<uint16_t, rlc_common*> rlc_map_t;

@ -25,6 +25,7 @@
#include "srsran/adt/accumulators.h" #include "srsran/adt/accumulators.h"
#include "srsran/adt/circular_array.h" #include "srsran/adt/circular_array.h"
#include "srsran/adt/circular_map.h" #include "srsran/adt/circular_map.h"
#include "srsran/adt/intrusive_list.h"
#include "srsran/common/buffer_pool.h" #include "srsran/common/buffer_pool.h"
#include "srsran/common/common.h" #include "srsran/common/common.h"
#include "srsran/common/srsran_assert.h" #include "srsran/common/srsran_assert.h"
@ -42,23 +43,95 @@ namespace srsran {
#undef RLC_AM_BUFFER_DEBUG #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<rlc_list_tag>,
public intrusive_forward_list_element<free_list_tag>,
public intrusive_double_linked_list_element<> {
const static uint32_t invalid_rlc_sn = std::numeric_limits<uint32_t>::max();
const static uint32_t invalid_pdcp_sn = std::numeric_limits<uint32_t>::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<segment_resource, free_list_tag> free_list;
std::array<segment_resource, MAX_POOL_SIZE> 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; rlc_amd_pdu_header_t header;
unique_byte_buffer_t buf; unique_byte_buffer_t buf;
uint32_t rlc_sn; 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 { struct rlc_amd_rx_pdu_segments_t {
std::list<rlc_amd_rx_pdu_t> segments; std::list<rlc_amd_rx_pdu> 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<rlc_am_pdu_segment>;
const static uint32_t invalid_rlc_sn = std::numeric_limits<uint32_t>::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; rlc_amd_pdu_header_t header;
unique_byte_buffer_t buf; unique_byte_buffer_t buf;
pdcp_sn_vector_t pdcp_sns;
uint32_t retx_count; explicit rlc_amd_tx_pdu(uint32_t rlc_sn_) : rlc_sn(rlc_sn_) {}
uint32_t rlc_sn; rlc_amd_tx_pdu(const rlc_amd_tx_pdu&) = delete;
bool is_acked; 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 { struct rlc_amd_retx_t {
@ -73,12 +146,47 @@ struct rlc_sn_info_t {
bool is_acked; bool is_acked;
}; };
struct pdcp_sdu_info_t { /// Class that contains the parameters and state (e.g. unACKed segments) of a PDCP PDU
uint32_t sn; class pdcp_pdu_info
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 using list_type = intrusive_double_linked_list<rlc_am_pdu_segment>;
// duplicate removal from the queue while processing the status report
std::vector<rlc_sn_info_t> rlc_sn_info_list; // List of RLC PDUs in transit and whether they have been acked or not. 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<uint32_t>::max();
const static uint32_t invalid_pdcp_sn = std::numeric_limits<uint32_t>::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 <class T> template <class T>
@ -86,8 +194,7 @@ struct rlc_ringbuffer_t {
T& add_pdu(size_t sn) T& add_pdu(size_t sn)
{ {
srsran_expect(not has_sn(sn), "The same SN=%zd should not be added twice", sn); srsran_expect(not has_sn(sn), "The same SN=%zd should not be added twice", sn);
window.overwrite(sn, T{}); window.overwrite(sn, T(sn));
window[sn].rlc_sn = sn;
return window[sn]; return window[sn];
} }
void remove_pdu(size_t sn) void remove_pdu(size_t sn)
@ -125,52 +232,55 @@ public:
void add_pdcp_sdu(uint32_t sn) 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"); srsran_assert(not has_pdcp_sn(sn), "Cannot re-add same PDCP SN twice");
uint32_t sn_idx = get_idx(sn); pdcp_pdu_info& pdu = get_pdu_(sn);
if (buffered_pdus[sn_idx].sn != invalid_sn) { if (pdu.valid()) {
clear_pdcp_sdu(buffered_pdus[sn_idx].sn); pdu.clear();
count--;
} }
buffered_pdus[get_idx(sn)].sn = sn; pdu.sn = sn;
count++; count++;
} }
void clear_pdcp_sdu(uint32_t sn) void clear_pdcp_sdu(uint32_t sn)
{ {
uint32_t sn_idx = get_idx(sn); pdcp_pdu_info& pdu = get_pdu_(sn);
if (buffered_pdus[sn_idx].sn == invalid_sn) { if (not pdu.valid()) {
return; return;
} }
buffered_pdus[sn_idx].sn = invalid_sn; pdu.clear();
buffered_pdus[sn_idx].fully_acked = false;
buffered_pdus[sn_idx].fully_txed = false;
buffered_pdus[sn_idx].rlc_sn_info_list.clear();
count--; count--;
} }
pdcp_sdu_info_t& operator[](uint32_t sn) pdcp_pdu_info& operator[](uint32_t sn)
{ {
assert(has_pdcp_sn(sn)); srsran_expect(has_pdcp_sn(sn), "Invalid access to non-existent PDCP SN=%d", sn);
return buffered_pdus[get_idx(sn)]; return get_pdu_(sn);
} }
bool has_pdcp_sn(uint32_t pdcp_sn) const bool has_pdcp_sn(uint32_t pdcp_sn) const
{ {
assert(pdcp_sn <= max_pdcp_sn or pdcp_sn == status_report_sn); srsran_expect(pdcp_sn <= max_pdcp_sn or pdcp_sn == status_report_sn, "Invalid PDCP SN=%d", pdcp_sn);
return buffered_pdus[get_idx(pdcp_sn)].sn == pdcp_sn; return get_pdu_(pdcp_sn).sn == pdcp_sn;
} }
uint32_t nof_sdus() const { return count; } uint32_t nof_sdus() const { return count; }
private: private:
const static size_t max_pdcp_sn = 262143u; const static size_t max_pdcp_sn = 262143u;
const static size_t max_buffer_idx = 4096u; const static size_t buffer_size = 4096u;
const static uint32_t status_report_sn = std::numeric_limits<uint32_t>::max(); const static uint32_t status_report_sn = pdcp_pdu_info::status_report_sn;
const static uint32_t invalid_sn = std::numeric_limits<uint32_t>::max() - 1;
size_t get_idx(uint32_t sn) const pdcp_pdu_info& get_pdu_(uint32_t sn)
{
return (sn == status_report_sn) ? status_report_pdu : buffered_pdus[static_cast<size_t>(sn % buffer_size)];
}
const pdcp_pdu_info& get_pdu_(uint32_t sn) const
{ {
return (sn != status_report_sn) ? static_cast<size_t>(sn % max_buffer_idx) : max_buffer_idx; return (sn == status_report_sn) ? status_report_pdu : buffered_pdus[static_cast<size_t>(sn % buffer_size)];
} }
// size equal to buffer_size + 1 (last element for Status Report) // size equal to buffer_size
std::vector<pdcp_sdu_info_t> buffered_pdus; std::vector<pdcp_pdu_info> buffered_pdus;
pdcp_pdu_info status_report_pdu;
uint32_t count = 0; uint32_t count = 0;
}; };
@ -287,7 +397,7 @@ private:
int build_retx_pdu(uint8_t* payload, uint32_t nof_bytes); 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_segment(uint8_t* payload, uint32_t nof_bytes, rlc_amd_retx_t retx);
int build_data_pdu(uint8_t* payload, uint32_t nof_bytes); 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(); void debug_state();
@ -302,6 +412,7 @@ private:
rlc_am_lte* parent = nullptr; rlc_am_lte* parent = nullptr;
byte_buffer_pool* pool = nullptr; byte_buffer_pool* pool = nullptr;
srslog::basic_logger& logger; srslog::basic_logger& logger;
rlc_am_pdu_segment_pool segment_pool;
/**************************************************************************** /****************************************************************************
* Configurable parameters * Configurable parameters
@ -348,7 +459,7 @@ private:
bsr_callback_t bsr_callback; bsr_callback_t bsr_callback;
// Tx windows // Tx windows
rlc_ringbuffer_t<rlc_amd_tx_pdu_t> tx_window; rlc_ringbuffer_t<rlc_amd_tx_pdu> tx_window;
pdu_retx_queue retx_queue; pdu_retx_queue retx_queue;
pdcp_sn_vector_t notify_info_vec; pdcp_sn_vector_t notify_info_vec;
@ -391,7 +502,7 @@ private:
bool inside_rx_window(const int16_t sn); bool inside_rx_window(const int16_t sn);
void debug_state(); void debug_state();
void print_rx_segments(); 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; rlc_am_lte* parent = nullptr;
byte_buffer_pool* pool = nullptr; byte_buffer_pool* pool = nullptr;
@ -422,7 +533,7 @@ private:
std::mutex mutex; std::mutex mutex;
// Rx windows // Rx windows
rlc_ringbuffer_t<rlc_amd_rx_pdu_t> rx_window; rlc_ringbuffer_t<rlc_amd_rx_pdu> rx_window;
std::map<uint32_t, rlc_amd_rx_pdu_segments_t> rx_segments; std::map<uint32_t, rlc_amd_rx_pdu_segments_t> rx_segments;
bool poll_received = false; 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); 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_valid_status_pdu(const rlc_status_pdu_t& status);
bool rlc_am_is_pdu_segment(uint8_t* payload); bool rlc_am_is_pdu_segment(uint8_t* payload);
std::string rlc_am_undelivered_sdu_info_to_string(const std::map<uint32_t, pdcp_sdu_info_t>& info_queue); std::string rlc_am_undelivered_sdu_info_to_string(const std::map<uint32_t, pdcp_pdu_info>& info_queue);
void log_rlc_amd_pdu_header_to_string(srslog::log_channel& log_ch, const rlc_amd_pdu_header_t& header); 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_start_aligned(const uint8_t fi);
bool rlc_am_end_aligned(const uint8_t fi); bool rlc_am_end_aligned(const uint8_t fi);

@ -113,10 +113,18 @@ typedef struct {
class rlc_amd_pdu_header_t class rlc_amd_pdu_header_t
{ {
public: 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(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) 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); copy(h);
return *this; return *this;

@ -75,6 +75,19 @@ logical_channel_config_t make_mac_logical_channel_cfg_t(uint8_t lcid, const lc_c
return logical_channel_config; 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) 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; 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, sn_len,
t_reordering, t_reordering,
discard_timer, discard_timer,
false); false,
srsran_rat_t::nr);
return cfg; 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, 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* 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) { switch (phys_cell_group_cfg.pdsch_harq_ack_codebook) {
case phys_cell_group_cfg_s::pdsch_harq_ack_codebook_opts::dynamic_value: 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; 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) 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_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) { switch (ctrl_res_set.precoder_granularity) {
case ctrl_res_set_s::precoder_granularity_opts::same_as_reg_bundle: case ctrl_res_set_s::precoder_granularity_opts::same_as_reg_bundle:
srsran_coreset.precoder_granularity = srsran_coreset_precoder_granularity_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()); asn1::log_warning("Invalid option for precoder_granularity %s", ctrl_res_set.precoder_granularity.to_string());
return false; 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; srsran_coreset.duration = ctrl_res_set.dur;
for (uint32_t i = 0; i < SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE; i++) { 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); 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; 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 srsran
namespace srsenb { namespace srsenb {

@ -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_SN_LEN_5,
pdcp_t_reordering_t::ms500, pdcp_t_reordering_t::ms500,
pdcp_discard_timer_t::infinity, pdcp_discard_timer_t::infinity,
false); false,
srsran_rat_t::lte);
return cfg; 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_SN_LEN_12,
pdcp_t_reordering_t::ms500, pdcp_t_reordering_t::ms500,
pdcp_discard_timer_t::infinity, pdcp_discard_timer_t::infinity,
false); false,
srsran_rat_t::lte);
return cfg; 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, sn_len,
t_reordering, t_reordering,
discard_timer, discard_timer,
status_report_required); status_report_required,
srsran_rat_t::lte);
return cfg; 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 = cfg->rach_cfg.messagePowerOffsetGroupB =
asn1_type.preamb_info.preambs_group_a_cfg.msg_pwr_offset_group_b.to_number(); asn1_type.preamb_info.preambs_group_a_cfg.msg_pwr_offset_group_b.to_number();
} else { } 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 // Power ramping

@ -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) { for (uint32_t i = 0; i < msg->nof_pdus; ++i) {
dl_grant.tb[i] = srsran::make_byte_buffer(); srsue::stack_interface_phy_nr::tb_action_dl_result_t result = {};
if (dl_grant.tb[i] && dl_grant.tb[i]->get_tailroom() >= msg->pdus[i].length) { result.payload = srsran::make_byte_buffer();
memcpy(dl_grant.tb[i]->msg, msg->pdus[i].data, msg->pdus[i].length); if (result.payload != nullptr && result.payload->get_tailroom() >= msg->pdus[i].length) {
dl_grant.tb[i]->N_bytes = 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) { 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 { } else {
logger.error("TB too big to fit into buffer (%d)", msg->pdus[i].length); logger.error("TB too big to fit into buffer (%d)", msg->pdus[i].length);

@ -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_) : 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) { if (not start_deferred) {
start(prio_, mask_); start(prio_, mask_);
@ -331,6 +331,10 @@ void task_thread_pool::push_task(task_t&& task)
{ {
{ {
std::lock_guard<std::mutex> lock(queue_mutex); std::lock_guard<std::mutex> 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)); pending_tasks.push(std::move(task));
} }
cv_empty.notify_one(); cv_empty.notify_one();
@ -367,7 +371,7 @@ bool task_thread_pool::worker_t::wait_task(task_t* task)
return false; return false;
} }
if (task) { if (task) {
*task = std::move(parent->pending_tasks.front()); *task = std::move(parent->pending_tasks.top());
} }
parent->pending_tasks.pop(); parent->pending_tasks.pop();
return true; return true;

@ -183,7 +183,7 @@ static uint32_t csi_rs_cinit(const srsran_carrier_nr_t* carrier,
const srsran_csi_rs_nzp_resource_t* resource, const srsran_csi_rs_nzp_resource_t* resource,
uint32_t l) 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; uint32_t n_id = resource->scrambling_id;
return ((SRSRAN_NSYMB_PER_SLOT_NR * n + l + 1UL) * (2UL * n_id) << 10UL) + n_id; return ((SRSRAN_NSYMB_PER_SLOT_NR * n + l + 1UL) * (2UL * n_id) << 10UL) + n_id;

@ -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 // 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) { if (coreset->dmrs_scrambling_id_present) {
n_id = coreset->dmrs_scrambling_id; n_id = coreset->dmrs_scrambling_id;
} }
// Bound slot index // 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++) { for (uint32_t l = 0; l < coreset->duration; l++) {
// Get Cin // 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 // 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) { if (q->coreset.dmrs_scrambling_id_present) {
n_id = q->coreset.dmrs_scrambling_id; n_id = q->coreset.dmrs_scrambling_id;
} }
// Bound slot index // 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 // Extract pilots
for (uint32_t l = 0; l < q->coreset.duration; l++) { 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 // Measure CFO only from the second and third symbols
if (l != 0) { if (l != 0) {
// Calculates the time between the previous and the current symbol // 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)) { if (isnormal(Ts)) {
// Compute phase difference between symbols and convert to Hz // 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); 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->cfo_hz = NAN;
} }
measure->sync_error_us = 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 // Convert power measurements into logarithmic scale
measure->rsrp_dBfs = srsran_convert_power_to_dB(measure->rsrp); measure->rsrp_dBfs = srsran_convert_power_to_dB(measure->rsrp);

@ -256,7 +256,7 @@ int srsran_dmrs_pucch_format1_estimate(const srsran_pucch_nr_t* q,
// Compute Time Aligment error in microseconds // Compute Time Aligment error in microseconds
if (isnormal(ta_err)) { 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 *= 1e6f; // Convert to micro-seconds
ta_err = roundf(ta_err * 10.0f) / 10.0f; // Round to one tenth of micro-second ta_err = roundf(ta_err * 10.0f) / 10.0f; // Round to one tenth of micro-second
res->ta_us = ta_err; 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, const srsran_slot_cfg_t* slot,
uint32_t l) uint32_t l)
{ {
uint64_t n = SRSRAN_SLOT_NR_MOD(carrier->numerology, slot->idx); uint64_t n = SRSRAN_SLOT_NR_MOD(carrier->scs, slot->idx);
uint64_t n_id = (cfg->scrambling_id_present) ? cfg->scambling_id : carrier->id; 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); 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 // Compute Time Aligment error in microseconds
if (isnormal(ta_err)) { 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 *= 1e6f; // Convert to micro-seconds
ta_err = roundf(ta_err * 10.0f) / 10.0f; // Round to one tenth of micro-second ta_err = roundf(ta_err * 10.0f) / 10.0f; // Round to one tenth of micro-second
res->ta_us = ta_err; res->ta_us = ta_err;

@ -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; const srsran_dmrs_sch_cfg_t* dmrs_cfg = &cfg->dmrs;
// Calculate scrambling IDs // Calculate scrambling IDs
uint32_t n_id = carrier->id; uint32_t n_id = carrier->pci;
uint32_t n_scid = (grant->n_scid) ? 1 : 0; uint32_t n_scid = (grant->n_scid) ? 1 : 0;
if (!grant->n_scid && dmrs_cfg->scrambling_id0_present) { if (!grant->n_scid && dmrs_cfg->scrambling_id0_present) {
// n_scid = 0 and 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 // Iterate symbols
for (uint32_t i = 0; i < nof_symbols; i++) { for (uint32_t i = 0; i < nof_symbols; i++) {
uint32_t l = symbols[i]; // Symbol index inside the slot 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); 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]); 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 l = symbols[i]; // Symbol index inside the slot
uint32_t cinit = 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( 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]); 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 += srsran_vec_estimate_frequency(&q->pilot_estimates[nof_pilots_x_symbol * i], nof_pilots_x_symbol);
} }
sync_err /= (float)nof_symbols; 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 #if DMRS_SCH_SYNC_PRECOMPENSATE
// Pre-compensate synchronization error // 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 // Measure CFO if more than one symbol is used
float cfo_avg = 0.0; float cfo_avg = 0.0;
for (uint32_t i = 0; i < nof_symbols - 1; i++) { 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])); float phase_diff = cargf(corr[i + 1] * conjf(corr[i]));
if (isnormal(time_diff)) { if (isnormal(time_diff)) {
@ -852,11 +852,11 @@ int srsran_dmrs_sch_estimate(srsran_dmrs_sch_t* q,
if (isnormal(cfo_avg)) { if (isnormal(cfo_avg)) {
// Calculate phase of the first OFDM symbol (l = 0) // Calculate phase of the first OFDM symbol (l = 0)
float arg0 = 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 // Calculate CFO corrections
for (uint32_t l = 0; l < SRSRAN_NSYMB_PER_SLOT_NR; l++) { 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); cfo_correction[l] = cexpf(I * arg);
} }

@ -27,8 +27,10 @@
#include <stdlib.h> #include <stdlib.h>
static srsran_carrier_nr_t carrier = { static srsran_carrier_nr_t carrier = {
0, // cell_id 1, // pci
0, // numerology 0, // absolute_frequency_ssb
0, // absolute_frequency_point_a
srsran_subcarrier_spacing_15kHz, // scs
50, // nof_prb 50, // nof_prb
0, // start 0, // start
1 // max_mimo_layers 1 // max_mimo_layers
@ -79,7 +81,7 @@ static void usage(char* prog)
{ {
printf("Usage: %s [recov]\n", prog); printf("Usage: %s [recov]\n", prog);
printf("\t-p nof_prb [Default %d]\n", carrier.nof_prb); 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 SNR in dB [Default %.2f]\n", snr_dB);
printf("\t-S Start RB index [Default %d]\n", start_rb); printf("\t-S Start RB index [Default %d]\n", start_rb);
printf("\t-L Number of RB [Default %d]\n", nof_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); carrier.nof_prb = (uint32_t)strtol(argv[optind], NULL, 10);
break; break;
case 'c': case 'c':
carrier.id = (uint32_t)strtol(argv[optind], NULL, 10); carrier.pci = (uint32_t)strtol(argv[optind], NULL, 10);
break; break;
case 'o': case 'o':
power_control_offset = strtof(argv[optind], NULL); 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 <= nof_rb_end;
resource.resource_mapping.freq_band.nof_rb += 4) { resource.resource_mapping.freq_band.nof_rb += 4) {
// Iterate for all slot numbers // 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 // Steer Frequency allocation
for (uint32_t freq_dom_alloc = 0; freq_dom_alloc < nof_freq_dom_alloc; freq_dom_alloc++) { 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++) { for (uint32_t i = 0; i < nof_freq_dom_alloc; i++) {

@ -39,7 +39,7 @@ void usage(char* prog)
printf("\t-r nof_prb [Default %d]\n", carrier.nof_prb); printf("\t-r nof_prb [Default %d]\n", carrier.nof_prb);
printf("\t-e extended cyclic prefix [Default normal]\n"); 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"); 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); carrier.nof_prb = (uint32_t)strtol(argv[optind], NULL, 10);
break; break;
case 'c': case 'c':
carrier.id = (uint32_t)strtol(argv[optind], NULL, 10); carrier.pci = (uint32_t)strtol(argv[optind], NULL, 10);
break; break;
case 'v': case 'v':
srsran_verbose++; srsran_verbose++;
@ -77,7 +77,7 @@ static int run_test(srsran_dmrs_pdcch_estimator_t* estimator,
srsran_dci_location_t dci_location = {}; srsran_dci_location_t dci_location = {};
dci_location.L = aggregation_level; 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] = {}; uint32_t locations[SRSRAN_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR] = {};
int nof_locations = int nof_locations =

@ -29,9 +29,12 @@
#include <strings.h> #include <strings.h>
#include <unistd.h> #include <unistd.h>
static srsran_carrier_nr_t carrier = { static srsran_carrier_nr_t carrier = {
0, // cell_id 1, // pci
0, // numerology 0, // absolute_frequency_ssb
0, // absolute_frequency_point_a
srsran_subcarrier_spacing_15kHz, // scs
50, // nof_prb 50, // nof_prb
0, // start 0, // start
1 // max_mimo_layers 1 // max_mimo_layers
@ -139,7 +142,7 @@ static void usage(char* prog)
printf("\t-r nof_prb [Default %d]\n", carrier.nof_prb); 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"); 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); carrier.nof_prb = (uint32_t)strtol(argv[optind], NULL, 10);
break; break;
case 'c': case 'c':
carrier.id = (uint32_t)strtol(argv[optind], NULL, 10); carrier.pci = (uint32_t)strtol(argv[optind], NULL, 10);
break; break;
case 'v': case 'v':
srsran_verbose++; srsran_verbose++;
@ -227,7 +230,7 @@ static int run_test(srsran_dmrs_sch_t* dmrs_pdsch,
TESTASSERT(assert_cfg(pdsch_cfg, grant) == SRSRAN_SUCCESS); TESTASSERT(assert_cfg(pdsch_cfg, grant) == SRSRAN_SUCCESS);
srsran_slot_cfg_t slot_cfg = {}; 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_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) == TESTASSERT(srsran_dmrs_sch_estimate(dmrs_pdsch, &slot_cfg, pdsch_cfg, grant, sf_symbols, chest_res) ==

@ -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) 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) { switch (modulation) {
case SRSRAN_MOD_BPSK: case SRSRAN_MOD_BPSK:
demod_bpsk_lte_s(symbols, llr, nsymbols); 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) 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) { switch (modulation) {
case SRSRAN_MOD_BPSK: case SRSRAN_MOD_BPSK:
demod_bpsk_lte_b(symbols, llr, nsymbols); 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; break;
default: default:
ERROR("Invalid modulation %d", modulation); ERROR("Invalid modulation %d", modulation);
return SRSRAN_ERROR; return -1;
}
return SRSRAN_SUCCESS;
}
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 0;
return SRSRAN_SUCCESS;
} }

@ -19,8 +19,11 @@
* *
*/ */
#include <math.h>
#include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <strings.h> #include <strings.h>
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
@ -31,7 +34,7 @@ static uint32_t nof_frames = 10;
static uint32_t num_bits = 1000; static uint32_t num_bits = 1000;
static srsran_mod_t modulation = SRSRAN_MOD_NITEMS; 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("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); 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"); 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; int opt;
while ((opt = getopt(argc, argv, "nmvf")) != -1) { 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 main(int argc, char** argv)
{ {
int i;
srsran_modem_table_t mod; srsran_modem_table_t mod;
uint8_t* input = NULL; uint8_t * input, *output;
cf_t* symbols = NULL; cf_t* symbols;
float* llr = NULL; float* llr;
short* llr_s = NULL; short* llr_s;
int8_t* llr_b = NULL; int8_t* llr_b;
int8_t* llr_b2 = NULL;
srsran_random_t random_gen = srsran_random_init(0);
parse_args(argc, argv); parse_args(argc, argv);
@ -116,6 +136,11 @@ int main(int argc, char** argv)
perror("malloc"); perror("malloc");
exit(-1); 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); symbols = srsran_vec_cf_malloc(num_bits / mod.nbits_x_symbol);
if (!symbols) { if (!symbols) {
perror("malloc"); perror("malloc");
@ -140,21 +165,17 @@ int main(int argc, char** argv)
exit(-1); exit(-1);
} }
llr_b2 = srsran_vec_i8_malloc(num_bits); /* generate random data */
if (!llr_b2) { srand(0);
perror("malloc");
exit(-1);
}
int ret = -1; int ret = -1;
struct timeval t[3]; struct timeval t[3];
float mean_texec = 0.0f; float mean_texec = 0.0;
float mean_texec_s = 0.0f; float mean_texec_s = 0.0;
float mean_texec_b = 0.0f; float mean_texec_b = 0.0;
float mean_texec_b2 = 0.0f;
for (int n = 0; n < nof_frames; n++) { for (int n = 0; n < nof_frames; n++) {
for (int i = 0; i < num_bits; i++) { for (i = 0; i < num_bits; i++) {
input[i] = srsran_random_uniform_int_dist(random_gen, 0, 1); input[i] = rand() % 2;
} }
/* modulate */ /* 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); 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()) { if (SRSRAN_VERBOSE_ISDEBUG()) {
printf("bits="); printf("bits=");
srsran_vec_fprint_b(stdout, input, num_bits); srsran_vec_fprint_b(stdout, input, num_bits);
@ -212,27 +224,12 @@ int main(int argc, char** argv)
printf("llr_b="); printf("llr_b=");
srsran_vec_fprint_bs(stdout, llr_b, num_bits); srsran_vec_fprint_bs(stdout, llr_b, num_bits);
printf("llr_b2=");
srsran_vec_fprint_bs(stdout, llr_b2, num_bits);
} }
// Check demodulation errors // Check demodulation errors
for (int j = 0; j < num_bits; j++) { for (int i = 0; i < num_bits; i++) {
if (input[j] != (llr[j] > 0 ? 1 : 0)) { if (input[i] != (llr[i] > 0 ? 1 : 0)) {
ERROR("Error in bit %d\n", j); printf("Error in bit %d\n", i);
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);
goto clean_exit; goto clean_exit;
} }
} }
@ -240,23 +237,21 @@ int main(int argc, char** argv)
ret = 0; ret = 0;
clean_exit: clean_exit:
srsran_random_free(random_gen);
free(llr_b); free(llr_b);
free(llr_s); free(llr_s);
free(llr); free(llr);
free(symbols); free(symbols);
free(output);
free(input); free(input);
srsran_modem_table_free(&mod); 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,
num_bits / mean_texec_s, num_bits / mean_texec_s,
num_bits / mean_texec_b, num_bits / mean_texec_b,
num_bits / mean_texec_b2,
mean_texec, mean_texec,
mean_texec_s, mean_texec_s,
mean_texec_b, mean_texec_b);
mean_texec_b2);
exit(ret); exit(ret);
} }

@ -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++) { for (uint32_t i = 0; i < nof_reports; i++) {
if (report_cfg[i].freq_cfg == SRSRAN_CSI_REPORT_FREQ_WIDEBAND && if (report_cfg[i].freq_cfg == SRSRAN_CSI_REPORT_FREQ_WIDEBAND &&
report_cfg[i].quantity == SRSRAN_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI) { 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) { } else if (report_cfg[i].quantity == SRSRAN_CSI_REPORT_QUANTITY_NONE) {
char tmp[20] = {}; char tmp[20] = {};
srsran_vec_sprint_bin(tmp, sizeof(tmp), report_value[i].none, report_cfg->K_csi_rs); 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; return len;

@ -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) 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->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) uint32_t n_rnti = (dci_msg->ctx.ss_type == srsran_search_space_type_ue && q->coreset.dmrs_scrambling_id_present)
? dci_msg->ctx.rnti ? dci_msg->ctx.rnti
: 0U; : 0U;

@ -26,9 +26,6 @@
#include "srsran/phy/mimo/precoding.h" #include "srsran/phy/mimo/precoding.h"
#include "srsran/phy/modem/demod_soft.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) 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); 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; return SRSRAN_SUCCESS;
} }
@ -194,6 +183,8 @@ void srsran_pdsch_nr_free(srsran_pdsch_nr_t* q)
if (q->evm_buffer != NULL) { if (q->evm_buffer != NULL) {
srsran_evm_free(q->evm_buffer); 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) static inline uint32_t pdsch_nr_put_rb(cf_t* dst, cf_t* src, bool* rvd_mask)
@ -256,27 +247,11 @@ static int srsran_pdsch_nr_cp(const srsran_pdsch_nr_t* q,
// Put or get // Put or get
if (put) { if (put) {
count += pdsch_nr_put_rb(&sf_symbols[re_idx], &symbols[count], &rvd_mask[rb * SRSRAN_NRE]); 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 { } 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]);
} }
} }
} }
}
return count; return count;
} }
@ -302,7 +277,7 @@ static int srsran_pdsch_nr_get(const srsran_pdsch_nr_t* q,
static uint32_t 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) 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)) { if (cfg->scrambling_id_present && SRSRAN_RNTI_ISUSER(rnti)) {
n_id = cfg->scambling_id; n_id = cfg->scambling_id;
} }
@ -465,7 +440,7 @@ static inline int pdsch_nr_decode_codeword(srsran_pdsch_nr_t* q,
// Demodulation // Demodulation
int8_t* llr = (int8_t*)q->b[tb->cw_idx]; 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; 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 str_len)
{ {
uint32_t len = 0; 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; 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++) { 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 // Append time-domain resource mapping
len = srsran_print_check(str, len = srsran_print_check(
str_len, str, str_len, len, "rnti=0x%x prb=%d:%d symb=%d:%d ", grant->rnti, first_prb, grant->nof_prb, grant->S, grant->L);
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);
// Append TB info // Append TB info
for (uint32_t i = 0; i < SRSRAN_MAX_TB; i++) { 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); 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) { 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; return len;

@ -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;
}

@ -37,7 +37,7 @@ int srsran_pucch_nr_group_sequence(const srsran_carrier_nr_t* carrier,
{ {
uint32_t f_gh = 0; uint32_t f_gh = 0;
uint32_t f_ss = 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) { switch (cfg->group_hopping) {
case SRSRAN_PUCCH_NR_GROUP_HOPPING_NEITHER: 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 // 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 // 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] = {}; uint8_t cs[SRSRAN_NSYMB_PER_SLOT_NR * SRSRAN_NSLOTS_PER_FRAME_NR(SRSRAN_NR_MAX_NUMEROLOGY) * 8U] = {};
srsran_sequence_apply_bit( 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 // Create n_cs parameter
uint32_t n_cs = 0; 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_pucch_nr_common_cfg_t* pucch_cfg,
const srsran_uci_cfg_nr_t* uci_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; return ((uint32_t)uci_cfg->pucch.rnti << 15U) + n_id;
} }

@ -236,106 +236,29 @@ void srsran_pusch_nr_free(srsran_pusch_nr_t* q)
SRSRAN_MEM_ZERO(q, srsran_pusch_nr_t, 1); SRSRAN_MEM_ZERO(q, srsran_pusch_nr_t, 1);
} }
/** static inline uint32_t pusch_nr_put_rb(cf_t* dst, cf_t* src, bool* rvd_mask)
* @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 count = 0;
uint32_t delta = 0; for (uint32_t i = 0; i < SRSRAN_NRE; i++) {
if (!rvd_mask[i]) {
if (grant->nof_dmrs_cdm_groups_without_data != 1) { dst[i] = src[count++];
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; return count;
} }
/* static inline uint32_t pusch_nr_get_rb(cf_t* dst, cf_t* src, bool* rvd_mask)
* 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)
{ {
uint32_t count = 0; uint32_t count = 0;
for (uint32_t i = 0; i < SRSRAN_NRE; i++) {
if (grant->nof_dmrs_cdm_groups_without_data != 1 && grant->nof_dmrs_cdm_groups_without_data != 2) { if (!rvd_mask[i]) {
return count; dst[count++] = src[i];
}
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;
} }
} }
return count; return count;
} }
static uint32_t srsran_pusch_nr_cp_dmrs(const srsran_pusch_nr_t* q, static int srsran_pusch_nr_cp(const srsran_pusch_nr_t* q,
const srsran_sch_cfg_nr_t* cfg, const srsran_sch_cfg_nr_t* cfg,
const srsran_sch_grant_nr_t* grant, const srsran_sch_grant_nr_t* grant,
cf_t* symbols, cf_t* symbols,
@ -344,109 +267,45 @@ static uint32_t srsran_pusch_nr_cp_dmrs(const srsran_pusch_nr_t* q,
{ {
uint32_t count = 0; uint32_t count = 0;
const srsran_dmrs_sch_cfg_t* dmrs_cfg = &cfg->dmrs; 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] = {};
switch (dmrs_cfg->type) { // Reserve DMRS
case srsran_dmrs_sch_type_1: if (srsran_re_pattern_to_symbol_mask(&q->dmrs_re_pattern, l, rvd_mask) < SRSRAN_SUCCESS) {
count = srsran_pusch_nr_cp_dmrs_type1(q, grant, symbols, sf_symbols, put); ERROR("Error generating DMRS reserved RE mask");
break; return SRSRAN_ERROR;
case srsran_dmrs_sch_type_2:
count = srsran_pusch_nr_cp_dmrs_type2(q, grant, symbols, sf_symbols, put);
break;
} }
return 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;
} }
static uint32_t srsran_pusch_nr_cp_clean(const srsran_pusch_nr_t* q, // Actual copy
const srsran_sch_grant_nr_t* grant, for (uint32_t rb = 0; rb < q->carrier.nof_prb; rb++) {
cf_t* symbols, // Skip PRB if not available in grant
cf_t* sf_symbols, if (!grant->prb_idx[rb]) {
bool put) continue;
{
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 // Calculate RE index at the begin of the symbol
count += length; uint32_t re_idx = (q->carrier.nof_prb * l + rb) * SRSRAN_NRE;
// Reset consecutive block // Put or get
length = 0;
}
}
// Copy last contiguous block
if (length > 0) {
if (put) { if (put) {
srsran_vec_cf_copy(&sf_symbols[start], &symbols[count], length); count += pusch_nr_put_rb(&sf_symbols[re_idx], &symbols[count], &rvd_mask[rb * SRSRAN_NRE]);
} else { } else {
srsran_vec_cf_copy(&symbols[count], &sf_symbols[start], length); count += pusch_nr_get_rb(&symbols[count], &sf_symbols[re_idx], &rvd_mask[rb * SRSRAN_NRE]);
} }
count += length;
}
return count;
}
static int srsran_pusch_nr_cp(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)
{
uint32_t count = 0;
uint32_t dmrs_l_idx[SRSRAN_DMRS_SCH_MAX_SYMBOLS] = {};
uint32_t dmrs_l_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;
}
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);
}
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++;
}
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);
} }
} }
return count; return count;
} }
static int srsran_pusch_nr_put(const srsran_pusch_nr_t* q, static int pusch_nr_put(const srsran_pusch_nr_t* q,
const srsran_sch_cfg_nr_t* cfg, const srsran_sch_cfg_nr_t* cfg,
const srsran_sch_grant_nr_t* grant, const srsran_sch_grant_nr_t* grant,
cf_t* symbols, cf_t* symbols,
@ -455,7 +314,7 @@ static int srsran_pusch_nr_put(const srsran_pusch_nr_t* q,
return srsran_pusch_nr_cp(q, cfg, grant, symbols, sf_symbols, true); return srsran_pusch_nr_cp(q, cfg, grant, symbols, sf_symbols, true);
} }
static int srsran_pusch_nr_get(const srsran_pusch_nr_t* q, static int pusch_nr_get(const srsran_pusch_nr_t* q,
const srsran_sch_cfg_nr_t* cfg, const srsran_sch_cfg_nr_t* cfg,
const srsran_sch_grant_nr_t* grant, const srsran_sch_grant_nr_t* grant,
cf_t* symbols, cf_t* symbols,
@ -467,7 +326,7 @@ static int srsran_pusch_nr_get(const srsran_pusch_nr_t* q,
static uint32_t 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) 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)) { if (cfg->scrambling_id_present && SRSRAN_RNTI_ISUSER(rnti)) {
n_id = cfg->scambling_id; 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; 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) // 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) 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) { if (cfg->o_ack <= 2) {
// the number of reserved resource elements for potential HARQ-ACK transmission is calculated according to Clause // 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 ; // 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 // Disable non reserved HARQ-ACK bits
G_ack = 0; G_ack = 0;
@ -845,7 +589,7 @@ static inline int pusch_nr_encode_codeword(srsran_pusch_nr_t* q,
} }
// Encode HARQ-ACK bits // 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) { if (E_uci_ack < SRSRAN_SUCCESS) {
ERROR("Error encoding HARQ-ACK bits"); ERROR("Error encoding HARQ-ACK bits");
return SRSRAN_ERROR; 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; q->G_ack = (uint32_t)E_uci_ack;
// Encode CSI part 1 // 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) { if (E_uci_csi1 < SRSRAN_SUCCESS) {
ERROR("Error encoding HARQ-ACK bits"); ERROR("Error encoding HARQ-ACK bits");
return SRSRAN_ERROR; return SRSRAN_ERROR;
@ -865,7 +609,7 @@ static inline int pusch_nr_encode_codeword(srsran_pusch_nr_t* q,
q->G_csi2 = 0; q->G_csi2 = 0;
// Generate PUSCH UCI/UL-SCH multiplexing // 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"); ERROR("Error generating PUSCH mux tables");
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
@ -877,6 +621,7 @@ static inline int pusch_nr_encode_codeword(srsran_pusch_nr_t* q,
} }
// Multiplex UL-SCH with UCI only if it is necessary // Multiplex UL-SCH with UCI only if it is necessary
uint32_t nof_bits = tb->nof_re * srsran_mod_bits_x_symbol(tb->mod);
uint8_t* b = q->g_ulsch; uint8_t* b = q->g_ulsch;
if (q->uci_mux) { if (q->uci_mux) {
// Change b location // Change b location
@ -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) { if (SRSRAN_DEBUG_ENABLED && srsran_verbose >= SRSRAN_VERBOSE_DEBUG && !handler_registered) {
DEBUG("b="); DEBUG("b=");
srsran_vec_fprint_b(stdout, b, tb->nof_bits); srsran_vec_fprint_b(stdout, b, nof_bits);
} }
// 7.3.1.1 Scrambling // 7.3.1.1 Scrambling
uint32_t cinit = pusch_nr_cinit(&q->carrier, cfg, rnti, tb->cw_idx); 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 // 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++) { for (uint32_t i = 0; i < q->G_ack; i++) {
uint32_t idx = q->pos_ack[i]; uint32_t idx = q->pos_ack[i];
if (q->g_ack[i] == (uint8_t)UCI_BIT_REPETITION) { 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 // 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) { if (SRSRAN_DEBUG_ENABLED && srsran_verbose >= SRSRAN_VERBOSE_DEBUG && !handler_registered) {
DEBUG("d="); DEBUG("d=");
@ -945,6 +690,7 @@ int srsran_pusch_nr_encode(srsran_pusch_nr_t* q,
{ {
// Check input pointers // Check input pointers
if (!q || !cfg || !grant || !data || !sf_symbols) { if (!q || !cfg || !grant || !data || !sf_symbols) {
ERROR("Invalid inputs");
return SRSRAN_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; return SRSRAN_ERROR;
} }
// Fill UCI configuration for PUSCH configuration // Compute DMRS pattern
if (pusch_nr_fill_uci_cfg(q, cfg) < SRSRAN_SUCCESS) { if (srsran_dmrs_sch_rvd_re_pattern(&cfg->dmrs, grant, &q->dmrs_re_pattern) < SRSRAN_SUCCESS) {
ERROR("Error filling UCI configuration for PUSCH"); ERROR("Error computing DMRS pattern");
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
@ -991,7 +737,7 @@ int srsran_pusch_nr_encode(srsran_pusch_nr_t* q,
// ... Not implemented // ... Not implemented
// 7.3.1.6 Mapping from virtual to physical resource blocks // 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) { if (n < SRSRAN_SUCCESS) {
ERROR("Putting NR PUSCH resources"); ERROR("Putting NR PUSCH resources");
return SRSRAN_ERROR; 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); 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 // 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) { if (n < SRSRAN_SUCCESS) {
ERROR("Calculating G_ack"); ERROR("Calculating G_ack");
return SRSRAN_ERROR; 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; q->G_ack = (uint32_t)n;
// Calculate CSI part 1 bits // 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) { if (n < SRSRAN_SUCCESS) {
ERROR("Calculating G_csi1"); ERROR("Calculating G_csi1");
return SRSRAN_ERROR; return SRSRAN_ERROR;
@ -1060,7 +809,7 @@ static inline int pusch_nr_decode_codeword(srsran_pusch_nr_t* q,
q->G_csi2 = 0; q->G_csi2 = 0;
// Generate PUSCH UCI/UL-SCH multiplexing // 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"); ERROR("Error generating PUSCH mux tables");
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
@ -1073,16 +822,15 @@ static inline int pusch_nr_decode_codeword(srsran_pusch_nr_t* q,
// EVM // EVM
if (q->evm_buffer != NULL) { if (q->evm_buffer != NULL) {
res->evm[tb->cw_idx] = 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);
srsran_evm_run_b(q->evm_buffer, &q->modem_tables[tb->mod], q->d[tb->cw_idx], llr, tb->nof_bits);
} }
// Descrambling // 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) { if (SRSRAN_DEBUG_ENABLED && srsran_verbose >= SRSRAN_VERBOSE_DEBUG && !handler_registered) {
DEBUG("b="); DEBUG("b=");
srsran_vec_fprint_bs(stdout, llr, tb->nof_bits); srsran_vec_fprint_bs(stdout, llr, nof_bits);
} }
// Demultiplex UCI only if necessary // 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++) { for (uint32_t i = 0; i < q->G_ulsch; i++) {
g_ulsch[i] = -llr[q->pos_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; g_ulsch[i] = 0;
} }
@ -1116,7 +864,7 @@ static inline int pusch_nr_decode_codeword(srsran_pusch_nr_t* q,
// Decode HARQ-ACK // Decode HARQ-ACK
if (q->G_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"); ERROR("Error in UCI decoding");
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
@ -1124,7 +872,7 @@ static inline int pusch_nr_decode_codeword(srsran_pusch_nr_t* q,
// Decode CSI part 1 // Decode CSI part 1
if (q->G_csi1) { 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"); ERROR("Error in UCI decoding");
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
@ -1136,13 +884,13 @@ static inline int pusch_nr_decode_codeword(srsran_pusch_nr_t* q,
// Change LLR pointer // Change LLR pointer
llr = g_ulsch; llr = g_ulsch;
} else { } else {
for (uint32_t i = 0; i < tb->nof_bits; i++) { for (uint32_t i = 0; i < nof_bits; i++) {
llr[i] *= -1; llr[i] *= -1;
} }
} }
// Decode Ul-SCH // 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) { if (srsran_ulsch_nr_decode(&q->sch, &cfg->sch_cfg, tb, llr, &res->tb[tb->cw_idx]) < SRSRAN_SUCCESS) {
ERROR("Error in SCH decoding"); ERROR("Error in SCH decoding");
return SRSRAN_ERROR; return SRSRAN_ERROR;
@ -1175,9 +923,9 @@ int srsran_pusch_nr_decode(srsran_pusch_nr_t* q,
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
// Fill UCI configuration for PUSCH configuration // Compute DMRS pattern
if (pusch_nr_fill_uci_cfg(q, cfg) < SRSRAN_SUCCESS) { if (srsran_dmrs_sch_rvd_re_pattern(&cfg->dmrs, grant, &q->dmrs_re_pattern) < SRSRAN_SUCCESS) {
ERROR("Error filling UCI configuration for PUSCH"); ERROR("Error computing DMRS pattern");
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
@ -1194,7 +942,7 @@ int srsran_pusch_nr_decode(srsran_pusch_nr_t* q,
} }
// Demapping from virtual to physical resource blocks // 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) { if (nof_re_get != nof_re) {
ERROR("Inconsistent number of RE (%d!=%d)", nof_re_get, nof_re); ERROR("Inconsistent number of RE (%d!=%d)", nof_re_get, nof_re);
return SRSRAN_ERROR; return SRSRAN_ERROR;
@ -1239,14 +987,14 @@ int srsran_pusch_nr_decode(srsran_pusch_nr_t* q,
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
static uint32_t srsran_pusch_nr_grant_info(const srsran_sch_cfg_nr_t* cfg, 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_sch_grant_nr_t* grant,
const srsran_pusch_res_nr_t* res, const srsran_pusch_res_nr_t* res,
char* str, char* str,
uint32_t str_len) uint32_t str_len)
{ {
uint32_t len = 0; 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; 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++) { 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 // Append time-domain resource mapping
len = srsran_print_check(str, len = srsran_print_check(
str_len, str, str_len, len, "rnti=0x%x prb=%d:%d symb=%d:%d ", grant->rnti, first_prb, grant->nof_prb, grant->S, grant->L);
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);
// Append TB info // Append TB info
for (uint32_t i = 0; i < SRSRAN_MAX_TB; i++) { 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); 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; return len;
@ -1297,45 +1036,18 @@ uint32_t srsran_pusch_nr_rx_info(const srsran_pusch_nr_t* q,
return 0; 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) { if (res != NULL && srsran_uci_nr_total_bits(&cfg->uci) > 0) {
len = srsran_print_check(str, str_len, len, ",evm={", 0); len = srsran_print_check(str, str_len, len, "UCI: ");
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) {
srsran_uci_data_nr_t uci_data = {}; srsran_uci_data_nr_t uci_data = {};
uci_data.cfg = cfg->uci; 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_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) { 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; return len;
@ -1354,7 +1066,7 @@ uint32_t srsran_pusch_nr_tx_info(const srsran_pusch_nr_t* q,
return 0; 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) { if (uci_value != NULL) {
srsran_uci_data_nr_t uci_data = {}; 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) { 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; return len;

@ -25,6 +25,7 @@
#include "srsran/phy/phch/pdsch_nr.h" #include "srsran/phy/phch/pdsch_nr.h"
#include "srsran/phy/phch/ra_dl_nr.h" #include "srsran/phy/phch/ra_dl_nr.h"
#include "srsran/phy/phch/ra_ul_nr.h" #include "srsran/phy/phch/ra_ul_nr.h"
#include "srsran/phy/phch/uci_nr.h"
#include "srsran/phy/utils/debug.h" #include "srsran/phy/utils/debug.h"
typedef struct { 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->rnti_type = dci_dl->ctx.rnti_type;
pdsch_grant->tb[0].rv = dci_dl->rv; pdsch_grant->tb[0].rv = dci_dl->rv;
pdsch_grant->tb[0].mcs = dci_dl->mcs; pdsch_grant->tb[0].mcs = dci_dl->mcs;
pdsch_grant->tb[0].ndi = dci_dl->ndi;
// 5.1.4 PDSCH resource mapping // 5.1.4 PDSCH resource mapping
if (ra_dl_resource_mapping(carrier, slot, pdsch_hl_cfg, pdsch_cfg) < SRSRAN_SUCCESS) { 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].rv = dci_ul->rv;
pusch_grant->tb[0].mcs = dci_ul->mcs; pusch_grant->tb[0].mcs = dci_ul->mcs;
pusch_grant->tb[0].ndi = dci_ul->ndi; pusch_grant->tb[0].ndi = dci_ul->ndi;
pusch_grant->tb[0].pid = dci_ul->pid;
// 5.1.6.2 DM-RS reception procedure // 5.1.6.2 DM-RS reception procedure
if (ra_ul_dmrs(pusch_hl_cfg, pusch_grant, pusch_cfg) < SRSRAN_SUCCESS) { 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, static float ra_ul_beta_offset_ack_semistatic(const srsran_beta_offsets_t* beta_offsets,
const srsran_uci_cfg_nr_t* uci_cfg) 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 // Select Beta Offset index from the number of HARQ-ACK bits
uint32_t beta_offset_index = beta_offsets->ack_index1; uint32_t beta_offset_index = beta_offsets->ack_index1;
if (uci_cfg->o_ack > 11) { if (uci_cfg->o_ack > 11) {
beta_offset_index = beta_offsets->ack_index3; beta_offset_index = beta_offsets->ack_index3;
} else if (uci_cfg->o_ack > 2) { } else if (uci_cfg->o_ack > 2) {
beta_offset_index = beta_offsets->ack_index1; beta_offset_index = beta_offsets->ack_index2;
} }
// Protect table boundary // 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, const srsran_uci_cfg_nr_t* uci_cfg,
bool part2) 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. // 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); 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]; 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, const srsran_uci_cfg_nr_t* uci_cfg,
srsran_sch_cfg_nr_t* pusch_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 // Select beta offsets
pusch_cfg->beta_harq_ack_offset = ra_ul_beta_offset_ack_semistatic(&pusch_hl_cfg->beta_offsets, uci_cfg); 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->beta_harq_ack_offset)) { if (!isnormal(pusch_cfg->uci.pusch.beta_harq_ack_offset)) {
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
pusch_cfg->beta_csi_part1_offset = ra_ul_beta_offset_csi_semistatic(&pusch_hl_cfg->beta_offsets, uci_cfg, false); 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->beta_csi_part1_offset)) { if (!isnormal(pusch_cfg->uci.pusch.beta_csi1_offset)) {
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
pusch_cfg->beta_csi_part2_offset = ra_ul_beta_offset_csi_semistatic(&pusch_hl_cfg->beta_offsets, uci_cfg, true); 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->beta_csi_part2_offset)) { if (!isnormal(pusch_cfg->uci.pusch.beta_csi2_offset)) {
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
// pusch_cfg->beta_csi_part2_offset = pusch_hl_cfg->beta_offset_csi2; pusch_cfg->uci.pusch.alpha = pusch_hl_cfg->scaling;
pusch_cfg->scaling = pusch_hl_cfg->scaling; if (!isnormal(pusch_cfg->uci.pusch.alpha)) {
if (!isnormal(pusch_cfg->scaling)) { ERROR("Invalid Scaling (%f)", pusch_cfg->uci.pusch.alpha);
ERROR("Invalid Scaling (%f)", pusch_cfg->scaling);
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
// Copy UCI configuration // Calculate number of UCI encoded bits
pusch_cfg->uci = *uci_cfg; 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; return SRSRAN_SUCCESS;
} }

@ -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, len = srsran_print_check(str,
str_len, str_len,
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, tb->cw_idx,
srsran_mod_string(tb->mod), srsran_mod_string(tb->mod),
tb->N_L,
tb->tbs / 8, tb->tbs / 8,
tb->R, tb->R,
tb->rv, tb->rv);
tb->nof_re,
tb->nof_bits);
if (res != NULL) { if (res != NULL) {
len = srsran_print_check(str, str_len, len, "CRC=%s iter=%.1f ", res->crc ? "OK" : "KO", res->avg_iter); len = srsran_print_check(str, str_len, len, "CRC=%s iter=%.1f ", res->crc ? "OK" : "KO", res->avg_iter);

@ -25,8 +25,10 @@
#include <getopt.h> #include <getopt.h>
static srsran_carrier_nr_t carrier = { static srsran_carrier_nr_t carrier = {
0, // cell_id 1, // pci
0, // numerology 0, // absolute_frequency_ssb
0, // absolute_frequency_point_a
srsran_subcarrier_spacing_15kHz, // scs
50, // nof_prb 50, // nof_prb
0, // start 0, // start
1 // max_mimo_layers 1 // max_mimo_layers
@ -194,7 +196,7 @@ int main(int argc, char** argv)
aggregation_level++) { aggregation_level++) {
uint32_t L = 1U << 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] = {}; uint32_t dci_locations[SRSRAN_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR] = {};
// Calculate candidate locations // Calculate candidate locations

@ -30,13 +30,16 @@
#include <math.h> #include <math.h>
static srsran_carrier_nr_t carrier = { static srsran_carrier_nr_t carrier = {
1, // cell_id 1, // pci
0, // numerology 0, // absolute_frequency_ssb
0, // absolute_frequency_point_a
srsran_subcarrier_spacing_15kHz, // scs
SRSRAN_MAX_PRB_NR, // nof_prb SRSRAN_MAX_PRB_NR, // nof_prb
0, // start 0, // start
1 // max_mimo_layers 1 // max_mimo_layers
}; };
static uint32_t n_prb = 0; // Set to 0 for steering static uint32_t n_prb = 0; // Set to 0 for steering
static uint32_t mcs = 30; // Set to 30 for steering static uint32_t mcs = 30; // Set to 30 for steering
static srsran_sch_cfg_nr_t pdsch_cfg = {}; static srsran_sch_cfg_nr_t pdsch_cfg = {};

@ -32,8 +32,10 @@
#include <unistd.h> #include <unistd.h>
static srsran_carrier_nr_t carrier = { static srsran_carrier_nr_t carrier = {
0, // cell_id 1, // pci
0, // numerology 0, // absolute_frequency_ssb
0, // absolute_frequency_point_a
srsran_subcarrier_spacing_15kHz, // scs
6, // nof_prb 6, // nof_prb
0, // start 0, // start
1 // max_mimo_layers 1 // max_mimo_layers
@ -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 = {}; srsran_pucch_nr_resource_t resource = {};
resource.format = SRSRAN_PUCCH_NR_FORMAT_0; 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; for (resource.starting_prb = 0; resource.starting_prb < carrier.nof_prb;
resource.starting_prb += starting_prb_stride) { resource.starting_prb += starting_prb_stride) {
for (resource.nof_symbols = 1; resource.nof_symbols <= 2; resource.nof_symbols++) { 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 = {}; srsran_pucch_nr_resource_t resource = {};
resource.format = SRSRAN_PUCCH_NR_FORMAT_1; 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; for (resource.starting_prb = 0; resource.starting_prb < carrier.nof_prb;
resource.starting_prb += starting_prb_stride) { resource.starting_prb += starting_prb_stride) {
for (resource.nof_symbols = SRSRAN_PUCCH_NR_FORMAT1_MIN_NSYMB; 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 = {}; srsran_pucch_nr_resource_t resource = {};
resource.format = SRSRAN_PUCCH_NR_FORMAT_2; 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; for (resource.nof_symbols = SRSRAN_PUCCH_NR_FORMAT2_MIN_NSYMB;
resource.nof_symbols <= SRSRAN_PUCCH_NR_FORMAT2_MAX_NSYMB; resource.nof_symbols <= SRSRAN_PUCCH_NR_FORMAT2_MAX_NSYMB;
resource.nof_symbols++) { resource.nof_symbols++) {
@ -256,7 +258,7 @@ static int test_pucch_format2(srsran_pucch_nr_t* pucch,
static void usage(char* prog) static void usage(char* prog)
{ {
printf("Usage: %s [csNnv]\n", 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-n nof_prb [Default %d]\n", carrier.nof_prb);
printf("\t-f format [Default %d]\n", format); printf("\t-f format [Default %d]\n", format);
printf("\t-s SNR in dB [Default %.2f]\n", snr_db); 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) { while ((opt = getopt(argc, argv, "cnfsv")) != -1) {
switch (opt) { switch (opt) {
case 'c': case 'c':
carrier.id = (uint32_t)strtol(argv[optind], NULL, 10); carrier.pci = (uint32_t)strtol(argv[optind], NULL, 10);
break; break;
case 'n': case 'n':
carrier.nof_prb = (uint32_t)strtol(argv[optind], NULL, 10); carrier.nof_prb = (uint32_t)strtol(argv[optind], NULL, 10);

@ -29,8 +29,10 @@
#include <getopt.h> #include <getopt.h>
static srsran_carrier_nr_t carrier = { static srsran_carrier_nr_t carrier = {
1, // cell_id 1, // pci
0, // numerology 0, // absolute_frequency_ssb
0, // absolute_frequency_point_a
srsran_subcarrier_spacing_15kHz, // scs
SRSRAN_MAX_PRB_NR, // nof_prb SRSRAN_MAX_PRB_NR, // nof_prb
0, // start 0, // start
1 // max_mimo_layers 1 // max_mimo_layers
@ -167,7 +169,7 @@ int main(int argc, char** argv)
} }
// Use grant default A time resources with m=0 // 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"); ERROR("Error loading default grant");
goto clean_exit; goto clean_exit;
} }
@ -196,9 +198,11 @@ int main(int argc, char** argv)
mcs_end = SRSRAN_MIN(mcs + 1, mcs_end); mcs_end = SRSRAN_MIN(mcs + 1, mcs_end);
} }
pusch_cfg.scaling = 0.5f; srsran_sch_hl_cfg_nr_t sch_hl_cfg = {};
pusch_cfg.beta_harq_ack_offset = 2.0f; sch_hl_cfg.scaling = 1.0f;
pusch_cfg.beta_csi_part1_offset = 2.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) { if (srsran_chest_dl_res_init(&chest, carrier.nof_prb) < SRSRAN_SUCCESS) {
ERROR("Initiating chest"); ERROR("Initiating chest");
@ -254,6 +258,11 @@ int main(int argc, char** argv)
data_rx.uci.csi[0].none = csi_report_rx; 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) { if (srsran_pusch_nr_encode(&pusch_tx, &pusch_cfg, &pusch_cfg.grant, &data_tx, sf_symbols) < SRSRAN_SUCCESS) {
ERROR("Error encoding"); ERROR("Error encoding");
goto clean_exit; 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]); 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]);
} }
} }

@ -28,8 +28,10 @@
#include <srsran/phy/utils/random.h> #include <srsran/phy/utils/random.h>
static srsran_carrier_nr_t carrier = { static srsran_carrier_nr_t carrier = {
0, // cell_id 1, // pci
0, // numerology 0, // absolute_frequency_ssb
0, // absolute_frequency_point_a
srsran_subcarrier_spacing_15kHz, // scs
SRSRAN_MAX_PRB_NR, // nof_prb SRSRAN_MAX_PRB_NR, // nof_prb
0, // start 0, // start
1 // max_mimo_layers 1 // max_mimo_layers

@ -394,14 +394,16 @@ static int uci_nr_decode_1_bit(srsran_uci_nr_t* q,
// Correlate LLR // Correlate LLR
float corr = 0.0f; float corr = 0.0f;
float pwr = 0.0f; float pwr = 0.0f;
uint32_t count = 0;
for (uint32_t i = 0; i < E; i += Qm) { for (uint32_t i = 0; i < E; i += Qm) {
float t = (float)llr[i]; float t = (float)llr[i];
corr += t; corr += t;
pwr += t * t; pwr += t * t;
count++;
} }
// Normalise correlation // Normalise correlation
float norm_corr = Qm * corr / (E * sqrtf(pwr)); float norm_corr = fabsf(corr) / sqrtf(pwr * count);
// Take decoded decision with threshold // Take decoded decision with threshold
*decoded_ok = (norm_corr > q->one_bit_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; uint32_t len = 0;
if (uci_data->cfg.o_ack > 0) { if (uci_data->cfg.o_ack > 0) {
char str2[10]; char str_ack[10];
srsran_vec_sprint_bin(str2, 10, uci_data->value.ack, uci_data->cfg.o_ack); 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", str2); len = srsran_print_check(str, str_len, len, "ack=%s ", str_ack);
} }
if (uci_data->cfg.nof_csi > 0) { 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) { 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; return len;

@ -33,6 +33,7 @@ private:
uhd::stream_args_t stream_args = {}; uhd::stream_args_t stream_args = {};
double lo_freq_tx_hz = 0.0; double lo_freq_tx_hz = 0.0;
double lo_freq_rx_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 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"); 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 // Make USRP
uhd_error err = usrp_multi_make(dev_addr); uhd_error err = usrp_multi_make(dev_addr);
if (err != UHD_ERROR_NONE) { if (err != UHD_ERROR_NONE) {
@ -348,6 +363,10 @@ public:
// Create Tune request // Create Tune request
uhd::tune_request_t tune_request(target_freq); 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 the LO frequency is defined, force a LO frequency and use the
if (std::isnormal(lo_freq_tx_hz)) { if (std::isnormal(lo_freq_tx_hz)) {
tune_request.rf_freq = lo_freq_tx_hz; tune_request.rf_freq = lo_freq_tx_hz;
@ -365,6 +384,10 @@ public:
// Create Tune request // Create Tune request
uhd::tune_request_t tune_request(target_freq); 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 the LO frequency is defined, force a LO frequency and use the
if (std::isnormal(lo_freq_rx_hz)) { if (std::isnormal(lo_freq_rx_hz)) {
tune_request.rf_freq = lo_freq_rx_hz; tune_request.rf_freq = lo_freq_rx_hz;

@ -382,7 +382,7 @@ static int ue_dl_nr_find_dci_ss(srsran_ue_dl_nr_t* q,
// Calculate possible PDCCH DCI candidates // Calculate possible PDCCH DCI candidates
uint32_t candidates[SRSRAN_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR] = {}; uint32_t candidates[SRSRAN_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR] = {};
int nof_candidates = srsran_pdcch_nr_locations_coreset( 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) { if (nof_candidates < SRSRAN_SUCCESS) {
ERROR("Error calculating DCI candidate location"); ERROR("Error calculating DCI candidate location");
return SRSRAN_ERROR; return SRSRAN_ERROR;

@ -132,6 +132,13 @@ int srsran_ue_ul_nr_encode_pusch(srsran_ue_ul_nr_t* q,
// Generate signal // Generate signal
srsran_ofdm_tx_sf(&q->ifft); 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; return SRSRAN_SUCCESS;
} }

@ -39,6 +39,15 @@ pdcp::~pdcp()
pdcp_array_mrb.clear(); 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_) void pdcp::init(srsue::rlc_interface_pdcp* rlc_, srsue::rrc_interface_pdcp* rrc_, srsue::gw_interface_pdcp* gw_)
{ {
rlc = rlc_; rlc = rlc_;
@ -104,7 +113,16 @@ void pdcp::add_bearer(uint32_t lcid, pdcp_config_t cfg)
if (not valid_lcid(lcid)) { if (not valid_lcid(lcid)) {
std::unique_ptr<pdcp_entity_base> entity; std::unique_ptr<pdcp_entity_base> entity;
// For now we create an pdcp entity lte for nr due to it's maturity // For now we create an pdcp entity lte for nr due to it's maturity
if (cfg.rat == srsran::srsran_rat_t::lte) {
entity.reset(new pdcp_entity_lte{rlc, rrc, gw, task_sched, logger, lcid}); 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)) { if (not entity->configure(cfg)) {
logger.error("Can not configure PDCP entity"); logger.error("Can not configure PDCP entity");
return; return;

@ -728,7 +728,7 @@ void pdcp_entity_lte::notify_delivery(const pdcp_sn_vector_t& pdcp_sns)
} }
// Find undelivered PDU info // Find undelivered PDU info
if (not undelivered_sdus->has_sdu(sn)) { 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 { } else {
// Metrics // Metrics
auto& sdu = (*undelivered_sdus)[sn]; auto& sdu = (*undelivered_sdus)[sn];

@ -54,6 +54,16 @@ rlc::~rlc()
pthread_rwlock_destroy(&rwlock); 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_, void rlc::init(srsue::pdcp_interface_rlc* pdcp_,
srsue::rrc_interface_rlc* rrc_, srsue::rrc_interface_rlc* rrc_,
srsran::timer_handler* timers_, srsran::timer_handler* timers_,
@ -157,7 +167,7 @@ void rlc::reestablish()
void rlc::reestablish(uint32_t lcid) void rlc::reestablish(uint32_t lcid)
{ {
if (valid_lcid(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(); rlc_array.at(lcid)->reestablish();
} else { } else {
logger.warning("RLC LCID %d doesn't exist.", lcid); 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; 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 (cnfg.rlc_mode != rlc_mode_t::tm and rlc_array.find(lcid) != rlc_array.end()) {
if (rlc_array[lcid]->get_mode() != cnfg.rlc_mode) { if (rlc_array[lcid]->get_mode() != cnfg.rlc_mode) {
logger.info("Switching RLC entity type. Recreating it."); logger.info("Switching RLC entity type. Recreating it.");
@ -412,7 +428,8 @@ void rlc::add_bearer(uint32_t lcid, const rlc_config_t& cnfg)
} }
if (not valid_lcid(lcid)) { if (not valid_lcid(lcid)) {
if (cnfg.rat == srsran_rat_t::lte) { switch (cnfg.rat) {
case srsran_rat_t::lte:
switch (cnfg.rlc_mode) { switch (cnfg.rlc_mode) {
case rlc_mode_t::tm: case rlc_mode_t::tm:
rlc_entity = new rlc_tm(logger, lcid, pdcp, rrc); rlc_entity = new rlc_tm(logger, lcid, pdcp, rrc);
@ -430,19 +447,21 @@ void rlc::add_bearer(uint32_t lcid, const rlc_config_t& cnfg)
if (rlc_entity != nullptr) { if (rlc_entity != nullptr) {
rlc_entity->set_bsr_callback(bsr_callback); rlc_entity->set_bsr_callback(bsr_callback);
} }
} else if (cnfg.rat == srsran_rat_t::nr) { break;
case srsran_rat_t::nr:
switch (cnfg.rlc_mode) { switch (cnfg.rlc_mode) {
case rlc_mode_t::tm: case rlc_mode_t::tm:
rlc_entity = new rlc_tm(logger, lcid, pdcp, rrc); rlc_entity = new rlc_tm(logger, lcid, pdcp, rrc_nr);
break; break;
case rlc_mode_t::um: case rlc_mode_t::um:
rlc_entity = new rlc_um_nr(logger, lcid, pdcp, rrc, timers); rlc_entity = new rlc_um_nr(logger, lcid, pdcp, rrc_nr, timers);
break; break;
default: default:
logger.error("Cannot add RLC entity - invalid mode"); logger.error("Cannot add RLC entity - invalid mode");
return; return;
} }
} else { break;
default:
logger.error("RAT not supported"); logger.error("RAT not supported");
return; return;
} }
@ -451,7 +470,9 @@ void rlc::add_bearer(uint32_t lcid, const rlc_config_t& cnfg)
logger.error("Error inserting RLC entity in to array."); logger.error("Error inserting RLC entity in to array.");
goto delete_and_exit; 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; 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: delete_and_exit:
if (rlc_entity) { if (rlc_entity) {
@ -510,9 +532,9 @@ void rlc::del_bearer(uint32_t lcid)
it->second->stop(); it->second->stop();
delete (it->second); delete (it->second);
rlc_array.erase(it); 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 { } 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(); it->second->stop();
delete (it->second); delete (it->second);
rlc_array_mrb.erase(it); 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 { } 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); logger.error("Error during LCID change of RLC bearer from %d to %d", old_lcid, new_lcid);
} }
} else { } else {
logger.error("Can't change LCID of bearer %s from %d to %d. Bearer doesn't exist or new LCID already occupied.", logger.error("Can't change LCID of bearer LCID %d to %d. Bearer doesn't exist or new LCID already occupied.",
rrc->get_rb_name(old_lcid),
old_lcid, old_lcid,
new_lcid); new_lcid);
} }
@ -565,26 +586,26 @@ void rlc::suspend_bearer(uint32_t lcid)
{ {
if (valid_lcid(lcid)) { if (valid_lcid(lcid)) {
if (rlc_array.at(lcid)->suspend()) { 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 { } else {
logger.error("Error suspending RLC entity: bearer already suspended."); logger.error("Error suspending RLC entity: bearer already suspended.");
} }
} else { } 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) 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 (valid_lcid(lcid)) {
if (rlc_array.at(lcid)->resume()) { 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 { } else {
logger.error("Error resuming RLC entity: bearer not suspended."); logger.error("Error resuming RLC entity: bearer not suspended.");
} }
} else { } 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);
} }
} }

@ -66,6 +66,70 @@ void log_rlc_am_status_pdu_to_string(srslog::log_channel& log_ch,
log_ch(fmt_str, std::forward<Args>(args)..., to_c_str(buffer)); log_ch(fmt_str, std::forward<Args>(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 * 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 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 (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 (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) 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) { 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->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++; 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 // 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); logger.info("%s Schedule SN=%d for reTx.", RB_NAME, pdu.rlc_sn);
rlc_amd_retx_t& retx = retx_queue.push(); rlc_amd_retx_t& retx = retx_queue.push();
retx.is_segment = false; 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("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("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()); srsran::console("retx_queue size: %zd PDUs\n", retx_queue.size());
std::map<uint32_t, rlc_amd_tx_pdu_t>::iterator txit; std::map<uint32_t, rlc_amd_tx_pdu>::iterator txit;
for (txit = tx_window.begin(); txit != tx_window.end(); txit++) { for (txit = tx_window.begin(); txit != tx_window.end(); txit++) {
srsran::console("tx_window - SN=%d\n", txit->first); 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.fi = RLC_FI_FIELD_START_AND_END_ALIGNED;
header.sn = vt_s; 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 // 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 // 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); rlc_amd_tx_pdu& tx_pdu = tx_window.add_pdu(header.sn);
tx_pdu.pdcp_sns.clear();
uint32_t head_len = rlc_am_packed_length(&header); uint32_t head_len = rlc_am_packed_length(&header);
uint32_t to_move = 0; 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->N_bytes -= to_move;
tx_sdu->msg += to_move; tx_sdu->msg += to_move;
if (undelivered_sdu_info_queue.has_pdcp_sn(tx_sdu->md.pdcp_sn)) { 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_pdu_info& pdcp_pdu = undelivered_sdu_info_queue[tx_sdu->md.pdcp_sn];
pdcp_sdu.rlc_sn_info_list.push_back({header.sn, false}); segment_pool.make_segment(tx_pdu, pdcp_pdu);
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);
}
if (tx_sdu->N_bytes == 0) { if (tx_sdu->N_bytes == 0) {
pdcp_sdu.fully_txed = true; pdcp_pdu.fully_txed = true;
} }
} else { } else {
// PDCP SNs for the RLC SDU has been removed from the queue // 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 // Pull SDUs from queue
while (pdu_space > head_len && tx_sdu_queue.get_n_sdus() > 0 && header.N_li < RLC_AM_WINDOW_SIZE) { 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) { if (last_li > 0) {
header.li[header.N_li] = last_li; header.li[header.N_li] = last_li;
header.N_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->N_bytes -= to_move;
tx_sdu->msg += to_move; tx_sdu->msg += to_move;
if (undelivered_sdu_info_queue.has_pdcp_sn(tx_sdu->md.pdcp_sn)) { 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_pdu_info& pdcp_pdu = undelivered_sdu_info_queue[tx_sdu->md.pdcp_sn];
pdcp_sdu.rlc_sn_info_list.push_back({header.sn, false}); segment_pool.make_segment(tx_pdu, pdcp_pdu);
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);
}
if (tx_sdu->N_bytes == 0) { if (tx_sdu->N_bytes == 0) {
pdcp_sdu.fully_txed = true; pdcp_pdu.fully_txed = true;
} }
} else { } else {
// PDCP SNs for the RLC SDU has been removed from the queue // 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 // Write final header and TX
tx_pdu.buf = std::move(pdu); tx_pdu.buf = std::move(pdu);
tx_pdu.header = header; 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(); const byte_buffer_t* buffer_ptr = tx_pdu.buf.get();
uint8_t* ptr = payload; 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) { if (!nack) {
// ACKed SNs get marked and removed from tx_window so PDCP get's only notified once // ACKed SNs get marked and removed from tx_window so PDCP get's only notified once
if (tx_window.has_sn(i)) { if (tx_window.has_sn(i)) {
auto& pdu = tx_window[i]; update_notification_ack_info(i);
update_notification_ack_info(pdu); logger.debug("Tx PDU SN=%zd being removed from tx window", i);
tx_window.remove_pdu(i); tx_window.remove_pdu(i);
} }
// Advance window if possible // 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); 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(); debug_state();
lock.unlock(); lock.unlock();
@ -1238,43 +1294,38 @@ 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. * @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. * @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", 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(), notify_info_vec.size(),
undelivered_sdu_info_queue.nof_sdus()); undelivered_sdu_info_queue.nof_sdus());
// Iterate over all undelivered 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; return;
} }
pdcp_sn_vector_t& pdcp_sns = tx_window[tx_pdu.header.sn].pdcp_sns; auto& acked_pdu = tx_window[rlc_sn];
for (uint32_t pdcp_sn : pdcp_sns) { // Iterate over all PDCP SNs of the same RLC PDU that were TX'ed
// Iterate over all SNs that were TX'ed for (rlc_am_pdu_segment& acked_segment : acked_pdu) {
auto& info = undelivered_sdu_info_queue[pdcp_sn]; uint32_t pdcp_sn = acked_segment.pdcp_sn();
for (auto& rlc_sn_info : info.rlc_sn_info_list) { pdcp_pdu_info& info = undelivered_sdu_info_queue[pdcp_sn];
// Mark this SN as acked, if necessary
if (rlc_sn_info.is_acked == false && rlc_sn_info.sn == tx_pdu.header.sn) { // Remove RLC SN from PDCP PDU undelivered list
rlc_sn_info.is_acked = true; info.ack_segment(acked_segment);
}
} // Check whether the SDU was fully acked
// Check wether the SDU was fully acked if (info.fully_acked()) {
if (info.fully_txed and not info.fully_acked) {
// Check if all SNs were ACK'ed // 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()) { if (not notify_info_vec.full()) {
notify_info_vec.push_back(pdcp_sn); notify_info_vec.push_back(pdcp_sn);
} else { } else {
logger.warning("Can't notify delivery of PDCP_SN=%d.", pdcp_sn); 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() 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) 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<uint32_t, rlc_amd_rx_pdu_t>::iterator it; std::map<uint32_t, rlc_amd_rx_pdu>::iterator it;
logger.info(payload, nof_bytes, "%s Rx data PDU SN=%d (%d B)", RB_NAME, header.sn, nof_bytes); 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); log_rlc_amd_pdu_header_to_string(logger.debug, header);
@ -1461,7 +1512,7 @@ void rlc_am_lte::rlc_am_lte_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_b
} }
// Write to rx window // Write to rx window
rlc_amd_rx_pdu_t& pdu = rx_window.add_pdu(header.sn); rlc_amd_rx_pdu& pdu = rx_window.add_pdu(header.sn);
pdu.buf = srsran::make_byte_buffer(); pdu.buf = srsran::make_byte_buffer();
if (pdu.buf == NULL) { if (pdu.buf == NULL) {
#ifdef RLC_AM_BUFFER_DEBUG #ifdef RLC_AM_BUFFER_DEBUG
@ -1566,7 +1617,7 @@ void rlc_am_lte::rlc_am_lte_rx::handle_data_pdu_segment(uint8_t* pa
return; return;
} }
rlc_amd_rx_pdu_t segment; rlc_amd_rx_pdu segment;
segment.buf = srsran::make_byte_buffer(); segment.buf = srsran::make_byte_buffer();
if (segment.buf == NULL) { if (segment.buf == NULL) {
#ifdef RLC_AM_BUFFER_DEBUG #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); it = rx_segments.find(vr_r);
if (rx_segments.end() != it) { if (rx_segments.end() != it) {
logger.debug("Erasing segments of SN=%d", vr_r); logger.debug("Erasing segments of SN=%d", vr_r);
std::list<rlc_amd_rx_pdu_t>::iterator segit; std::list<rlc_amd_rx_pdu>::iterator segit;
for (segit = it->second.segments.begin(); segit != it->second.segments.end(); ++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", logger.debug(" Erasing segment of SN=%d SO=%d Len=%d N_li=%d",
segit->header.sn, segit->header.sn,
@ -1921,7 +1972,7 @@ void rlc_am_lte::rlc_am_lte_rx::print_rx_segments()
std::stringstream ss; std::stringstream ss;
ss << "rx_segments:" << std::endl; ss << "rx_segments:" << std::endl;
for (it = rx_segments.begin(); it != rx_segments.end(); it++) { for (it = rx_segments.begin(); it != rx_segments.end(); it++) {
std::list<rlc_amd_rx_pdu_t>::iterator segit; std::list<rlc_amd_rx_pdu>::iterator segit;
for (segit = it->second.segments.begin(); segit != it->second.segments.end(); 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 ss << " SN=" << segit->header.sn << " SO:" << segit->header.so << " N:" << segit->buf->N_bytes
<< " N_li: " << segit->header.N_li << std::endl; << " 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 // 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 // Find segment insertion point in the list of segments
auto it1 = pdu->segments.begin(); 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 // Check if the insertion point was found
if (it1 != pdu->segments.end()) { if (it1 != pdu->segments.end()) {
// Found insertion point // Found insertion point
rlc_amd_rx_pdu_t& s = *it1; rlc_amd_rx_pdu& s = *it1;
if (s.header.so == segment->header.so) { if (s.header.so == segment->header.so) {
// Same Segment offset // Same Segment offset
if (segment->buf->N_bytes > s.buf->N_bytes) { if (segment->buf->N_bytes > s.buf->N_bytes) {
@ -1962,7 +2013,7 @@ bool rlc_am_lte::rlc_am_lte_rx::add_segment_and_check(rlc_amd_rx_pdu_segments_t*
// Check for complete // Check for complete
uint32_t so = 0; uint32_t so = 0;
std::list<rlc_amd_rx_pdu_t>::iterator it, tmpit; std::list<rlc_amd_rx_pdu>::iterator it, tmpit;
for (it = pdu->segments.begin(); it != pdu->segments.end(); /* Do not increment */) { 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 // Check that there is no gap between last segment and current; overlap allowed
if (so < it->header.so) { 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); 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(buffered_pdcp_pdu_list::buffer_size)
buffered_pdcp_pdu_list::buffered_pdcp_pdu_list() : buffered_pdus(max_buffer_idx + 1)
{ {
for (size_t i = 0; i < buffered_pdus.size(); ++i) {
buffered_pdus[i].rlc_sn_info_list.reserve(5);
}
clear(); clear();
} }
void buffered_pdcp_pdu_list::clear() void buffered_pdcp_pdu_list::clear()
{ {
count = 0; count = 0;
for (auto& b : buffered_pdus) { for (pdcp_pdu_info& b : buffered_pdus) {
b.sn = invalid_sn; b.clear();
b.fully_acked = false;
b.fully_txed = false;
b.rlc_sn_info_list.clear();
} }
} }
@ -2402,26 +2445,16 @@ bool rlc_am_is_pdu_segment(uint8_t* payload)
return ((*(payload) >> 6) & 0x01) == 1; return ((*(payload) >> 6) & 0x01) == 1;
} }
std::string rlc_am_undelivered_sdu_info_to_string(const std::map<uint32_t, pdcp_sdu_info_t>& info_queue) void rlc_am_undelivered_sdu_info_to_string(fmt::memory_buffer& buffer, const std::vector<pdcp_pdu_info>& info_queue)
{ {
std::string str = "\n"; fmt::format_to(buffer, "\n");
for (const auto& info_it : info_queue) { for (const auto& pdcp_pdu : info_queue) {
uint32_t pdcp_sn = info_it.first; fmt::format_to(buffer, "\tPDCP_SN = {}, undelivered RLC SNs = [", pdcp_pdu.sn);
auto info = info_it.second; for (const auto& nacked_segment : pdcp_pdu) {
std::string tmp_str = fmt::format("\tPDCP_SN = {}, RLC_SNs = [", pdcp_sn); fmt::format_to(buffer, "{} ", nacked_segment.rlc_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;
} }
tmp_str += "]\n"; fmt::format_to(buffer, "]\n");
str += tmp_str;
} }
return str;
} }
void log_rlc_amd_pdu_header_to_string(srslog::log_channel& log_ch, const rlc_amd_pdu_header_t& header) void log_rlc_amd_pdu_header_to_string(srslog::log_channel& log_ch, const rlc_amd_pdu_header_t& header)

@ -20,7 +20,7 @@
*/ */
#include "srsran/upper/rlc_tm.h" #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_pdcp_interfaces.h"
#include "srsran/interfaces/ue_rrc_interfaces.h" #include "srsran/interfaces/ue_rrc_interfaces.h"

@ -165,7 +165,7 @@ int rlc_um_nr::rlc_um_nr_tx::build_data_pdu(unique_byte_buffer_t pdu, uint8_t* p
// Calculate actual header length // Calculate actual header length
uint32_t head_len = rlc_um_nr_packed_length(header); uint32_t head_len = rlc_um_nr_packed_length(header);
if (pdu_space <= head_len + 1) { if (pdu_space <= head_len + 1) {
logger.warning("%s Cannot build a PDU - %d bytes available, %d bytes required for header", logger.info("%s Cannot build a PDU - %d bytes available, %d bytes required for header",
rb_name.c_str(), rb_name.c_str(),
nof_bytes, nof_bytes,
head_len); head_len);
@ -296,7 +296,7 @@ void rlc_um_nr::rlc_um_nr_rx::timer_expired(uint32_t timeout_id)
if (reassembly_timer.id() == 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.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++; metrics.num_lost_pdus++;
if (rx_sdu != nullptr) { 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) const uint32_t nof_bytes)
{ {
unique_byte_buffer_t sdu = make_byte_buffer(); unique_byte_buffer_t sdu = make_byte_buffer();
if (!sdu) { if (sdu == nullptr) {
logger.error("Discarting packet: no space in buffer pool"); logger.error("Couldn't allocate PDU in %s().", __FUNCTION__);
return nullptr; return nullptr;
} }
memcpy(sdu->msg, payload, nof_bytes); memcpy(sdu->msg, payload, nof_bytes);

@ -22,6 +22,39 @@
#include "srsran/adt/bounded_bitset.h" #include "srsran/adt/bounded_bitset.h"
#include "srsran/common/test_common.h" #include "srsran/common/test_common.h"
void test_bit_operations()
{
TESTASSERT(0 == srsran::mask_lsb_ones<uint8_t>(0));
TESTASSERT(0 == srsran::mask_msb_ones<uint8_t>(0));
TESTASSERT(0 == srsran::mask_lsb_ones<uint32_t>(0));
TESTASSERT(0 == srsran::mask_msb_ones<uint32_t>(0));
TESTASSERT(0b11111111 == srsran::mask_lsb_zeros<uint8_t>(0));
TESTASSERT(0b11111111 == srsran::mask_msb_zeros<uint8_t>(0));
TESTASSERT((uint32_t)-1 == srsran::mask_lsb_zeros<uint32_t>(0));
TESTASSERT((uint32_t)-1 == srsran::mask_msb_zeros<uint32_t>(0));
TESTASSERT(0b11 == srsran::mask_lsb_ones<uint8_t>(2));
TESTASSERT(0b11000000 == srsran::mask_msb_ones<uint8_t>(2));
TESTASSERT(0b11111100 == srsran::mask_lsb_zeros<uint8_t>(2));
TESTASSERT(0b00111111 == srsran::mask_msb_zeros<uint8_t>(2));
TESTASSERT(0b11111111 == srsran::mask_lsb_ones<uint8_t>(8));
TESTASSERT(0b1111 == srsran::mask_lsb_ones<uint8_t>(4));
TESTASSERT(srsran::find_first_lsb_one<uint8_t>(0) == std::numeric_limits<uint8_t>::digits);
TESTASSERT(srsran::find_first_msb_one<uint8_t>(0) == std::numeric_limits<uint8_t>::digits);
TESTASSERT(srsran::find_first_lsb_one<uint8_t>(1) == 0);
TESTASSERT(srsran::find_first_msb_one<uint8_t>(1) == 0);
TESTASSERT(srsran::find_first_lsb_one<uint8_t>(0b11) == 0);
TESTASSERT(srsran::find_first_lsb_one<uint8_t>(0b10) == 1);
TESTASSERT(srsran::find_first_msb_one<uint8_t>(0b11) == 1);
TESTASSERT(srsran::find_first_msb_one<uint8_t>(0b10) == 1);
TESTASSERT(srsran::find_first_lsb_one<uint32_t>(0b11) == 0);
TESTASSERT(srsran::find_first_lsb_one<uint32_t>(0b10) == 1);
TESTASSERT(srsran::find_first_msb_one<uint32_t>(0b11) == 1);
TESTASSERT(srsran::find_first_msb_one<uint32_t>(0b10) == 1);
}
int test_zero_bitset() int test_zero_bitset()
{ {
srsran::bounded_bitset<25> mask; srsran::bounded_bitset<25> mask;
@ -185,14 +218,77 @@ int test_bitset_resize()
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
template <bool reversed>
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() int main()
{ {
test_bit_operations();
TESTASSERT(test_zero_bitset() == SRSRAN_SUCCESS); TESTASSERT(test_zero_bitset() == SRSRAN_SUCCESS);
TESTASSERT(test_ones_bitset() == SRSRAN_SUCCESS); TESTASSERT(test_ones_bitset() == SRSRAN_SUCCESS);
TESTASSERT(test_bitset_set() == SRSRAN_SUCCESS); TESTASSERT(test_bitset_set() == SRSRAN_SUCCESS);
TESTASSERT(test_bitset_bitwise_oper() == SRSRAN_SUCCESS); TESTASSERT(test_bitset_bitwise_oper() == SRSRAN_SUCCESS);
TESTASSERT(test_bitset_print() == SRSRAN_SUCCESS); TESTASSERT(test_bitset_print() == SRSRAN_SUCCESS);
TESTASSERT(test_bitset_resize() == SRSRAN_SUCCESS); TESTASSERT(test_bitset_resize() == SRSRAN_SUCCESS);
test_bitset_find<false>();
test_bitset_find<true>();
printf("Success\n"); printf("Success\n");
return 0; return 0;
} }

@ -135,7 +135,7 @@ int make_phy_coreset_cfg_test()
srsran_coreset_t srsran_coreset; srsran_coreset_t srsran_coreset;
TESTASSERT(make_phy_coreset_cfg(ctrl_res_set, &srsran_coreset) == true); 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.precoder_granularity == srsran_coreset_precoder_granularity_reg_bundle);
TESTASSERT(srsran_coreset.duration == 1); TESTASSERT(srsran_coreset.duration == 1);
TESTASSERT(srsran_coreset.mapping_type == srsran_coreset_mapping_type_non_interleaved); TESTASSERT(srsran_coreset.mapping_type == srsran_coreset_mapping_type_non_interleaved);
@ -555,6 +555,127 @@ int make_phy_pusch_scaling_test()
return SRSRAN_SUCCESS; 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() int main()
{ {
auto& asn1_logger = srslog::fetch_basic_logger("ASN1", false); 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_dmrs_additional_pos_test() == SRSRAN_SUCCESS);
TESTASSERT(make_phy_beta_offsets_test() == SRSRAN_SUCCESS); TESTASSERT(make_phy_beta_offsets_test() == SRSRAN_SUCCESS);
TESTASSERT(make_phy_pusch_scaling_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(); srslog::flush();
printf("Success\n"); printf("Success\n");

@ -29,12 +29,13 @@
#include <getopt.h> #include <getopt.h>
static srsran_carrier_nr_t carrier = { static srsran_carrier_nr_t carrier = {
501, // cell_id 501, // pci
0, // numerology 0, // absolute_frequency_ssb
0, // absolute_frequency_point_a
srsran_subcarrier_spacing_15kHz, // scs
52, // nof_prb 52, // nof_prb
0, // start 0, // start
1 // max_mimo_layers 1 // max_mimo_layers
}; };
static uint32_t n_prb = 0; // Set to 0 for steering 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.disable_simd = false;
ue_dl_args.pdsch.sch.decoder_use_flooded = false; ue_dl_args.pdsch.sch.decoder_use_flooded = false;
ue_dl_args.pdsch.measure_evm = true; 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.disable_simd = false;
ue_dl_args.pdcch.measure_evm = true; ue_dl_args.pdcch.measure_evm = true;
ue_dl_args.nof_max_prb = carrier.nof_prb; ue_dl_args.nof_max_prb = carrier.nof_prb;
@ -384,7 +384,7 @@ int main(int argc, char** argv)
search_space, search_space,
pdsch_cfg.grant.rnti, pdsch_cfg.grant.rnti,
L, L,
SRSRAN_SLOT_NR_MOD(carrier.numerology, slot.idx), SRSRAN_SLOT_NR_MOD(carrier.scs, slot.idx),
ncce_candidates); ncce_candidates);
if (nof_candidates < SRSRAN_SUCCESS) { if (nof_candidates < SRSRAN_SUCCESS) {
ERROR("Error getting PDCCH candidates"); ERROR("Error getting PDCCH candidates");
@ -416,7 +416,7 @@ int main(int argc, char** argv)
// Emulate channel CFO // Emulate channel CFO
if (isnormal(cfo_hz) && ue_dl.fft[0].cfg.symbol_sz > 0) { if (isnormal(cfo_hz) && ue_dl.fft[0].cfg.symbol_sz > 0) {
srsran_vec_apply_cfo(buffer_ue[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], buffer_ue[0],
sf_len); 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]); 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 // Count the Tx/Rx'd number of bits

@ -101,7 +101,8 @@ srsran::unique_byte_buffer_t gen_expected_pdu(const srsran::unique_byte_buffer_t
pdcp_sn_len, pdcp_sn_len,
srsran::pdcp_t_reordering_t::ms500, srsran::pdcp_t_reordering_t::ms500,
srsran::pdcp_discard_timer_t::infinity, srsran::pdcp_discard_timer_t::infinity,
false}; false,
srsran::srsran_rat_t::lte};
pdcp_lte_test_helper pdcp_hlp(cfg, sec_cfg, logger); pdcp_lte_test_helper pdcp_hlp(cfg, sec_cfg, logger);
srsran::pdcp_entity_lte* pdcp = &pdcp_hlp.pdcp; srsran::pdcp_entity_lte* pdcp = &pdcp_hlp.pdcp;

@ -35,7 +35,8 @@ int test_tx_sdu_notify(const srsran::pdcp_lte_state_t& init_state,
srsran::PDCP_SN_LEN_12, srsran::PDCP_SN_LEN_12,
srsran::pdcp_t_reordering_t::ms500, srsran::pdcp_t_reordering_t::ms500,
discard_timeout, discard_timeout,
false}; false,
srsran::srsran_rat_t::lte};
pdcp_lte_test_helper pdcp_hlp(cfg, sec_cfg, logger); pdcp_lte_test_helper pdcp_hlp(cfg, sec_cfg, logger);
srsran::pdcp_entity_lte* pdcp = &pdcp_hlp.pdcp; 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_SN_LEN_12,
srsran::pdcp_t_reordering_t::ms500, srsran::pdcp_t_reordering_t::ms500,
discard_timeout, discard_timeout,
false}; false,
srsran::srsran_rat_t::lte};
pdcp_lte_test_helper pdcp_hlp(cfg, sec_cfg, logger); pdcp_lte_test_helper pdcp_hlp(cfg, sec_cfg, logger);
srsran::pdcp_entity_lte* pdcp = &pdcp_hlp.pdcp; srsran::pdcp_entity_lte* pdcp = &pdcp_hlp.pdcp;

@ -40,7 +40,8 @@ int test_rx(std::vector<pdcp_test_event_t> events,
pdcp_sn_len, pdcp_sn_len,
srsran::pdcp_t_reordering_t::ms500, srsran::pdcp_t_reordering_t::ms500,
srsran::pdcp_discard_timer_t::infinity, 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); pdcp_lte_test_helper pdcp_hlp_rx(cfg_rx, sec_cfg, logger);
srsran::pdcp_entity_lte* pdcp_rx = &pdcp_hlp_rx.pdcp; srsran::pdcp_entity_lte* pdcp_rx = &pdcp_hlp_rx.pdcp;

@ -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_SN_LEN_12,
srsran::pdcp_t_reordering_t::ms500, srsran::pdcp_t_reordering_t::ms500,
srsran::pdcp_discard_timer_t::ms500, srsran::pdcp_discard_timer_t::ms500,
true}; true,
srsran::srsran_rat_t::lte};
srsran::pdcp_config_t cfg_rx = {1, srsran::pdcp_config_t cfg_rx = {1,
srsran::PDCP_RB_IS_DRB, 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_SN_LEN_12,
srsran::pdcp_t_reordering_t::ms500, srsran::pdcp_t_reordering_t::ms500,
srsran::pdcp_discard_timer_t::ms500, srsran::pdcp_discard_timer_t::ms500,
true}; true,
srsran::srsran_rat_t::lte};
// Setup TX // Setup TX
pdcp_lte_test_helper pdcp_hlp_tx(cfg_tx, sec_cfg, logger); 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_SN_LEN_12,
srsran::pdcp_t_reordering_t::ms500, srsran::pdcp_t_reordering_t::ms500,
srsran::pdcp_discard_timer_t::ms500, srsran::pdcp_discard_timer_t::ms500,
true}; true,
srsran::srsran_rat_t::lte};
srsran::pdcp_config_t cfg_rx = {1, srsran::pdcp_config_t cfg_rx = {1,
srsran::PDCP_RB_IS_DRB, 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_SN_LEN_12,
srsran::pdcp_t_reordering_t::ms500, srsran::pdcp_t_reordering_t::ms500,
srsran::pdcp_discard_timer_t::ms500, srsran::pdcp_discard_timer_t::ms500,
true}; true,
srsran::srsran_rat_t::lte};
// Setup TX // Setup TX
pdcp_lte_test_helper pdcp_hlp_tx(cfg_tx, sec_cfg, logger); 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_SN_LEN_12,
srsran::pdcp_t_reordering_t::ms500, srsran::pdcp_t_reordering_t::ms500,
srsran::pdcp_discard_timer_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); pdcp_lte_test_helper pdcp_hlp(cfg, sec_cfg, logger);
srsran::pdcp_entity_lte* pdcp = &pdcp_hlp.pdcp; srsran::pdcp_entity_lte* pdcp = &pdcp_hlp.pdcp;

@ -134,7 +134,8 @@ srsran::unique_byte_buffer_t gen_expected_pdu(const srsran::unique_byte_buffer_t
pdcp_sn_len, pdcp_sn_len,
srsran::pdcp_t_reordering_t::ms500, srsran::pdcp_t_reordering_t::ms500,
srsran::pdcp_discard_timer_t::infinity, srsran::pdcp_discard_timer_t::infinity,
false}; false,
srsran::srsran_rat_t::nr};
pdcp_nr_test_helper pdcp_hlp(cfg, sec_cfg, logger); pdcp_nr_test_helper pdcp_hlp(cfg, sec_cfg, logger);
srsran::pdcp_entity_nr* pdcp = &pdcp_hlp.pdcp; srsran::pdcp_entity_nr* pdcp = &pdcp_hlp.pdcp;

@ -36,7 +36,8 @@ int test_tx_sdu_discard(const pdcp_initial_state& init_state,
srsran::PDCP_SN_LEN_12, srsran::PDCP_SN_LEN_12,
srsran::pdcp_t_reordering_t::ms500, srsran::pdcp_t_reordering_t::ms500,
discard_timeout, discard_timeout,
false}; false,
srsran::srsran_rat_t::nr};
pdcp_nr_test_helper pdcp_hlp(cfg, sec_cfg, logger); pdcp_nr_test_helper pdcp_hlp(cfg, sec_cfg, logger);
srsran::pdcp_entity_nr* pdcp = &pdcp_hlp.pdcp; srsran::pdcp_entity_nr* pdcp = &pdcp_hlp.pdcp;

@ -39,7 +39,8 @@ int test_rx(std::vector<pdcp_test_event_t> events,
pdcp_sn_len, pdcp_sn_len,
srsran::pdcp_t_reordering_t::ms500, srsran::pdcp_t_reordering_t::ms500,
srsran::pdcp_discard_timer_t::infinity, 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); pdcp_nr_test_helper pdcp_hlp_rx(cfg_rx, sec_cfg, logger);
srsran::pdcp_entity_nr* pdcp_rx = &pdcp_hlp_rx.pdcp; srsran::pdcp_entity_nr* pdcp_rx = &pdcp_hlp_rx.pdcp;

@ -38,7 +38,8 @@ int test_tx(uint32_t n_packets,
pdcp_sn_len, pdcp_sn_len,
srsran::pdcp_t_reordering_t::ms500, srsran::pdcp_t_reordering_t::ms500,
srsran::pdcp_discard_timer_t::infinity, srsran::pdcp_discard_timer_t::infinity,
false}; false,
srsran::srsran_rat_t::nr};
pdcp_nr_test_helper pdcp_hlp(cfg, sec_cfg, logger); pdcp_nr_test_helper pdcp_hlp(cfg, sec_cfg, logger);
srsran::pdcp_entity_nr* pdcp = &pdcp_hlp.pdcp; srsran::pdcp_entity_nr* pdcp = &pdcp_hlp.pdcp;

@ -26,7 +26,7 @@
INCLUDES INCLUDES
*******************************************************************************/ *******************************************************************************/
#include "srsran/common/lte_common.h" #include "srsran/common/common_lte.h"
#include <stdint.h> #include <stdint.h>
namespace srsenb { namespace srsenb {

@ -95,7 +95,7 @@ public:
// TODO // TODO
void read_pdu_pcch(uint8_t* payload, uint32_t payload_size) {} void read_pdu_pcch(uint8_t* payload, uint32_t payload_size) {}
void max_retx_attempted(uint16_t rnti) {} void max_retx_attempted(uint16_t rnti) {}
const char* get_rb_name(uint32_t lcid) { return "invalid"; }
// PDCP interface // PDCP interface
void write_pdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t pdu) final; void write_pdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t pdu) final;

@ -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_nr_t phy_cell_cfg = {};
phy_cell_cfg.carrier.max_mimo_layers = cell_cfg_.nof_ports; 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.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.cell_id = cfg.cell_id;
phy_cell_cfg.root_seq_idx = cfg.root_seq_idx; phy_cell_cfg.root_seq_idx = cfg.root_seq_idx;
phy_cell_cfg.rf_port = cfg.rf_port; phy_cell_cfg.rf_port = cfg.rf_port;

@ -277,15 +277,15 @@ std::array<int, SRSRAN_MAX_CARRIERS> sched::get_enb_ue_cc_map(uint16_t rnti)
std::array<bool, SRSRAN_MAX_CARRIERS> sched::get_scell_activation_mask(uint16_t rnti) std::array<bool, SRSRAN_MAX_CARRIERS> sched::get_scell_activation_mask(uint16_t rnti)
{ {
std::array<int, SRSRAN_MAX_CARRIERS> enb_ue_cc_map = get_enb_ue_cc_map(rnti);
std::array<bool, SRSRAN_MAX_CARRIERS> scell_mask = {}; std::array<bool, SRSRAN_MAX_CARRIERS> scell_mask = {};
for (int ue_cc : enb_ue_cc_map) { ue_db_access_locked(rnti, [this, &scell_mask](sched_ue& ue) {
if (ue_cc <= 0) { for (size_t enb_cc_idx = 0; enb_cc_idx < carrier_schedulers.size(); ++enb_cc_idx) {
// inactive or PCell const sched_ue_cell* cc_ue = ue.find_ue_carrier(enb_cc_idx);
continue; 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; return scell_mask;
} }

@ -86,10 +86,12 @@ void sched_ue::set_cfg(const ue_cfg_t& cfg_)
scell_activation_state_changed |= scell_activation_state_changed |=
c.is_scell() and (c.cc_state() == cc_st::activating or c.cc_state() == cc_st::deactivating); 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); 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); lch_handler.pending_ces.emplace_back(srsran::dl_sch_lcid::SCELL_ACTIVATION);
logger.info("SCHED: Enqueueing SCell Activation CMD for rnti=0x%x", rnti); logger.info("SCHED: Enqueueing SCell Activation CMD for rnti=0x%x", rnti);
} }

@ -32,22 +32,26 @@ template <typename RBMask,
typename std::conditional<std::is_same<RBMask, prbmask_t>::value, prb_interval, rbg_interval>::type> typename std::conditional<std::is_same<RBMask, prbmask_t>::value, prb_interval, rbg_interval>::type>
RBInterval find_contiguous_interval(const RBMask& in_mask, uint32_t max_size) 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++) { for (size_t n = 0; n < in_mask.size();) {
if (not in_mask.test(n) and interv.empty()) { int pos = in_mask.find_lowest(n, in_mask.size(), false);
// new interval if (pos < 0) {
interv.set(n, n + 1); break;
} else if (not in_mask.test(n)) { }
// extend current interval
interv.resize_by(1); size_t max_pos = std::min(in_mask.size(), (size_t)pos + max_size);
} else if (not interv.empty()) { int pos2 = in_mask.find_lowest(pos, max_pos, true);
// reset interval RBInterval interv(pos, pos2 < 0 ? max_pos : pos2);
max_interv = interv.length() > max_interv.length() ? interv : max_interv; if (interv.length() >= max_size) {
interv = {}; return interv;
} }
} if (interv.length() > max_interv.length()) {
return interv.length() > max_interv.length() ? interv : max_interv; max_interv = interv;
}
n = interv.stop();
}
return max_interv;
} }
/**************************** /****************************

@ -136,9 +136,7 @@ int mac_controller::handle_crnti_ce(uint32_t temp_crnti)
current_sched_ue_cfg = next_sched_ue_cfg; current_sched_ue_cfg = next_sched_ue_cfg;
// Disable SCells, until RRCReconfComplete is received, otherwise the SCell Act MAC CE is sent too early // 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) { set_scell_activation({0});
current_sched_ue_cfg.supported_cc_list[i].active = false;
}
// keep DRBs disabled until RRCReconfComplete is received // keep DRBs disabled until RRCReconfComplete is received
set_drb_activation(false); set_drb_activation(false);

@ -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); logger.error("Failed to allocate GTPU TEID for E-RAB id=%d", fwd_erab.erab_id);
not_admitted_erabs.emplace_back(); not_admitted_erabs.emplace_back();
not_admitted_erabs.back().erab_id = erab.second.id; not_admitted_erabs.back().erab_id = erab.second.id;
not_admitted_erabs.back().cause.set_radio_network().value = not_admitted_erabs.back().cause.set_transport().value =
asn1::s1ap::cause_radio_network_opts::no_radio_res_available_in_target_cell; asn1::s1ap::cause_transport_opts::transport_res_unavailable;
admitted_erabs.pop_back(); admitted_erabs.pop_back();
continue; 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) { if (rrc_ue->bearer_list.add_gtpu_bearer(erab.erab_id) != SRSRAN_SUCCESS) {
erabs_failed_to_setup.emplace_back(); erabs_failed_to_setup.emplace_back();
erabs_failed_to_setup.back().erab_id = erab.erab_id; erabs_failed_to_setup.back().erab_id = erab.erab_id;
erabs_failed_to_setup.back().cause.set_radio_network().value = erabs_failed_to_setup.back().cause.set_transport().value =
asn1::s1ap::cause_radio_network_opts::no_radio_res_available_in_target_cell; asn1::s1ap::cause_transport_opts::transport_res_unavailable;
continue; continue;
} }
} }

@ -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/stack/rrc/rrc_nr.h"
#include "srsenb/hdr/common/common_enb.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; 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_SN_LEN_18,
srsran::pdcp_t_reordering_t::ms500, srsran::pdcp_t_reordering_t::ms500,
srsran::pdcp_discard_timer_t::infinity, 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); pdcp->add_bearer(cfg.coreless.rnti, cfg.coreless.drb_lcid, pdcp_cnfg);
logger.info("Started"); 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) void rrc_nr::handle_pdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t pdu)
{ {
if (pdu) { if (pdu) {
logger.info(pdu->msg, pdu->N_bytes, "Rx %s PDU", srsran::to_string(static_cast<srsran::rb_id_nr_t>(lcid))); logger.info(pdu->msg, pdu->N_bytes, "Rx %s PDU", get_rb_name(lcid));
} }
if (users.count(rnti) == 1) { if (users.count(rnti) == 1) {
switch (static_cast<srsran::rb_id_nr_t>(lcid)) { switch (static_cast<srsran::nr_srb>(lcid)) {
case srsran::rb_id_nr_t::NR_SRB0: case srsran::nr_srb::srb0:
// parse_ul_ccch(rnti, std::move(pdu)); // parse_ul_ccch(rnti, std::move(pdu));
break; break;
case srsran::rb_id_nr_t::NR_SRB1: case srsran::nr_srb::srb1:
case srsran::rb_id_nr_t::NR_SRB2: case srsran::nr_srb::srb2:
// parse_ul_dcch(p.rnti, p.lcid, std::move(p.pdu)); // parse_ul_dcch(p.rnti, p.lcid, std::move(p.pdu));
break; break;
default: default:
@ -405,7 +406,7 @@ void rrc_nr::ue::send_dl_ccch(dl_ccch_msg_s* dl_ccch_msg)
char buf[32] = {}; char buf[32] = {};
sprintf(buf, "SRB0 - rnti=0x%x", rnti); sprintf(buf, "SRB0 - rnti=0x%x", rnti);
parent->log_rrc_message(buf, Tx, pdu.get(), *dl_ccch_msg); 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 } // namespace srsenb

@ -20,7 +20,6 @@
*/ */
#include "srsenb/hdr/stack/upper/pdcp_nr.h" #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" #include "srsenb/hdr/common/common_enb.h"
namespace srsenb { namespace srsenb {

@ -20,8 +20,7 @@
*/ */
#include "srsenb/hdr/stack/upper/rlc_nr.h" #include "srsenb/hdr/stack/upper/rlc_nr.h"
#include "srsran/interfaces/nr_common_interface_types.h" #include "srsran/common/common_nr.h"
namespace srsenb { namespace srsenb {
rlc_nr::rlc_nr(const char* logname) : logger(srslog::fetch_basic_logger(logname)) {} 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.parent = this;
user_itf.m_rlc.reset(new srsran::rlc(logger.id().c_str())); user_itf.m_rlc.reset(new srsran::rlc(logger.id().c_str()));
users[rnti] = std::move(user_itf); 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) 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)); m_rrc->write_pdu(rnti, lcid, std::move(sdu));
} else { } else {
m_pdcp->write_pdu(rnti, lcid, std::move(sdu)); 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) const char* rlc_nr::user_interface::get_rb_name(uint32_t lcid)
{ {
return srsran::to_string(static_cast<srsran::rb_id_nr_t>(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) void rlc_nr::user_interface::notify_delivery(uint32_t lcid, const srsran::pdcp_sn_vector_t& pdcp_sns)

@ -22,7 +22,7 @@
#include "sched_test_common.h" #include "sched_test_common.h"
#include "srsenb/hdr/stack/mac/sched.h" #include "srsenb/hdr/stack/mac/sched.h"
#include "srsran/adt/accumulators.h" #include "srsran/adt/accumulators.h"
#include "srsran/common/lte_common.h" #include "srsran/common/common_lte.h"
#include <chrono> #include <chrono>
namespace srsenb { namespace srsenb {

@ -22,7 +22,7 @@
#include "sched_test_common.h" #include "sched_test_common.h"
#include "sched_test_utils.h" #include "sched_test_utils.h"
#include "srsenb/hdr/stack/mac/sched.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" #include "srsran/mac/pdu.h"
using namespace srsenb; using namespace srsenb;

@ -22,7 +22,7 @@
#include "sched_test_utils.h" #include "sched_test_utils.h"
#include "srsenb/hdr/stack/mac/sched_common.h" #include "srsenb/hdr/stack/mac/sched_common.h"
#include "srsenb/hdr/stack/mac/sched_phy_ch/sched_dci.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" #include "srsran/common/test_common.h"
namespace srsenb { namespace srsenb {

@ -21,7 +21,7 @@
#include "sched_test_common.h" #include "sched_test_common.h"
#include "srsenb/hdr/stack/mac/sched_grid.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" #include "srsran/common/test_common.h"
using namespace srsenb; using namespace srsenb;

@ -34,7 +34,7 @@
#include "sched_common_test_suite.h" #include "sched_common_test_suite.h"
#include "sched_test_common.h" #include "sched_test_common.h"
#include "sched_test_utils.h" #include "sched_test_utils.h"
#include "srsran/common/lte_common.h" #include "srsran/common/common_lte.h"
#include "srsran/common/test_common.h" #include "srsran/common/test_common.h"
namespace srsenb { namespace srsenb {

@ -48,6 +48,10 @@ public:
int read_pdsch_d(cf_t* pdsch_d); int read_pdsch_d(cf_t* pdsch_d);
private: private:
// PHY lib temporal logger types
typedef std::array<char, 512> str_info_t;
typedef std::array<char, 2048> str_extra_t;
bool configured = false; bool configured = false;
srsran_slot_cfg_t dl_slot_cfg = {}; srsran_slot_cfg_t dl_slot_cfg = {};
srsran_slot_cfg_t ul_slot_cfg = {}; srsran_slot_cfg_t ul_slot_cfg = {};
@ -60,10 +64,7 @@ private:
srsran_ue_ul_nr_t ue_ul = {}; srsran_ue_ul_nr_t ue_ul = {};
srslog::basic_logger& logger; srslog::basic_logger& logger;
// Temporal attributes // Methods for DCI blind search
srsran_softbuffer_rx_t softbuffer_rx = {};
// Methods for DL...
void decode_pdcch_ul(); void decode_pdcch_ul();
void decode_pdcch_dl(); void decode_pdcch_dl();
}; };

@ -95,11 +95,11 @@ public:
state() state()
{ {
carrier.id = 500; carrier.pci = 500;
carrier.nof_prb = 100; carrier.nof_prb = 100;
carrier.max_mimo_layers = 1; 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 // Hard-coded values, this should be set when the measurements take place
csi_measurements[0].K_csi_rs = 1; csi_measurements[0].K_csi_rs = 1;
@ -157,8 +157,9 @@ public:
return false; return false;
} }
// Load shared channel configuration // Load shared channel configuration and PID
pusch_cfg = pending_grant.sch_cfg; pusch_cfg = pending_grant.sch_cfg;
pid = pending_grant.pid;
// Reset entry // Reset entry
pending_grant.enable = false; pending_grant.enable = false;

@ -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<srsran::unique_byte_buffer_t> pdu_queue;
srsran::mac_sch_pdu_nr rx_pdu;
};
} // namespace srsue
#endif // SRSLTE_DEMUX_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 <mutex>
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<srsran_softbuffer_rx_t> softbuffer_rx;
};
// Private members of dl_harq_entity_nr
mac_interface_harq_nr* mac = nullptr;
srsran::dl_harq_cfg_nr_t cfg = {};
std::array<std::unique_ptr<dl_harq_process_nr>, 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> dl_harq_entity_nr_ptr;
typedef std::array<dl_harq_entity_nr_ptr, SRSRAN_MAX_CARRIERS> dl_harq_entity_nr_vector;
} // namespace srsue
#endif // SRSLTE_DL_HARQ_NR_H

@ -22,16 +22,17 @@
#ifndef SRSUE_MAC_NR_H #ifndef SRSUE_MAC_NR_H
#define SRSUE_MAC_NR_H #define SRSUE_MAC_NR_H
#include "dl_harq_nr.h"
#include "mac_nr_interfaces.h" #include "mac_nr_interfaces.h"
#include "proc_bsr_nr.h" #include "proc_bsr_nr.h"
#include "proc_ra_nr.h" #include "proc_ra_nr.h"
#include "proc_sr_nr.h" #include "proc_sr_nr.h"
#include "srsran/common/block_queue.h"
#include "srsran/common/mac_pcap.h" #include "srsran/common/mac_pcap.h"
#include "srsran/interfaces/mac_interface_types.h" #include "srsran/interfaces/mac_interface_types.h"
#include "srsran/interfaces/ue_nr_interfaces.h" #include "srsran/interfaces/ue_nr_interfaces.h"
#include "srsran/srslog/srslog.h" #include "srsran/srslog/srslog.h"
#include "srsue/hdr/stack/mac_common/mac_common.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/mac_nr/mux_nr.h"
#include "srsue/hdr/stack/ue_stack_base.h" #include "srsue/hdr/stack/ue_stack_base.h"
#include "ul_harq_nr.h" #include "ul_harq_nr.h"
@ -53,7 +54,7 @@ public:
mac_nr(srsran::ext_task_sched_handle task_sched_); mac_nr(srsran::ext_task_sched_handle task_sched_);
~mac_nr(); ~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 stop();
void reset(); void reset();
@ -68,7 +69,8 @@ public:
sched_rnti_t get_ul_sched_rnti_nr(const uint32_t tti); sched_rnti_t get_ul_sched_rnti_nr(const uint32_t tti);
int sf_indication(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 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, void prach_sent(const uint32_t tti,
const uint32_t s_id, 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::bsr_cfg_nr_t& bsr_cfg);
int set_config(const srsran::sr_cfg_nr_t& sr_cfg); int set_config(const srsran::sr_cfg_nr_t& sr_cfg);
void set_config(const srsran::rach_nr_cfg_t& rach_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); void set_contention_id(const uint64_t ue_identity);
bool set_crnti(const uint16_t crnti); bool set_crnti(const uint16_t crnti);
int add_tag_config(const srsran::tag_cfg_nr_t& tag_cfg); 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); static bool is_in_window(uint32_t tti, int* start, int* len);
private: 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 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); 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; uint16_t c_rnti = SRSRAN_INVALID_RNTI;
uint64_t contention_id = 0; uint64_t contention_id = 0;
srsran::block_queue<srsran::unique_byte_buffer_t>
pdu_queue; ///< currently only DCH PDUs supported (add BCH, PCH, etc)
std::array<mac_metrics_t, SRSRAN_MAX_CARRIERS> metrics = {}; std::array<mac_metrics_t, SRSRAN_MAX_CARRIERS> metrics = {};
/// Rx buffer
srsran::mac_sch_pdu_nr rx_pdu;
srsran::task_multiqueue::queue_handle stack_task_dispatch_queue; srsran::task_multiqueue::queue_handle stack_task_dispatch_queue;
// MAC Uplink-related procedures // MAC Uplink-related procedures
@ -169,10 +168,11 @@ private:
proc_sr_nr proc_sr; proc_sr_nr proc_sr;
proc_bsr_nr proc_bsr; proc_bsr_nr proc_bsr;
mux_nr mux; 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_entity_nr_vector ul_harq = {};
ul_harq_cfg_t ul_harq_cfg;
const uint8_t PCELL_CC_IDX = 0; const uint8_t PCELL_CC_IDX = 0;
}; };

@ -86,6 +86,16 @@ public:
virtual uint16_t get_csrnti() = 0; 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 } // namespace srsue
#endif // SRSUE_MAC_NR_INTERFACES_H #endif // SRSUE_MAC_NR_INTERFACES_H

@ -52,7 +52,7 @@ public:
// PHY interfaces // 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 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 pdcch_to_crnti();
void start_by_rrc(); void start_by_rrc();
@ -113,7 +113,7 @@ private:
void ra_procedure_initialization(); void ra_procedure_initialization();
void ra_resource_selection(); void ra_resource_selection();
void ra_preamble_transmission(); 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();
void ra_contention_resolution(uint64_t rx_contention_id); void ra_contention_resolution(uint64_t rx_contention_id);
void ra_completion(); void ra_completion();

@ -30,7 +30,7 @@
#include "srsran/common/block_queue.h" #include "srsran/common/block_queue.h"
#include "srsran/common/buffer_pool.h" #include "srsran/common/buffer_pool.h"
#include "srsran/common/common.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/security.h"
#include "srsran/common/stack_procedure.h" #include "srsran/common/stack_procedure.h"
#include "srsran/interfaces/ue_interfaces.h" #include "srsran/interfaces/ue_interfaces.h"
@ -58,9 +58,9 @@ typedef struct {
#define SRSRAN_UE_CATEGORY_DEFAULT "4" #define SRSRAN_UE_CATEGORY_DEFAULT "4"
#define SRSRAN_UE_CATEGORY_MIN 1 #define SRSRAN_UE_CATEGORY_MIN 1
#define SRSRAN_UE_CATEGORY_MAX 21 #define SRSRAN_UE_CATEGORY_MAX 21
#define SRSRAN_RELEASE_DEFAULT 8
#define SRSRAN_RELEASE_MIN 8 #define SRSRAN_RELEASE_MIN 8
#define SRSRAN_RELEASE_MAX 15 #define SRSRAN_RELEASE_MAX 15
#define SRSRAN_RELEASE_DEFAULT (SRSRAN_RELEASE_MAX)
using srsran::byte_buffer_t; using srsran::byte_buffer_t;

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save