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
=======================
## 21.04
* Rename project from srsLTE to srsRAN
* Add initial 5G NSA support to srsUE (including x86-optimized FEC and PHY layer)
* Add PDCP discard support
* Add UL power control, measurement gaps and a new proportional fair scheduler to srsENB
* Extend GTP-U tunneling to support tunnel forwarding over S1
* Optimize many data structures, remove dynamic memory allocations in data plane
* Improved S1AP error handling and enhanced event reporting
* Update ASN.1 packing/unpacking, RRC to Rel 15.11, S1AP to Rel 16.1
* Update PCAP writer to use UDP framing
* Other bug-fixes and improved stability and performance in all parts
## 20.10.1
* Fix bug in srsENB that effectively disabled UL HARQ

@ -9,7 +9,7 @@ srsRAN is a 4G/5G software radio suite developed by SRS (www.softwareradiosystem
See the srsRAN project pages (www.srsran.com) for documentation, guides and project news.
It includes:
* srsUE - a complete SDR LTE UE application featuring all layers from PHY to IP
* srsUE - a complete SDR 4G/5G UE application featuring all layers from PHY to IP
* srsENB - a complete SDR LTE eNodeB application
* srsEPC - a light-weight LTE core network implementation with MME, HSS and S/P-GW
* a highly modular set of common libraries for PHY, MAC, RLC, PDCP, RRC, NAS, S1AP and GW layers.
@ -58,7 +58,8 @@ srsENB Features
---------------
* FDD configuration
* Round Robin MAC scheduler with FAPI-like C++ API
* IntraENB- and InterENB (S1) mobility support
* Proportional-fair and Round Robin MAC scheduler with FAPI-like C++ API
* SR support
* Periodic and Aperiodic CQI feedback support
* Standard S1AP and GTP-U interfaces to the Core Network

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

@ -35,6 +35,116 @@ constexpr uint32_t ceil_div(uint32_t x, uint32_t 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>
class bounded_bitset
{
@ -109,8 +219,7 @@ public:
bounded_bitset<N, reversed>& fill(size_t startpos, size_t endpos, bool value = true)
{
assert_within_bounds_(startpos, false);
assert_within_bounds_(endpos, false);
assert_range_bounds_(startpos, endpos);
// NOTE: can be optimized
if (value) {
for (size_t i = startpos; i < endpos; ++i) {
@ -124,6 +233,19 @@ public:
return *this;
}
int find_lowest(size_t startpos, size_t endpos, bool value = true) const noexcept
{
assert_range_bounds_(startpos, endpos);
if (startpos == endpos) {
return -1;
}
if (not reversed) {
return find_first_(startpos, endpos, value);
}
return find_first_reversed_(startpos, endpos, value);
}
bool all() const noexcept
{
const size_t nw = nof_words_();
@ -282,33 +404,35 @@ private:
}
}
bool test_(size_t pos) const noexcept
size_t get_bitidx_(size_t bitpos) const noexcept { return reversed ? size() - 1 - bitpos : bitpos; }
bool test_(size_t bitpos) const noexcept
{
pos = reversed ? size() - 1 - pos : pos;
return ((get_word_(pos) & maskbit(pos)) != static_cast<word_t>(0));
bitpos = get_bitidx_(bitpos);
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;
get_word_(pos) |= maskbit(pos);
bitpos = get_bitidx_(bitpos);
get_word_(bitpos) |= maskbit(bitpos);
}
void reset_(size_t pos) noexcept
void reset_(size_t bitpos) noexcept
{
pos = reversed ? size() - 1 - pos : pos;
get_word_(pos) &= ~(maskbit(pos));
bitpos = get_bitidx_(bitpos);
get_word_(bitpos) &= ~(maskbit(bitpos));
}
size_t nof_words_() const noexcept { return size() > 0 ? (size() - 1) / bits_per_word + 1 : 0; }
word_t& get_word_(size_t pos) noexcept { return buffer[pos / bits_per_word]; }
word_t& get_word_(size_t bitidx) noexcept { return buffer[bitidx / bits_per_word]; }
const word_t& get_word_(size_t pos) const { return buffer[pos / bits_per_word]; }
const word_t& get_word_(size_t bitidx) const { return buffer[bitidx / bits_per_word]; }
size_t word_idx_(size_t pos) const { return pos / bits_per_word; }
void assert_within_bounds_(size_t pos, bool strict) const
void assert_within_bounds_(size_t pos, bool strict) const noexcept
{
srsran_assert(pos < size() or (not strict and pos == size()),
"ERROR: index=%zd is out-of-bounds for bitset of size=%zd",
@ -316,9 +440,98 @@ private:
size());
}
static word_t maskbit(size_t pos) { return (static_cast<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;
static size_t max_nof_words_() { return (N - 1) / bits_per_word + 1; }
for (size_t i = lastword; i != startpos - 1; --i) {
word_t w = buffer[i];
if (not value) {
w = ~w;
}
if (i == startword) {
size_t offset = startpos % bits_per_word;
w &= (reversed) ? mask_msb_zeros<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;
}
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>

@ -45,15 +45,15 @@ class expected
public:
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(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) {}
template <
typename U,
typename std::enable_if<std::is_convertible<U, T>::value and not is_expected<typename std::decay<U>::type>::value,
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)
{

@ -57,6 +57,10 @@ struct sched_request_res_cfg_s;
struct dmrs_ul_cfg_s;
struct beta_offsets_s;
struct uci_on_pusch_s;
struct zp_csi_rs_res_s;
struct nzp_csi_rs_res_s;
struct pdsch_serving_cell_cfg_s;
struct freq_info_dl_s;
} // namespace rrc_nr
} // namespace asn1
@ -97,12 +101,17 @@ bool make_phy_dmrs_additional_pos(const asn1::rrc_nr::dmrs_ul_cfg_s& dmrs_ul_cfg
bool make_phy_beta_offsets(const asn1::rrc_nr::beta_offsets_s& beta_offsets,
srsran_beta_offsets_t* srsran_beta_offsets);
bool make_phy_pusch_scaling(const asn1::rrc_nr::uci_on_pusch_s& uci_on_pusch, float* scaling);
bool make_phy_zp_csi_rs_resource(const asn1::rrc_nr::zp_csi_rs_res_s & zp_csi_rs_res, srsran_csi_rs_zp_resource_t* zp_csi_rs_resource);
bool make_phy_nzp_csi_rs_resource(const asn1::rrc_nr::nzp_csi_rs_res_s & nzp_csi_rs_res, srsran_csi_rs_nzp_resource_t* csi_rs_nzp_resource);
bool make_phy_carrier_cfg(const asn1::rrc_nr::freq_info_dl_s &freq_info_dl, srsran_carrier_nr_t* carrier_nr);
/***************************
* MAC Config
**************************/
logical_channel_config_t make_mac_logical_channel_cfg_t(uint8_t lcid, const asn1::rrc_nr::lc_ch_cfg_s& asn1_type);
rach_nr_cfg_t make_mac_rach_cfg(const asn1::rrc_nr::rach_cfg_common_s& asn1_type);
bool make_mac_phr_cfg_t(const asn1::rrc_nr::phr_cfg_s& asn1_type, phr_cfg_nr_t* phr_cfg_nr);
bool make_mac_dl_harq_cfg_nr_t(const asn1::rrc_nr::pdsch_serving_cell_cfg_s& asn1_type,
dl_harq_cfg_nr_t* out_dl_harq_cfg_nr);
/***************************
* RLC Config
**************************/

@ -19,8 +19,8 @@
*
*/
#ifndef SRSRAN_LTE_COMMON_H
#define SRSRAN_LTE_COMMON_H
#ifndef SRSRAN_COMMON_LTE_H
#define SRSRAN_COMMON_LTE_H
#include <array>
#include <cstdint>
@ -97,4 +97,4 @@ inline const char* get_drb_name(lte_drb drb_id)
} // namespace srsran
#endif // SRSRAN_LTE_COMMON_H
#endif // SRSRAN_COMMON_LTE_H

@ -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
#define SRSRAN_THREAD_POOL_H
#include "srsran/adt/circular_buffer.h"
#include "srsran/adt/move_callback.h"
#include "srsran/srslog/srslog.h"
#include <condition_variable>
#include <functional>
#include <memory>
#include <mutex>
#include <queue>
#include <stack>
#include <stdint.h>
#include <string>
@ -98,7 +98,9 @@ private:
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:
task_thread_pool(uint32_t nof_workers = 1, bool start_deferred = false, int32_t prio_ = -1, uint32_t mask_ = 255);
@ -139,7 +141,7 @@ private:
uint32_t mask = 255;
srslog::basic_logger& logger;
std::queue<task_t> pending_tasks;
srsran::dyn_circular_buffer<task_t> pending_tasks;
std::vector<std::unique_ptr<worker_t> > workers;
mutable std::mutex queue_mutex;
std::condition_variable cv_empty;

@ -158,9 +158,10 @@ public:
class rrc_interface_rlc_nr
{
public:
virtual void read_pdu_pcch(uint8_t* payload, uint32_t payload_size) = 0;
virtual void max_retx_attempted(uint16_t rnti) = 0;
virtual void write_pdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t sdu) = 0;
virtual void read_pdu_pcch(uint8_t* payload, uint32_t payload_size) = 0;
virtual void max_retx_attempted(uint16_t rnti) = 0;
virtual void write_pdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t sdu) = 0;
virtual const char* get_rb_name(uint32_t lcid) = 0;
};
class rrc_interface_pdcp_nr
{

@ -96,6 +96,13 @@ struct ul_harq_cfg_t {
}
};
/// NR specific config for DL HARQ with configurable number of processes
struct dl_harq_cfg_nr_t {
uint8_t nof_procs; // Number of HARQ processes used in the DL
dl_harq_cfg_nr_t() { reset(); }
void reset() { nof_procs = SRSRAN_DEFAULT_HARQ_PROC_DL_NR; }
};
struct rach_cfg_t {
bool enabled;
uint32_t nof_preambles;
@ -154,7 +161,7 @@ struct sr_cfg_item_nr_t {
#define SRSRAN_MAX_MAX_NR_OF_SR_CFG_PER_CELL_GROUP (8)
struct sr_cfg_nr_t {
bool enabled;
bool enabled;
uint8_t num_items;
sr_cfg_item_nr_t item[SRSRAN_MAX_MAX_NR_OF_SR_CFG_PER_CELL_GROUP];
};

@ -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_,
pdcp_t_reordering_t t_reordering_,
pdcp_discard_timer_t discard_timer_,
bool status_report_required_) :
bool status_report_required_,
srsran::srsran_rat_t rat_) :
bearer_id(bearer_id_),
rb_type(rb_type_),
tx_direction(tx_direction_),
@ -143,7 +144,8 @@ public:
sn_len(sn_len_),
t_reordering(t_reordering_),
discard_timer(discard_timer_),
status_report_required(status_report_required_)
status_report_required(status_report_required_),
rat(rat_)
{
hdr_len_bytes = ceilf((float)sn_len / 8);
}
@ -157,6 +159,7 @@ public:
pdcp_t_reordering_t t_reordering = pdcp_t_reordering_t::ms500;
pdcp_discard_timer_t discard_timer = pdcp_discard_timer_t::infinity;
srsran::srsran_rat_t rat = srsran::srsran_rat_t::lte;
bool status_report_required = false;

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

@ -42,13 +42,31 @@ public:
class mac_interface_phy_nr
{
public:
/// For DL, PDU buffer is allocated and passed to MAC in tb_decoded()
typedef struct {
bool enabled; /// Whether or not PHY should attempt to decode PDSCH
srsran_softbuffer_rx_t* softbuffer; /// Pointer to softbuffer to use
} tb_dl_t;
/// Struct provided by MAC with all necessary information for PHY
typedef struct {
tb_dl_t tb; // only single TB in DL
} tb_action_dl_t;
typedef struct {
srsran::unique_byte_buffer_t tb[SRSRAN_MAX_TB];
uint32_t pid;
uint16_t rnti;
uint32_t tti;
uint8_t pid; // HARQ process ID
uint8_t rv; // Redundancy Version
uint8_t ndi; // Raw new data indicator extracted from DCI
uint32_t tbs; // Transport block size in Bytes
} mac_nr_grant_dl_t;
typedef struct {
srsran::unique_byte_buffer_t payload; // TB when decoded successfully, nullptr otherwise
bool ack; // HARQ information
} tb_action_dl_result_t;
// UL grant as conveyed between PHY and MAC
typedef struct {
uint16_t rnti;
@ -83,8 +101,25 @@ public:
virtual sched_rnti_t get_dl_sched_rnti_nr(const uint32_t tti) = 0;
virtual sched_rnti_t get_ul_sched_rnti_nr(const uint32_t tti) = 0;
/// Indicate succussfully received TB to MAC. The TB buffer is allocated in the PHY and handed as unique_ptr to MAC
virtual void tb_decoded(const uint32_t cc_idx, mac_nr_grant_dl_t& grant) = 0;
/**
* @brief Indicate reception of DL grant to MAC
*
* The TB buffer is allocated in the PHY and handed as unique_ptr to MAC.
*
* @param cc_idx The carrier index on which the grant has been received
* @param grant Reference to the grant
* @param action Pointer to the TB action to be filled by MAC
*/
virtual void new_grant_dl(const uint32_t cc_idx, const mac_nr_grant_dl_t& grant, tb_action_dl_t* action) = 0;
/**
* Indicate decoding of PDSCH
*
* @param cc_idx The index of the carrier for which the PDSCH has been decoded
* @param grant The original DL grant
* @param result Payload (if any) and ack information
*/
virtual void tb_decoded(const uint32_t cc_idx, const mac_nr_grant_dl_t& grant, tb_action_dl_result_t result) = 0;
/**
* @brief Indicate reception of UL grant to MAC
@ -123,6 +158,7 @@ public:
virtual int setup_lcid(const srsran::logical_channel_config_t& config) = 0;
virtual int set_config(const srsran::bsr_cfg_nr_t& bsr_cfg) = 0;
virtual int set_config(const srsran::sr_cfg_nr_t& sr_cfg) = 0;
virtual int set_config(const srsran::dl_harq_cfg_nr_t& dl_hrq_cfg) = 0;
virtual void set_config(const srsran::rach_nr_cfg_t& rach_cfg) = 0;
virtual int add_tag_config(const srsran::tag_cfg_nr_t& tag_cfg) = 0;
virtual int set_config(const srsran::phr_cfg_nr_t& phr_cfg) = 0;

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

@ -269,14 +269,29 @@ typedef enum SRSRAN_API {
srsran_resource_alloc_dynamic,
} srsran_resource_alloc_t;
/**
* @brief Subcarrier spacing 15 or 30 kHz <6GHz and 60 or 120 kHz >6GHz
* @remark Described in TS 38.331 V15.10.0 subcarrier spacing
*/
typedef enum SRSRAN_API {
srsran_subcarrier_spacing_15kHz = 0,
srsran_subcarrier_spacing_30kHz,
srsran_subcarrier_spacing_60kHz,
srsran_subcarrier_spacing_120kHz,
srsran_subcarrier_spacing_240kHz,
} srsran_subcarrier_spacing_t;
/**
* @brief NR carrier parameters. It is a combination of fixed cell and bandwidth-part (BWP)
*/
typedef struct SRSRAN_API {
uint32_t id;
uint32_t numerology;
uint32_t nof_prb;
uint32_t start;
uint32_t pci;
uint32_t absolute_frequency_ssb;
uint32_t absolute_frequency_point_a;
srsran_subcarrier_spacing_t scs;
uint32_t nof_prb;
uint32_t start;
uint32_t max_mimo_layers; ///< @brief DL: Indicates the maximum number of MIMO layers to be used for PDSCH in all BWPs
///< of this serving cell. (see TS 38.212 [17], clause 5.4.2.1). UL: Indicates the maximum
///< MIMO layer to be used for PUSCH in all BWPs of the normal UL of this serving cell (see
@ -319,7 +334,6 @@ typedef struct SRSRAN_API {
*/
typedef struct SRSRAN_API {
uint32_t id;
uint32_t coreset_id;
srsran_coreset_mapping_type_t mapping_type;
uint32_t duration;
bool freq_resources[SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE];

@ -42,14 +42,4 @@ SRSRAN_API int srsran_demod_soft_demodulate_s(srsran_mod_t modulation, const cf_
SRSRAN_API int srsran_demod_soft_demodulate_b(srsran_mod_t modulation, const cf_t* symbols, int8_t* llr, int nsymbols);
/**
* @brief Soft-demodulates complex symbols into 8-bit LLR. It forces zero symbols produce zero LLRs.
* @param modulation Modulation
* @param symbols Complex symbols
* @param llr 8-bit LLRs
* @param nsymbols Number of symbols
* @return SRSLTE_SUCCESS if the provided pointers are valid, SRSLTE_ERROR code otherwise
*/
SRSRAN_API int srsran_demod_soft_demodulate2_b(srsran_mod_t modulation, const cf_t* symbols, int8_t* llr, int nsymbols);
#endif // SRSRAN_DEMOD_SOFT_H

@ -46,8 +46,6 @@ typedef struct SRSRAN_API {
srsran_sch_nr_args_t sch;
bool measure_evm;
bool measure_time;
bool disable_zero_re_around_dc; ///< PDSCH NR sets the LLR around the DC to zero to avoid noise
uint32_t nof_zero_re_around_dc; ///< Number of RE to set to zero around DC. It uses default value if 0.
} srsran_pdsch_nr_args_t;
/**
@ -68,8 +66,6 @@ typedef struct SRSRAN_API {
uint32_t meas_time_us;
srsran_re_pattern_t dmrs_re_pattern;
uint32_t nof_rvd_re;
uint32_t nof_zero_re_around_dc; ///< Sets a number of RE surrounding the center of the resource grid to zero. Set to 0
///< for disabling.
} srsran_pdsch_nr_t;
/**

@ -173,6 +173,11 @@ typedef struct {
uint32_t csi1_index2; ///< Use for more than 11 CSI bits. Set to 13 if absent.
uint32_t csi2_index1; ///< Use for up to 11 CSI bits. Set to 13 if absent.
uint32_t csi2_index2; ///< Use for more than 11 CSI bits. Set to 13 if absent.
/// Fix values for testing purposes
float fix_ack; ///< Set to a non-zero value for fixing a beta offset value
float fix_csi1;
float fix_csi2;
} srsran_beta_offsets_t;
/**
@ -247,11 +252,11 @@ typedef struct SRSRAN_API {
/// PUSCH only parameters
srsran_uci_cfg_nr_t uci; ///< Uplink Control Information configuration
bool enable_transform_precoder;
float beta_harq_ack_offset;
float beta_csi_part1_offset;
float beta_csi_part2_offset;
float scaling;
bool freq_hopping_enabled;
} srsran_sch_cfg_nr_t;
SRSRAN_API uint32_t srsran_sch_cfg_nr_nof_re(const srsran_sch_cfg_nr_t* sch_cfg);
SRSRAN_API uint32_t srsran_sch_cfg_nr_info(const srsran_sch_cfg_nr_t* sch_cfg, char* str, uint32_t str_len);
#endif // SRSRAN_PHCH_CFG_NR_H

@ -59,7 +59,7 @@ typedef struct SRSRAN_API {
srsran_evm_buffer_t* evm_buffer;
bool meas_time_en;
uint32_t meas_time_us;
srsran_uci_cfg_nr_t uci_cfg; ///< Internal UCI bits configuration
srsran_re_pattern_t dmrs_re_pattern;
uint8_t* g_ulsch; ///< Temporal Encoded UL-SCH data
uint8_t* g_ack; ///< Temporal Encoded HARQ-ACK bits
uint8_t* g_csi1; ///< Temporal Encoded CSI part 1 bits

@ -137,12 +137,14 @@ SRSRAN_API int srsran_ra_ul_dci_to_grant_nr(const srsran_carrier_nr_t* carrie
*
* @remark Implement procedure described in TS 38.213 9.3 UCI reporting in physical uplink shared channel
*
* @param carrier Carrier information struct
* @param pusch_hl_cfg PUSCH configuration provided by higher layers
* @param uci_cfg Uplink Control Information configuration for this PUSCH transmission
* @param pusch_cfg PUSCH configuration after applying the procedure
* @return SRSRAN_SUCCESS if the procedure is successful, SRSRAN_ERROR code otherwise
*/
SRSRAN_API int srsran_ra_ul_set_grant_uci_nr(const srsran_sch_hl_cfg_nr_t* pusch_hl_cfg,
SRSRAN_API int srsran_ra_ul_set_grant_uci_nr(const srsran_carrier_nr_t* carrier,
const srsran_sch_hl_cfg_nr_t* pusch_hl_cfg,
const srsran_uci_cfg_nr_t* uci_cfg,
srsran_sch_cfg_nr_t* pusch_cfg);

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

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

@ -35,6 +35,10 @@ class pdcp : public srsue::pdcp_interface_rlc, public srsue::pdcp_interface_rrc
public:
pdcp(srsran::task_sched_handle task_sched_, const char* logname);
virtual ~pdcp();
void init(srsue::rlc_interface_pdcp* rlc_,
srsue::rrc_interface_pdcp* rrc_,
srsue::rrc_interface_pdcp* rrc_nr_,
srsue::gw_interface_pdcp* gw_);
void init(srsue::rlc_interface_pdcp* rlc_, srsue::rrc_interface_pdcp* rrc_, srsue::gw_interface_pdcp* gw_);
void stop();
@ -78,9 +82,10 @@ public:
void reset_metrics();
private:
srsue::rlc_interface_pdcp* rlc = nullptr;
srsue::rrc_interface_pdcp* rrc = nullptr;
srsue::gw_interface_pdcp* gw = nullptr;
srsue::rlc_interface_pdcp* rlc = nullptr;
srsue::rrc_interface_pdcp* rrc = nullptr;
srsue::rrc_interface_pdcp* rrc_nr = nullptr;
srsue::gw_interface_pdcp* gw = nullptr;
srsran::task_sched_handle task_sched;
srslog::basic_logger& logger;

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

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

@ -25,6 +25,7 @@
#include "srsran/adt/accumulators.h"
#include "srsran/adt/circular_array.h"
#include "srsran/adt/circular_map.h"
#include "srsran/adt/intrusive_list.h"
#include "srsran/common/buffer_pool.h"
#include "srsran/common/common.h"
#include "srsran/common/srsran_assert.h"
@ -42,23 +43,95 @@ namespace srsran {
#undef RLC_AM_BUFFER_DEBUG
struct rlc_amd_rx_pdu_t {
class rlc_amd_tx_pdu;
class pdcp_pdu_info;
/// Pool that manages the allocation of RLC AM PDU Segments to RLC PDUs and tracking of segments ACK state
struct rlc_am_pdu_segment_pool {
const static size_t MAX_POOL_SIZE = 16384;
using rlc_list_tag = default_intrusive_tag;
struct free_list_tag {};
/// RLC AM PDU Segment, containing the PDCP SN and RLC SN it has been assigned to, and its current ACK state
struct segment_resource : public intrusive_forward_list_element<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;
unique_byte_buffer_t buf;
uint32_t rlc_sn;
rlc_amd_rx_pdu() = default;
explicit rlc_amd_rx_pdu(uint32_t rlc_sn_) : rlc_sn(rlc_sn_) {}
};
struct rlc_amd_rx_pdu_segments_t {
std::list<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;
unique_byte_buffer_t buf;
pdcp_sn_vector_t pdcp_sns;
uint32_t retx_count;
uint32_t rlc_sn;
bool is_acked;
explicit rlc_amd_tx_pdu(uint32_t rlc_sn_) : rlc_sn(rlc_sn_) {}
rlc_amd_tx_pdu(const rlc_amd_tx_pdu&) = delete;
rlc_amd_tx_pdu(rlc_amd_tx_pdu&& other) noexcept = default;
rlc_amd_tx_pdu& operator=(const rlc_amd_tx_pdu& other) = delete;
rlc_amd_tx_pdu& operator=(rlc_amd_tx_pdu&& other) = delete;
~rlc_amd_tx_pdu();
// Segment List Interface
void add_segment(rlc_am_pdu_segment& segment) { list.push_front(&segment); }
const_iterator begin() const { return list.begin(); }
const_iterator end() const { return list.end(); }
iterator begin() { return list.begin(); }
iterator end() { return list.end(); }
};
struct rlc_amd_retx_t {
@ -73,12 +146,47 @@ struct rlc_sn_info_t {
bool is_acked;
};
struct pdcp_sdu_info_t {
uint32_t sn;
bool fully_txed; // Boolean indicating if the SDU is fully transmitted.
bool fully_acked; // Boolean indicating if the SDU is fully acked. This is only necessary temporarely to avoid
// duplicate removal from the queue while processing the status report
std::vector<rlc_sn_info_t> rlc_sn_info_list; // List of RLC PDUs in transit and whether they have been acked or not.
/// Class that contains the parameters and state (e.g. unACKed segments) of a PDCP PDU
class pdcp_pdu_info
{
using list_type = intrusive_double_linked_list<rlc_am_pdu_segment>;
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>
@ -86,8 +194,7 @@ struct rlc_ringbuffer_t {
T& add_pdu(size_t sn)
{
srsran_expect(not has_sn(sn), "The same SN=%zd should not be added twice", sn);
window.overwrite(sn, T{});
window[sn].rlc_sn = sn;
window.overwrite(sn, T(sn));
return window[sn];
}
void remove_pdu(size_t sn)
@ -125,53 +232,56 @@ public:
void add_pdcp_sdu(uint32_t sn)
{
srsran_expect(sn <= max_pdcp_sn or sn == status_report_sn, "Invalid PDCP SN=%d", sn);
srsran_assert(not has_pdcp_sn(sn), "Cannot re-add same PDCP SN twice");
uint32_t sn_idx = get_idx(sn);
if (buffered_pdus[sn_idx].sn != invalid_sn) {
clear_pdcp_sdu(buffered_pdus[sn_idx].sn);
pdcp_pdu_info& pdu = get_pdu_(sn);
if (pdu.valid()) {
pdu.clear();
count--;
}
buffered_pdus[get_idx(sn)].sn = sn;
pdu.sn = sn;
count++;
}
void clear_pdcp_sdu(uint32_t sn)
{
uint32_t sn_idx = get_idx(sn);
if (buffered_pdus[sn_idx].sn == invalid_sn) {
pdcp_pdu_info& pdu = get_pdu_(sn);
if (not pdu.valid()) {
return;
}
buffered_pdus[sn_idx].sn = invalid_sn;
buffered_pdus[sn_idx].fully_acked = false;
buffered_pdus[sn_idx].fully_txed = false;
buffered_pdus[sn_idx].rlc_sn_info_list.clear();
pdu.clear();
count--;
}
pdcp_sdu_info_t& operator[](uint32_t sn)
pdcp_pdu_info& operator[](uint32_t sn)
{
assert(has_pdcp_sn(sn));
return buffered_pdus[get_idx(sn)];
srsran_expect(has_pdcp_sn(sn), "Invalid access to non-existent PDCP SN=%d", sn);
return get_pdu_(sn);
}
bool has_pdcp_sn(uint32_t pdcp_sn) const
{
assert(pdcp_sn <= max_pdcp_sn or pdcp_sn == status_report_sn);
return buffered_pdus[get_idx(pdcp_sn)].sn == pdcp_sn;
srsran_expect(pdcp_sn <= max_pdcp_sn or pdcp_sn == status_report_sn, "Invalid PDCP SN=%d", pdcp_sn);
return get_pdu_(pdcp_sn).sn == pdcp_sn;
}
uint32_t nof_sdus() const { return count; }
private:
const static size_t max_pdcp_sn = 262143u;
const static size_t max_buffer_idx = 4096u;
const static uint32_t status_report_sn = std::numeric_limits<uint32_t>::max();
const static uint32_t invalid_sn = std::numeric_limits<uint32_t>::max() - 1;
const static size_t buffer_size = 4096u;
const static uint32_t status_report_sn = pdcp_pdu_info::status_report_sn;
size_t get_idx(uint32_t sn) const
pdcp_pdu_info& get_pdu_(uint32_t sn)
{
return (sn != status_report_sn) ? static_cast<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)];
}
const pdcp_pdu_info& get_pdu_(uint32_t sn) const
{
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)
std::vector<pdcp_sdu_info_t> buffered_pdus;
uint32_t count = 0;
// size equal to buffer_size
std::vector<pdcp_pdu_info> buffered_pdus;
pdcp_pdu_info status_report_pdu;
uint32_t count = 0;
};
class pdu_retx_queue
@ -287,7 +397,7 @@ private:
int build_retx_pdu(uint8_t* payload, uint32_t nof_bytes);
int build_segment(uint8_t* payload, uint32_t nof_bytes, rlc_amd_retx_t retx);
int build_data_pdu(uint8_t* payload, uint32_t nof_bytes);
void update_notification_ack_info(const rlc_amd_tx_pdu_t& tx_pdu);
void update_notification_ack_info(uint32_t rlc_sn);
void debug_state();
@ -299,9 +409,10 @@ private:
bool do_status();
void check_sn_reached_max_retx(uint32_t sn);
rlc_am_lte* parent = nullptr;
byte_buffer_pool* pool = nullptr;
srslog::basic_logger& logger;
rlc_am_lte* parent = nullptr;
byte_buffer_pool* pool = nullptr;
srslog::basic_logger& logger;
rlc_am_pdu_segment_pool segment_pool;
/****************************************************************************
* Configurable parameters
@ -348,9 +459,9 @@ private:
bsr_callback_t bsr_callback;
// Tx windows
rlc_ringbuffer_t<rlc_amd_tx_pdu_t> tx_window;
pdu_retx_queue retx_queue;
pdcp_sn_vector_t notify_info_vec;
rlc_ringbuffer_t<rlc_amd_tx_pdu> tx_window;
pdu_retx_queue retx_queue;
pdcp_sn_vector_t notify_info_vec;
// Mutexes
std::mutex mutex;
@ -391,7 +502,7 @@ private:
bool inside_rx_window(const int16_t sn);
void debug_state();
void print_rx_segments();
bool add_segment_and_check(rlc_amd_rx_pdu_segments_t* pdu, rlc_amd_rx_pdu_t* segment);
bool add_segment_and_check(rlc_amd_rx_pdu_segments_t* pdu, rlc_amd_rx_pdu* segment);
rlc_am_lte* parent = nullptr;
byte_buffer_pool* pool = nullptr;
@ -422,7 +533,7 @@ private:
std::mutex mutex;
// Rx windows
rlc_ringbuffer_t<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;
bool poll_received = false;
@ -474,7 +585,7 @@ uint32_t rlc_am_packed_length(rlc_status_pdu_t* status);
uint32_t rlc_am_packed_length(rlc_amd_retx_t retx);
bool rlc_am_is_valid_status_pdu(const rlc_status_pdu_t& status);
bool rlc_am_is_pdu_segment(uint8_t* payload);
std::string rlc_am_undelivered_sdu_info_to_string(const std::map<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);
bool rlc_am_start_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
{
public:
rlc_amd_pdu_header_t() {}
rlc_amd_pdu_header_t() = default;
rlc_amd_pdu_header_t(const rlc_amd_pdu_header_t& h) { copy(h); }
rlc_amd_pdu_header_t(rlc_amd_pdu_header_t&& h) noexcept { copy(h); }
rlc_amd_pdu_header_t& operator=(const rlc_amd_pdu_header_t& h)
{
if (this == &h) {
return *this;
}
copy(h);
return *this;
}
rlc_amd_pdu_header_t& operator=(rlc_amd_pdu_header_t&& h) noexcept
{
copy(h);
return *this;

@ -75,6 +75,19 @@ logical_channel_config_t make_mac_logical_channel_cfg_t(uint8_t lcid, const lc_c
return logical_channel_config;
}
bool make_mac_dl_harq_cfg_nr_t(const pdsch_serving_cell_cfg_s& asn1_type, dl_harq_cfg_nr_t* out_dl_harq_cfg_nr)
{
dl_harq_cfg_nr_t dl_harq_cfg_nr;
if (asn1_type.nrof_harq_processes_for_pdsch_present) {
dl_harq_cfg_nr.nof_procs = asn1_type.nrof_harq_processes_for_pdsch.to_number();
} else {
asn1::log_warning("Option nrof_harq_processes_for_pdsch not present");
return false;
}
*out_dl_harq_cfg_nr = dl_harq_cfg_nr;
return true;
}
bool make_mac_phr_cfg_t(const phr_cfg_s& asn1_type, phr_cfg_nr_t* phr_cfg_nr)
{
phr_cfg_nr->extended = asn1_type.ext;
@ -208,7 +221,8 @@ srsran::pdcp_config_t make_drb_pdcp_config_t(const uint8_t bearer_id, bool is_ue
sn_len,
t_reordering,
discard_timer,
false);
false,
srsran_rat_t::nr);
return cfg;
}
@ -319,7 +333,7 @@ bool make_phy_tdd_cfg(const tdd_ul_dl_cfg_common_s& tdd_ul_dl_cfg_common,
bool make_phy_harq_ack_cfg(const phys_cell_group_cfg_s& phys_cell_group_cfg,
srsran_ue_dl_nr_harq_ack_cfg_t* in_srsran_ue_dl_nr_harq_ack_cfg)
{
srsran_ue_dl_nr_harq_ack_cfg_t srsran_ue_dl_nr_harq_ack_cfg;
srsran_ue_dl_nr_harq_ack_cfg_t srsran_ue_dl_nr_harq_ack_cfg = {};
switch (phys_cell_group_cfg.pdsch_harq_ack_codebook) {
case phys_cell_group_cfg_s::pdsch_harq_ack_codebook_opts::dynamic_value:
srsran_ue_dl_nr_harq_ack_cfg.harq_ack_codebook = srsran_pdsch_harq_ack_codebook_dynamic;
@ -573,8 +587,7 @@ bool make_phy_csi_report(const csi_report_cfg_s& csi_report_cfg,
bool make_phy_coreset_cfg(const ctrl_res_set_s& ctrl_res_set, srsran_coreset_t* in_srsran_coreset)
{
srsran_coreset_t srsran_coreset = {};
srsran_coreset.coreset_id = ctrl_res_set.ctrl_res_set_id;
srsran_coreset.id = ctrl_res_set.ctrl_res_set_id;
switch (ctrl_res_set.precoder_granularity) {
case ctrl_res_set_s::precoder_granularity_opts::same_as_reg_bundle:
srsran_coreset.precoder_granularity = srsran_coreset_precoder_granularity_reg_bundle;
@ -585,6 +598,18 @@ bool make_phy_coreset_cfg(const ctrl_res_set_s& ctrl_res_set, srsran_coreset_t*
asn1::log_warning("Invalid option for precoder_granularity %s", ctrl_res_set.precoder_granularity.to_string());
return false;
};
switch (ctrl_res_set.cce_reg_map_type.type()) {
case ctrl_res_set_s::cce_reg_map_type_c_::types_opts::options::interleaved:
srsran_coreset.mapping_type = srsran_coreset_mapping_type_interleaved;
break;
case ctrl_res_set_s::cce_reg_map_type_c_::types_opts::options::non_interleaved:
srsran_coreset.mapping_type = srsran_coreset_mapping_type_non_interleaved;
break;
default:
asn1::log_warning("Invalid option for cce_reg_map_type: %s", ctrl_res_set.cce_reg_map_type.type().to_string());
return false;
}
srsran_coreset.duration = ctrl_res_set.dur;
for (uint32_t i = 0; i < SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE; i++) {
srsran_coreset.freq_resources[i] = ctrl_res_set.freq_domain_res.get(SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE - 1 - i);
@ -837,6 +862,368 @@ bool make_phy_pusch_scaling(const uci_on_pusch_s& uci_on_pusch, float* in_scalin
return true;
}
bool make_phy_zp_csi_rs_resource(const asn1::rrc_nr::zp_csi_rs_res_s& zp_csi_rs_res,
srsran_csi_rs_zp_resource_t* out_zp_csi_rs_resource)
{
srsran_csi_rs_zp_resource_t zp_csi_rs_resource;
zp_csi_rs_resource.id = zp_csi_rs_res.zp_csi_rs_res_id;
switch (zp_csi_rs_res.res_map.freq_domain_alloc.type()) {
case csi_rs_res_map_s::freq_domain_alloc_c_::types_opts::options::row1:
zp_csi_rs_resource.resource_mapping.row = srsran_csi_rs_resource_mapping_row_1;
for (uint32_t i = 0; i < zp_csi_rs_res.res_map.freq_domain_alloc.row1().length(); i++) {
zp_csi_rs_resource.resource_mapping.frequency_domain_alloc[i] =
zp_csi_rs_res.res_map.freq_domain_alloc.row1().get(zp_csi_rs_res.res_map.freq_domain_alloc.row1().length() -
1 - i);
}
break;
case csi_rs_res_map_s::freq_domain_alloc_c_::types_opts::options::row2:
zp_csi_rs_resource.resource_mapping.row = srsran_csi_rs_resource_mapping_row_2;
for (uint32_t i = 0; i < zp_csi_rs_res.res_map.freq_domain_alloc.row2().length(); i++) {
zp_csi_rs_resource.resource_mapping.frequency_domain_alloc[i] =
zp_csi_rs_res.res_map.freq_domain_alloc.row2().get(zp_csi_rs_res.res_map.freq_domain_alloc.row2().length() -
1 - i);
}
break;
case csi_rs_res_map_s::freq_domain_alloc_c_::types_opts::options::row4:
zp_csi_rs_resource.resource_mapping.row = srsran_csi_rs_resource_mapping_row_4;
for (uint32_t i = 0; i < zp_csi_rs_res.res_map.freq_domain_alloc.row4().length(); i++) {
zp_csi_rs_resource.resource_mapping.frequency_domain_alloc[i] =
zp_csi_rs_res.res_map.freq_domain_alloc.row4().get(zp_csi_rs_res.res_map.freq_domain_alloc.row4().length() -
1 - i);
}
break;
case csi_rs_res_map_s::freq_domain_alloc_c_::types_opts::options::other:
zp_csi_rs_resource.resource_mapping.row = srsran_csi_rs_resource_mapping_row_other;
break;
default:
asn1::log_warning("Invalid option for freq_domain_alloc %s",
zp_csi_rs_res.res_map.freq_domain_alloc.type().to_string());
return false;
}
zp_csi_rs_resource.resource_mapping.nof_ports = zp_csi_rs_res.res_map.nrof_ports.to_number();
zp_csi_rs_resource.resource_mapping.first_symbol_idx = zp_csi_rs_res.res_map.first_ofdm_symbol_in_time_domain;
switch (zp_csi_rs_res.res_map.cdm_type) {
case csi_rs_res_map_s::cdm_type_opts::options::no_cdm:
zp_csi_rs_resource.resource_mapping.cdm = srsran_csi_rs_cdm_t::srsran_csi_rs_cdm_nocdm;
break;
case csi_rs_res_map_s::cdm_type_opts::options::fd_cdm2:
zp_csi_rs_resource.resource_mapping.cdm = srsran_csi_rs_cdm_t::srsran_csi_rs_cdm_fd_cdm2;
break;
case csi_rs_res_map_s::cdm_type_opts::options::cdm4_fd2_td2:
zp_csi_rs_resource.resource_mapping.cdm = srsran_csi_rs_cdm_t::srsran_csi_rs_cdm_cdm4_fd2_td2;
break;
case csi_rs_res_map_s::cdm_type_opts::options::cdm8_fd2_td4:
zp_csi_rs_resource.resource_mapping.cdm = srsran_csi_rs_cdm_t::srsran_csi_rs_cdm_cdm8_fd2_td4;
break;
default:
asn1::log_warning("Invalid option for cdm_type %s", zp_csi_rs_res.res_map.cdm_type.to_string());
return false;
}
switch (zp_csi_rs_res.res_map.density.type()) {
case csi_rs_res_map_s::density_c_::types_opts::options::dot5:
switch (zp_csi_rs_res.res_map.density.dot5()) {
case csi_rs_res_map_s::density_c_::dot5_opts::options::even_prbs:
zp_csi_rs_resource.resource_mapping.density = srsran_csi_rs_resource_mapping_density_dot5_even;
break;
case csi_rs_res_map_s::density_c_::dot5_opts::options::odd_prbs:
zp_csi_rs_resource.resource_mapping.density = srsran_csi_rs_resource_mapping_density_dot5_odd;
break;
default:
asn1::log_warning("Invalid option for dot5 %s", zp_csi_rs_res.res_map.density.dot5().to_string());
return false;
}
break;
case csi_rs_res_map_s::density_c_::types_opts::options::one:
zp_csi_rs_resource.resource_mapping.density = srsran_csi_rs_resource_mapping_density_one;
break;
case csi_rs_res_map_s::density_c_::types_opts::options::three:
zp_csi_rs_resource.resource_mapping.density = srsran_csi_rs_resource_mapping_density_three;
break;
case csi_rs_res_map_s::density_c_::types_opts::options::spare:
zp_csi_rs_resource.resource_mapping.density = srsran_csi_rs_resource_mapping_density_spare;
break;
default:
asn1::log_warning("Invalid option for density %s", zp_csi_rs_res.res_map.density.type().to_string());
return false;
}
zp_csi_rs_resource.resource_mapping.freq_band.nof_rb = zp_csi_rs_res.res_map.freq_band.nrof_rbs;
zp_csi_rs_resource.resource_mapping.freq_band.start_rb = zp_csi_rs_res.res_map.freq_band.start_rb;
if(zp_csi_rs_res.periodicity_and_offset_present){
switch (zp_csi_rs_res.periodicity_and_offset.type())
{
case csi_res_periodicity_and_offset_c::types_opts::options::slots4:
zp_csi_rs_resource.periodicity.period = 4;
zp_csi_rs_resource.periodicity.offset = zp_csi_rs_res.periodicity_and_offset.slots4();
break;
case csi_res_periodicity_and_offset_c::types_opts::options::slots5:
zp_csi_rs_resource.periodicity.period = 5;
zp_csi_rs_resource.periodicity.offset = zp_csi_rs_res.periodicity_and_offset.slots5();
break;
case csi_res_periodicity_and_offset_c::types_opts::options::slots8:
zp_csi_rs_resource.periodicity.period = 8;
zp_csi_rs_resource.periodicity.offset = zp_csi_rs_res.periodicity_and_offset.slots8();
break;
case csi_res_periodicity_and_offset_c::types_opts::options::slots10:
zp_csi_rs_resource.periodicity.period = 10;
zp_csi_rs_resource.periodicity.offset = zp_csi_rs_res.periodicity_and_offset.slots10();
break;
case csi_res_periodicity_and_offset_c::types_opts::options::slots16:
zp_csi_rs_resource.periodicity.period = 16;
zp_csi_rs_resource.periodicity.offset = zp_csi_rs_res.periodicity_and_offset.slots16();
break;
case csi_res_periodicity_and_offset_c::types_opts::options::slots20:
zp_csi_rs_resource.periodicity.period = 20;
zp_csi_rs_resource.periodicity.offset = zp_csi_rs_res.periodicity_and_offset.slots20();
break;
case csi_res_periodicity_and_offset_c::types_opts::options::slots32:
zp_csi_rs_resource.periodicity.period = 32;
zp_csi_rs_resource.periodicity.offset = zp_csi_rs_res.periodicity_and_offset.slots32();
break;
case csi_res_periodicity_and_offset_c::types_opts::options::slots40:
zp_csi_rs_resource.periodicity.period = 40;
zp_csi_rs_resource.periodicity.offset = zp_csi_rs_res.periodicity_and_offset.slots40();
break;
case csi_res_periodicity_and_offset_c::types_opts::options::slots64:
zp_csi_rs_resource.periodicity.period = 64;
zp_csi_rs_resource.periodicity.offset = zp_csi_rs_res.periodicity_and_offset.slots64();
break;
case csi_res_periodicity_and_offset_c::types_opts::options::slots80:
zp_csi_rs_resource.periodicity.period = 80;
zp_csi_rs_resource.periodicity.offset = zp_csi_rs_res.periodicity_and_offset.slots80();
break;
case csi_res_periodicity_and_offset_c::types_opts::options::slots160:
zp_csi_rs_resource.periodicity.period = 160;
zp_csi_rs_resource.periodicity.offset = zp_csi_rs_res.periodicity_and_offset.slots160();
break;
case csi_res_periodicity_and_offset_c::types_opts::options::slots320:
zp_csi_rs_resource.periodicity.period = 320;
zp_csi_rs_resource.periodicity.offset = zp_csi_rs_res.periodicity_and_offset.slots320();
break;
case csi_res_periodicity_and_offset_c::types_opts::options::slots640:
zp_csi_rs_resource.periodicity.period = 640;
zp_csi_rs_resource.periodicity.offset = zp_csi_rs_res.periodicity_and_offset.slots640();
break;
default:
asn1::log_warning("Invalid option for periodicity_and_offset %s",
zp_csi_rs_res.periodicity_and_offset.type().to_string());
return false;
}
} else {
asn1::log_warning("Option periodicity_and_offset not present");
return false;
}
*out_zp_csi_rs_resource = zp_csi_rs_resource;
return true;
}
bool make_phy_nzp_csi_rs_resource(const asn1::rrc_nr::nzp_csi_rs_res_s& asn1_nzp_csi_rs_res,
srsran_csi_rs_nzp_resource_t* out_csi_rs_nzp_resource)
{
srsran_csi_rs_nzp_resource_t csi_rs_nzp_resource;
csi_rs_nzp_resource.id = asn1_nzp_csi_rs_res.nzp_csi_rs_res_id;
switch (asn1_nzp_csi_rs_res.res_map.freq_domain_alloc.type()) {
case csi_rs_res_map_s::freq_domain_alloc_c_::types_opts::options::row1:
csi_rs_nzp_resource.resource_mapping.row = srsran_csi_rs_resource_mapping_row_1;
for (uint32_t i = 0; i < asn1_nzp_csi_rs_res.res_map.freq_domain_alloc.row1().length(); i++) {
csi_rs_nzp_resource.resource_mapping.frequency_domain_alloc[i] =
asn1_nzp_csi_rs_res.res_map.freq_domain_alloc.row1().get(asn1_nzp_csi_rs_res.res_map.freq_domain_alloc.row1().length() -
1 - i);
}
break;
case csi_rs_res_map_s::freq_domain_alloc_c_::types_opts::options::row2:
csi_rs_nzp_resource.resource_mapping.row = srsran_csi_rs_resource_mapping_row_2;
for (uint32_t i = 0; i < asn1_nzp_csi_rs_res.res_map.freq_domain_alloc.row2().length(); i++) {
csi_rs_nzp_resource.resource_mapping.frequency_domain_alloc[i] =
asn1_nzp_csi_rs_res.res_map.freq_domain_alloc.row2().get(asn1_nzp_csi_rs_res.res_map.freq_domain_alloc.row2().length() -
1 - i);
}
break;
case csi_rs_res_map_s::freq_domain_alloc_c_::types_opts::options::row4:
csi_rs_nzp_resource.resource_mapping.row = srsran_csi_rs_resource_mapping_row_4;
for (uint32_t i = 0; i < asn1_nzp_csi_rs_res.res_map.freq_domain_alloc.row4().length(); i++) {
csi_rs_nzp_resource.resource_mapping.frequency_domain_alloc[i] =
asn1_nzp_csi_rs_res.res_map.freq_domain_alloc.row4().get(asn1_nzp_csi_rs_res.res_map.freq_domain_alloc.row4().length() -
1 - i);
}
break;
case csi_rs_res_map_s::freq_domain_alloc_c_::types_opts::options::other:
csi_rs_nzp_resource.resource_mapping.row = srsran_csi_rs_resource_mapping_row_other;
break;
default:
asn1::log_warning("Invalid option for freq_domain_alloc %s",
asn1_nzp_csi_rs_res.res_map.freq_domain_alloc.type().to_string());
return false;
}
csi_rs_nzp_resource.resource_mapping.nof_ports = asn1_nzp_csi_rs_res.res_map.nrof_ports.to_number();
csi_rs_nzp_resource.resource_mapping.first_symbol_idx = asn1_nzp_csi_rs_res.res_map.first_ofdm_symbol_in_time_domain;
switch (asn1_nzp_csi_rs_res.res_map.cdm_type) {
case csi_rs_res_map_s::cdm_type_opts::options::no_cdm:
csi_rs_nzp_resource.resource_mapping.cdm = srsran_csi_rs_cdm_t::srsran_csi_rs_cdm_nocdm;
break;
case csi_rs_res_map_s::cdm_type_opts::options::fd_cdm2:
csi_rs_nzp_resource.resource_mapping.cdm = srsran_csi_rs_cdm_t::srsran_csi_rs_cdm_fd_cdm2;
break;
case csi_rs_res_map_s::cdm_type_opts::options::cdm4_fd2_td2:
csi_rs_nzp_resource.resource_mapping.cdm = srsran_csi_rs_cdm_t::srsran_csi_rs_cdm_cdm4_fd2_td2;
break;
case csi_rs_res_map_s::cdm_type_opts::options::cdm8_fd2_td4:
csi_rs_nzp_resource.resource_mapping.cdm = srsran_csi_rs_cdm_t::srsran_csi_rs_cdm_cdm8_fd2_td4;
break;
default:
asn1::log_warning("Invalid option for cdm_type %s", asn1_nzp_csi_rs_res.res_map.cdm_type.to_string());
return false;
}
switch (asn1_nzp_csi_rs_res.res_map.density.type()) {
case csi_rs_res_map_s::density_c_::types_opts::options::dot5:
switch (asn1_nzp_csi_rs_res.res_map.density.dot5()) {
case csi_rs_res_map_s::density_c_::dot5_opts::options::even_prbs:
csi_rs_nzp_resource.resource_mapping.density = srsran_csi_rs_resource_mapping_density_dot5_even;
break;
case csi_rs_res_map_s::density_c_::dot5_opts::options::odd_prbs:
csi_rs_nzp_resource.resource_mapping.density = srsran_csi_rs_resource_mapping_density_dot5_odd;
break;
default:
asn1::log_warning("Invalid option for dot5 %s", asn1_nzp_csi_rs_res.res_map.density.dot5().to_string());
return false;
}
break;
case csi_rs_res_map_s::density_c_::types_opts::options::one:
csi_rs_nzp_resource.resource_mapping.density = srsran_csi_rs_resource_mapping_density_one;
break;
case csi_rs_res_map_s::density_c_::types_opts::options::three:
csi_rs_nzp_resource.resource_mapping.density = srsran_csi_rs_resource_mapping_density_three;
break;
case csi_rs_res_map_s::density_c_::types_opts::options::spare:
csi_rs_nzp_resource.resource_mapping.density = srsran_csi_rs_resource_mapping_density_spare;
break;
default:
asn1::log_warning("Invalid option for density %s", asn1_nzp_csi_rs_res.res_map.density.type().to_string());
return false;
}
csi_rs_nzp_resource.resource_mapping.freq_band.nof_rb = asn1_nzp_csi_rs_res.res_map.freq_band.nrof_rbs;
csi_rs_nzp_resource.resource_mapping.freq_band.start_rb = asn1_nzp_csi_rs_res.res_map.freq_band.start_rb;
csi_rs_nzp_resource.power_control_offset = asn1_nzp_csi_rs_res.pwr_ctrl_offset;
if (asn1_nzp_csi_rs_res.pwr_ctrl_offset_ss_present) {
csi_rs_nzp_resource.power_control_offset_ss = asn1_nzp_csi_rs_res.pwr_ctrl_offset_ss.to_number();
}
if(asn1_nzp_csi_rs_res.periodicity_and_offset_present){
switch (asn1_nzp_csi_rs_res.periodicity_and_offset.type())
{
case csi_res_periodicity_and_offset_c::types_opts::options::slots4:
csi_rs_nzp_resource.periodicity.period = 4;
csi_rs_nzp_resource.periodicity.offset = asn1_nzp_csi_rs_res.periodicity_and_offset.slots4();
break;
case csi_res_periodicity_and_offset_c::types_opts::options::slots5:
csi_rs_nzp_resource.periodicity.period = 5;
csi_rs_nzp_resource.periodicity.offset = asn1_nzp_csi_rs_res.periodicity_and_offset.slots5();
break;
case csi_res_periodicity_and_offset_c::types_opts::options::slots8:
csi_rs_nzp_resource.periodicity.period = 8;
csi_rs_nzp_resource.periodicity.offset = asn1_nzp_csi_rs_res.periodicity_and_offset.slots8();
break;
case csi_res_periodicity_and_offset_c::types_opts::options::slots10:
csi_rs_nzp_resource.periodicity.period = 10;
csi_rs_nzp_resource.periodicity.offset = asn1_nzp_csi_rs_res.periodicity_and_offset.slots10();
break;
case csi_res_periodicity_and_offset_c::types_opts::options::slots16:
csi_rs_nzp_resource.periodicity.period = 16;
csi_rs_nzp_resource.periodicity.offset = asn1_nzp_csi_rs_res.periodicity_and_offset.slots16();
break;
case csi_res_periodicity_and_offset_c::types_opts::options::slots20:
csi_rs_nzp_resource.periodicity.period = 20;
csi_rs_nzp_resource.periodicity.offset = asn1_nzp_csi_rs_res.periodicity_and_offset.slots20();
break;
case csi_res_periodicity_and_offset_c::types_opts::options::slots32:
csi_rs_nzp_resource.periodicity.period = 32;
csi_rs_nzp_resource.periodicity.offset = asn1_nzp_csi_rs_res.periodicity_and_offset.slots32();
break;
case csi_res_periodicity_and_offset_c::types_opts::options::slots40:
csi_rs_nzp_resource.periodicity.period = 40;
csi_rs_nzp_resource.periodicity.offset = asn1_nzp_csi_rs_res.periodicity_and_offset.slots40();
break;
case csi_res_periodicity_and_offset_c::types_opts::options::slots64:
csi_rs_nzp_resource.periodicity.period = 64;
csi_rs_nzp_resource.periodicity.offset = asn1_nzp_csi_rs_res.periodicity_and_offset.slots64();
break;
case csi_res_periodicity_and_offset_c::types_opts::options::slots80:
csi_rs_nzp_resource.periodicity.period = 80;
csi_rs_nzp_resource.periodicity.offset = asn1_nzp_csi_rs_res.periodicity_and_offset.slots80();
break;
case csi_res_periodicity_and_offset_c::types_opts::options::slots160:
csi_rs_nzp_resource.periodicity.period = 160;
csi_rs_nzp_resource.periodicity.offset = asn1_nzp_csi_rs_res.periodicity_and_offset.slots160();
break;
case csi_res_periodicity_and_offset_c::types_opts::options::slots320:
csi_rs_nzp_resource.periodicity.period = 320;
csi_rs_nzp_resource.periodicity.offset = asn1_nzp_csi_rs_res.periodicity_and_offset.slots320();
break;
case csi_res_periodicity_and_offset_c::types_opts::options::slots640:
csi_rs_nzp_resource.periodicity.period = 640;
csi_rs_nzp_resource.periodicity.offset = asn1_nzp_csi_rs_res.periodicity_and_offset.slots640();
break;
default:
asn1::log_warning("Invalid option for periodicity_and_offset %s",
asn1_nzp_csi_rs_res.periodicity_and_offset.type().to_string());
return false;
}
} else {
asn1::log_warning("Option periodicity_and_offset not present");
return false;
}
csi_rs_nzp_resource.scrambling_id = asn1_nzp_csi_rs_res.scrambling_id;
*out_csi_rs_nzp_resource = csi_rs_nzp_resource;
return true;
}
bool make_phy_carrier_cfg(const freq_info_dl_s& asn1_freq_info_dl, srsran_carrier_nr_t* out_carrier_nr)
{
srsran_carrier_nr_t carrier_nr = {};
if (asn1_freq_info_dl.absolute_freq_ssb_present) {
carrier_nr.absolute_frequency_ssb = asn1_freq_info_dl.absolute_freq_ssb_present;
} else {
asn1::log_warning("Option absolute_freq_ssb not present");
return false;
}
carrier_nr.absolute_frequency_point_a = asn1_freq_info_dl.absolute_freq_point_a;
if (asn1_freq_info_dl.scs_specific_carrier_list.size() != 1) {
asn1::log_warning("Option absolute_freq_ssb not present");
return false;
}
carrier_nr.nof_prb = asn1_freq_info_dl.scs_specific_carrier_list[0].carrier_bw;
switch (asn1_freq_info_dl.scs_specific_carrier_list[0].subcarrier_spacing) {
case subcarrier_spacing_opts::options::khz15:
carrier_nr.scs = srsran_subcarrier_spacing_15kHz;
break;
case subcarrier_spacing_opts::options::khz30:
carrier_nr.scs = srsran_subcarrier_spacing_30kHz;
break;
case subcarrier_spacing_opts::options::khz60:
carrier_nr.scs = srsran_subcarrier_spacing_60kHz;
break;
case subcarrier_spacing_opts::options::khz120:
carrier_nr.scs = srsran_subcarrier_spacing_120kHz;
break;
case subcarrier_spacing_opts::options::khz240:
carrier_nr.scs = srsran_subcarrier_spacing_240kHz;
break;
default:
asn1::log_warning("Not supported subcarrier spacing ");
}
*out_carrier_nr = carrier_nr;
return true;
}
} // namespace srsran
namespace srsenb {

@ -216,7 +216,8 @@ srsran::pdcp_config_t make_srb_pdcp_config_t(const uint8_t bearer_id, bool is_ue
PDCP_SN_LEN_5,
pdcp_t_reordering_t::ms500,
pdcp_discard_timer_t::infinity,
false);
false,
srsran_rat_t::lte);
return cfg;
}
@ -229,7 +230,8 @@ srsran::pdcp_config_t make_drb_pdcp_config_t(const uint8_t bearer_id, bool is_ue
PDCP_SN_LEN_12,
pdcp_t_reordering_t::ms500,
pdcp_discard_timer_t::infinity,
false);
false,
srsran_rat_t::lte);
return cfg;
}
@ -334,7 +336,8 @@ srsran::pdcp_config_t make_drb_pdcp_config_t(const uint8_t bearer_id, bool is_ue
sn_len,
t_reordering,
discard_timer,
status_report_required);
status_report_required,
srsran_rat_t::lte);
return cfg;
}
@ -388,7 +391,9 @@ void set_mac_cfg_t_rach_cfg_common(mac_cfg_t* cfg, const asn1::rrc::rach_cfg_com
cfg->rach_cfg.messagePowerOffsetGroupB =
asn1_type.preamb_info.preambs_group_a_cfg.msg_pwr_offset_group_b.to_number();
} else {
cfg->rach_cfg.nof_groupA_preambles = 0;
// If the field is not signalled, the size of the random access preambles group A [6] is equal to
// numberOfRA-Preambles
cfg->rach_cfg.nof_groupA_preambles = cfg->rach_cfg.nof_preambles;
}
// Power ramping

@ -191,12 +191,14 @@ int srsran_basic_vnf::handle_dl_ind(basic_vnf_api::dl_ind_msg_t* msg)
}
for (uint32_t i = 0; i < msg->nof_pdus; ++i) {
dl_grant.tb[i] = srsran::make_byte_buffer();
if (dl_grant.tb[i] && dl_grant.tb[i]->get_tailroom() >= msg->pdus[i].length) {
memcpy(dl_grant.tb[i]->msg, msg->pdus[i].data, msg->pdus[i].length);
dl_grant.tb[i]->N_bytes = msg->pdus[i].length;
srsue::stack_interface_phy_nr::tb_action_dl_result_t result = {};
result.payload = srsran::make_byte_buffer();
if (result.payload != nullptr && result.payload->get_tailroom() >= msg->pdus[i].length) {
result.ack = true;
memcpy(result.payload->msg, msg->pdus[i].data, msg->pdus[i].length);
result.payload->N_bytes = msg->pdus[i].length;
if (msg->pdus[i].type == basic_vnf_api::PDSCH) {
m_ue_stack->tb_decoded(cc_idx, dl_grant);
m_ue_stack->tb_decoded(cc_idx, dl_grant, std::move(result));
}
} else {
logger.error("TB too big to fit into buffer (%d)", msg->pdus[i].length);

@ -262,7 +262,7 @@ uint32_t thread_pool::get_nof_workers()
*************************************************************************/
task_thread_pool::task_thread_pool(uint32_t nof_workers, bool start_deferred, int32_t prio_, uint32_t mask_) :
logger(srslog::fetch_basic_logger("POOL")), workers(std::max(1u, nof_workers))
logger(srslog::fetch_basic_logger("POOL")), pending_tasks(max_task_num), workers(std::max(1u, nof_workers))
{
if (not start_deferred) {
start(prio_, mask_);
@ -331,6 +331,10 @@ void task_thread_pool::push_task(task_t&& task)
{
{
std::lock_guard<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));
}
cv_empty.notify_one();
@ -367,7 +371,7 @@ bool task_thread_pool::worker_t::wait_task(task_t* task)
return false;
}
if (task) {
*task = std::move(parent->pending_tasks.front());
*task = std::move(parent->pending_tasks.top());
}
parent->pending_tasks.pop();
return true;

@ -183,7 +183,7 @@ static uint32_t csi_rs_cinit(const srsran_carrier_nr_t* carrier,
const srsran_csi_rs_nzp_resource_t* resource,
uint32_t l)
{
uint32_t n = SRSRAN_SLOT_NR_MOD(carrier->numerology, slot_cfg->idx);
uint32_t n = SRSRAN_SLOT_NR_MOD(carrier->scs, slot_cfg->idx);
uint32_t n_id = resource->scrambling_id;
return ((SRSRAN_NSYMB_PER_SLOT_NR * n + l + 1UL) * (2UL * n_id) << 10UL) + n_id;

@ -163,13 +163,13 @@ int srsran_dmrs_pdcch_put(const srsran_carrier_nr_t* carrier,
}
// Use cell id if the DMR scrambling id is not provided by higher layers
uint32_t n_id = carrier->id;
uint32_t n_id = carrier->pci;
if (coreset->dmrs_scrambling_id_present) {
n_id = coreset->dmrs_scrambling_id;
}
// Bound slot index
uint32_t slot_idx = SRSRAN_SLOT_NR_MOD(carrier->numerology, slot_cfg->idx);
uint32_t slot_idx = SRSRAN_SLOT_NR_MOD(carrier->scs, slot_cfg->idx);
for (uint32_t l = 0; l < coreset->duration; l++) {
// Get Cin
@ -359,13 +359,13 @@ int srsran_dmrs_pdcch_estimate(srsran_dmrs_pdcch_estimator_t* q,
}
// Use cell id if the DMR scrambling id is not provided by higher layers
uint32_t n_id = q->carrier.id;
uint32_t n_id = q->carrier.pci;
if (q->coreset.dmrs_scrambling_id_present) {
n_id = q->coreset.dmrs_scrambling_id;
}
// Bound slot index
uint32_t slot_idx = SRSRAN_SLOT_NR_MOD(q->carrier.numerology, slot_cfg->idx);
uint32_t slot_idx = SRSRAN_SLOT_NR_MOD(q->carrier.scs, slot_cfg->idx);
// Extract pilots
for (uint32_t l = 0; l < q->coreset.duration; l++) {
@ -485,7 +485,7 @@ int srsran_dmrs_pdcch_get_measure(const srsran_dmrs_pdcch_estimator_t* q,
// Measure CFO only from the second and third symbols
if (l != 0) {
// Calculates the time between the previous and the current symbol
float Ts = srsran_symbol_distance_s(l - 1, l, q->carrier.numerology);
float Ts = srsran_symbol_distance_s(l - 1, l, q->carrier.scs);
if (isnormal(Ts)) {
// Compute phase difference between symbols and convert to Hz
cfo_avg_Hz += cargf(corr[l] * conjf(corr[l - 1])) / (2.0f * (float)M_PI * Ts);
@ -504,7 +504,7 @@ int srsran_dmrs_pdcch_get_measure(const srsran_dmrs_pdcch_estimator_t* q,
measure->cfo_hz = NAN;
}
measure->sync_error_us =
sync_err_avg / (4.0e-6f * (float)q->coreset.duration * SRSRAN_SUBC_SPACING_NR(q->carrier.numerology));
sync_err_avg / (4.0e-6f * (float)q->coreset.duration * SRSRAN_SUBC_SPACING_NR(q->carrier.scs));
// Convert power measurements into logarithmic scale
measure->rsrp_dBfs = srsran_convert_power_to_dB(measure->rsrp);

@ -256,7 +256,7 @@ int srsran_dmrs_pucch_format1_estimate(const srsran_pucch_nr_t* q,
// Compute Time Aligment error in microseconds
if (isnormal(ta_err)) {
ta_err /= 15e3f * (float)(1U << carrier->numerology); // Convert from normalized frequency to seconds
ta_err /= 15e3f * (float)(1U << carrier->scs); // Convert from normalized frequency to seconds
ta_err *= 1e6f; // Convert to micro-seconds
ta_err = roundf(ta_err * 10.0f) / 10.0f; // Round to one tenth of micro-second
res->ta_us = ta_err;
@ -298,8 +298,8 @@ static uint32_t dmrs_pucch_format2_cinit(const srsran_carrier_nr_t* car
const srsran_slot_cfg_t* slot,
uint32_t l)
{
uint64_t n = SRSRAN_SLOT_NR_MOD(carrier->numerology, slot->idx);
uint64_t n_id = (cfg->scrambling_id_present) ? cfg->scambling_id : carrier->id;
uint64_t n = SRSRAN_SLOT_NR_MOD(carrier->scs, slot->idx);
uint64_t n_id = (cfg->scrambling_id_present) ? cfg->scambling_id : carrier->pci;
return SRSRAN_SEQUENCE_MOD((((SRSRAN_NSYMB_PER_SLOT_NR * n + l + 1UL) * (2UL * n_id + 1UL)) << 17UL) + 2UL * n_id);
}
@ -418,7 +418,7 @@ int srsran_dmrs_pucch_format2_estimate(const srsran_pucch_nr_t* q,
// Compute Time Aligment error in microseconds
if (isnormal(ta_err)) {
ta_err /= 15e3f * (float)(1U << carrier->numerology) * 3; // Convert from normalized frequency to seconds
ta_err /= 15e3f * (float)(1U << carrier->scs) * 3; // Convert from normalized frequency to seconds
ta_err *= 1e6f; // Convert to micro-seconds
ta_err = roundf(ta_err * 10.0f) / 10.0f; // Round to one tenth of micro-second
res->ta_us = ta_err;

@ -512,7 +512,7 @@ static uint32_t srsran_dmrs_sch_seed(const srsran_carrier_nr_t* carrier,
const srsran_dmrs_sch_cfg_t* dmrs_cfg = &cfg->dmrs;
// Calculate scrambling IDs
uint32_t n_id = carrier->id;
uint32_t n_id = carrier->pci;
uint32_t n_scid = (grant->n_scid) ? 1 : 0;
if (!grant->n_scid && dmrs_cfg->scrambling_id0_present) {
// n_scid = 0 and ID0 present
@ -649,7 +649,7 @@ int srsran_dmrs_sch_put_sf(srsran_dmrs_sch_t* q,
// Iterate symbols
for (uint32_t i = 0; i < nof_symbols; i++) {
uint32_t l = symbols[i]; // Symbol index inside the slot
uint32_t slot_idx = SRSRAN_SLOT_NR_MOD(q->carrier.numerology, slot_cfg->idx); // Slot index in the frame
uint32_t slot_idx = SRSRAN_SLOT_NR_MOD(q->carrier.scs, slot_cfg->idx); // Slot index in the frame
uint32_t cinit = srsran_dmrs_sch_seed(&q->carrier, pdsch_cfg, grant, slot_idx, l);
srsran_dmrs_sch_put_symbol(q, pdsch_cfg, grant, cinit, delta, &sf_symbols[symbol_sz * l]);
@ -780,7 +780,7 @@ int srsran_dmrs_sch_estimate(srsran_dmrs_sch_t* q,
uint32_t l = symbols[i]; // Symbol index inside the slot
uint32_t cinit =
srsran_dmrs_sch_seed(&q->carrier, cfg, grant, SRSRAN_SLOT_NR_MOD(q->carrier.numerology, slot->idx), l);
srsran_dmrs_sch_seed(&q->carrier, cfg, grant, SRSRAN_SLOT_NR_MOD(q->carrier.scs, slot->idx), l);
nof_pilots_x_symbol = srsran_dmrs_sch_get_symbol(
q, cfg, grant, cinit, delta, &sf_symbols[symbol_sz * l], &q->pilot_estimates[nof_pilots_x_symbol * i]);
@ -798,7 +798,7 @@ int srsran_dmrs_sch_estimate(srsran_dmrs_sch_t* q,
sync_err += srsran_vec_estimate_frequency(&q->pilot_estimates[nof_pilots_x_symbol * i], nof_pilots_x_symbol);
}
sync_err /= (float)nof_symbols;
chest_res->sync_error = sync_err / (dmrs_stride * SRSRAN_SUBC_SPACING_NR(q->carrier.numerology));
chest_res->sync_error = sync_err / (dmrs_stride * SRSRAN_SUBC_SPACING_NR(q->carrier.scs));
#if DMRS_SCH_SYNC_PRECOMPENSATE
// Pre-compensate synchronization error
@ -837,7 +837,7 @@ int srsran_dmrs_sch_estimate(srsran_dmrs_sch_t* q,
// Measure CFO if more than one symbol is used
float cfo_avg = 0.0;
for (uint32_t i = 0; i < nof_symbols - 1; i++) {
float time_diff = srsran_symbol_distance_s(symbols[i], symbols[i + 1], q->carrier.numerology);
float time_diff = srsran_symbol_distance_s(symbols[i], symbols[i + 1], q->carrier.scs);
float phase_diff = cargf(corr[i + 1] * conjf(corr[i]));
if (isnormal(time_diff)) {
@ -852,11 +852,11 @@ int srsran_dmrs_sch_estimate(srsran_dmrs_sch_t* q,
if (isnormal(cfo_avg)) {
// Calculate phase of the first OFDM symbol (l = 0)
float arg0 =
cargf(corr[0]) - 2.0f * M_PI * srsran_symbol_distance_s(0, symbols[0], q->carrier.numerology) * cfo_avg;
cargf(corr[0]) - 2.0f * M_PI * srsran_symbol_distance_s(0, symbols[0], q->carrier.scs) * cfo_avg;
// Calculate CFO corrections
for (uint32_t l = 0; l < SRSRAN_NSYMB_PER_SLOT_NR; l++) {
float arg = arg0 + 2.0f * M_PI * cfo_avg * srsran_symbol_distance_s(0, l, q->carrier.numerology);
float arg = arg0 + 2.0f * M_PI * cfo_avg * srsran_symbol_distance_s(0, l, q->carrier.scs);
cfo_correction[l] = cexpf(I * arg);
}

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

@ -39,7 +39,7 @@ void usage(char* prog)
printf("\t-r nof_prb [Default %d]\n", carrier.nof_prb);
printf("\t-e extended cyclic prefix [Default normal]\n");
printf("\t-c cell_id [Default %d]\n", carrier.id);
printf("\t-c cell_id [Default %d]\n", carrier.pci);
printf("\t-v increase verbosity\n");
}
@ -53,7 +53,7 @@ static void parse_args(int argc, char** argv)
carrier.nof_prb = (uint32_t)strtol(argv[optind], NULL, 10);
break;
case 'c':
carrier.id = (uint32_t)strtol(argv[optind], NULL, 10);
carrier.pci = (uint32_t)strtol(argv[optind], NULL, 10);
break;
case 'v':
srsran_verbose++;
@ -77,7 +77,7 @@ static int run_test(srsran_dmrs_pdcch_estimator_t* estimator,
srsran_dci_location_t dci_location = {};
dci_location.L = aggregation_level;
for (slot_cfg.idx = 0; slot_cfg.idx < SRSRAN_NSLOTS_PER_FRAME_NR(carrier.numerology); slot_cfg.idx++) {
for (slot_cfg.idx = 0; slot_cfg.idx < SRSRAN_NSLOTS_PER_FRAME_NR(carrier.scs); slot_cfg.idx++) {
uint32_t locations[SRSRAN_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR] = {};
int nof_locations =

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

@ -892,9 +892,6 @@ int srsran_demod_soft_demodulate(srsran_mod_t modulation, const cf_t* symbols, f
int srsran_demod_soft_demodulate_s(srsran_mod_t modulation, const cf_t* symbols, short* llr, int nsymbols)
{
if (symbols == NULL || llr == NULL) {
return SRSRAN_ERROR_INVALID_INPUTS;
}
switch (modulation) {
case SRSRAN_MOD_BPSK:
demod_bpsk_lte_s(symbols, llr, nsymbols);
@ -920,9 +917,6 @@ int srsran_demod_soft_demodulate_s(srsran_mod_t modulation, const cf_t* symbols,
int srsran_demod_soft_demodulate_b(srsran_mod_t modulation, const cf_t* symbols, int8_t* llr, int nsymbols)
{
if (symbols == NULL || llr == NULL) {
return SRSRAN_ERROR_INVALID_INPUTS;
}
switch (modulation) {
case SRSRAN_MOD_BPSK:
demod_bpsk_lte_b(symbols, llr, nsymbols);
@ -941,34 +935,7 @@ int srsran_demod_soft_demodulate_b(srsran_mod_t modulation, const cf_t* symbols,
break;
default:
ERROR("Invalid modulation %d", modulation);
return SRSRAN_ERROR;
}
return 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 -1;
}
return SRSRAN_SUCCESS;
return 0;
}

@ -19,8 +19,11 @@
*
*/
#include <math.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <time.h>
#include <unistd.h>
@ -31,7 +34,7 @@ static uint32_t nof_frames = 10;
static uint32_t num_bits = 1000;
static srsran_mod_t modulation = SRSRAN_MOD_NITEMS;
static void usage(char* prog)
void usage(char* prog)
{
printf("Usage: %s [nfv] -m modulation (1: BPSK, 2: QPSK, 4: QAM16, 6: QAM64)\n", prog);
printf("\t-n num_bits [Default %d]\n", num_bits);
@ -39,7 +42,7 @@ static void usage(char* prog)
printf("\t-v srsran_verbose [Default None]\n");
}
static void parse_args(int argc, char** argv)
void parse_args(int argc, char** argv)
{
int opt;
while ((opt = getopt(argc, argv, "nmvf")) != -1) {
@ -88,16 +91,33 @@ static void parse_args(int argc, char** argv)
}
}
float mse_threshold()
{
switch (modulation) {
case SRSRAN_MOD_BPSK:
return 1.0e-6;
case SRSRAN_MOD_QPSK:
return 1.0e-6;
case SRSRAN_MOD_16QAM:
return 0.11;
case SRSRAN_MOD_64QAM:
return 0.19;
case SRSRAN_MOD_256QAM:
return 0.3;
default:
return -1.0f;
}
}
int main(int argc, char** argv)
{
int i;
srsran_modem_table_t mod;
uint8_t* input = NULL;
cf_t* symbols = NULL;
float* llr = NULL;
short* llr_s = NULL;
int8_t* llr_b = NULL;
int8_t* llr_b2 = NULL;
srsran_random_t random_gen = srsran_random_init(0);
uint8_t * input, *output;
cf_t* symbols;
float* llr;
short* llr_s;
int8_t* llr_b;
parse_args(argc, argv);
@ -116,6 +136,11 @@ int main(int argc, char** argv)
perror("malloc");
exit(-1);
}
output = srsran_vec_u8_malloc(num_bits);
if (!output) {
perror("malloc");
exit(-1);
}
symbols = srsran_vec_cf_malloc(num_bits / mod.nbits_x_symbol);
if (!symbols) {
perror("malloc");
@ -140,21 +165,17 @@ int main(int argc, char** argv)
exit(-1);
}
llr_b2 = srsran_vec_i8_malloc(num_bits);
if (!llr_b2) {
perror("malloc");
exit(-1);
}
/* generate random data */
srand(0);
int ret = -1;
struct timeval t[3];
float mean_texec = 0.0f;
float mean_texec_s = 0.0f;
float mean_texec_b = 0.0f;
float mean_texec_b2 = 0.0f;
float mean_texec = 0.0;
float mean_texec_s = 0.0;
float mean_texec_b = 0.0;
for (int n = 0; n < nof_frames; n++) {
for (int i = 0; i < num_bits; i++) {
input[i] = srsran_random_uniform_int_dist(random_gen, 0, 1);
for (i = 0; i < num_bits; i++) {
input[i] = rand() % 2;
}
/* modulate */
@ -188,15 +209,6 @@ int main(int argc, char** argv)
mean_texec_b = SRSRAN_VEC_CMA((float)t[0].tv_usec, mean_texec_b, n - 1);
}
gettimeofday(&t[1], NULL);
srsran_demod_soft_demodulate2_b(modulation, symbols, llr_b2, num_bits / mod.nbits_x_symbol);
gettimeofday(&t[2], NULL);
get_time_interval(t);
if (n > 0) {
mean_texec_b2 = SRSRAN_VEC_CMA((float)t[0].tv_usec, mean_texec_b2, n - 1);
}
if (SRSRAN_VERBOSE_ISDEBUG()) {
printf("bits=");
srsran_vec_fprint_b(stdout, input, num_bits);
@ -212,27 +224,12 @@ int main(int argc, char** argv)
printf("llr_b=");
srsran_vec_fprint_bs(stdout, llr_b, num_bits);
printf("llr_b2=");
srsran_vec_fprint_bs(stdout, llr_b2, num_bits);
}
// Check demodulation errors
for (int j = 0; j < num_bits; j++) {
if (input[j] != (llr[j] > 0 ? 1 : 0)) {
ERROR("Error in bit %d\n", j);
goto clean_exit;
}
if (input[j] != (llr_s[j] > 0 ? 1 : 0)) {
ERROR("Error in bit %d\n", j);
goto clean_exit;
}
if (input[j] != (llr_b[j] > 0 ? 1 : 0)) {
ERROR("Error in bit %d\n", j);
goto clean_exit;
}
if (input[j] != (llr_b2[j] > 0 ? 1 : 0)) {
ERROR("Error in bit %d\n", j);
for (int i = 0; i < num_bits; i++) {
if (input[i] != (llr[i] > 0 ? 1 : 0)) {
printf("Error in bit %d\n", i);
goto clean_exit;
}
}
@ -240,23 +237,21 @@ int main(int argc, char** argv)
ret = 0;
clean_exit:
srsran_random_free(random_gen);
free(llr_b);
free(llr_s);
free(llr);
free(symbols);
free(output);
free(input);
srsran_modem_table_free(&mod);
printf("Mean Throughput: %.2f/%.2f/%.2f/%.2f. Mbps ExTime: %.2f/%.2f/%.2f/%.2f us\n",
printf("Mean Throughput: %.2f/%.2f/%.2f. Mbps ExTime: %.2f/%.2f/%.2f us\n",
num_bits / mean_texec,
num_bits / mean_texec_s,
num_bits / mean_texec_b,
num_bits / mean_texec_b2,
mean_texec,
mean_texec_s,
mean_texec_b,
mean_texec_b2);
mean_texec_b);
exit(ret);
}

@ -316,11 +316,11 @@ uint32_t srsran_csi_str(const srsran_csi_report_cfg_t* report_cfg,
for (uint32_t i = 0; i < nof_reports; i++) {
if (report_cfg[i].freq_cfg == SRSRAN_CSI_REPORT_FREQ_WIDEBAND &&
report_cfg[i].quantity == SRSRAN_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI) {
len = srsran_print_check(str, str_len, len, ", cqi=%d", report_value[i].wideband_cri_ri_pmi_cqi.cqi);
len = srsran_print_check(str, str_len, len, "cqi=%d ", report_value[i].wideband_cri_ri_pmi_cqi.cqi);
} else if (report_cfg[i].quantity == SRSRAN_CSI_REPORT_QUANTITY_NONE) {
char tmp[20] = {};
srsran_vec_sprint_bin(tmp, sizeof(tmp), report_value[i].none, report_cfg->K_csi_rs);
len = srsran_print_check(str, str_len, len, ", csi=%s", tmp);
len = srsran_print_check(str, str_len, len, "csi=%s ", tmp);
}
}
return len;

@ -336,7 +336,7 @@ static uint32_t pdcch_nr_c_init(const srsran_pdcch_nr_t* q, const srsran_dci_msg
{
uint32_t n_id = (dci_msg->ctx.ss_type == srsran_search_space_type_ue && q->coreset.dmrs_scrambling_id_present)
? q->coreset.dmrs_scrambling_id
: q->carrier.id;
: q->carrier.pci;
uint32_t n_rnti = (dci_msg->ctx.ss_type == srsran_search_space_type_ue && q->coreset.dmrs_scrambling_id_present)
? dci_msg->ctx.rnti
: 0U;

@ -26,9 +26,6 @@
#include "srsran/phy/mimo/precoding.h"
#include "srsran/phy/modem/demod_soft.h"
///@brief Default number of zero RE around DC
#define PDSCH_NR_DEFAULT_NOF_ZERO_RE_AROUND_DC 3
int pdsch_nr_init_common(srsran_pdsch_nr_t* q, const srsran_pdsch_nr_args_t* args)
{
SRSRAN_MEM_ZERO(q, srsran_pdsch_nr_t, 1);
@ -43,14 +40,6 @@ int pdsch_nr_init_common(srsran_pdsch_nr_t* q, const srsran_pdsch_nr_args_t* arg
}
}
if (!args->disable_zero_re_around_dc) {
if (args->nof_zero_re_around_dc == 0) {
q->nof_zero_re_around_dc = PDSCH_NR_DEFAULT_NOF_ZERO_RE_AROUND_DC;
} else {
q->nof_zero_re_around_dc = args->nof_zero_re_around_dc;
}
}
return SRSRAN_SUCCESS;
}
@ -194,6 +183,8 @@ void srsran_pdsch_nr_free(srsran_pdsch_nr_t* q)
if (q->evm_buffer != NULL) {
srsran_evm_free(q->evm_buffer);
}
SRSRAN_MEM_ZERO(q, srsran_pdsch_nr_t, 1);
}
static inline uint32_t pdsch_nr_put_rb(cf_t* dst, cf_t* src, bool* rvd_mask)
@ -257,23 +248,7 @@ static int srsran_pdsch_nr_cp(const srsran_pdsch_nr_t* q,
if (put) {
count += pdsch_nr_put_rb(&sf_symbols[re_idx], &symbols[count], &rvd_mask[rb * SRSRAN_NRE]);
} else {
uint32_t k_begin = rb * SRSRAN_NRE;
uint32_t k_end = (rb + 1) * SRSRAN_NRE;
uint32_t k_dc_begin = q->carrier.nof_prb * SRSRAN_NRE / 2 - q->nof_zero_re_around_dc / 2;
uint32_t k_dc_end = q->carrier.nof_prb * SRSRAN_NRE / 2 + SRSRAN_CEIL(q->nof_zero_re_around_dc, 2);
if (k_begin <= k_dc_end && k_end >= k_dc_begin && q->nof_zero_re_around_dc > 0) {
for (uint32_t k = k_begin; k < k_end; k++) {
if (!rvd_mask[k]) {
if (k >= k_dc_begin && k < k_dc_end) {
symbols[count++] = 0.0f;
} else {
symbols[count++] = sf_symbols[q->carrier.nof_prb * l * SRSRAN_NRE + k];
}
}
}
} else {
count += pdsch_nr_get_rb(&symbols[count], &sf_symbols[re_idx], &rvd_mask[rb * SRSRAN_NRE]);
}
count += pdsch_nr_get_rb(&symbols[count], &sf_symbols[re_idx], &rvd_mask[rb * SRSRAN_NRE]);
}
}
}
@ -302,7 +277,7 @@ static int srsran_pdsch_nr_get(const srsran_pdsch_nr_t* q,
static uint32_t
pdsch_nr_cinit(const srsran_carrier_nr_t* carrier, const srsran_sch_cfg_nr_t* cfg, uint16_t rnti, uint32_t cw_idx)
{
uint32_t n_id = carrier->id;
uint32_t n_id = carrier->pci;
if (cfg->scrambling_id_present && SRSRAN_RNTI_ISUSER(rnti)) {
n_id = cfg->scambling_id;
}
@ -465,7 +440,7 @@ static inline int pdsch_nr_decode_codeword(srsran_pdsch_nr_t* q,
// Demodulation
int8_t* llr = (int8_t*)q->b[tb->cw_idx];
if (srsran_demod_soft_demodulate2_b(tb->mod, q->d[tb->cw_idx], llr, tb->nof_re)) {
if (srsran_demod_soft_demodulate_b(tb->mod, q->d[tb->cw_idx], llr, tb->nof_re)) {
return SRSRAN_ERROR;
}
@ -584,7 +559,6 @@ static uint32_t pdsch_nr_grant_info(const srsran_pdsch_nr_t* q,
uint32_t str_len)
{
uint32_t len = 0;
len = srsran_print_check(str, str_len, len, "rnti=0x%x ", grant->rnti);
uint32_t first_prb = SRSRAN_MAX_PRB_NR;
for (uint32_t i = 0; i < SRSRAN_MAX_PRB_NR && first_prb == SRSRAN_MAX_PRB_NR; i++) {
@ -594,27 +568,8 @@ static uint32_t pdsch_nr_grant_info(const srsran_pdsch_nr_t* q,
}
// Append time-domain resource mapping
len = srsran_print_check(str,
str_len,
len,
"beta_dmrs=%.3f CDM-grp=%d k0=%d prb=%d:%d symb=%d:%d mapping=%s ",
isnormal(grant->beta_dmrs) ? grant->beta_dmrs : 1.0f,
grant->nof_dmrs_cdm_groups_without_data,
grant->k,
first_prb,
grant->nof_prb,
grant->S,
grant->L,
srsran_sch_mapping_type_to_str(grant->mapping));
// Skip frequency domain resources...
// ...
// Append spatial resources
len = srsran_print_check(str, str_len, len, "Nl=%d ", grant->nof_layers);
// Append scrambling ID
len = srsran_print_check(str, str_len, len, "n_scid=%d ", grant->n_scid);
len = srsran_print_check(
str, str_len, len, "rnti=0x%x prb=%d:%d symb=%d:%d ", grant->rnti, first_prb, grant->nof_prb, grant->S, grant->L);
// Append TB info
for (uint32_t i = 0; i < SRSRAN_MAX_TB; i++) {
@ -643,13 +598,8 @@ uint32_t srsran_pdsch_nr_rx_info(const srsran_pdsch_nr_t* q,
len += pdsch_nr_grant_info(q, cfg, grant, res, &str[len], str_len - len);
if (cfg->rvd_re.count != 0) {
len = srsran_print_check(str, str_len, len, "Reserved: ");
len += srsran_re_pattern_list_info(&cfg->rvd_re, &str[len], str_len - len);
}
if (q->meas_time_en) {
len = srsran_print_check(str, str_len, len, " t=%d us", q->meas_time_us);
len = srsran_print_check(str, str_len, len, "t_us=%d ", q->meas_time_us);
}
return len;

@ -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_ss = 0;
uint32_t n_id = cfg->hopping_id_present ? cfg->hopping_id : carrier->id;
uint32_t n_id = cfg->hopping_id_present ? cfg->hopping_id : carrier->pci;
switch (cfg->group_hopping) {
case SRSRAN_PUCCH_NR_GROUP_HOPPING_NEITHER:
@ -80,13 +80,13 @@ int srsran_pucch_nr_alpha_idx(const srsran_carrier_nr_t* carrier,
}
// Compute number of slot
uint32_t n_slot = SRSRAN_SLOT_NR_MOD(carrier->numerology, slot->idx);
uint32_t n_slot = SRSRAN_SLOT_NR_MOD(carrier->scs, slot->idx);
// Generate pseudo-random sequence
uint32_t cinit = cfg->hopping_id_present ? cfg->hopping_id : carrier->id;
uint32_t cinit = cfg->hopping_id_present ? cfg->hopping_id : carrier->pci;
uint8_t cs[SRSRAN_NSYMB_PER_SLOT_NR * SRSRAN_NSLOTS_PER_FRAME_NR(SRSRAN_NR_MAX_NUMEROLOGY) * 8U] = {};
srsran_sequence_apply_bit(
cs, cs, SRSRAN_NSYMB_PER_SLOT_NR * SRSRAN_NSLOTS_PER_FRAME_NR(carrier->numerology) * 8, cinit);
cs, cs, SRSRAN_NSYMB_PER_SLOT_NR * SRSRAN_NSLOTS_PER_FRAME_NR(carrier->scs) * 8, cinit);
// Create n_cs parameter
uint32_t n_cs = 0;
@ -545,7 +545,7 @@ static uint32_t pucch_nr_format2_cinit(const srsran_carrier_nr_t* carri
const srsran_pucch_nr_common_cfg_t* pucch_cfg,
const srsran_uci_cfg_nr_t* uci_cfg)
{
uint32_t n_id = (pucch_cfg->scrambling_id_present) ? pucch_cfg->scrambling_id_present : carrier->id;
uint32_t n_id = (pucch_cfg->scrambling_id_present) ? pucch_cfg->scrambling_id_present : carrier->pci;
return ((uint32_t)uci_cfg->pucch.rnti << 15U) + n_id;
}

@ -236,171 +236,25 @@ void srsran_pusch_nr_free(srsran_pusch_nr_t* q)
SRSRAN_MEM_ZERO(q, srsran_pusch_nr_t, 1);
}
/**
* @brief copies a number of countiguous Resource Elements
* @param sf_symbols slot symbols in frequency domain
* @param symbols resource elements
* @param count number of resource elements to copy
* @param put Direction, symbols are copied into sf_symbols if put is true, otherwise sf_symbols are copied into symbols
*/
static void srsran_pusch_re_cp(cf_t* sf_symbols, cf_t* symbols, uint32_t count, bool put)
{
if (put) {
srsran_vec_cf_copy(sf_symbols, symbols, count);
} else {
srsran_vec_cf_copy(symbols, sf_symbols, count);
}
}
/*
* As a RB is 12 RE wide, positions marked as 1 will be used for the 1st CDM group, and the same with group 2:
*
* +---+---+---+---+---+---+---+---+---+---+---+---+
* | 1 | 1 | 2 | 2 | 1 | 1 | 2 | 2 | 1 | 1 | 2 | 2 |
* +---+---+---+---+---+---+---+---+---+---+---+---+
* -- k -->
*
* If the number of DMRS CDM groups without data is set to:
* - 1, data is mapped in RE marked as 2
* - Otherwise, no data is mapped in this symbol
*/
static uint32_t srsran_pusch_nr_cp_dmrs_type1(const srsran_pusch_nr_t* q,
const srsran_sch_grant_nr_t* grant,
cf_t* symbols,
cf_t* sf_symbols,
bool put)
{
uint32_t count = 0;
uint32_t delta = 0;
if (grant->nof_dmrs_cdm_groups_without_data != 1) {
return count;
}
for (uint32_t i = 0; i < q->carrier.nof_prb; i++) {
if (grant->prb_idx[i]) {
for (uint32_t j = 0; j < SRSRAN_NRE; j += 2) {
if (put) {
sf_symbols[i * SRSRAN_NRE + delta + j + 1] = symbols[count++];
} else {
symbols[count++] = sf_symbols[i * SRSRAN_NRE + delta + j + 1];
}
}
}
}
return count;
}
/*
* As a RB is 12 RE wide, positions marked as 1 will be used for the 1st CDM group, and the same with groups 2 and 3:
*
* +---+---+---+---+---+---+---+---+---+---+---+---+
* | 1 | 1 | 2 | 2 | 3 | 3 | 1 | 1 | 2 | 2 | 3 | 3 |
* +---+---+---+---+---+---+---+---+---+---+---+---+
* -- k -->
*
* If the number of DMRS CDM groups without data is set to:
* - 1, data is mapped in RE marked as 2 and 3
* - 2, data is mapped in RE marked as 3
* - otherwise, no data is mapped in this symbol
*/
static uint32_t srsran_pusch_nr_cp_dmrs_type2(const srsran_pusch_nr_t* q,
const srsran_sch_grant_nr_t* grant,
cf_t* symbols,
cf_t* sf_symbols,
bool put)
static inline uint32_t pusch_nr_put_rb(cf_t* dst, cf_t* src, bool* rvd_mask)
{
uint32_t count = 0;
if (grant->nof_dmrs_cdm_groups_without_data != 1 && grant->nof_dmrs_cdm_groups_without_data != 2) {
return count;
}
uint32_t re_offset = (grant->nof_dmrs_cdm_groups_without_data == 1) ? 2 : 4;
uint32_t re_count = (grant->nof_dmrs_cdm_groups_without_data == 1) ? 4 : 2;
for (uint32_t i = 0; i < q->carrier.nof_prb; i++) {
if (grant->prb_idx[i]) {
// Copy RE between pilot pairs
srsran_pusch_re_cp(&sf_symbols[i * SRSRAN_NRE + re_offset], &symbols[count], re_count, put);
count += re_count;
// Copy RE after second pilot
srsran_pusch_re_cp(&sf_symbols[(i + 1) * SRSRAN_NRE - re_count], &symbols[count], re_count, put);
count += re_count;
for (uint32_t i = 0; i < SRSRAN_NRE; i++) {
if (!rvd_mask[i]) {
dst[i] = src[count++];
}
}
return count;
}
static uint32_t srsran_pusch_nr_cp_dmrs(const srsran_pusch_nr_t* q,
const srsran_sch_cfg_nr_t* cfg,
const srsran_sch_grant_nr_t* grant,
cf_t* symbols,
cf_t* sf_symbols,
bool put)
static inline uint32_t pusch_nr_get_rb(cf_t* dst, cf_t* src, bool* rvd_mask)
{
uint32_t count = 0;
const srsran_dmrs_sch_cfg_t* dmrs_cfg = &cfg->dmrs;
switch (dmrs_cfg->type) {
case srsran_dmrs_sch_type_1:
count = srsran_pusch_nr_cp_dmrs_type1(q, grant, symbols, sf_symbols, put);
break;
case srsran_dmrs_sch_type_2:
count = srsran_pusch_nr_cp_dmrs_type2(q, grant, symbols, sf_symbols, put);
break;
}
return count;
}
static uint32_t srsran_pusch_nr_cp_clean(const srsran_pusch_nr_t* q,
const srsran_sch_grant_nr_t* grant,
cf_t* symbols,
cf_t* sf_symbols,
bool put)
{
uint32_t count = 0;
uint32_t start = 0; // Index of the start of continuous data
uint32_t length = 0; // End of continuous RE
for (uint32_t i = 0; i < q->carrier.nof_prb; i++) {
if (grant->prb_idx[i]) {
// If fist continuous block, save start
if (length == 0) {
start = i * SRSRAN_NRE;
}
length += SRSRAN_NRE;
} else {
// Consecutive block is finished
if (put) {
srsran_vec_cf_copy(&sf_symbols[start], &symbols[count], length);
} else {
srsran_vec_cf_copy(&symbols[count], &sf_symbols[start], length);
}
// Increase RE count
count += length;
// Reset consecutive block
length = 0;
for (uint32_t i = 0; i < SRSRAN_NRE; i++) {
if (!rvd_mask[i]) {
dst[count++] = src[i];
}
}
// Copy last contiguous block
if (length > 0) {
if (put) {
srsran_vec_cf_copy(&sf_symbols[start], &symbols[count], length);
} else {
srsran_vec_cf_copy(&symbols[count], &sf_symbols[start], length);
}
count += length;
}
return count;
}
@ -411,55 +265,60 @@ static int srsran_pusch_nr_cp(const srsran_pusch_nr_t* q,
cf_t* sf_symbols,
bool put)
{
uint32_t count = 0;
uint32_t dmrs_l_idx[SRSRAN_DMRS_SCH_MAX_SYMBOLS] = {};
uint32_t dmrs_l_count = 0;
uint32_t count = 0;
// Get symbol indexes carrying DMRS
int32_t nof_dmrs_symbols = srsran_dmrs_sch_get_symbols_idx(&cfg->dmrs, grant, dmrs_l_idx);
if (nof_dmrs_symbols < SRSRAN_SUCCESS) {
return SRSRAN_ERROR;
}
for (uint32_t l = grant->S; l < grant->S + grant->L; l++) {
// Initialise reserved RE mask to all false
bool rvd_mask[SRSRAN_NRE * SRSRAN_MAX_PRB_NR] = {};
if (SRSRAN_DEBUG_ENABLED && srsran_verbose >= SRSRAN_VERBOSE_DEBUG && !handler_registered) {
DEBUG("dmrs_l_idx=");
srsran_vec_fprint_i(stdout, (int32_t*)dmrs_l_idx, nof_dmrs_symbols);
}
// Reserve DMRS
if (srsran_re_pattern_to_symbol_mask(&q->dmrs_re_pattern, l, rvd_mask) < SRSRAN_SUCCESS) {
ERROR("Error generating DMRS reserved RE mask");
return SRSRAN_ERROR;
}
for (uint32_t l = grant->S; l < grant->S + grant->L; l++) {
// Advance DMRS symbol counter until:
// - the current DMRS symbol index is greater or equal than current symbol l
// - no more DMRS symbols
while (dmrs_l_idx[dmrs_l_count] < l && dmrs_l_count < nof_dmrs_symbols) {
dmrs_l_count++;
// Reserve RE from configuration
if (srsran_re_pattern_list_to_symbol_mask(&cfg->rvd_re, l, rvd_mask) < SRSRAN_SUCCESS) {
ERROR("Error generating reserved RE mask");
return SRSRAN_ERROR;
}
if (l == dmrs_l_idx[dmrs_l_count]) {
count += srsran_pusch_nr_cp_dmrs(
q, cfg, grant, &symbols[count], &sf_symbols[l * q->carrier.nof_prb * SRSRAN_NRE], put);
} else {
count +=
srsran_pusch_nr_cp_clean(q, grant, &symbols[count], &sf_symbols[l * q->carrier.nof_prb * SRSRAN_NRE], put);
// Actual copy
for (uint32_t rb = 0; rb < q->carrier.nof_prb; rb++) {
// Skip PRB if not available in grant
if (!grant->prb_idx[rb]) {
continue;
}
// Calculate RE index at the begin of the symbol
uint32_t re_idx = (q->carrier.nof_prb * l + rb) * SRSRAN_NRE;
// Put or get
if (put) {
count += pusch_nr_put_rb(&sf_symbols[re_idx], &symbols[count], &rvd_mask[rb * SRSRAN_NRE]);
} else {
count += pusch_nr_get_rb(&symbols[count], &sf_symbols[re_idx], &rvd_mask[rb * SRSRAN_NRE]);
}
}
}
return count;
}
static int srsran_pusch_nr_put(const srsran_pusch_nr_t* q,
const srsran_sch_cfg_nr_t* cfg,
const srsran_sch_grant_nr_t* grant,
cf_t* symbols,
cf_t* sf_symbols)
static int pusch_nr_put(const srsran_pusch_nr_t* q,
const srsran_sch_cfg_nr_t* cfg,
const srsran_sch_grant_nr_t* grant,
cf_t* symbols,
cf_t* sf_symbols)
{
return srsran_pusch_nr_cp(q, cfg, grant, symbols, sf_symbols, true);
}
static int srsran_pusch_nr_get(const srsran_pusch_nr_t* q,
const srsran_sch_cfg_nr_t* cfg,
const srsran_sch_grant_nr_t* grant,
cf_t* symbols,
cf_t* sf_symbols)
static int pusch_nr_get(const srsran_pusch_nr_t* q,
const srsran_sch_cfg_nr_t* cfg,
const srsran_sch_grant_nr_t* grant,
cf_t* symbols,
cf_t* sf_symbols)
{
return srsran_pusch_nr_cp(q, cfg, grant, symbols, sf_symbols, false);
}
@ -467,7 +326,7 @@ static int srsran_pusch_nr_get(const srsran_pusch_nr_t* q,
static uint32_t
pusch_nr_cinit(const srsran_carrier_nr_t* carrier, const srsran_sch_cfg_nr_t* cfg, uint16_t rnti, uint32_t cw_idx)
{
uint32_t n_id = carrier->id;
uint32_t n_id = carrier->pci;
if (cfg->scrambling_id_present && SRSRAN_RNTI_ISUSER(rnti)) {
n_id = cfg->scambling_id;
}
@ -478,121 +337,6 @@ pusch_nr_cinit(const srsran_carrier_nr_t* carrier, const srsran_sch_cfg_nr_t* cf
return cinit;
}
static inline int pusch_nr_fill_uci_cfg(srsran_pusch_nr_t* q, const srsran_sch_cfg_nr_t* cfg)
{
if (cfg->grant.nof_prb == 0) {
ERROR("Invalid number of PRB (%d)", cfg->grant.nof_prb);
return SRSRAN_ERROR;
}
// Initially, copy all fields
q->uci_cfg = cfg->uci;
// Reset UCI PUSCH configuration
SRSRAN_MEM_ZERO(&q->uci_cfg.pusch, srsran_uci_nr_pusch_cfg_t, 1);
// Get DMRS symbol indexes
uint32_t nof_dmrs_l = 0;
uint32_t dmrs_l[SRSRAN_DMRS_SCH_MAX_SYMBOLS] = {};
int n = srsran_dmrs_sch_get_symbols_idx(&cfg->dmrs, &cfg->grant, dmrs_l);
if (n < SRSRAN_SUCCESS) {
return SRSRAN_ERROR;
}
nof_dmrs_l = (uint32_t)n;
// Find OFDM symbol index of the first OFDM symbol after the first set of consecutive OFDM symbol(s) carrying DMRS
// Starts at first OFDM symbol carrying DMRS
for (uint32_t l = dmrs_l[0], dmrs_l_idx = 0; l < cfg->grant.S + cfg->grant.L; l++) {
// Check if it is not carrying DMRS...
if (l != dmrs_l[dmrs_l_idx]) {
// Set value and stop iterating
q->uci_cfg.pusch.l0 = l;
break;
}
// Move to the next DMRS OFDM symbol index
if (dmrs_l_idx < nof_dmrs_l) {
dmrs_l_idx++;
}
}
// Find OFDM symbol index of the first OFDM symbol that does not carry DMRS
// Starts at first OFDM symbol of the PUSCH transmission
for (uint32_t l = cfg->grant.S, dmrs_l_idx = 0; l < cfg->grant.S + cfg->grant.L; l++) {
// Check if it is not carrying DMRS...
if (l != dmrs_l[dmrs_l_idx]) {
q->uci_cfg.pusch.l1 = l;
break;
}
// Move to the next DMRS OFDM symbol index
if (dmrs_l_idx < nof_dmrs_l) {
dmrs_l_idx++;
}
}
// Number of DMRS per PRB
uint32_t n_sc_dmrs = SRSRAN_DMRS_SCH_SC(cfg->grant.nof_dmrs_cdm_groups_without_data, cfg->dmrs.type);
// Set UCI RE number of candidates per OFDM symbol according to TS 38.312 6.3.2.4.2.1
for (uint32_t l = 0, dmrs_l_idx = 0; l < SRSRAN_NSYMB_PER_SLOT_NR; l++) {
// Skip if OFDM symbol is outside of the PUSCH transmission
if (l < cfg->grant.S || l >= (cfg->grant.S + cfg->grant.L)) {
q->uci_cfg.pusch.M_pusch_sc[l] = 0;
q->uci_cfg.pusch.M_uci_sc[l] = 0;
continue;
}
// OFDM symbol carries DMRS
if (l == dmrs_l[dmrs_l_idx]) {
// Calculate PUSCH RE candidates
q->uci_cfg.pusch.M_pusch_sc[l] = cfg->grant.nof_prb * (SRSRAN_NRE - n_sc_dmrs);
// The Number of RE candidates for UCI are 0
q->uci_cfg.pusch.M_uci_sc[l] = 0;
// Advance DMRS symbol index
dmrs_l_idx++;
// Skip to next symbol
continue;
}
// Number of RE for Phase Tracking Reference Signals (PT-RS)
uint32_t M_ptrs_sc = 0; // Not implemented yet
// Number of RE given by the grant
q->uci_cfg.pusch.M_pusch_sc[l] = cfg->grant.nof_prb * SRSRAN_NRE;
// Calculate the number of UCI candidates
q->uci_cfg.pusch.M_uci_sc[l] = q->uci_cfg.pusch.M_pusch_sc[l] - M_ptrs_sc;
}
// Generate SCH Transport block information
srsran_sch_nr_tb_info_t sch_tb_info = {};
if (srsran_sch_nr_fill_tb_info(&q->carrier, &cfg->sch_cfg, &cfg->grant.tb[0], &sch_tb_info) < SRSRAN_SUCCESS) {
ERROR("Generating TB info");
return SRSRAN_ERROR;
}
// Calculate the sum of codeblock sizes
for (uint32_t i = 0; i < sch_tb_info.C; i++) {
// Accumulate codeblock size if mask is enabled
q->uci_cfg.pusch.K_sum += (sch_tb_info.mask[i]) ? sch_tb_info.Kr : 0;
}
// Set other PUSCH parameters
q->uci_cfg.pusch.modulation = cfg->grant.tb[0].mod;
q->uci_cfg.pusch.nof_layers = cfg->grant.nof_layers;
q->uci_cfg.pusch.R = (float)cfg->grant.tb[0].R;
q->uci_cfg.pusch.alpha = cfg->scaling;
q->uci_cfg.pusch.beta_harq_ack_offset = cfg->beta_harq_ack_offset;
q->uci_cfg.pusch.beta_csi1_offset = cfg->beta_csi_part1_offset;
q->uci_cfg.pusch.nof_re = cfg->grant.tb[0].nof_re;
return SRSRAN_SUCCESS;
}
// Implements TS 38.212 6.2.7 Data and control multiplexing (for NR-PUSCH)
static int pusch_nr_gen_mux_uci(srsran_pusch_nr_t* q, const srsran_uci_cfg_nr_t* cfg)
{
@ -629,7 +373,7 @@ static int pusch_nr_gen_mux_uci(srsran_pusch_nr_t* q, const srsran_uci_cfg_nr_t*
if (cfg->o_ack <= 2) {
// the number of reserved resource elements for potential HARQ-ACK transmission is calculated according to Clause
// 6.3.2.4.2.1, by setting O_ACK = 2 ;
G_ack_rvd = srsran_uci_nr_pusch_ack_nof_bits(&q->uci_cfg.pusch, 2);
G_ack_rvd = srsran_uci_nr_pusch_ack_nof_bits(&cfg->pusch, 2);
// Disable non reserved HARQ-ACK bits
G_ack = 0;
@ -845,7 +589,7 @@ static inline int pusch_nr_encode_codeword(srsran_pusch_nr_t* q,
}
// Encode HARQ-ACK bits
int E_uci_ack = srsran_uci_nr_encode_pusch_ack(&q->uci, &q->uci_cfg, uci, q->g_ack);
int E_uci_ack = srsran_uci_nr_encode_pusch_ack(&q->uci, &cfg->uci, uci, q->g_ack);
if (E_uci_ack < SRSRAN_SUCCESS) {
ERROR("Error encoding HARQ-ACK bits");
return SRSRAN_ERROR;
@ -853,7 +597,7 @@ static inline int pusch_nr_encode_codeword(srsran_pusch_nr_t* q,
q->G_ack = (uint32_t)E_uci_ack;
// Encode CSI part 1
int E_uci_csi1 = srsran_uci_nr_encode_pusch_csi1(&q->uci, &q->uci_cfg, uci, q->g_csi1);
int E_uci_csi1 = srsran_uci_nr_encode_pusch_csi1(&q->uci, &cfg->uci, uci, q->g_csi1);
if (E_uci_csi1 < SRSRAN_SUCCESS) {
ERROR("Error encoding HARQ-ACK bits");
return SRSRAN_ERROR;
@ -865,7 +609,7 @@ static inline int pusch_nr_encode_codeword(srsran_pusch_nr_t* q,
q->G_csi2 = 0;
// Generate PUSCH UCI/UL-SCH multiplexing
if (pusch_nr_gen_mux_uci(q, &q->uci_cfg) < SRSRAN_SUCCESS) {
if (pusch_nr_gen_mux_uci(q, &cfg->uci) < SRSRAN_SUCCESS) {
ERROR("Error generating PUSCH mux tables");
return SRSRAN_ERROR;
}
@ -877,7 +621,8 @@ static inline int pusch_nr_encode_codeword(srsran_pusch_nr_t* q,
}
// Multiplex UL-SCH with UCI only if it is necessary
uint8_t* b = q->g_ulsch;
uint32_t nof_bits = tb->nof_re * srsran_mod_bits_x_symbol(tb->mod);
uint8_t* b = q->g_ulsch;
if (q->uci_mux) {
// Change b location
b = q->b[tb->cw_idx];
@ -905,15 +650,15 @@ static inline int pusch_nr_encode_codeword(srsran_pusch_nr_t* q,
if (SRSRAN_DEBUG_ENABLED && srsran_verbose >= SRSRAN_VERBOSE_DEBUG && !handler_registered) {
DEBUG("b=");
srsran_vec_fprint_b(stdout, b, tb->nof_bits);
srsran_vec_fprint_b(stdout, b, nof_bits);
}
// 7.3.1.1 Scrambling
uint32_t cinit = pusch_nr_cinit(&q->carrier, cfg, rnti, tb->cw_idx);
srsran_sequence_apply_bit(b, q->b[tb->cw_idx], tb->nof_bits, cinit);
srsran_sequence_apply_bit(b, q->b[tb->cw_idx], nof_bits, cinit);
// Special Scrambling condition
if (q->uci_cfg.o_ack <= 2) {
if (cfg->uci.o_ack <= 2) {
for (uint32_t i = 0; i < q->G_ack; i++) {
uint32_t idx = q->pos_ack[i];
if (q->g_ack[i] == (uint8_t)UCI_BIT_REPETITION) {
@ -927,7 +672,7 @@ static inline int pusch_nr_encode_codeword(srsran_pusch_nr_t* q,
}
// 7.3.1.2 Modulation
srsran_mod_modulate(&q->modem_tables[tb->mod], q->b[tb->cw_idx], q->d[tb->cw_idx], tb->nof_bits);
srsran_mod_modulate(&q->modem_tables[tb->mod], q->b[tb->cw_idx], q->d[tb->cw_idx], nof_bits);
if (SRSRAN_DEBUG_ENABLED && srsran_verbose >= SRSRAN_VERBOSE_DEBUG && !handler_registered) {
DEBUG("d=");
@ -945,6 +690,7 @@ int srsran_pusch_nr_encode(srsran_pusch_nr_t* q,
{
// Check input pointers
if (!q || !cfg || !grant || !data || !sf_symbols) {
ERROR("Invalid inputs");
return SRSRAN_ERROR_INVALID_INPUTS;
}
@ -959,9 +705,9 @@ int srsran_pusch_nr_encode(srsran_pusch_nr_t* q,
return SRSRAN_ERROR;
}
// Fill UCI configuration for PUSCH configuration
if (pusch_nr_fill_uci_cfg(q, cfg) < SRSRAN_SUCCESS) {
ERROR("Error filling UCI configuration for PUSCH");
// Compute DMRS pattern
if (srsran_dmrs_sch_rvd_re_pattern(&cfg->dmrs, grant, &q->dmrs_re_pattern) < SRSRAN_SUCCESS) {
ERROR("Error computing DMRS pattern");
return SRSRAN_ERROR;
}
@ -991,7 +737,7 @@ int srsran_pusch_nr_encode(srsran_pusch_nr_t* q,
// ... Not implemented
// 7.3.1.6 Mapping from virtual to physical resource blocks
int n = srsran_pusch_nr_put(q, cfg, grant, x[0], sf_symbols[0]);
int n = pusch_nr_put(q, cfg, grant, x[0], sf_symbols[0]);
if (n < SRSRAN_SUCCESS) {
ERROR("Putting NR PUSCH resources");
return SRSRAN_ERROR;
@ -1039,8 +785,11 @@ static inline int pusch_nr_decode_codeword(srsran_pusch_nr_t* q,
srsran_vec_fprint_c(stdout, q->d[tb->cw_idx], tb->nof_re);
}
// Total number of bits
uint32_t nof_bits = tb->nof_re * srsran_mod_bits_x_symbol(tb->mod);
// Calculate HARQ-ACK bits
int n = srsran_uci_nr_pusch_ack_nof_bits(&q->uci_cfg.pusch, q->uci_cfg.o_ack);
int n = srsran_uci_nr_pusch_ack_nof_bits(&cfg->uci.pusch, cfg->uci.o_ack);
if (n < SRSRAN_SUCCESS) {
ERROR("Calculating G_ack");
return SRSRAN_ERROR;
@ -1048,7 +797,7 @@ static inline int pusch_nr_decode_codeword(srsran_pusch_nr_t* q,
q->G_ack = (uint32_t)n;
// Calculate CSI part 1 bits
n = srsran_uci_nr_pusch_csi1_nof_bits(&q->uci_cfg);
n = srsran_uci_nr_pusch_csi1_nof_bits(&cfg->uci);
if (n < SRSRAN_SUCCESS) {
ERROR("Calculating G_csi1");
return SRSRAN_ERROR;
@ -1060,7 +809,7 @@ static inline int pusch_nr_decode_codeword(srsran_pusch_nr_t* q,
q->G_csi2 = 0;
// Generate PUSCH UCI/UL-SCH multiplexing
if (pusch_nr_gen_mux_uci(q, &q->uci_cfg) < SRSRAN_SUCCESS) {
if (pusch_nr_gen_mux_uci(q, &cfg->uci) < SRSRAN_SUCCESS) {
ERROR("Error generating PUSCH mux tables");
return SRSRAN_ERROR;
}
@ -1073,16 +822,15 @@ static inline int pusch_nr_decode_codeword(srsran_pusch_nr_t* q,
// EVM
if (q->evm_buffer != NULL) {
res->evm[tb->cw_idx] =
srsran_evm_run_b(q->evm_buffer, &q->modem_tables[tb->mod], q->d[tb->cw_idx], llr, tb->nof_bits);
res->evm[tb->cw_idx] = srsran_evm_run_b(q->evm_buffer, &q->modem_tables[tb->mod], q->d[tb->cw_idx], llr, nof_bits);
}
// Descrambling
srsran_sequence_apply_c(llr, llr, tb->nof_bits, pusch_nr_cinit(&q->carrier, cfg, rnti, tb->cw_idx));
srsran_sequence_apply_c(llr, llr, nof_bits, pusch_nr_cinit(&q->carrier, cfg, rnti, tb->cw_idx));
if (SRSRAN_DEBUG_ENABLED && srsran_verbose >= SRSRAN_VERBOSE_DEBUG && !handler_registered) {
DEBUG("b=");
srsran_vec_fprint_bs(stdout, llr, tb->nof_bits);
srsran_vec_fprint_bs(stdout, llr, nof_bits);
}
// Demultiplex UCI only if necessary
@ -1092,7 +840,7 @@ static inline int pusch_nr_decode_codeword(srsran_pusch_nr_t* q,
for (uint32_t i = 0; i < q->G_ulsch; i++) {
g_ulsch[i] = -llr[q->pos_ulsch[i]];
}
for (uint32_t i = q->G_ulsch; i < tb->nof_bits; i++) {
for (uint32_t i = q->G_ulsch; i < nof_bits; i++) {
g_ulsch[i] = 0;
}
@ -1116,7 +864,7 @@ static inline int pusch_nr_decode_codeword(srsran_pusch_nr_t* q,
// Decode HARQ-ACK
if (q->G_ack) {
if (srsran_uci_nr_decode_pusch_ack(&q->uci, &q->uci_cfg, g_ack, &res->uci)) {
if (srsran_uci_nr_decode_pusch_ack(&q->uci, &cfg->uci, g_ack, &res->uci)) {
ERROR("Error in UCI decoding");
return SRSRAN_ERROR;
}
@ -1124,7 +872,7 @@ static inline int pusch_nr_decode_codeword(srsran_pusch_nr_t* q,
// Decode CSI part 1
if (q->G_csi1) {
if (srsran_uci_nr_decode_pusch_csi1(&q->uci, &q->uci_cfg, g_csi1, &res->uci)) {
if (srsran_uci_nr_decode_pusch_csi1(&q->uci, &cfg->uci, g_csi1, &res->uci)) {
ERROR("Error in UCI decoding");
return SRSRAN_ERROR;
}
@ -1136,13 +884,13 @@ static inline int pusch_nr_decode_codeword(srsran_pusch_nr_t* q,
// Change LLR pointer
llr = g_ulsch;
} else {
for (uint32_t i = 0; i < tb->nof_bits; i++) {
for (uint32_t i = 0; i < nof_bits; i++) {
llr[i] *= -1;
}
}
// Decode Ul-SCH
if (tb->nof_bits != 0) {
if (nof_bits != 0) {
if (srsran_ulsch_nr_decode(&q->sch, &cfg->sch_cfg, tb, llr, &res->tb[tb->cw_idx]) < SRSRAN_SUCCESS) {
ERROR("Error in SCH decoding");
return SRSRAN_ERROR;
@ -1175,9 +923,9 @@ int srsran_pusch_nr_decode(srsran_pusch_nr_t* q,
return SRSRAN_ERROR;
}
// Fill UCI configuration for PUSCH configuration
if (pusch_nr_fill_uci_cfg(q, cfg) < SRSRAN_SUCCESS) {
ERROR("Error filling UCI configuration for PUSCH");
// Compute DMRS pattern
if (srsran_dmrs_sch_rvd_re_pattern(&cfg->dmrs, grant, &q->dmrs_re_pattern) < SRSRAN_SUCCESS) {
ERROR("Error computing DMRS pattern");
return SRSRAN_ERROR;
}
@ -1194,7 +942,7 @@ int srsran_pusch_nr_decode(srsran_pusch_nr_t* q,
}
// Demapping from virtual to physical resource blocks
uint32_t nof_re_get = srsran_pusch_nr_get(q, cfg, grant, q->x[0], sf_symbols[0]);
uint32_t nof_re_get = pusch_nr_get(q, cfg, grant, q->x[0], sf_symbols[0]);
if (nof_re_get != nof_re) {
ERROR("Inconsistent number of RE (%d!=%d)", nof_re_get, nof_re);
return SRSRAN_ERROR;
@ -1239,14 +987,14 @@ int srsran_pusch_nr_decode(srsran_pusch_nr_t* q,
return SRSRAN_SUCCESS;
}
static uint32_t srsran_pusch_nr_grant_info(const srsran_sch_cfg_nr_t* cfg,
const srsran_sch_grant_nr_t* grant,
const srsran_pusch_res_nr_t* res,
char* str,
uint32_t str_len)
static uint32_t pusch_nr_grant_info(const srsran_pusch_nr_t* q,
const srsran_sch_cfg_nr_t* cfg,
const srsran_sch_grant_nr_t* grant,
const srsran_pusch_res_nr_t* res,
char* str,
uint32_t str_len)
{
uint32_t len = 0;
len = srsran_print_check(str, str_len, len, "rnti=0x%x", grant->rnti);
uint32_t first_prb = SRSRAN_MAX_PRB_NR;
for (uint32_t i = 0; i < SRSRAN_MAX_PRB_NR && first_prb == SRSRAN_MAX_PRB_NR; i++) {
@ -1256,29 +1004,20 @@ static uint32_t srsran_pusch_nr_grant_info(const srsran_sch_cfg_nr_t* cfg,
}
// Append time-domain resource mapping
len = srsran_print_check(str,
str_len,
len,
",k2=%d,prb=%d:%d,S=%d,L=%d,mapping=%s",
grant->k,
first_prb,
grant->nof_prb,
grant->S,
grant->L,
srsran_sch_mapping_type_to_str(grant->mapping));
// Skip frequency domain resources...
// ...
// Append spatial resources
len = srsran_print_check(str, str_len, len, ",Nl=%d", grant->nof_layers);
// Append scrambling ID
len = srsran_print_check(str, str_len, len, ",n_scid=%d,", grant->n_scid);
len = srsran_print_check(
str, str_len, len, "rnti=0x%x prb=%d:%d symb=%d:%d ", grant->rnti, first_prb, grant->nof_prb, grant->S, grant->L);
// Append TB info
for (uint32_t i = 0; i < SRSRAN_MAX_TB; i++) {
len += srsran_sch_nr_tb_info(&grant->tb[i], &res->tb[i], &str[len], str_len - len);
if (res != NULL) {
if (grant->tb[i].enabled && !isnan(res->evm[i])) {
len = srsran_print_check(str, str_len, len, "evm=%.2f ", res->evm[i]);
if (i < SRSRAN_MAX_CODEWORDS - 1) {
}
}
}
}
return len;
@ -1297,45 +1036,18 @@ uint32_t srsran_pusch_nr_rx_info(const srsran_pusch_nr_t* q,
return 0;
}
len += srsran_pusch_nr_grant_info(cfg, grant, res, &str[len], str_len - len);
len += pusch_nr_grant_info(q, cfg, grant, res, &str[len], str_len - len);
if (q->evm_buffer != NULL) {
len = srsran_print_check(str, str_len, len, ",evm={", 0);
for (uint32_t i = 0; i < SRSRAN_MAX_CODEWORDS; i++) {
if (grant->tb[i].enabled && !isnan(res->evm[i])) {
len = srsran_print_check(str, str_len, len, "%.2f", res[i].evm);
if (i < SRSRAN_MAX_CODEWORDS - 1) {
if (grant->tb[i + 1].enabled) {
len = srsran_print_check(str, str_len, len, ",", 0);
}
}
}
}
len = srsran_print_check(str, str_len, len, "}", 0);
}
if (res != NULL) {
if (res != NULL && srsran_uci_nr_total_bits(&cfg->uci) > 0) {
len = srsran_print_check(str, str_len, len, "UCI: ");
srsran_uci_data_nr_t uci_data = {};
uci_data.cfg = cfg->uci;
uci_data.value = res[0].uci;
uci_data.value = res->uci;
len += srsran_uci_nr_info(&uci_data, &str[len], str_len - len);
len = srsran_print_check(str, str_len, len, ",crc={", 0);
for (uint32_t i = 0; i < SRSRAN_MAX_CODEWORDS; i++) {
if (grant->tb[i].enabled) {
len = srsran_print_check(str, str_len, len, "%s", res->tb[i].crc ? "OK" : "KO");
if (i < SRSRAN_MAX_CODEWORDS - 1) {
if (grant->tb[i + 1].enabled) {
len = srsran_print_check(str, str_len, len, ",", 0);
}
}
}
}
len = srsran_print_check(str, str_len, len, "}", 0);
}
if (q->meas_time_en) {
len = srsran_print_check(str, str_len, len, ", t=%d us", q->meas_time_us);
len = srsran_print_check(str, str_len, len, "t_us=%d ", q->meas_time_us);
}
return len;
@ -1354,7 +1066,7 @@ uint32_t srsran_pusch_nr_tx_info(const srsran_pusch_nr_t* q,
return 0;
}
len += srsran_pusch_nr_grant_info(cfg, grant, NULL, &str[len], str_len - len);
len += pusch_nr_grant_info(q, cfg, grant, NULL, &str[len], str_len - len);
if (uci_value != NULL) {
srsran_uci_data_nr_t uci_data = {};
@ -1364,7 +1076,7 @@ uint32_t srsran_pusch_nr_tx_info(const srsran_pusch_nr_t* q,
}
if (q->meas_time_en) {
len = srsran_print_check(str, str_len, len, ", t=%d us", q->meas_time_us);
len = srsran_print_check(str, str_len, len, " t=%d us", q->meas_time_us);
}
return len;

@ -25,6 +25,7 @@
#include "srsran/phy/phch/pdsch_nr.h"
#include "srsran/phy/phch/ra_dl_nr.h"
#include "srsran/phy/phch/ra_ul_nr.h"
#include "srsran/phy/phch/uci_nr.h"
#include "srsran/phy/utils/debug.h"
typedef struct {
@ -686,6 +687,7 @@ int srsran_ra_dl_dci_to_grant_nr(const srsran_carrier_nr_t* carrier,
pdsch_grant->rnti_type = dci_dl->ctx.rnti_type;
pdsch_grant->tb[0].rv = dci_dl->rv;
pdsch_grant->tb[0].mcs = dci_dl->mcs;
pdsch_grant->tb[0].ndi = dci_dl->ndi;
// 5.1.4 PDSCH resource mapping
if (ra_dl_resource_mapping(carrier, slot, pdsch_hl_cfg, pdsch_cfg) < SRSRAN_SUCCESS) {
@ -797,7 +799,6 @@ int srsran_ra_ul_dci_to_grant_nr(const srsran_carrier_nr_t* carrier,
pusch_grant->tb[0].rv = dci_ul->rv;
pusch_grant->tb[0].mcs = dci_ul->mcs;
pusch_grant->tb[0].ndi = dci_ul->ndi;
pusch_grant->tb[0].pid = dci_ul->pid;
// 5.1.6.2 DM-RS reception procedure
if (ra_ul_dmrs(pusch_hl_cfg, pusch_grant, pusch_cfg) < SRSRAN_SUCCESS) {
@ -821,12 +822,16 @@ int srsran_ra_ul_dci_to_grant_nr(const srsran_carrier_nr_t* carrier,
static float ra_ul_beta_offset_ack_semistatic(const srsran_beta_offsets_t* beta_offsets,
const srsran_uci_cfg_nr_t* uci_cfg)
{
if (isnormal(beta_offsets->fix_ack)) {
return beta_offsets->fix_ack;
}
// Select Beta Offset index from the number of HARQ-ACK bits
uint32_t beta_offset_index = beta_offsets->ack_index1;
if (uci_cfg->o_ack > 11) {
beta_offset_index = beta_offsets->ack_index3;
} else if (uci_cfg->o_ack > 2) {
beta_offset_index = beta_offsets->ack_index1;
beta_offset_index = beta_offsets->ack_index2;
}
// Protect table boundary
@ -850,6 +855,11 @@ static float ra_ul_beta_offset_csi_semistatic(const srsran_beta_offsets_t* beta_
const srsran_uci_cfg_nr_t* uci_cfg,
bool part2)
{
float fix_beta_offset = part2 ? beta_offsets->fix_csi2 : beta_offsets->fix_csi1;
if (isnormal(fix_beta_offset)) {
return fix_beta_offset;
}
// Calculate number of CSI bits; CSI part 2 is not supported.
uint32_t O_csi = part2 ? 0 : srsran_csi_part1_nof_bits(uci_cfg->csi, uci_cfg->nof_csi);
@ -872,35 +882,162 @@ static float ra_ul_beta_offset_csi_semistatic(const srsran_beta_offsets_t* beta_
return ra_nr_beta_offset_csi_table[beta_offset_index];
}
int srsran_ra_ul_set_grant_uci_nr(const srsran_sch_hl_cfg_nr_t* pusch_hl_cfg,
int srsran_ra_ul_set_grant_uci_nr(const srsran_carrier_nr_t* carrier,
const srsran_sch_hl_cfg_nr_t* pusch_hl_cfg,
const srsran_uci_cfg_nr_t* uci_cfg,
srsran_sch_cfg_nr_t* pusch_cfg)
{
if (pusch_cfg->grant.nof_prb == 0) {
ERROR("Invalid number of PRB (%d)", pusch_cfg->grant.nof_prb);
return SRSRAN_ERROR;
}
// Initially, copy all fields
pusch_cfg->uci = *uci_cfg;
// Reset UCI PUSCH configuration
SRSRAN_MEM_ZERO(&pusch_cfg->uci.pusch, srsran_uci_nr_pusch_cfg_t, 1);
// Get DMRS symbol indexes
uint32_t nof_dmrs_l = 0;
uint32_t dmrs_l[SRSRAN_DMRS_SCH_MAX_SYMBOLS] = {};
int n = srsran_dmrs_sch_get_symbols_idx(&pusch_cfg->dmrs, &pusch_cfg->grant, dmrs_l);
if (n < SRSRAN_SUCCESS) {
return SRSRAN_ERROR;
}
nof_dmrs_l = (uint32_t)n;
// Find OFDM symbol index of the first OFDM symbol after the first set of consecutive OFDM symbol(s) carrying DMRS
// Starts at first OFDM symbol carrying DMRS
for (uint32_t l = dmrs_l[0], dmrs_l_idx = 0; l < pusch_cfg->grant.S + pusch_cfg->grant.L; l++) {
// Check if it is not carrying DMRS...
if (l != dmrs_l[dmrs_l_idx]) {
// Set value and stop iterating
pusch_cfg->uci.pusch.l0 = l;
break;
}
// Move to the next DMRS OFDM symbol index
if (dmrs_l_idx < nof_dmrs_l) {
dmrs_l_idx++;
}
}
// Find OFDM symbol index of the first OFDM symbol that does not carry DMRS
// Starts at first OFDM symbol of the PUSCH transmission
for (uint32_t l = pusch_cfg->grant.S, dmrs_l_idx = 0; l < pusch_cfg->grant.S + pusch_cfg->grant.L; l++) {
// Check if it is not carrying DMRS...
if (l != dmrs_l[dmrs_l_idx]) {
pusch_cfg->uci.pusch.l1 = l;
break;
}
// Move to the next DMRS OFDM symbol index
if (dmrs_l_idx < nof_dmrs_l) {
dmrs_l_idx++;
}
}
// Number of DMRS per PRB
uint32_t n_sc_dmrs = SRSRAN_DMRS_SCH_SC(pusch_cfg->grant.nof_dmrs_cdm_groups_without_data, pusch_cfg->dmrs.type);
// Set UCI RE number of candidates per OFDM symbol according to TS 38.312 6.3.2.4.2.1
for (uint32_t l = 0, dmrs_l_idx = 0; l < SRSRAN_NSYMB_PER_SLOT_NR; l++) {
// Skip if OFDM symbol is outside of the PUSCH transmission
if (l < pusch_cfg->grant.S || l >= (pusch_cfg->grant.S + pusch_cfg->grant.L)) {
pusch_cfg->uci.pusch.M_pusch_sc[l] = 0;
pusch_cfg->uci.pusch.M_uci_sc[l] = 0;
continue;
}
// OFDM symbol carries DMRS
if (l == dmrs_l[dmrs_l_idx]) {
// Calculate PUSCH RE candidates
pusch_cfg->uci.pusch.M_pusch_sc[l] = pusch_cfg->grant.nof_prb * (SRSRAN_NRE - n_sc_dmrs);
// The Number of RE candidates for UCI are 0
pusch_cfg->uci.pusch.M_uci_sc[l] = 0;
// Advance DMRS symbol index
dmrs_l_idx++;
// Skip to next symbol
continue;
}
// Number of RE for Phase Tracking Reference Signals (PT-RS)
uint32_t M_ptrs_sc = 0; // Not implemented yet
// Number of RE given by the grant
pusch_cfg->uci.pusch.M_pusch_sc[l] = pusch_cfg->grant.nof_prb * SRSRAN_NRE;
// Calculate the number of UCI candidates
pusch_cfg->uci.pusch.M_uci_sc[l] = pusch_cfg->uci.pusch.M_pusch_sc[l] - M_ptrs_sc;
}
// Generate SCH Transport block information
srsran_sch_nr_tb_info_t sch_tb_info = {};
if (srsran_sch_nr_fill_tb_info(carrier, &pusch_cfg->sch_cfg, &pusch_cfg->grant.tb[0], &sch_tb_info) <
SRSRAN_SUCCESS) {
ERROR("Generating TB info");
return SRSRAN_ERROR;
}
// Calculate the sum of codeblock sizes
for (uint32_t i = 0; i < sch_tb_info.C; i++) {
// Accumulate codeblock size if mask is enabled
pusch_cfg->uci.pusch.K_sum += (sch_tb_info.mask[i]) ? sch_tb_info.Kr : 0;
}
// Set other PUSCH parameters
pusch_cfg->uci.pusch.modulation = pusch_cfg->grant.tb[0].mod;
pusch_cfg->uci.pusch.nof_layers = pusch_cfg->grant.nof_layers;
pusch_cfg->uci.pusch.R = (float)pusch_cfg->grant.tb[0].R;
pusch_cfg->uci.pusch.nof_re = pusch_cfg->grant.tb[0].nof_re;
// Select beta offsets
pusch_cfg->beta_harq_ack_offset = ra_ul_beta_offset_ack_semistatic(&pusch_hl_cfg->beta_offsets, uci_cfg);
if (!isnormal(pusch_cfg->beta_harq_ack_offset)) {
pusch_cfg->uci.pusch.beta_harq_ack_offset = ra_ul_beta_offset_ack_semistatic(&pusch_hl_cfg->beta_offsets, uci_cfg);
if (!isnormal(pusch_cfg->uci.pusch.beta_harq_ack_offset)) {
return SRSRAN_ERROR;
}
pusch_cfg->beta_csi_part1_offset = ra_ul_beta_offset_csi_semistatic(&pusch_hl_cfg->beta_offsets, uci_cfg, false);
if (!isnormal(pusch_cfg->beta_csi_part1_offset)) {
pusch_cfg->uci.pusch.beta_csi1_offset = ra_ul_beta_offset_csi_semistatic(&pusch_hl_cfg->beta_offsets, uci_cfg, false);
if (!isnormal(pusch_cfg->uci.pusch.beta_csi1_offset)) {
return SRSRAN_ERROR;
}
pusch_cfg->beta_csi_part2_offset = ra_ul_beta_offset_csi_semistatic(&pusch_hl_cfg->beta_offsets, uci_cfg, true);
if (!isnormal(pusch_cfg->beta_csi_part2_offset)) {
pusch_cfg->uci.pusch.beta_csi2_offset = ra_ul_beta_offset_csi_semistatic(&pusch_hl_cfg->beta_offsets, uci_cfg, true);
if (!isnormal(pusch_cfg->uci.pusch.beta_csi2_offset)) {
return SRSRAN_ERROR;
}
// pusch_cfg->beta_csi_part2_offset = pusch_hl_cfg->beta_offset_csi2;
pusch_cfg->scaling = pusch_hl_cfg->scaling;
if (!isnormal(pusch_cfg->scaling)) {
ERROR("Invalid Scaling (%f)", pusch_cfg->scaling);
pusch_cfg->uci.pusch.alpha = pusch_hl_cfg->scaling;
if (!isnormal(pusch_cfg->uci.pusch.alpha)) {
ERROR("Invalid Scaling (%f)", pusch_cfg->uci.pusch.alpha);
return SRSRAN_ERROR;
}
// Copy UCI configuration
pusch_cfg->uci = *uci_cfg;
// Calculate number of UCI encoded bits
int Gack = 0;
if (pusch_cfg->uci.o_ack > 2) {
Gack = srsran_uci_nr_pusch_ack_nof_bits(&pusch_cfg->uci.pusch, pusch_cfg->uci.o_ack);
if (Gack < SRSRAN_SUCCESS) {
ERROR("Error calculating Qdack");
return SRSRAN_ERROR;
}
}
int Gcsi1 = srsran_uci_nr_pusch_csi1_nof_bits(&pusch_cfg->uci);
if (Gcsi1 < SRSRAN_SUCCESS) {
ERROR("Error calculating Qdack");
return SRSRAN_ERROR;
}
int Gcsi2 = 0; // NOT supported
// Update Number of TB encoded bits
for (uint32_t i = 0; i < SRSRAN_MAX_TB; i++) {
pusch_cfg->grant.tb[i].nof_bits =
pusch_cfg->grant.tb[i].nof_re * srsran_mod_bits_x_symbol(pusch_cfg->grant.tb[i].mod) - Gack - Gcsi1 - Gcsi2;
}
return SRSRAN_SUCCESS;
}

@ -743,15 +743,12 @@ int srsran_sch_nr_tb_info(const srsran_sch_tb_t* tb, const srsran_sch_tb_res_nr_
len = srsran_print_check(str,
str_len,
len,
"CW%d: mod=%s Nl=%d tbs=%d R=%.3f rv=%d Nre=%d Nbit=%d ",
"CW%d: mod=%s tbs=%d R=%.3f rv=%d ",
tb->cw_idx,
srsran_mod_string(tb->mod),
tb->N_L,
tb->tbs / 8,
tb->R,
tb->rv,
tb->nof_re,
tb->nof_bits);
tb->rv);
if (res != NULL) {
len = srsran_print_check(str, str_len, len, "CRC=%s iter=%.1f ", res->crc ? "OK" : "KO", res->avg_iter);

@ -25,11 +25,13 @@
#include <getopt.h>
static srsran_carrier_nr_t carrier = {
0, // cell_id
0, // numerology
50, // nof_prb
0, // start
1 // max_mimo_layers
1, // pci
0, // absolute_frequency_ssb
0, // absolute_frequency_point_a
srsran_subcarrier_spacing_15kHz, // scs
50, // nof_prb
0, // start
1 // max_mimo_layers
};
static uint16_t rnti = 0x1234;
@ -194,7 +196,7 @@ int main(int argc, char** argv)
aggregation_level++) {
uint32_t L = 1U << aggregation_level;
for (uint32_t slot_idx = 0; slot_idx < SRSRAN_NSLOTS_PER_FRAME_NR(carrier.numerology); slot_idx++) {
for (uint32_t slot_idx = 0; slot_idx < SRSRAN_NSLOTS_PER_FRAME_NR(carrier.scs); slot_idx++) {
uint32_t dci_locations[SRSRAN_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR] = {};
// Calculate candidate locations

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

@ -32,11 +32,13 @@
#include <unistd.h>
static srsran_carrier_nr_t carrier = {
0, // cell_id
0, // numerology
6, // nof_prb
0, // start
1 // max_mimo_layers
1, // pci
0, // absolute_frequency_ssb
0, // absolute_frequency_point_a
srsran_subcarrier_spacing_15kHz, // scs
6, // nof_prb
0, // start
1 // max_mimo_layers
};
static uint32_t starting_prb_stride = 4;
@ -52,7 +54,7 @@ static int test_pucch_format0(srsran_pucch_nr_t* pucch, const srsran_pucch_nr_co
srsran_pucch_nr_resource_t resource = {};
resource.format = SRSRAN_PUCCH_NR_FORMAT_0;
for (slot.idx = 0; slot.idx < SRSRAN_NSLOTS_PER_FRAME_NR(carrier.numerology); slot.idx++) {
for (slot.idx = 0; slot.idx < SRSRAN_NSLOTS_PER_FRAME_NR(carrier.scs); slot.idx++) {
for (resource.starting_prb = 0; resource.starting_prb < carrier.nof_prb;
resource.starting_prb += starting_prb_stride) {
for (resource.nof_symbols = 1; resource.nof_symbols <= 2; resource.nof_symbols++) {
@ -100,7 +102,7 @@ static int test_pucch_format1(srsran_pucch_nr_t* pucch,
srsran_pucch_nr_resource_t resource = {};
resource.format = SRSRAN_PUCCH_NR_FORMAT_1;
for (slot.idx = 0; slot.idx < SRSRAN_NSLOTS_PER_FRAME_NR(carrier.numerology); slot.idx++) {
for (slot.idx = 0; slot.idx < SRSRAN_NSLOTS_PER_FRAME_NR(carrier.scs); slot.idx++) {
for (resource.starting_prb = 0; resource.starting_prb < carrier.nof_prb;
resource.starting_prb += starting_prb_stride) {
for (resource.nof_symbols = SRSRAN_PUCCH_NR_FORMAT1_MIN_NSYMB;
@ -173,7 +175,7 @@ static int test_pucch_format2(srsran_pucch_nr_t* pucch,
srsran_pucch_nr_resource_t resource = {};
resource.format = SRSRAN_PUCCH_NR_FORMAT_2;
for (slot.idx = 0; slot.idx < SRSRAN_NSLOTS_PER_FRAME_NR(carrier.numerology); slot.idx++) {
for (slot.idx = 0; slot.idx < SRSRAN_NSLOTS_PER_FRAME_NR(carrier.scs); slot.idx++) {
for (resource.nof_symbols = SRSRAN_PUCCH_NR_FORMAT2_MIN_NSYMB;
resource.nof_symbols <= SRSRAN_PUCCH_NR_FORMAT2_MAX_NSYMB;
resource.nof_symbols++) {
@ -256,7 +258,7 @@ static int test_pucch_format2(srsran_pucch_nr_t* pucch,
static void usage(char* prog)
{
printf("Usage: %s [csNnv]\n", prog);
printf("\t-c cell id [Default %d]\n", carrier.id);
printf("\t-c cell id [Default %d]\n", carrier.pci);
printf("\t-n nof_prb [Default %d]\n", carrier.nof_prb);
printf("\t-f format [Default %d]\n", format);
printf("\t-s SNR in dB [Default %.2f]\n", snr_db);
@ -269,7 +271,7 @@ static void parse_args(int argc, char** argv)
while ((opt = getopt(argc, argv, "cnfsv")) != -1) {
switch (opt) {
case 'c':
carrier.id = (uint32_t)strtol(argv[optind], NULL, 10);
carrier.pci = (uint32_t)strtol(argv[optind], NULL, 10);
break;
case 'n':
carrier.nof_prb = (uint32_t)strtol(argv[optind], NULL, 10);

@ -29,11 +29,13 @@
#include <getopt.h>
static srsran_carrier_nr_t carrier = {
1, // cell_id
0, // numerology
SRSRAN_MAX_PRB_NR, // nof_prb
0, // start
1 // max_mimo_layers
1, // pci
0, // absolute_frequency_ssb
0, // absolute_frequency_point_a
srsran_subcarrier_spacing_15kHz, // scs
SRSRAN_MAX_PRB_NR, // nof_prb
0, // start
1 // max_mimo_layers
};
static uint32_t n_prb = 0; // Set to 0 for steering
@ -167,7 +169,7 @@ int main(int argc, char** argv)
}
// Use grant default A time resources with m=0
if (srsran_ra_ul_nr_pusch_time_resource_default_A(carrier.numerology, 0, &pusch_cfg.grant) < SRSRAN_SUCCESS) {
if (srsran_ra_ul_nr_pusch_time_resource_default_A(carrier.scs, 0, &pusch_cfg.grant) < SRSRAN_SUCCESS) {
ERROR("Error loading default grant");
goto clean_exit;
}
@ -196,9 +198,11 @@ int main(int argc, char** argv)
mcs_end = SRSRAN_MIN(mcs + 1, mcs_end);
}
pusch_cfg.scaling = 0.5f;
pusch_cfg.beta_harq_ack_offset = 2.0f;
pusch_cfg.beta_csi_part1_offset = 2.0f;
srsran_sch_hl_cfg_nr_t sch_hl_cfg = {};
sch_hl_cfg.scaling = 1.0f;
sch_hl_cfg.beta_offsets.fix_ack = 12.625f;
sch_hl_cfg.beta_offsets.fix_csi1 = 2.25f;
sch_hl_cfg.beta_offsets.fix_csi2 = 2.25f;
if (srsran_chest_dl_res_init(&chest, carrier.nof_prb) < SRSRAN_SUCCESS) {
ERROR("Initiating chest");
@ -254,6 +258,11 @@ int main(int argc, char** argv)
data_rx.uci.csi[0].none = csi_report_rx;
}
if (srsran_ra_ul_set_grant_uci_nr(&carrier, &sch_hl_cfg, &pusch_cfg.uci, &pusch_cfg) < SRSRAN_SUCCESS) {
ERROR("Setting UCI");
goto clean_exit;
}
if (srsran_pusch_nr_encode(&pusch_tx, &pusch_cfg, &pusch_cfg.grant, &data_tx, sf_symbols) < SRSRAN_SUCCESS) {
ERROR("Error encoding");
goto clean_exit;
@ -349,6 +358,15 @@ int main(int argc, char** argv)
}
}
if (srsran_verbose >= SRSRAN_VERBOSE_INFO) {
char str[512];
srsran_pusch_nr_rx_info(&pusch_rx, &pusch_cfg, &pusch_cfg.grant, &data_rx, str, (uint32_t)sizeof(str));
char str_extra[2048];
srsran_sch_cfg_nr_info(&pusch_cfg, str_extra, (uint32_t)sizeof(str_extra));
INFO("PUSCH: %s\n%s", str, str_extra);
}
printf("n_prb=%d; mcs=%d; TBS=%d; EVM=%f; PASSED!\n", n_prb, mcs, pusch_cfg.grant.tb[0].tbs, data_rx.evm[0]);
}
}

@ -28,11 +28,13 @@
#include <srsran/phy/utils/random.h>
static srsran_carrier_nr_t carrier = {
0, // cell_id
0, // numerology
SRSRAN_MAX_PRB_NR, // nof_prb
0, // start
1 // max_mimo_layers
1, // pci
0, // absolute_frequency_ssb
0, // absolute_frequency_point_a
srsran_subcarrier_spacing_15kHz, // scs
SRSRAN_MAX_PRB_NR, // nof_prb
0, // start
1 // max_mimo_layers
};
static uint32_t n_prb = 0; // Set to 0 for steering

@ -392,16 +392,18 @@ static int uci_nr_decode_1_bit(srsran_uci_nr_t* q,
}
// Correlate LLR
float corr = 0.0f;
float pwr = 0.0f;
float corr = 0.0f;
float pwr = 0.0f;
uint32_t count = 0;
for (uint32_t i = 0; i < E; i += Qm) {
float t = (float)llr[i];
corr += t;
pwr += t * t;
count++;
}
// Normalise correlation
float norm_corr = Qm * corr / (E * sqrtf(pwr));
float norm_corr = fabsf(corr) / sqrtf(pwr * count);
// Take decoded decision with threshold
*decoded_ok = (norm_corr > q->one_bit_threshold);
@ -995,9 +997,9 @@ uint32_t srsran_uci_nr_info(const srsran_uci_data_nr_t* uci_data, char* str, uin
uint32_t len = 0;
if (uci_data->cfg.o_ack > 0) {
char str2[10];
srsran_vec_sprint_bin(str2, 10, uci_data->value.ack, uci_data->cfg.o_ack);
len = srsran_print_check(str, str_len, len, ", ack=%s", str2);
char str_ack[10];
srsran_vec_sprint_bin(str_ack, (uint32_t)sizeof(str_ack), uci_data->value.ack, uci_data->cfg.o_ack);
len = srsran_print_check(str, str_len, len, "ack=%s ", str_ack);
}
if (uci_data->cfg.nof_csi > 0) {
@ -1005,7 +1007,7 @@ uint32_t srsran_uci_nr_info(const srsran_uci_data_nr_t* uci_data, char* str, uin
}
if (uci_data->cfg.o_sr > 0) {
len = srsran_print_check(str, str_len, len, ", sr=%d", uci_data->value.sr);
len = srsran_print_check(str, str_len, len, "sr=%d ", uci_data->value.sr);
}
return len;

@ -33,6 +33,7 @@ private:
uhd::stream_args_t stream_args = {};
double lo_freq_tx_hz = 0.0;
double lo_freq_rx_hz = 0.0;
double lo_freq_offset_hz = 0.0;
uhd_error usrp_make_internal(const uhd::device_addr_t& dev_addr) override
{
@ -170,6 +171,20 @@ public:
dev_addr.pop("lo_freq_rx_hz");
}
// LO Frequency offset automatic
if (dev_addr.has_key("lo_freq_offset_hz")) {
lo_freq_offset_hz = dev_addr.cast("lo_freq_offset_hz", lo_freq_offset_hz);
dev_addr.pop("lo_freq_offset_hz");
if (std::isnormal(lo_freq_tx_hz)) {
Warning("'lo_freq_offset_hz' overrides 'lo_freq_tx_hz' (" << lo_freq_tx_hz / 1e6 << " MHz)");
}
if (std::isnormal(lo_freq_rx_hz)) {
Warning("'lo_freq_offset_hz' overrides 'lo_freq_rx_hz' (" << lo_freq_rx_hz / 1e6 << " MHz)");
}
}
// Make USRP
uhd_error err = usrp_multi_make(dev_addr);
if (err != UHD_ERROR_NONE) {
@ -348,6 +363,10 @@ public:
// Create Tune request
uhd::tune_request_t tune_request(target_freq);
if (std::isnormal(lo_freq_offset_hz)) {
lo_freq_tx_hz = target_freq + lo_freq_offset_hz;
}
// If the LO frequency is defined, force a LO frequency and use the
if (std::isnormal(lo_freq_tx_hz)) {
tune_request.rf_freq = lo_freq_tx_hz;
@ -365,6 +384,10 @@ public:
// Create Tune request
uhd::tune_request_t tune_request(target_freq);
if (std::isnormal(lo_freq_offset_hz)) {
lo_freq_rx_hz = target_freq + lo_freq_offset_hz;
}
// If the LO frequency is defined, force a LO frequency and use the
if (std::isnormal(lo_freq_rx_hz)) {
tune_request.rf_freq = lo_freq_rx_hz;

@ -382,7 +382,7 @@ static int ue_dl_nr_find_dci_ss(srsran_ue_dl_nr_t* q,
// Calculate possible PDCCH DCI candidates
uint32_t candidates[SRSRAN_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR] = {};
int nof_candidates = srsran_pdcch_nr_locations_coreset(
coreset, search_space, rnti, L, SRSRAN_SLOT_NR_MOD(q->carrier.numerology, slot_cfg->idx), candidates);
coreset, search_space, rnti, L, SRSRAN_SLOT_NR_MOD(q->carrier.scs, slot_cfg->idx), candidates);
if (nof_candidates < SRSRAN_SUCCESS) {
ERROR("Error calculating DCI candidate location");
return SRSRAN_ERROR;

@ -132,6 +132,13 @@ int srsran_ue_ul_nr_encode_pusch(srsran_ue_ul_nr_t* q,
// Generate signal
srsran_ofdm_tx_sf(&q->ifft);
// Normalise to peak
uint32_t max_idx = srsran_vec_max_abs_ci(q->ifft.cfg.out_buffer, q->ifft.sf_sz);
float max_peak = cabsf(q->ifft.cfg.out_buffer[max_idx]);
if (isnormal(max_peak)) {
srsran_vec_sc_prod_cfc(q->ifft.cfg.out_buffer, 0.99f / max_peak, q->ifft.cfg.out_buffer, q->ifft.sf_sz);
}
return SRSRAN_SUCCESS;
}

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

@ -728,7 +728,7 @@ void pdcp_entity_lte::notify_delivery(const pdcp_sn_vector_t& pdcp_sns)
}
// Find undelivered PDU info
if (not undelivered_sdus->has_sdu(sn)) {
logger.warning("Could not find PDU for delivery notification. Notified SN=%d", sn);
logger.info("Could not find PDU for delivery notification. Notified SN=%d", sn);
} else {
// Metrics
auto& sdu = (*undelivered_sdus)[sn];

@ -54,6 +54,16 @@ rlc::~rlc()
pthread_rwlock_destroy(&rwlock);
}
void rlc::init(srsue::pdcp_interface_rlc* pdcp_,
srsue::rrc_interface_rlc* rrc_,
srsue::rrc_interface_rlc* rrc_nr_,
srsran::timer_handler* timers_,
uint32_t lcid_)
{
init(pdcp_, rrc_, timers_, lcid_);
rrc_nr = rrc_nr_;
}
void rlc::init(srsue::pdcp_interface_rlc* pdcp_,
srsue::rrc_interface_rlc* rrc_,
srsran::timer_handler* timers_,
@ -157,7 +167,7 @@ void rlc::reestablish()
void rlc::reestablish(uint32_t lcid)
{
if (valid_lcid(lcid)) {
logger.info("Reestablishing %s", rrc->get_rb_name(lcid));
logger.info("Reestablishing LCID %d", lcid);
rlc_array.at(lcid)->reestablish();
} else {
logger.warning("RLC LCID %d doesn't exist.", lcid);
@ -404,6 +414,12 @@ void rlc::add_bearer(uint32_t lcid, const rlc_config_t& cnfg)
rlc_common* rlc_entity = nullptr;
// Check this for later rrc_nr pointer access
if (cnfg.rat == srsran::srsran_rat_t::nr && rrc_nr == nullptr) {
logger.error("Cannot add/modify RLC entity - missing rrc_nr parent pointer for rat type nr");
return;
}
if (cnfg.rlc_mode != rlc_mode_t::tm and rlc_array.find(lcid) != rlc_array.end()) {
if (rlc_array[lcid]->get_mode() != cnfg.rlc_mode) {
logger.info("Switching RLC entity type. Recreating it.");
@ -412,46 +428,51 @@ void rlc::add_bearer(uint32_t lcid, const rlc_config_t& cnfg)
}
if (not valid_lcid(lcid)) {
if (cnfg.rat == srsran_rat_t::lte) {
switch (cnfg.rlc_mode) {
case rlc_mode_t::tm:
rlc_entity = new rlc_tm(logger, lcid, pdcp, rrc);
break;
case rlc_mode_t::am:
rlc_entity = new rlc_am_lte(logger, lcid, pdcp, rrc, timers);
break;
case rlc_mode_t::um:
rlc_entity = new rlc_um_lte(logger, lcid, pdcp, rrc, timers);
break;
default:
logger.error("Cannot add RLC entity - invalid mode");
return;
}
if (rlc_entity != nullptr) {
rlc_entity->set_bsr_callback(bsr_callback);
}
} else if (cnfg.rat == srsran_rat_t::nr) {
switch (cnfg.rlc_mode) {
case rlc_mode_t::tm:
rlc_entity = new rlc_tm(logger, lcid, pdcp, rrc);
break;
case rlc_mode_t::um:
rlc_entity = new rlc_um_nr(logger, lcid, pdcp, rrc, timers);
break;
default:
logger.error("Cannot add RLC entity - invalid mode");
return;
}
} else {
logger.error("RAT not supported");
return;
switch (cnfg.rat) {
case srsran_rat_t::lte:
switch (cnfg.rlc_mode) {
case rlc_mode_t::tm:
rlc_entity = new rlc_tm(logger, lcid, pdcp, rrc);
break;
case rlc_mode_t::am:
rlc_entity = new rlc_am_lte(logger, lcid, pdcp, rrc, timers);
break;
case rlc_mode_t::um:
rlc_entity = new rlc_um_lte(logger, lcid, pdcp, rrc, timers);
break;
default:
logger.error("Cannot add RLC entity - invalid mode");
return;
}
if (rlc_entity != nullptr) {
rlc_entity->set_bsr_callback(bsr_callback);
}
break;
case srsran_rat_t::nr:
switch (cnfg.rlc_mode) {
case rlc_mode_t::tm:
rlc_entity = new rlc_tm(logger, lcid, pdcp, rrc_nr);
break;
case rlc_mode_t::um:
rlc_entity = new rlc_um_nr(logger, lcid, pdcp, rrc_nr, timers);
break;
default:
logger.error("Cannot add RLC entity - invalid mode");
return;
}
break;
default:
logger.error("RAT not supported");
return;
}
if (not rlc_array.insert(rlc_map_pair_t(lcid, rlc_entity)).second) {
logger.error("Error inserting RLC entity in to array.");
goto delete_and_exit;
}
logger.info("Added radio bearer %s in %s", rrc->get_rb_name(lcid), to_string(cnfg.rlc_mode).c_str());
logger.info(
"Added %s radio bearer with LCID %d in %s", to_string(cnfg.rat), lcid, to_string(cnfg.rlc_mode).c_str());
rlc_entity = NULL;
}
@ -463,7 +484,8 @@ void rlc::add_bearer(uint32_t lcid, const rlc_config_t& cnfg)
}
}
logger.info("Configured radio bearer %s in %s", rrc->get_rb_name(lcid), to_string(cnfg.rlc_mode).c_str());
logger.info(
"Configured %s radio bearer with LCID %d in %s", to_string(cnfg.rat), lcid, to_string(cnfg.rlc_mode).c_str());
delete_and_exit:
if (rlc_entity) {
@ -510,9 +532,9 @@ void rlc::del_bearer(uint32_t lcid)
it->second->stop();
delete (it->second);
rlc_array.erase(it);
logger.warning("Deleted RLC bearer %s", rrc->get_rb_name(lcid));
logger.info("Deleted RLC bearer with LCID %d", lcid);
} else {
logger.error("Can't delete bearer %s. Bearer doesn't exist.", rrc->get_rb_name(lcid));
logger.error("Can't delete bearer with LCID %d. Bearer doesn't exist.", lcid);
}
}
@ -525,9 +547,9 @@ void rlc::del_bearer_mrb(uint32_t lcid)
it->second->stop();
delete (it->second);
rlc_array_mrb.erase(it);
logger.warning("Deleted RLC MRB bearer %s", rrc->get_rb_name(lcid));
logger.warning("Deleted RLC MRB bearer with LCID %d", lcid);
} else {
logger.error("Can't delete bearer %s. Bearer doesn't exist.", rrc->get_rb_name(lcid));
logger.error("Can't delete bearer with LCID %d. Bearer doesn't exist.", lcid);
}
}
@ -553,8 +575,7 @@ void rlc::change_lcid(uint32_t old_lcid, uint32_t new_lcid)
logger.error("Error during LCID change of RLC bearer from %d to %d", old_lcid, new_lcid);
}
} else {
logger.error("Can't change LCID of bearer %s from %d to %d. Bearer doesn't exist or new LCID already occupied.",
rrc->get_rb_name(old_lcid),
logger.error("Can't change LCID of bearer LCID %d to %d. Bearer doesn't exist or new LCID already occupied.",
old_lcid,
new_lcid);
}
@ -565,26 +586,26 @@ void rlc::suspend_bearer(uint32_t lcid)
{
if (valid_lcid(lcid)) {
if (rlc_array.at(lcid)->suspend()) {
logger.info("Suspended radio bearer %s", rrc->get_rb_name(lcid));
logger.info("Suspended radio bearer with LCID %d", lcid);
} else {
logger.error("Error suspending RLC entity: bearer already suspended.");
}
} else {
logger.error("Suspending bearer: bearer %s not configured.", rrc->get_rb_name(lcid));
logger.error("Suspending bearer: bearer with LCID %d not configured.", lcid);
}
}
void rlc::resume_bearer(uint32_t lcid)
{
logger.info("Resuming radio bearer %s", rrc->get_rb_name(lcid));
logger.info("Resuming radio LCID %d", lcid);
if (valid_lcid(lcid)) {
if (rlc_array.at(lcid)->resume()) {
logger.info("Resumed radio bearer %s", rrc->get_rb_name(lcid));
logger.info("Resumed radio LCID %d", lcid);
} else {
logger.error("Error resuming RLC entity: bearer not suspended.");
}
} else {
logger.error("Resuming bearer: bearer %s not configured.", rrc->get_rb_name(lcid));
logger.error("Resuming bearer: bearer with LCID %d not configured.", lcid);
}
}

@ -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));
}
/*******************************
* RLC AM Segments
******************************/
int rlc_am_pdu_segment_pool::segment_resource::id() const
{
return std::distance(parent_pool->segments.cbegin(), this);
}
void rlc_am_pdu_segment_pool::segment_resource::release_pdcp_sn()
{
pdcp_sn_ = invalid_pdcp_sn;
if (empty()) {
parent_pool->free_list.push_front(this);
}
}
void rlc_am_pdu_segment_pool::segment_resource::release_rlc_sn()
{
rlc_sn_ = invalid_rlc_sn;
if (empty()) {
parent_pool->free_list.push_front(this);
}
}
rlc_am_pdu_segment_pool::rlc_am_pdu_segment_pool()
{
for (segment_resource& s : segments) {
s.parent_pool = this;
free_list.push_front(&s);
}
}
bool rlc_am_pdu_segment_pool::make_segment(rlc_amd_tx_pdu& rlc_list, pdcp_pdu_info& pdcp_list)
{
if (not has_segments()) {
return false;
}
segment_resource* segment = free_list.pop_front();
segment->rlc_sn_ = rlc_list.rlc_sn;
segment->pdcp_sn_ = pdcp_list.sn;
rlc_list.add_segment(*segment);
pdcp_list.add_segment(*segment);
return true;
}
void pdcp_pdu_info::ack_segment(rlc_am_pdu_segment& segment)
{
// remove from list
list.pop(&segment);
// signal pool that the pdcp handle is released
segment.release_pdcp_sn();
}
rlc_amd_tx_pdu::~rlc_amd_tx_pdu()
{
while (not list.empty()) {
// remove from list
rlc_am_pdu_segment* segment = list.pop_front();
// deallocate if also removed from PDCP
segment->release_rlc_sn();
}
}
/*******************************
* rlc_am_lte class
******************************/
@ -325,7 +389,7 @@ bool rlc_am_lte::rlc_am_lte_tx::has_data()
{
return (((do_status() && not status_prohibit_timer.is_running())) || // if we have a status PDU to transmit
(not retx_queue.empty()) || // if we have a retransmission
(tx_sdu != NULL) || // if we are currently transmitting a SDU
(tx_sdu != nullptr) || // if we are currently transmitting a SDU
(tx_sdu_queue.get_n_sdus() != 0)); // or if there is a SDU queued up for transmission
}
@ -341,9 +405,13 @@ bool rlc_am_lte::rlc_am_lte_tx::has_data()
void rlc_am_lte::rlc_am_lte_tx::check_sn_reached_max_retx(uint32_t sn)
{
if (tx_window[sn].retx_count == cfg.max_retx_thresh) {
logger.warning("%s Signaling max number of reTx=%d for for SN=%d", RB_NAME, tx_window[sn].retx_count, sn);
logger.warning("%s Signaling max number of reTx=%d for SN=%d", RB_NAME, tx_window[sn].retx_count, sn);
parent->rrc->max_retx_attempted();
parent->pdcp->notify_failure(parent->lcid, tx_window[sn].pdcp_sns);
srsran::pdcp_sn_vector_t pdcp_sns;
for (const rlc_am_pdu_segment& segment : tx_window[sn]) {
pdcp_sns.push_back(segment.pdcp_sn());
}
parent->pdcp->notify_failure(parent->lcid, pdcp_sns);
parent->metrics.num_lost_pdus++;
}
}
@ -560,7 +628,7 @@ void rlc_am_lte::rlc_am_lte_tx::retransmit_pdu()
}
// select first PDU in tx window for retransmission
rlc_amd_tx_pdu_t& pdu = tx_window[vt_a];
rlc_amd_tx_pdu& pdu = tx_window[vt_a];
logger.info("%s Schedule SN=%d for reTx.", RB_NAME, pdu.rlc_sn);
rlc_amd_retx_t& retx = retx_queue.push();
retx.is_segment = false;
@ -921,7 +989,7 @@ int rlc_am_lte::rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_byt
srsran::console("tx_window size: %zd PDUs\n", tx_window.size());
srsran::console("vt_a = %d, vt_ms = %d, vt_s = %d, poll_sn = %d\n", vt_a, vt_ms, vt_s, poll_sn);
srsran::console("retx_queue size: %zd PDUs\n", retx_queue.size());
std::map<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++) {
srsran::console("tx_window - SN=%d\n", txit->first);
}
@ -936,10 +1004,14 @@ int rlc_am_lte::rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_byt
header.fi = RLC_FI_FIELD_START_AND_END_ALIGNED;
header.sn = vt_s;
if (not segment_pool.has_segments()) {
logger.info("Can't build a PDU - No segments available");
return 0;
}
// insert newly assigned SN into window and use reference for in-place operations
// NOTE: from now on, we can't return from this function anymore before increasing vt_s
rlc_amd_tx_pdu_t& tx_pdu = tx_window.add_pdu(header.sn);
tx_pdu.pdcp_sns.clear();
rlc_amd_tx_pdu& tx_pdu = tx_window.add_pdu(header.sn);
uint32_t head_len = rlc_am_packed_length(&header);
uint32_t to_move = 0;
@ -959,15 +1031,10 @@ int rlc_am_lte::rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_byt
tx_sdu->N_bytes -= to_move;
tx_sdu->msg += to_move;
if (undelivered_sdu_info_queue.has_pdcp_sn(tx_sdu->md.pdcp_sn)) {
pdcp_sdu_info_t& pdcp_sdu = undelivered_sdu_info_queue[tx_sdu->md.pdcp_sn];
pdcp_sdu.rlc_sn_info_list.push_back({header.sn, false});
if (not tx_pdu.pdcp_sns.full()) {
tx_pdu.pdcp_sns.push_back(tx_sdu->md.pdcp_sn);
} else {
logger.warning("Cant't store PDCP_SN=%d for delivery notification.", tx_sdu->md.pdcp_sn);
}
pdcp_pdu_info& pdcp_pdu = undelivered_sdu_info_queue[tx_sdu->md.pdcp_sn];
segment_pool.make_segment(tx_pdu, pdcp_pdu);
if (tx_sdu->N_bytes == 0) {
pdcp_sdu.fully_txed = true;
pdcp_pdu.fully_txed = true;
}
} else {
// PDCP SNs for the RLC SDU has been removed from the queue
@ -996,6 +1063,14 @@ int rlc_am_lte::rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_byt
// Pull SDUs from queue
while (pdu_space > head_len && tx_sdu_queue.get_n_sdus() > 0 && header.N_li < RLC_AM_WINDOW_SIZE) {
if (not segment_pool.has_segments()) {
logger.info("Can't build a PDU segment - No segment resources available");
if (pdu_ptr != pdu->msg) {
break; // continue with the segments created up to this point
}
tx_window.remove_pdu(tx_pdu.rlc_sn);
return 0;
}
if (last_li > 0) {
header.li[header.N_li] = last_li;
header.N_li++;
@ -1027,15 +1102,10 @@ int rlc_am_lte::rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_byt
tx_sdu->N_bytes -= to_move;
tx_sdu->msg += to_move;
if (undelivered_sdu_info_queue.has_pdcp_sn(tx_sdu->md.pdcp_sn)) {
pdcp_sdu_info_t& pdcp_sdu = undelivered_sdu_info_queue[tx_sdu->md.pdcp_sn];
pdcp_sdu.rlc_sn_info_list.push_back({header.sn, false});
if (not tx_pdu.pdcp_sns.full()) {
tx_pdu.pdcp_sns.push_back(tx_sdu->md.pdcp_sn);
} else {
logger.warning("Cant't store PDCP_SN=%d for delivery notification.", tx_sdu->md.pdcp_sn);
}
pdcp_pdu_info& pdcp_pdu = undelivered_sdu_info_queue[tx_sdu->md.pdcp_sn];
segment_pool.make_segment(tx_pdu, pdcp_pdu);
if (tx_sdu->N_bytes == 0) {
pdcp_sdu.fully_txed = true;
pdcp_pdu.fully_txed = true;
}
} else {
// PDCP SNs for the RLC SDU has been removed from the queue
@ -1090,9 +1160,6 @@ int rlc_am_lte::rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_byt
// Write final header and TX
tx_pdu.buf = std::move(pdu);
tx_pdu.header = header;
tx_pdu.is_acked = false;
tx_pdu.retx_count = 0;
tx_pdu.rlc_sn = header.sn;
const byte_buffer_t* buffer_ptr = tx_pdu.buf.get();
uint8_t* ptr = payload;
@ -1193,8 +1260,8 @@ void rlc_am_lte::rlc_am_lte_tx::handle_control_pdu(uint8_t* payload, uint32_t no
if (!nack) {
// ACKed SNs get marked and removed from tx_window so PDCP get's only notified once
if (tx_window.has_sn(i)) {
auto& pdu = tx_window[i];
update_notification_ack_info(pdu);
update_notification_ack_info(i);
logger.debug("Tx PDU SN=%zd being removed from tx window", i);
tx_window.remove_pdu(i);
}
// Advance window if possible
@ -1211,17 +1278,6 @@ void rlc_am_lte::rlc_am_lte_tx::handle_control_pdu(uint8_t* payload, uint32_t no
logger.error("%s vt_a=%d points to invalid position in Tx window", RB_NAME, vt_a);
}
if (not notify_info_vec.empty()) {
// Remove all SDUs that were fully acked
for (uint32_t acked_pdcp_sn : notify_info_vec) {
logger.debug("Erasing SDU info: PDCP_SN=%d", acked_pdcp_sn);
if (not undelivered_sdu_info_queue.has_pdcp_sn(acked_pdcp_sn)) {
logger.error("Could not find info to erase: SN=%d", acked_pdcp_sn);
}
undelivered_sdu_info_queue.clear_pdcp_sdu(acked_pdcp_sn);
}
}
debug_state();
lock.unlock();
@ -1238,42 +1294,37 @@ void rlc_am_lte::rlc_am_lte_tx::handle_control_pdu(uint8_t* payload, uint32_t no
* @tx_pdu: RLC PDU that was ack'ed.
* @notify_info_vec: Vector which will keep track of the PDCP PDU SNs that have been fully ack'ed.
*/
void rlc_am_lte::rlc_am_lte_tx::update_notification_ack_info(const rlc_amd_tx_pdu_t& tx_pdu)
void rlc_am_lte::rlc_am_lte_tx::update_notification_ack_info(uint32_t rlc_sn)
{
logger.debug("Updating ACK info: RLC SN=%d, number of notified SDU=%ld, number of undelivered SDUs=%ld",
tx_pdu.header.sn,
rlc_sn,
notify_info_vec.size(),
undelivered_sdu_info_queue.nof_sdus());
// Iterate over all undelivered SDUs
if (not tx_window.has_sn(tx_pdu.header.sn)) {
if (not tx_window.has_sn(rlc_sn)) {
return;
}
pdcp_sn_vector_t& pdcp_sns = tx_window[tx_pdu.header.sn].pdcp_sns;
for (uint32_t pdcp_sn : pdcp_sns) {
// Iterate over all SNs that were TX'ed
auto& info = undelivered_sdu_info_queue[pdcp_sn];
for (auto& rlc_sn_info : info.rlc_sn_info_list) {
// Mark this SN as acked, if necessary
if (rlc_sn_info.is_acked == false && rlc_sn_info.sn == tx_pdu.header.sn) {
rlc_sn_info.is_acked = true;
}
}
// Check wether the SDU was fully acked
if (info.fully_txed and not info.fully_acked) {
auto& acked_pdu = tx_window[rlc_sn];
// Iterate over all PDCP SNs of the same RLC PDU that were TX'ed
for (rlc_am_pdu_segment& acked_segment : acked_pdu) {
uint32_t pdcp_sn = acked_segment.pdcp_sn();
pdcp_pdu_info& info = undelivered_sdu_info_queue[pdcp_sn];
// Remove RLC SN from PDCP PDU undelivered list
info.ack_segment(acked_segment);
// Check whether the SDU was fully acked
if (info.fully_acked()) {
// Check if all SNs were ACK'ed
info.fully_acked = std::all_of(info.rlc_sn_info_list.begin(),
info.rlc_sn_info_list.end(),
[](rlc_sn_info_t rlc_sn_info) { return rlc_sn_info.is_acked; });
if (info.fully_acked) {
if (not notify_info_vec.full()) {
notify_info_vec.push_back(pdcp_sn);
} else {
logger.warning("Can't notify delivery of PDCP_SN=%d.", pdcp_sn);
}
if (not notify_info_vec.full()) {
notify_info_vec.push_back(pdcp_sn);
} else {
logger.warning("Can't notify delivery of PDCP_SN=%d.", pdcp_sn);
}
logger.debug("Erasing SDU info: PDCP_SN=%d", pdcp_sn);
undelivered_sdu_info_queue.clear_pdcp_sdu(pdcp_sn);
}
}
pdcp_sns.clear();
}
void rlc_am_lte::rlc_am_lte_tx::debug_state()
@ -1425,7 +1476,7 @@ void rlc_am_lte::rlc_am_lte_rx::stop()
*/
void rlc_am_lte::rlc_am_lte_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_bytes, rlc_amd_pdu_header_t& header)
{
std::map<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);
log_rlc_amd_pdu_header_to_string(logger.debug, header);
@ -1461,8 +1512,8 @@ void rlc_am_lte::rlc_am_lte_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_b
}
// Write to rx window
rlc_amd_rx_pdu_t& pdu = rx_window.add_pdu(header.sn);
pdu.buf = srsran::make_byte_buffer();
rlc_amd_rx_pdu& pdu = rx_window.add_pdu(header.sn);
pdu.buf = srsran::make_byte_buffer();
if (pdu.buf == NULL) {
#ifdef RLC_AM_BUFFER_DEBUG
srsran::console("Fatal Error: Couldn't allocate PDU in handle_data_pdu().\n");
@ -1566,7 +1617,7 @@ void rlc_am_lte::rlc_am_lte_rx::handle_data_pdu_segment(uint8_t* pa
return;
}
rlc_amd_rx_pdu_t segment;
rlc_amd_rx_pdu segment;
segment.buf = srsran::make_byte_buffer();
if (segment.buf == NULL) {
#ifdef RLC_AM_BUFFER_DEBUG
@ -1759,7 +1810,7 @@ void rlc_am_lte::rlc_am_lte_rx::reassemble_rx_sdus()
it = rx_segments.find(vr_r);
if (rx_segments.end() != it) {
logger.debug("Erasing segments of SN=%d", vr_r);
std::list<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) {
logger.debug(" Erasing segment of SN=%d SO=%d Len=%d N_li=%d",
segit->header.sn,
@ -1921,7 +1972,7 @@ void rlc_am_lte::rlc_am_lte_rx::print_rx_segments()
std::stringstream ss;
ss << "rx_segments:" << std::endl;
for (it = rx_segments.begin(); it != rx_segments.end(); it++) {
std::list<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++) {
ss << " SN=" << segit->header.sn << " SO:" << segit->header.so << " N:" << segit->buf->N_bytes
<< " N_li: " << segit->header.N_li << std::endl;
@ -1931,7 +1982,7 @@ void rlc_am_lte::rlc_am_lte_rx::print_rx_segments()
}
// NOTE: Preference would be to capture by value, and then move; but header is stack allocated
bool rlc_am_lte::rlc_am_lte_rx::add_segment_and_check(rlc_amd_rx_pdu_segments_t* pdu, rlc_amd_rx_pdu_t* segment)
bool rlc_am_lte::rlc_am_lte_rx::add_segment_and_check(rlc_amd_rx_pdu_segments_t* pdu, rlc_amd_rx_pdu* segment)
{
// Find segment insertion point in the list of segments
auto it1 = pdu->segments.begin();
@ -1943,7 +1994,7 @@ bool rlc_am_lte::rlc_am_lte_rx::add_segment_and_check(rlc_amd_rx_pdu_segments_t*
// Check if the insertion point was found
if (it1 != pdu->segments.end()) {
// Found insertion point
rlc_amd_rx_pdu_t& s = *it1;
rlc_amd_rx_pdu& s = *it1;
if (s.header.so == segment->header.so) {
// Same Segment offset
if (segment->buf->N_bytes > s.buf->N_bytes) {
@ -1961,8 +2012,8 @@ bool rlc_am_lte::rlc_am_lte_rx::add_segment_and_check(rlc_amd_rx_pdu_segments_t*
}
// Check for complete
uint32_t so = 0;
std::list<rlc_amd_rx_pdu_t>::iterator it, tmpit;
uint32_t so = 0;
std::list<rlc_amd_rx_pdu>::iterator it, tmpit;
for (it = pdu->segments.begin(); it != pdu->segments.end(); /* Do not increment */) {
// Check that there is no gap between last segment and current; overlap allowed
if (so < it->header.so) {
@ -2125,24 +2176,16 @@ void rlc_am_lte::rlc_am_lte_rx::debug_state()
logger.debug("%s vr_r = %d, vr_mr = %d, vr_x = %d, vr_ms = %d, vr_h = %d", RB_NAME, vr_r, vr_mr, vr_x, vr_ms, vr_h);
}
const size_t buffered_pdcp_pdu_list::max_buffer_idx;
buffered_pdcp_pdu_list::buffered_pdcp_pdu_list() : buffered_pdus(max_buffer_idx + 1)
buffered_pdcp_pdu_list::buffered_pdcp_pdu_list() : buffered_pdus(buffered_pdcp_pdu_list::buffer_size)
{
for (size_t i = 0; i < buffered_pdus.size(); ++i) {
buffered_pdus[i].rlc_sn_info_list.reserve(5);
}
clear();
}
void buffered_pdcp_pdu_list::clear()
{
count = 0;
for (auto& b : buffered_pdus) {
b.sn = invalid_sn;
b.fully_acked = false;
b.fully_txed = false;
b.rlc_sn_info_list.clear();
for (pdcp_pdu_info& b : buffered_pdus) {
b.clear();
}
}
@ -2402,26 +2445,16 @@ bool rlc_am_is_pdu_segment(uint8_t* payload)
return ((*(payload) >> 6) & 0x01) == 1;
}
std::string rlc_am_undelivered_sdu_info_to_string(const std::map<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";
for (const auto& info_it : info_queue) {
uint32_t pdcp_sn = info_it.first;
auto info = info_it.second;
std::string tmp_str = fmt::format("\tPDCP_SN = {}, RLC_SNs = [", pdcp_sn);
for (auto rlc_sn_info : info.rlc_sn_info_list) {
std::string tmp_str2;
if (rlc_sn_info.is_acked) {
tmp_str2 = fmt::format("ACK={}, ", rlc_sn_info.sn);
} else {
tmp_str2 = fmt::format("NACK={}, ", rlc_sn_info.sn);
}
tmp_str += tmp_str2;
fmt::format_to(buffer, "\n");
for (const auto& pdcp_pdu : info_queue) {
fmt::format_to(buffer, "\tPDCP_SN = {}, undelivered RLC SNs = [", pdcp_pdu.sn);
for (const auto& nacked_segment : pdcp_pdu) {
fmt::format_to(buffer, "{} ", nacked_segment.rlc_sn());
}
tmp_str += "]\n";
str += tmp_str;
fmt::format_to(buffer, "]\n");
}
return str;
}
void log_rlc_amd_pdu_header_to_string(srslog::log_channel& log_ch, const rlc_amd_pdu_header_t& header)

@ -20,7 +20,7 @@
*/
#include "srsran/upper/rlc_tm.h"
#include "srsran/common/lte_common.h"
#include "srsran/common/common_lte.h"
#include "srsran/interfaces/ue_pdcp_interfaces.h"
#include "srsran/interfaces/ue_rrc_interfaces.h"

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

@ -22,6 +22,39 @@
#include "srsran/adt/bounded_bitset.h"
#include "srsran/common/test_common.h"
void test_bit_operations()
{
TESTASSERT(0 == srsran::mask_lsb_ones<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()
{
srsran::bounded_bitset<25> mask;
@ -185,14 +218,77 @@ int test_bitset_resize()
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()
{
test_bit_operations();
TESTASSERT(test_zero_bitset() == SRSRAN_SUCCESS);
TESTASSERT(test_ones_bitset() == SRSRAN_SUCCESS);
TESTASSERT(test_bitset_set() == SRSRAN_SUCCESS);
TESTASSERT(test_bitset_bitwise_oper() == SRSRAN_SUCCESS);
TESTASSERT(test_bitset_print() == SRSRAN_SUCCESS);
TESTASSERT(test_bitset_resize() == SRSRAN_SUCCESS);
test_bitset_find<false>();
test_bitset_find<true>();
printf("Success\n");
return 0;
}

@ -135,7 +135,7 @@ int make_phy_coreset_cfg_test()
srsran_coreset_t srsran_coreset;
TESTASSERT(make_phy_coreset_cfg(ctrl_res_set, &srsran_coreset) == true);
TESTASSERT(srsran_coreset.coreset_id == 1);
TESTASSERT(srsran_coreset.id == 1);
TESTASSERT(srsran_coreset.precoder_granularity == srsran_coreset_precoder_granularity_reg_bundle);
TESTASSERT(srsran_coreset.duration == 1);
TESTASSERT(srsran_coreset.mapping_type == srsran_coreset_mapping_type_non_interleaved);
@ -555,6 +555,127 @@ int make_phy_pusch_scaling_test()
return SRSRAN_SUCCESS;
}
int make_phy_zp_csi_rs_resource_test()
{
srsran_csi_rs_zp_resource_t zp_csi_rs_resource0 = {};
// Item 0
// ZP-CSI-RS-Resource
// zp-CSI-RS-ResourceId: 0
// resourceMapping
// frequencyDomainAllocation: row4 (2)
// row4: 80 [bit length 3, 5 LSB pad bits, 100. ....
// decimal value 4]
// nrofPorts: p4 (2)
// firstOFDMSymbolInTimeDomain: 8
// cdm-Type: fd-CDM2 (1)
// density: one (1)
// one: NULL
// freqBand
// startingRB: 0
// nrofRBs: 52
// periodicityAndOffset: slots80 (9)
// slots80: 1
asn1::rrc_nr::zp_csi_rs_res_s zp_csi_rs_res0;
zp_csi_rs_res0.res_map.freq_domain_alloc.set_row4();
zp_csi_rs_res0.res_map.freq_domain_alloc.row4().from_string("100");
zp_csi_rs_res0.res_map.nrof_ports = csi_rs_res_map_s::nrof_ports_opts::options::p4;
zp_csi_rs_res0.res_map.first_ofdm_symbol_in_time_domain = 8;
zp_csi_rs_res0.res_map.cdm_type = csi_rs_res_map_s::cdm_type_opts::options::fd_cdm2;
zp_csi_rs_res0.res_map.density.set_one();
zp_csi_rs_res0.res_map.freq_band.start_rb = 0;
zp_csi_rs_res0.res_map.freq_band.nrof_rbs = 52;
zp_csi_rs_res0.periodicity_and_offset_present = true;
zp_csi_rs_res0.periodicity_and_offset.set_slots80() = 1;
TESTASSERT(make_phy_zp_csi_rs_resource(zp_csi_rs_res0, &zp_csi_rs_resource0) == true);
TESTASSERT(zp_csi_rs_resource0.resource_mapping.row == srsran_csi_rs_resource_mapping_row_4);
TESTASSERT(zp_csi_rs_resource0.resource_mapping.frequency_domain_alloc[0] == true);
TESTASSERT(zp_csi_rs_resource0.resource_mapping.frequency_domain_alloc[1] == false);
TESTASSERT(zp_csi_rs_resource0.resource_mapping.frequency_domain_alloc[2] == false);
TESTASSERT(zp_csi_rs_resource0.resource_mapping.nof_ports == 4);
TESTASSERT(zp_csi_rs_resource0.resource_mapping.first_symbol_idx == 8);
TESTASSERT(zp_csi_rs_resource0.resource_mapping.cdm == srsran_csi_rs_cdm_fd_cdm2);
TESTASSERT(zp_csi_rs_resource0.resource_mapping.density == srsran_csi_rs_resource_mapping_density_one);
TESTASSERT(zp_csi_rs_resource0.resource_mapping.freq_band.start_rb == 0);
TESTASSERT(zp_csi_rs_resource0.resource_mapping.freq_band.nof_rb == 52);
TESTASSERT(zp_csi_rs_resource0.periodicity.period == 80);
TESTASSERT(zp_csi_rs_resource0.periodicity.offset == 1);
return SRSRAN_SUCCESS;
}
int make_phy_nzp_csi_rs_resource_test()
{
// nzp-CSI-RS-ResourceToAddModList: 5 items
// Item 0
// NZP-CSI-RS-Resource
// nzp-CSI-RS-ResourceId: 0
// resourceMapping
// frequencyDomainAllocation: row2 (1)
// row2: 8000 [bit length 12, 4 LSB pad bits, 1000 0000 0000 .... decimal value 2048]
// nrofPorts: p1 (0)
// firstOFDMSymbolInTimeDomain: 4
// cdm-Type: noCDM (0)
// density: one (1)
// one: NULL
// freqBand
// startingRB: 0
// nrofRBs: 52
// powerControlOffset: 0dB
// powerControlOffsetSS: db0 (1)
// scramblingID: 0
// periodicityAndOffset: slots80 (9)
// slots80: 1
// qcl-InfoPeriodicCSI-RS: 0
asn1::rrc_nr::nzp_csi_rs_res_s nzp_csi_rs_res;
nzp_csi_rs_res.nzp_csi_rs_res_id = 0;
nzp_csi_rs_res.res_map.freq_domain_alloc.set_row2();
nzp_csi_rs_res.res_map.freq_domain_alloc.row2().from_string("100000000000");
nzp_csi_rs_res.res_map.nrof_ports = csi_rs_res_map_s::nrof_ports_opts::options::p1;
nzp_csi_rs_res.res_map.first_ofdm_symbol_in_time_domain = 4;
nzp_csi_rs_res.res_map.cdm_type = csi_rs_res_map_s::cdm_type_opts::options::no_cdm;
nzp_csi_rs_res.res_map.density.set_one();
nzp_csi_rs_res.res_map.freq_band.start_rb = 0;
nzp_csi_rs_res.res_map.freq_band.nrof_rbs = 52;
nzp_csi_rs_res.pwr_ctrl_offset = 0;
nzp_csi_rs_res.pwr_ctrl_offset_ss_present = true;
nzp_csi_rs_res.pwr_ctrl_offset_ss = nzp_csi_rs_res_s::pwr_ctrl_offset_ss_opts::options::db0;
nzp_csi_rs_res.scrambling_id = 0;
nzp_csi_rs_res.periodicity_and_offset_present = true;
nzp_csi_rs_res.periodicity_and_offset.set_slots80() = 1;
srsran_csi_rs_nzp_resource_t nzp_resource_0;
TESTASSERT(make_phy_nzp_csi_rs_resource(nzp_csi_rs_res, &nzp_resource_0) == true);
TESTASSERT(nzp_resource_0.resource_mapping.row == srsran_csi_rs_resource_mapping_row_2);
TESTASSERT(nzp_resource_0.resource_mapping.frequency_domain_alloc[0] == true);
TESTASSERT(nzp_resource_0.resource_mapping.frequency_domain_alloc[1] == false);
TESTASSERT(nzp_resource_0.resource_mapping.frequency_domain_alloc[2] == false);
TESTASSERT(nzp_resource_0.resource_mapping.frequency_domain_alloc[3] == false);
TESTASSERT(nzp_resource_0.resource_mapping.frequency_domain_alloc[4] == false);
TESTASSERT(nzp_resource_0.resource_mapping.frequency_domain_alloc[5] == false);
TESTASSERT(nzp_resource_0.resource_mapping.frequency_domain_alloc[6] == false);
TESTASSERT(nzp_resource_0.resource_mapping.frequency_domain_alloc[7] == false);
TESTASSERT(nzp_resource_0.resource_mapping.frequency_domain_alloc[8] == false);
TESTASSERT(nzp_resource_0.resource_mapping.frequency_domain_alloc[9] == false);
TESTASSERT(nzp_resource_0.resource_mapping.frequency_domain_alloc[10] == false);
TESTASSERT(nzp_resource_0.resource_mapping.frequency_domain_alloc[11] == false);
TESTASSERT(nzp_resource_0.resource_mapping.nof_ports == 1);
TESTASSERT(nzp_resource_0.resource_mapping.first_symbol_idx == 4);
TESTASSERT(nzp_resource_0.resource_mapping.cdm == srsran_csi_rs_cdm_nocdm);
TESTASSERT(nzp_resource_0.resource_mapping.density == srsran_csi_rs_resource_mapping_density_one);
TESTASSERT(nzp_resource_0.resource_mapping.freq_band.start_rb == 0);
TESTASSERT(nzp_resource_0.resource_mapping.freq_band.nof_rb == 52);
TESTASSERT(nzp_resource_0.power_control_offset == 0);
TESTASSERT(nzp_resource_0.power_control_offset_ss == 0);
TESTASSERT(nzp_resource_0.scrambling_id == 0);
TESTASSERT(nzp_resource_0.periodicity.period == 80);
TESTASSERT(nzp_resource_0.periodicity.offset == 1);
return SRSRAN_SUCCESS;
}
int main()
{
auto& asn1_logger = srslog::fetch_basic_logger("ASN1", false);
@ -581,7 +702,8 @@ int main()
TESTASSERT(make_phy_dmrs_additional_pos_test() == SRSRAN_SUCCESS);
TESTASSERT(make_phy_beta_offsets_test() == SRSRAN_SUCCESS);
TESTASSERT(make_phy_pusch_scaling_test() == SRSRAN_SUCCESS);
TESTASSERT(make_phy_zp_csi_rs_resource_test() == SRSRAN_SUCCESS);
TESTASSERT(make_phy_nzp_csi_rs_resource_test() == SRSRAN_SUCCESS);
srslog::flush();
printf("Success\n");

@ -29,12 +29,13 @@
#include <getopt.h>
static srsran_carrier_nr_t carrier = {
501, // cell_id
0, // numerology
52, // nof_prb
0, // start
1 // max_mimo_layers
501, // pci
0, // absolute_frequency_ssb
0, // absolute_frequency_point_a
srsran_subcarrier_spacing_15kHz, // scs
52, // nof_prb
0, // start
1 // max_mimo_layers
};
static uint32_t n_prb = 0; // Set to 0 for steering
@ -222,7 +223,6 @@ int main(int argc, char** argv)
ue_dl_args.pdsch.sch.disable_simd = false;
ue_dl_args.pdsch.sch.decoder_use_flooded = false;
ue_dl_args.pdsch.measure_evm = true;
ue_dl_args.pdsch.disable_zero_re_around_dc = true;
ue_dl_args.pdcch.disable_simd = false;
ue_dl_args.pdcch.measure_evm = true;
ue_dl_args.nof_max_prb = carrier.nof_prb;
@ -384,7 +384,7 @@ int main(int argc, char** argv)
search_space,
pdsch_cfg.grant.rnti,
L,
SRSRAN_SLOT_NR_MOD(carrier.numerology, slot.idx),
SRSRAN_SLOT_NR_MOD(carrier.scs, slot.idx),
ncce_candidates);
if (nof_candidates < SRSRAN_SUCCESS) {
ERROR("Error getting PDCCH candidates");
@ -416,7 +416,7 @@ int main(int argc, char** argv)
// Emulate channel CFO
if (isnormal(cfo_hz) && ue_dl.fft[0].cfg.symbol_sz > 0) {
srsran_vec_apply_cfo(buffer_ue[0],
cfo_hz / (ue_dl.fft[0].cfg.symbol_sz * SRSRAN_SUBC_SPACING_NR(carrier.numerology)),
cfo_hz / (ue_dl.fft[0].cfg.symbol_sz * SRSRAN_SUBC_SPACING_NR(carrier.scs)),
buffer_ue[0],
sf_len);
}
@ -457,6 +457,15 @@ int main(int argc, char** argv)
}
}
if (srsran_verbose >= SRSRAN_VERBOSE_INFO) {
char str[512];
srsran_ue_dl_nr_pdsch_info(&ue_dl, &pdsch_cfg, &pdsch_res, str, (uint32_t)sizeof(str));
char str_extra[2048];
srsran_sch_cfg_nr_info(&pdsch_cfg, str_extra, (uint32_t)sizeof(str_extra));
INFO("PDSCH: %s\n%s", str, str_extra);
}
INFO("n_prb=%d; mcs=%d; TBS=%d; EVM=%f; PASSED!", n_prb, mcs, pdsch_cfg.grant.tb[0].tbs, pdsch_res.evm[0]);
// Count the Tx/Rx'd number of bits

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

@ -35,7 +35,8 @@ int test_tx_sdu_notify(const srsran::pdcp_lte_state_t& init_state,
srsran::PDCP_SN_LEN_12,
srsran::pdcp_t_reordering_t::ms500,
discard_timeout,
false};
false,
srsran::srsran_rat_t::lte};
pdcp_lte_test_helper pdcp_hlp(cfg, sec_cfg, logger);
srsran::pdcp_entity_lte* pdcp = &pdcp_hlp.pdcp;
@ -84,7 +85,8 @@ int test_tx_sdu_discard(const srsran::pdcp_lte_state_t& init_state,
srsran::PDCP_SN_LEN_12,
srsran::pdcp_t_reordering_t::ms500,
discard_timeout,
false};
false,
srsran::srsran_rat_t::lte};
pdcp_lte_test_helper pdcp_hlp(cfg, sec_cfg, logger);
srsran::pdcp_entity_lte* pdcp = &pdcp_hlp.pdcp;

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

@ -33,7 +33,8 @@ int test_tx_status_report(const srsran::pdcp_lte_state_t& init_state, srslog::ba
srsran::PDCP_SN_LEN_12,
srsran::pdcp_t_reordering_t::ms500,
srsran::pdcp_discard_timer_t::ms500,
true};
true,
srsran::srsran_rat_t::lte};
srsran::pdcp_config_t cfg_rx = {1,
srsran::PDCP_RB_IS_DRB,
@ -42,7 +43,8 @@ int test_tx_status_report(const srsran::pdcp_lte_state_t& init_state, srslog::ba
srsran::PDCP_SN_LEN_12,
srsran::pdcp_t_reordering_t::ms500,
srsran::pdcp_discard_timer_t::ms500,
true};
true,
srsran::srsran_rat_t::lte};
// Setup TX
pdcp_lte_test_helper pdcp_hlp_tx(cfg_tx, sec_cfg, logger);
@ -137,7 +139,8 @@ int test_tx_wraparound_status_report(const srsran::pdcp_lte_state_t& init_state,
srsran::PDCP_SN_LEN_12,
srsran::pdcp_t_reordering_t::ms500,
srsran::pdcp_discard_timer_t::ms500,
true};
true,
srsran::srsran_rat_t::lte};
srsran::pdcp_config_t cfg_rx = {1,
srsran::PDCP_RB_IS_DRB,
@ -146,7 +149,8 @@ int test_tx_wraparound_status_report(const srsran::pdcp_lte_state_t& init_state,
srsran::PDCP_SN_LEN_12,
srsran::pdcp_t_reordering_t::ms500,
srsran::pdcp_discard_timer_t::ms500,
true};
true,
srsran::srsran_rat_t::lte};
// Setup TX
pdcp_lte_test_helper pdcp_hlp_tx(cfg_tx, sec_cfg, logger);
@ -249,7 +253,8 @@ int test_rx_status_report(const srsran::pdcp_lte_state_t& init_state, srslog::ba
srsran::PDCP_SN_LEN_12,
srsran::pdcp_t_reordering_t::ms500,
srsran::pdcp_discard_timer_t::ms500,
true};
true,
srsran::srsran_rat_t::lte};
pdcp_lte_test_helper pdcp_hlp(cfg, sec_cfg, logger);
srsran::pdcp_entity_lte* pdcp = &pdcp_hlp.pdcp;

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

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

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

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

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

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

@ -1011,7 +1011,7 @@ int set_derived_args(all_args_t* args_, rrc_cfg_t* rrc_cfg_, phy_cfg_t* phy_cfg_
phy_cell_cfg_nr_t phy_cell_cfg = {};
phy_cell_cfg.carrier.max_mimo_layers = cell_cfg_.nof_ports;
phy_cell_cfg.carrier.nof_prb = cell_cfg_.nof_prb;
phy_cell_cfg.carrier.id = cfg.pci;
phy_cell_cfg.carrier.pci = cfg.pci;
phy_cell_cfg.cell_id = cfg.cell_id;
phy_cell_cfg.root_seq_idx = cfg.root_seq_idx;
phy_cell_cfg.rf_port = cfg.rf_port;

@ -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<int, SRSRAN_MAX_CARRIERS> enb_ue_cc_map = get_enb_ue_cc_map(rnti);
std::array<bool, SRSRAN_MAX_CARRIERS> scell_mask = {};
for (int ue_cc : enb_ue_cc_map) {
if (ue_cc <= 0) {
// inactive or PCell
continue;
std::array<bool, SRSRAN_MAX_CARRIERS> scell_mask = {};
ue_db_access_locked(rnti, [this, &scell_mask](sched_ue& ue) {
for (size_t enb_cc_idx = 0; enb_cc_idx < carrier_schedulers.size(); ++enb_cc_idx) {
const sched_ue_cell* cc_ue = ue.find_ue_carrier(enb_cc_idx);
if (cc_ue != nullptr and (cc_ue->cc_state() == cc_st::active or cc_ue->cc_state() == cc_st::activating)) {
scell_mask[cc_ue->get_ue_cc_idx()] = true;
}
}
scell_mask[ue_cc] = true;
}
});
return scell_mask;
}

@ -86,10 +86,12 @@ void sched_ue::set_cfg(const ue_cfg_t& cfg_)
scell_activation_state_changed |=
c.is_scell() and (c.cc_state() == cc_st::activating or c.cc_state() == cc_st::deactivating);
}
if (prev_supported_cc_list.empty() or prev_supported_cc_list[0].enb_cc_idx != cfg.supported_cc_list[0].enb_cc_idx) {
bool is_handover = not prev_supported_cc_list.empty() and
prev_supported_cc_list[0].enb_cc_idx != cfg.supported_cc_list[0].enb_cc_idx;
if (prev_supported_cc_list.empty() or is_handover) {
logger.info("SCHED: rnti=0x%x PCell is now enb_cc_idx=%d", rnti, cfg.supported_cc_list[0].enb_cc_idx);
}
if (scell_activation_state_changed) {
if (scell_activation_state_changed and not is_handover) {
lch_handler.pending_ces.emplace_back(srsran::dl_sch_lcid::SCELL_ACTIVATION);
logger.info("SCHED: Enqueueing SCell Activation CMD for rnti=0x%x", rnti);
}

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

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

@ -844,8 +844,8 @@ void rrc::ue::rrc_mobility::handle_ho_requested(idle_st& s, const ho_req_rx_ev&
logger.error("Failed to allocate GTPU TEID for E-RAB id=%d", fwd_erab.erab_id);
not_admitted_erabs.emplace_back();
not_admitted_erabs.back().erab_id = erab.second.id;
not_admitted_erabs.back().cause.set_radio_network().value =
asn1::s1ap::cause_radio_network_opts::no_radio_res_available_in_target_cell;
not_admitted_erabs.back().cause.set_transport().value =
asn1::s1ap::cause_transport_opts::transport_res_unavailable;
admitted_erabs.pop_back();
continue;
}
@ -921,8 +921,8 @@ bool rrc::ue::rrc_mobility::apply_ho_prep_cfg(const ho_prep_info_r8_ies_s&
if (rrc_ue->bearer_list.add_gtpu_bearer(erab.erab_id) != SRSRAN_SUCCESS) {
erabs_failed_to_setup.emplace_back();
erabs_failed_to_setup.back().erab_id = erab.erab_id;
erabs_failed_to_setup.back().cause.set_radio_network().value =
asn1::s1ap::cause_radio_network_opts::no_radio_res_available_in_target_cell;
erabs_failed_to_setup.back().cause.set_transport().value =
asn1::s1ap::cause_transport_opts::transport_res_unavailable;
continue;
}
}

@ -19,10 +19,10 @@
*
*/
#include "srsran/common/common_nr.h"
#include "srsran/asn1/rrc_nr_utils.h"
#include "srsenb/hdr/stack/rrc/rrc_nr.h"
#include "srsenb/hdr/common/common_enb.h"
#include "srsran/asn1/rrc_nr_utils.h"
#include "srsran/interfaces/nr_common_interface_types.h"
using namespace asn1::rrc_nr;
@ -74,7 +74,8 @@ int rrc_nr::init(const rrc_nr_cfg_t& cfg_,
srsran::PDCP_SN_LEN_18,
srsran::pdcp_t_reordering_t::ms500,
srsran::pdcp_discard_timer_t::infinity,
false};
false,
srsran::srsran_rat_t::nr};
pdcp->add_bearer(cfg.coreless.rnti, cfg.coreless.drb_lcid, pdcp_cnfg);
logger.info("Started");
@ -320,16 +321,16 @@ void rrc_nr::get_metrics(srsenb::rrc_metrics_t& m)
void rrc_nr::handle_pdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t pdu)
{
if (pdu) {
logger.info(pdu->msg, pdu->N_bytes, "Rx %s PDU", srsran::to_string(static_cast<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) {
switch (static_cast<srsran::rb_id_nr_t>(lcid)) {
case srsran::rb_id_nr_t::NR_SRB0:
switch (static_cast<srsran::nr_srb>(lcid)) {
case srsran::nr_srb::srb0:
// parse_ul_ccch(rnti, std::move(pdu));
break;
case srsran::rb_id_nr_t::NR_SRB1:
case srsran::rb_id_nr_t::NR_SRB2:
case srsran::nr_srb::srb1:
case srsran::nr_srb::srb2:
// parse_ul_dcch(p.rnti, p.lcid, std::move(p.pdu));
break;
default:
@ -405,7 +406,7 @@ void rrc_nr::ue::send_dl_ccch(dl_ccch_msg_s* dl_ccch_msg)
char buf[32] = {};
sprintf(buf, "SRB0 - rnti=0x%x", rnti);
parent->log_rrc_message(buf, Tx, pdu.get(), *dl_ccch_msg);
parent->rlc->write_sdu(rnti, srsran::NR_SRB0, std::move(pdu));
parent->rlc->write_sdu(rnti, (uint32_t)srsran::nr_srb::srb0, std::move(pdu));
}
} // namespace srsenb

@ -20,7 +20,6 @@
*/
#include "srsenb/hdr/stack/upper/pdcp_nr.h"
#include "lib/include/srsran/interfaces/nr_common_interface_types.h"
#include "srsenb/hdr/common/common_enb.h"
namespace srsenb {

@ -20,8 +20,7 @@
*/
#include "srsenb/hdr/stack/upper/rlc_nr.h"
#include "srsran/interfaces/nr_common_interface_types.h"
#include "srsran/common/common_nr.h"
namespace srsenb {
rlc_nr::rlc_nr(const char* logname) : logger(srslog::fetch_basic_logger(logname)) {}
@ -55,7 +54,7 @@ void rlc_nr::add_user(uint16_t rnti)
user_itf.parent = this;
user_itf.m_rlc.reset(new srsran::rlc(logger.id().c_str()));
users[rnti] = std::move(user_itf);
users[rnti].m_rlc->init(&users[rnti], &users[rnti], timers, (int)srsran::rb_id_nr_t::NR_SRB0);
users[rnti].m_rlc->init(&users[rnti], &users[rnti], timers, (int)srsran::nr_srb::srb0);
}
}
@ -189,7 +188,7 @@ void rlc_nr::user_interface::max_retx_attempted()
void rlc_nr::user_interface::write_pdu(uint32_t lcid, srsran::unique_byte_buffer_t sdu)
{
if (lcid == (int)srsran::rb_id_nr_t::NR_SRB0) {
if (lcid == (int)srsran::nr_srb::srb0) {
m_rrc->write_pdu(rnti, lcid, std::move(sdu));
} else {
m_pdcp->write_pdu(rnti, lcid, std::move(sdu));
@ -213,7 +212,7 @@ void rlc_nr::user_interface::write_pdu_pcch(srsran::unique_byte_buffer_t sdu)
const char* rlc_nr::user_interface::get_rb_name(uint32_t lcid)
{
return srsran::to_string(static_cast<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)

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

@ -22,7 +22,7 @@
#include "sched_test_common.h"
#include "sched_test_utils.h"
#include "srsenb/hdr/stack/mac/sched.h"
#include "srsran/common/lte_common.h"
#include "srsran/common/common_lte.h"
#include "srsran/mac/pdu.h"
using namespace srsenb;

@ -22,7 +22,7 @@
#include "sched_test_utils.h"
#include "srsenb/hdr/stack/mac/sched_common.h"
#include "srsenb/hdr/stack/mac/sched_phy_ch/sched_dci.h"
#include "srsran/common/lte_common.h"
#include "srsran/common/common_lte.h"
#include "srsran/common/test_common.h"
namespace srsenb {

@ -21,7 +21,7 @@
#include "sched_test_common.h"
#include "srsenb/hdr/stack/mac/sched_grid.h"
#include "srsran/common/lte_common.h"
#include "srsran/common/common_lte.h"
#include "srsran/common/test_common.h"
using namespace srsenb;

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

@ -48,6 +48,10 @@ public:
int read_pdsch_d(cf_t* pdsch_d);
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;
srsran_slot_cfg_t dl_slot_cfg = {};
srsran_slot_cfg_t ul_slot_cfg = {};
@ -60,10 +64,7 @@ private:
srsran_ue_ul_nr_t ue_ul = {};
srslog::basic_logger& logger;
// Temporal attributes
srsran_softbuffer_rx_t softbuffer_rx = {};
// Methods for DL...
// Methods for DCI blind search
void decode_pdcch_ul();
void decode_pdcch_dl();
};

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

@ -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
#define SRSUE_MAC_NR_H
#include "dl_harq_nr.h"
#include "mac_nr_interfaces.h"
#include "proc_bsr_nr.h"
#include "proc_ra_nr.h"
#include "proc_sr_nr.h"
#include "srsran/common/block_queue.h"
#include "srsran/common/mac_pcap.h"
#include "srsran/interfaces/mac_interface_types.h"
#include "srsran/interfaces/ue_nr_interfaces.h"
#include "srsran/srslog/srslog.h"
#include "srsue/hdr/stack/mac_common/mac_common.h"
#include "srsue/hdr/stack/mac_nr/demux_nr.h"
#include "srsue/hdr/stack/mac_nr/mux_nr.h"
#include "srsue/hdr/stack/ue_stack_base.h"
#include "ul_harq_nr.h"
@ -53,7 +54,7 @@ public:
mac_nr(srsran::ext_task_sched_handle task_sched_);
~mac_nr();
int init(const mac_nr_args_t& args_, phy_interface_mac_nr* phy, rlc_interface_mac* rlc, rrc_interface_mac* rrc_);
int init(const mac_nr_args_t& args_, phy_interface_mac_nr* phy_, rlc_interface_mac* rlc_, rrc_interface_mac* rrc_);
void stop();
void reset();
@ -68,7 +69,8 @@ public:
sched_rnti_t get_ul_sched_rnti_nr(const uint32_t tti);
int sf_indication(const uint32_t tti);
void tb_decoded(const uint32_t cc_idx, mac_nr_grant_dl_t& grant);
void tb_decoded(const uint32_t cc_idx, const mac_nr_grant_dl_t& grant, tb_action_dl_result_t result);
void new_grant_dl(const uint32_t cc_idx, const mac_nr_grant_dl_t& grant, tb_action_dl_t* action);
void new_grant_ul(const uint32_t cc_idx, const mac_nr_grant_ul_t& grant, tb_action_ul_t* action);
void prach_sent(const uint32_t tti,
const uint32_t s_id,
@ -86,6 +88,7 @@ public:
int set_config(const srsran::bsr_cfg_nr_t& bsr_cfg);
int set_config(const srsran::sr_cfg_nr_t& sr_cfg);
void set_config(const srsran::rach_nr_cfg_t& rach_cfg);
int set_config(const srsran::dl_harq_cfg_nr_t& dl_hrq_cfg);
void set_contention_id(const uint64_t ue_identity);
bool set_crnti(const uint16_t crnti);
int add_tag_config(const srsran::tag_cfg_nr_t& tag_cfg);
@ -120,7 +123,9 @@ public:
static bool is_in_window(uint32_t tti, int* start, int* len);
private:
void write_pcap(const uint32_t cc_idx, mac_nr_grant_dl_t& grant); // If PCAPs are enabled for this MAC
void write_pcap(const uint32_t cc_idx,
const mac_nr_grant_dl_t& grant,
tb_action_dl_result_t& tb); // If PCAPs are enabled for this MAC
void handle_pdu(srsran::unique_byte_buffer_t pdu);
void get_ul_data(const mac_nr_grant_ul_t& grant, srsran::byte_buffer_t* tx_pdu);
@ -154,14 +159,8 @@ private:
uint16_t c_rnti = SRSRAN_INVALID_RNTI;
uint64_t contention_id = 0;
srsran::block_queue<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 = {};
/// Rx buffer
srsran::mac_sch_pdu_nr rx_pdu;
srsran::task_multiqueue::queue_handle stack_task_dispatch_queue;
// MAC Uplink-related procedures
@ -169,10 +168,11 @@ private:
proc_sr_nr proc_sr;
proc_bsr_nr proc_bsr;
mux_nr mux;
demux_nr demux;
// UL HARQ
// DL/UL HARQ
dl_harq_entity_nr_vector dl_harq = {};
ul_harq_entity_nr_vector ul_harq = {};
ul_harq_cfg_t ul_harq_cfg;
const uint8_t PCELL_CC_IDX = 0;
};

@ -86,6 +86,16 @@ public:
virtual uint16_t get_csrnti() = 0;
};
/**
* @brief Interface from HARQ class to demux class
*/
class demux_interface_harq_nr
{
public:
/// Inform demux unit about a newly decoded TB.
virtual void push_pdu(srsran::unique_byte_buffer_t pdu, uint32_t tti) = 0;
};
} // namespace srsue
#endif // SRSUE_MAC_NR_INTERFACES_H

@ -52,7 +52,7 @@ public:
// PHY interfaces
void prach_sent(uint32_t tti, uint32_t s_id, uint32_t t_id, uint32_t f_id, uint32_t ul_carrier_id);
void handle_rar_pdu(mac_interface_phy_nr::mac_nr_grant_dl_t& grant);
void handle_rar_pdu(mac_interface_phy_nr::tb_action_dl_result_t& grant);
void pdcch_to_crnti();
void start_by_rrc();
@ -113,7 +113,7 @@ private:
void ra_procedure_initialization();
void ra_resource_selection();
void ra_preamble_transmission();
void ra_response_reception(const mac_interface_phy_nr::mac_nr_grant_dl_t& grant);
void ra_response_reception(const mac_interface_phy_nr::tb_action_dl_result_t& tb);
void ra_contention_resolution();
void ra_contention_resolution(uint64_t rx_contention_id);
void ra_completion();

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

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

Loading…
Cancel
Save