Merge branch 'next' into agpl_next

# Conflicts:
#	lib/include/srsran/rrc/nr/rrc_nr_cfg_utils.h
#	lib/src/rrc/CMakeLists.txt
#	lib/src/rrc/nr/rrc_nr_cfg_utils.cc
master
Codebot 3 years ago committed by Your Name
commit e0734e584d

@ -280,6 +280,9 @@ endif(BUILD_STATIC)
set(BOOST_REQUIRED_COMPONENTS set(BOOST_REQUIRED_COMPONENTS
program_options program_options
) )
if(UHD_FOUND) # Ubuntu 18.04 requires component 'system' to link UHD
list(APPEND BOOST_REQUIRED_COMPONENTS "system")
endif(UHD_FOUND)
if(UNIX AND EXISTS "/usr/lib64") if(UNIX AND EXISTS "/usr/lib64")
list(APPEND BOOST_LIBRARYDIR "/usr/lib64") #fedora 64-bit fix list(APPEND BOOST_LIBRARYDIR "/usr/lib64") #fedora 64-bit fix
endif(UNIX AND EXISTS "/usr/lib64") endif(UNIX AND EXISTS "/usr/lib64")

@ -300,7 +300,7 @@ public:
} }
return obj; return obj;
} }
bool pop_wait_until(T& obj, const std::chrono::system_clock::time_point& until) { return pop_(obj, true, &until); } bool pop_wait_until(T& obj, const std::chrono::steady_clock::time_point& until) { return pop_(obj, true, &until); }
void clear() void clear()
{ {
T obj; T obj;
@ -414,7 +414,7 @@ protected:
return {}; return {};
} }
bool pop_(T& obj, bool block, const std::chrono::system_clock::time_point* until = nullptr) bool pop_(T& obj, bool block, const std::chrono::steady_clock::time_point* until = nullptr)
{ {
std::unique_lock<std::mutex> lock(mutex); std::unique_lock<std::mutex> lock(mutex);
if (not active) { if (not active) {

@ -19,18 +19,37 @@
* *
*/ */
#ifndef SRSRAN_RRC_CFG_UTILS_H #ifndef SRSRAN_OBJ_ID_CMP_UTILS_H
#define SRSRAN_RRC_CFG_UTILS_H #define SRSRAN_OBJ_ID_CMP_UTILS_H
#include "srsran/asn1/rrc_utils.h"
#include "srsran/common/common.h" #include "srsran/common/common.h"
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
namespace srsran { namespace srsran {
template <typename rrcObj> using asn1_obj_id_t = uint8_t;
using rrc_obj_id_t = decltype(asn1::rrc::get_rrc_obj_id(std::declval<rrcObj>()));
/// Template function to generically obtain id of asn1 object (e.g. srb_id of srbs, drb_id of drbs, etc.)
template <typename Asn1Obj>
uint8_t get_asn1_obj_id(const Asn1Obj& obj);
/// Template function to generically set id of asn1 object (e.g. srb_id of srbs, drb_id of drbs, etc.)
template <typename Asn1Obj>
void set_asn1_obj_id(Asn1Obj& obj, uint8_t id);
/// helper macro to help define get_asn1_obj_id and set_asn1_obj_id for specific asn1 objects
#define ASN1_OBJ_ID_DEFINE(Asn1ObjType, member) \
template <> \
uint8_t get_asn1_obj_id<Asn1ObjType>(const Asn1ObjType& obj) \
{ \
return obj.member; \
} \
template <> \
void set_asn1_obj_id<Asn1ObjType>(Asn1ObjType & obj, uint8_t id) \
{ \
obj.member = id; \
}
//! Functor to compare RRC config elements (e.g. SRB/measObj/Rep) based on ID //! Functor to compare RRC config elements (e.g. SRB/measObj/Rep) based on ID
struct rrc_obj_id_cmp { struct rrc_obj_id_cmp {
@ -38,27 +57,27 @@ struct rrc_obj_id_cmp {
typename std::enable_if<not std::is_integral<T>::value and not std::is_integral<U>::value, bool>::type typename std::enable_if<not std::is_integral<T>::value and not std::is_integral<U>::value, bool>::type
operator()(const T& lhs, const U& rhs) const operator()(const T& lhs, const U& rhs) const
{ {
return asn1::rrc::get_rrc_obj_id(lhs) < asn1::rrc::get_rrc_obj_id(rhs); return get_asn1_obj_id(lhs) < get_asn1_obj_id(rhs);
} }
template <typename T> template <typename T>
bool operator()(const T& lhs, rrc_obj_id_t<T> id) const bool operator()(const T& lhs, asn1_obj_id_t id) const
{ {
return asn1::rrc::get_rrc_obj_id(lhs) < id; return get_asn1_obj_id(lhs) < id;
} }
template <typename T> template <typename T>
bool operator()(rrc_obj_id_t<T> id, const T& rhs) const bool operator()(asn1_obj_id_t id, const T& rhs) const
{ {
return id < asn1::rrc::get_rrc_obj_id(rhs); return id < get_asn1_obj_id(rhs);
} }
}; };
template <typename Container> template <typename Container>
struct unary_rrc_obj_id { struct unary_rrc_obj_id {
rrc_obj_id_t<typename Container::value_type> id; asn1_obj_id_t id;
template <typename T> template <typename T>
explicit unary_rrc_obj_id(T id_) : id(id_) explicit unary_rrc_obj_id(T id_) : id(id_)
{} {}
bool operator()(const typename Container::value_type& e) const { return asn1::rrc::get_rrc_obj_id(e) == id; } bool operator()(const typename Container::value_type& e) const { return get_asn1_obj_id(e) == id; }
}; };
/// Find rrc object in list based on ID /// Find rrc object in list based on ID
@ -78,13 +97,13 @@ template <typename Container, typename IdType>
typename Container::iterator sorted_find_rrc_obj_id(Container& c, IdType id) typename Container::iterator sorted_find_rrc_obj_id(Container& c, IdType id)
{ {
auto it = std::lower_bound(c.begin(), c.end(), id, rrc_obj_id_cmp{}); auto it = std::lower_bound(c.begin(), c.end(), id, rrc_obj_id_cmp{});
return (it == c.end() or asn1::rrc::get_rrc_obj_id(*it) != id) ? c.end() : it; return (it == c.end() or get_asn1_obj_id(*it) != id) ? c.end() : it;
} }
template <typename Container, typename IdType> template <typename Container, typename IdType>
typename Container::const_iterator sorted_find_rrc_obj_id(const Container& c, IdType id) typename Container::const_iterator sorted_find_rrc_obj_id(const Container& c, IdType id)
{ {
auto it = std::lower_bound(c.begin(), c.end(), id, rrc_obj_id_cmp{}); auto it = std::lower_bound(c.begin(), c.end(), id, rrc_obj_id_cmp{});
return (it == c.end() or asn1::rrc::get_rrc_obj_id(*it) != id) ? c.end() : it; return (it == c.end() or get_asn1_obj_id(*it) != id) ? c.end() : it;
} }
template <typename Container, typename Container2> template <typename Container, typename Container2>
@ -95,7 +114,7 @@ bool equal_rrc_obj_ids(const Container& c, const Container2& c2)
c2.begin(), c2.begin(),
c2.end(), c2.end(),
[](const typename Container::value_type& e, const typename Container2::value_type& e2) { [](const typename Container::value_type& e, const typename Container2::value_type& e2) {
return asn1::rrc::get_rrc_obj_id(e) == asn1::rrc::get_rrc_obj_id(e2); return get_asn1_obj_id(e) == get_asn1_obj_id(e2);
}); });
} }
@ -107,7 +126,7 @@ typename Container::iterator add_rrc_obj_id(Container& c, IdType id)
if (it == c.end()) { if (it == c.end()) {
c.push_back({}); c.push_back({});
it = c.end() - 1; it = c.end() - 1;
asn1::rrc::set_rrc_obj_id(*it, id); set_asn1_obj_id(*it, id);
std::sort(c.begin(), c.end(), rrc_obj_id_cmp{}); std::sort(c.begin(), c.end(), rrc_obj_id_cmp{});
it = sorted_find_rrc_obj_id(c, id); it = sorted_find_rrc_obj_id(c, id);
} }
@ -117,11 +136,11 @@ typename Container::iterator add_rrc_obj_id(Container& c, IdType id)
template <typename Container> template <typename Container>
typename Container::iterator add_rrc_obj(Container& c, const typename Container::value_type& v) typename Container::iterator add_rrc_obj(Container& c, const typename Container::value_type& v)
{ {
auto it = sorted_find_rrc_obj_id(c, asn1::rrc::get_rrc_obj_id(v)); auto it = sorted_find_rrc_obj_id(c, get_asn1_obj_id(v));
if (it == c.end()) { if (it == c.end()) {
c.push_back(v); c.push_back(v);
std::sort(c.begin(), c.end(), rrc_obj_id_cmp{}); std::sort(c.begin(), c.end(), rrc_obj_id_cmp{});
it = sorted_find_rrc_obj_id(c, asn1::rrc::get_rrc_obj_id(v)); it = sorted_find_rrc_obj_id(c, get_asn1_obj_id(v));
} else { } else {
*it = v; *it = v;
} }
@ -145,21 +164,21 @@ bool rem_rrc_obj_id(Container& c, IdType id)
* @return id value * @return id value
*/ */
template <typename Container> template <typename Container>
auto find_rrc_obj_id_gap(const Container& c) -> decltype(asn1::rrc::get_rrc_obj_id(c[0])) auto find_rrc_obj_id_gap(const Container& c) -> decltype(get_asn1_obj_id(c[0]))
{ {
auto id_cmp_op = rrc_obj_id_cmp{}; auto id_cmp_op = rrc_obj_id_cmp{};
assert(std::is_sorted(c.begin(), c.end(), id_cmp_op)); assert(std::is_sorted(c.begin(), c.end(), id_cmp_op));
auto prev_it = c.begin(); auto prev_it = c.begin();
if (prev_it != c.end() and asn1::rrc::get_rrc_obj_id(*prev_it) == 1) { if (prev_it != c.end() and get_asn1_obj_id(*prev_it) == 1) {
auto it = prev_it; auto it = prev_it;
for (++it; it != c.end(); prev_it = it, ++it) { for (++it; it != c.end(); prev_it = it, ++it) {
if (asn1::rrc::get_rrc_obj_id(*it) > asn1::rrc::get_rrc_obj_id(*prev_it) + 1) { if (get_asn1_obj_id(*it) > get_asn1_obj_id(*prev_it) + 1) {
break; break;
} }
} }
} }
return (prev_it == c.end()) ? 1 : asn1::rrc::get_rrc_obj_id(*prev_it) + 1; // starts at 1. return (prev_it == c.end()) ? 1 : get_asn1_obj_id(*prev_it) + 1; // starts at 1.
} }
/** /**
@ -316,7 +335,7 @@ void compute_cfg_diff(const toAddModList& src_list,
} }
using it_t = typename toAddModList::const_iterator; using it_t = typename toAddModList::const_iterator;
auto rem_func = [&rem_diff_list](it_t rem_it) { rem_diff_list.push_back(asn1::rrc::get_rrc_obj_id(*rem_it)); }; auto rem_func = [&rem_diff_list](it_t rem_it) { rem_diff_list.push_back(get_asn1_obj_id(*rem_it)); };
auto add_func = [&add_diff_list](it_t add_it) { add_diff_list.push_back(*add_it); }; auto add_func = [&add_diff_list](it_t add_it) { add_diff_list.push_back(*add_it); };
auto mod_func = [&add_diff_list](it_t src_it, it_t target_it) { auto mod_func = [&add_diff_list](it_t src_it, it_t target_it) {
if (not(*src_it == *target_it)) { if (not(*src_it == *target_it)) {
@ -328,4 +347,4 @@ void compute_cfg_diff(const toAddModList& src_list,
} // namespace srsran } // namespace srsran
#endif // SRSRAN_RRC_CFG_UTILS_H #endif // SRSRAN_OBJ_ID_CMP_UTILS_H

@ -67,6 +67,10 @@ struct serving_cell_cfg_common_s;
struct serving_cell_cfg_s; struct serving_cell_cfg_s;
struct pdcch_cfg_common_s; struct pdcch_cfg_common_s;
struct pdcch_cfg_s; struct pdcch_cfg_s;
struct mib_s;
struct srb_to_add_mod_s;
struct drb_to_add_mod_s;
} // namespace rrc_nr } // namespace rrc_nr
} // namespace asn1 } // namespace asn1
@ -124,6 +128,7 @@ bool make_phy_carrier_cfg(const asn1::rrc_nr::freq_info_dl_s& freq_info_dl, srsr
bool make_phy_ssb_cfg(const srsran_carrier_nr_t& carrier, bool make_phy_ssb_cfg(const srsran_carrier_nr_t& carrier,
const asn1::rrc_nr::serving_cell_cfg_common_s& serv_cell_cfg, const asn1::rrc_nr::serving_cell_cfg_common_s& serv_cell_cfg,
phy_cfg_nr_t::ssb_cfg_t* ssb); phy_cfg_nr_t::ssb_cfg_t* ssb);
bool make_phy_mib(const asn1::rrc_nr::mib_s& mib_cfg, srsran_mib_nr_t* mib);
bool make_pdsch_cfg_from_serv_cell(const asn1::rrc_nr::serving_cell_cfg_s& serv_cell, srsran_sch_hl_cfg_nr_t* sch_hl); bool make_pdsch_cfg_from_serv_cell(const asn1::rrc_nr::serving_cell_cfg_s& serv_cell, srsran_sch_hl_cfg_nr_t* sch_hl);
bool make_csi_cfg_from_serv_cell(const asn1::rrc_nr::serving_cell_cfg_s& serv_cell, srsran_csi_hl_cfg_t* csi_hl); bool make_csi_cfg_from_serv_cell(const asn1::rrc_nr::serving_cell_cfg_s& serv_cell, srsran_csi_hl_cfg_t* csi_hl);
bool make_duplex_cfg_from_serv_cell(const asn1::rrc_nr::serving_cell_cfg_common_s& serv_cell, bool make_duplex_cfg_from_serv_cell(const asn1::rrc_nr::serving_cell_cfg_common_s& serv_cell,
@ -151,4 +156,16 @@ pdcp_config_t make_drb_pdcp_config_t(const uint8_t bearer_id, bool is_ue, const
} // namespace srsran } // namespace srsran
/************************
* ASN1 RRC extensions
***********************/
namespace asn1 {
namespace rrc_nr {
bool operator==(const srb_to_add_mod_s& lhs, const srb_to_add_mod_s& rhs);
bool operator==(const drb_to_add_mod_s& lhs, const drb_to_add_mod_s& rhs);
} // namespace rrc_nr
} // namespace asn1
#endif // SRSRAN_RRC_NR_UTILS_H #endif // SRSRAN_RRC_NR_UTILS_H

@ -150,37 +150,4 @@ sib13_t make_sib13(const asn1::rrc::sib_type13_r9_s& asn1_type);
} // namespace srsran } // namespace srsran
/************************
* ASN1 RRC extensions
***********************/
namespace asn1 {
namespace rrc {
/**************************
* RRC Obj Id
*************************/
uint8_t get_rrc_obj_id(const srb_to_add_mod_s& srb);
uint8_t get_rrc_obj_id(const drb_to_add_mod_s& drb);
uint8_t get_rrc_obj_id(const cells_to_add_mod_s& obj);
uint8_t get_rrc_obj_id(const cells_to_add_mod_nr_r15_s& obj);
uint8_t get_rrc_obj_id(const black_cells_to_add_mod_s& obj);
uint8_t get_rrc_obj_id(const meas_obj_to_add_mod_s& obj);
uint8_t get_rrc_obj_id(const report_cfg_to_add_mod_s& obj);
uint8_t get_rrc_obj_id(const meas_id_to_add_mod_s& obj);
uint8_t get_rrc_obj_id(const scell_to_add_mod_r10_s& obj);
void set_rrc_obj_id(srb_to_add_mod_s& srb, uint8_t id);
void set_rrc_obj_id(drb_to_add_mod_s& drb, uint8_t id);
void set_rrc_obj_id(cells_to_add_mod_s& obj, uint8_t id);
void set_rrc_obj_id(cells_to_add_mod_nr_r15_s& obj, uint8_t id);
void set_rrc_obj_id(black_cells_to_add_mod_s& obj, uint8_t id);
void set_rrc_obj_id(meas_obj_to_add_mod_s& obj, uint8_t id);
void set_rrc_obj_id(report_cfg_to_add_mod_s& obj, uint8_t id);
void set_rrc_obj_id(meas_id_to_add_mod_s& obj, uint8_t id);
void set_rrc_obj_id(scell_to_add_mod_r10_s& obj, uint8_t id);
} // namespace rrc
} // namespace asn1
#endif // SRSRAN_RRC_UTILS_H #endif // SRSRAN_RRC_UTILS_H

@ -135,14 +135,29 @@ public:
/** /**
* @brief Compute the absolute frequency of the SSB for a DL ARFCN and a band. This selects an SSB center frequency * @brief Compute the absolute frequency of the SSB for a DL ARFCN and a band. This selects an SSB center frequency
* following the band SS/PBCH frequency raster provided by TS38.104 table 5.4.3.1-1, which is the upper bound
* of the provided center frequency
*
* @param scs ssb subcarrier spacing.
* @param min_center_freq_hz center frequency above which the SSB absolute frequency must be.
* @return absolute frequency of the SSB in arfcn notation.
*/
uint32_t find_lower_bound_abs_freq_ssb(uint16_t band, srsran_subcarrier_spacing_t scs, uint32_t min_center_freq_hz);
/**
* @brief Compute the absolute frequency of the SSB for a DL ARFCN and a band. This finds an SSB center frequency
* following the band SS/PBCH frequency raster provided by TS38.104 table 5.4.3.1-1 as close as possible to PointA * following the band SS/PBCH frequency raster provided by TS38.104 table 5.4.3.1-1 as close as possible to PointA
* without letting any SS/PBCH subcarrier below PointA * without letting any SS/PBCH subcarrier and CORESET#0 subcarrier (if RB offset is defined) below PointA
* *
* @param scs ssb subcarrier spacing. * @param scs ssb subcarrier spacing.
* @param freq_point_a_arfcn frequency point a in arfcn notation. * @param freq_point_a_arfcn frequency point a in arfcn notation.
* @param coreset0_offset_rb CORESET#0 RB offset. See TS 38.213, Table 13-1,2,3
* @return absolute frequency of the SSB in arfcn notation. * @return absolute frequency of the SSB in arfcn notation.
*/ */
uint32_t get_abs_freq_ssb_arfcn(uint16_t band, srsran_subcarrier_spacing_t scs, uint32_t freq_point_a_arfcn); uint32_t get_abs_freq_ssb_arfcn(uint16_t band,
srsran_subcarrier_spacing_t scs,
uint32_t freq_point_a_arfcn,
uint32_t coreset0_offset_rb = 0);
/** /**
* @brief Compute SSB center frequency for NR carrier * @brief Compute SSB center frequency for NR carrier

@ -104,6 +104,8 @@ public:
return value; return value;
} }
bool timedwait_pop(myobj* value, const struct timespec* abstime) { return pop_(value, true, abstime); }
bool empty() bool empty()
{ // queue is empty? { // queue is empty?
pthread_mutex_lock(&mutex); pthread_mutex_lock(&mutex);
@ -139,7 +141,7 @@ public:
} }
private: private:
bool pop_(myobj* value, bool block) bool pop_(myobj* value, bool block, const struct timespec* abstime = nullptr)
{ {
if (!enable) { if (!enable) {
return false; return false;
@ -151,7 +153,13 @@ private:
goto exit; goto exit;
} }
while (q.empty() && enable) { while (q.empty() && enable) {
pthread_cond_wait(&cv_empty, &mutex); if (abstime == nullptr) {
pthread_cond_wait(&cv_empty, &mutex);
} else {
if (pthread_cond_timedwait(&cv_empty, &mutex, abstime)) {
goto exit;
}
}
} }
if (!enable) { if (!enable) {
goto exit; goto exit;

@ -163,6 +163,12 @@ inline void copy_msg_to_buffer(unique_byte_buffer_t& pdu, const_byte_span msg)
pdu->N_bytes = msg.size(); pdu->N_bytes = msg.size();
} }
/**
* Delimits beginning/ending of a test with the following console output:
* ============= [Test <Name of the Test>] ===============
* <test log>
* =======================================================
*/
class test_delimit_logger class test_delimit_logger
{ {
const size_t delimiter_length = 128; const size_t delimiter_length = 128;

@ -41,6 +41,7 @@ struct s1ap_args_t {
std::string enb_name; std::string enb_name;
uint32_t ts1_reloc_prep_timeout; uint32_t ts1_reloc_prep_timeout;
uint32_t ts1_reloc_overall_timeout; uint32_t ts1_reloc_overall_timeout;
int32_t max_s1_setup_retries;
}; };
// S1AP interface for RRC // S1AP interface for RRC

@ -46,14 +46,14 @@ public:
virtual void initial_ue(uint16_t rnti, virtual void initial_ue(uint16_t rnti,
uint32_t gnb_cc_idx, uint32_t gnb_cc_idx,
asn1::ngap_nr::rrcestablishment_cause_e cause, asn1::ngap_nr::rrcestablishment_cause_e cause,
srsran::unique_byte_buffer_t pdu) = 0; srsran::const_byte_span pdu) = 0;
virtual void initial_ue(uint16_t rnti, virtual void initial_ue(uint16_t rnti,
uint32_t gnb_cc_idx, uint32_t gnb_cc_idx,
asn1::ngap_nr::rrcestablishment_cause_e cause, asn1::ngap_nr::rrcestablishment_cause_e cause,
srsran::unique_byte_buffer_t pdu, srsran::const_byte_span pdu,
uint32_t m_tmsi) = 0; uint32_t m_tmsi) = 0;
virtual void write_pdu(uint16_t rnti, srsran::unique_byte_buffer_t pdu) = 0; virtual void write_pdu(uint16_t rnti, srsran::const_byte_span pdu) = 0;
virtual bool user_exists(uint16_t rnti) = 0; virtual bool user_exists(uint16_t rnti) = 0;
virtual void user_mod(uint16_t old_rnti, uint16_t new_rnti) = 0; virtual void user_mod(uint16_t old_rnti, uint16_t new_rnti) = 0;
virtual bool user_release(uint16_t rnti, asn1::ngap_nr::cause_radio_network_e cause_radio) = 0; virtual bool user_release(uint16_t rnti, asn1::ngap_nr::cause_radio_network_e cause_radio) = 0;
@ -63,4 +63,4 @@ public:
} // namespace srsenb } // namespace srsenb
#endif // SRSRAN_GNB_NGAP_INTERFACES_H #endif // SRSRAN_GNB_NGAP_INTERFACES_H

@ -221,6 +221,8 @@ typedef enum SRSRAN_API {
srsran_coreset_bundle_size_n6, srsran_coreset_bundle_size_n6,
} srsran_coreset_bundle_size_t; } srsran_coreset_bundle_size_t;
uint32_t pdcch_nr_bundle_size(srsran_coreset_bundle_size_t x);
typedef enum SRSRAN_API { typedef enum SRSRAN_API {
srsran_coreset_precoder_granularity_contiguous = 0, srsran_coreset_precoder_granularity_contiguous = 0,
srsran_coreset_precoder_granularity_reg_bundle srsran_coreset_precoder_granularity_reg_bundle
@ -713,6 +715,26 @@ SRSRAN_API int srsran_coreset_zero(uint32_t n_cell_id,
uint32_t idx, uint32_t idx,
srsran_coreset_t* coreset); srsran_coreset_t* coreset);
/**
* @brief Obtain offset in RBs between CoresetZero and SSB. See TS 38.213, Tables 13-{1,...,10}
* @param idx Index of 13-{1,...10} table
* @param ssb_scs SS/PBCH block subcarrier spacing
* @param pdcch_scs PDCCH subcarrier spacing
* @return offset in RBs, or -1 in case of invalid inputs
*/
SRSRAN_API int
srsran_coreset0_ssb_offset(uint32_t idx, srsran_subcarrier_spacing_t ssb_scs, srsran_subcarrier_spacing_t pdcch_scs);
/**
* @brief Convert Coreset to string
*
* @param coreset The coreset structure as input
* @param str The string to write to
* @param str_len Maximum string length
* @return SRSRAN_API
*/
SRSRAN_API int srsran_coreset_to_str(srsran_coreset_t* coreset, char* str, uint32_t str_len);
/** /**
* @brief Convert SSB pattern to string * @brief Convert SSB pattern to string
* @param pattern * @param pattern

@ -86,6 +86,8 @@ typedef struct {
srsran_dmrs_sch_typeA_pos_t typeA_pos; srsran_dmrs_sch_typeA_pos_t typeA_pos;
bool lte_CRS_to_match_around; bool lte_CRS_to_match_around;
uint32_t reference_point_k_rb;
/// Parameters provided by FeatureSetDownlink-v1540 /// Parameters provided by FeatureSetDownlink-v1540
bool additional_DMRS_DL_Alt; bool additional_DMRS_DL_Alt;

@ -24,6 +24,8 @@
#include "srsran/common/buffer_pool.h" #include "srsran/common/buffer_pool.h"
#include "srsran/common/common.h" #include "srsran/common/common.h"
#include "srsran/common/timers.h"
#include "srsran/interfaces/ue_rrc_interfaces.h"
#include "srsran/rlc/rlc_common.h" #include "srsran/rlc/rlc_common.h"
#include "srsran/upper/byte_buffer_queue.h" #include "srsran/upper/byte_buffer_queue.h"
#include <map> #include <map>
@ -31,20 +33,172 @@
#include <pthread.h> #include <pthread.h>
#include <queue> #include <queue>
namespace srsran { namespace srsue {
class pdcp_interface_rlc;
class rrc_interface_rlc;
} // namespace srsue
///< Add rlc_am_base here namespace srsran {
bool rlc_am_is_control_pdu(uint8_t* payload); bool rlc_am_is_control_pdu(uint8_t* payload);
bool rlc_am_is_control_pdu(byte_buffer_t* pdu); bool rlc_am_is_control_pdu(byte_buffer_t* pdu);
} // namespace srsran /*******************************************************
* RLC AM entity
* This entity is common between LTE and NR
* and only the TX/RX entities change between them
*******************************************************/
class rlc_am : public rlc_common
{
public:
class rlc_am_base_tx;
class rlc_am_base_rx;
namespace srsue { friend class rlc_am_lte_tx;
friend class rlc_am_lte_rx;
friend class rlc_am_nr_tx;
friend class rlc_am_nr_rx;
class pdcp_interface_rlc; rlc_am(srsran_rat_t rat,
class rrc_interface_rlc; srslog::basic_logger& logger,
uint32_t lcid_,
srsue::pdcp_interface_rlc* pdcp_,
srsue::rrc_interface_rlc* rrc_,
srsran::timer_handler* timers_);
} // namespace srsue bool configure(const rlc_config_t& cfg_) final;
void reestablish() final;
void stop() final;
void empty_queue() final { tx_base->empty_queue(); }
rlc_mode_t get_mode() final { return rlc_mode_t::am; }
uint32_t get_lcid() final { return lcid; }
/****************************************************************************
* PDCP interface
***************************************************************************/
void write_sdu(unique_byte_buffer_t sdu) final;
void discard_sdu(uint32_t discard_sn) final;
bool sdu_queue_is_full() final;
/****************************************************************************
* MAC interface
***************************************************************************/
bool has_data() final;
uint32_t get_buffer_state() final;
void get_buffer_state(uint32_t& n_bytes_newtx, uint32_t& n_bytes_prio) final;
uint32_t read_pdu(uint8_t* payload, uint32_t nof_bytes) final;
void write_pdu(uint8_t* payload, uint32_t nof_bytes) final;
/****************************************************************************
* Metrics
***************************************************************************/
rlc_bearer_metrics_t get_metrics() final;
void reset_metrics() final;
/****************************************************************************
* BSR Callback
***************************************************************************/
void set_bsr_callback(bsr_callback_t callback) final;
protected:
// Common variables needed/provided by parent class
srslog::basic_logger& logger;
srsran::timer_handler* timers = nullptr;
uint32_t lcid = 0;
rlc_config_t cfg = {};
std::string rb_name;
static const int poll_periodicity = 8; // After how many data PDUs a status PDU shall be requested
std::mutex metrics_mutex;
rlc_bearer_metrics_t metrics = {};
srsue::rrc_interface_rlc* rrc = nullptr;
srsue::pdcp_interface_rlc* pdcp = nullptr;
/*******************************************************
* RLC AM TX entity
* This class is used for common code between the
* LTE and NR TX entitites
*******************************************************/
public:
class rlc_am_base_tx
{
public:
explicit rlc_am_base_tx(srslog::basic_logger* logger_) : logger(logger_) {}
virtual ~rlc_am_base_tx() = default;
virtual bool configure(const rlc_config_t& cfg_) = 0;
virtual void handle_control_pdu(uint8_t* payload, uint32_t nof_bytes) = 0;
virtual uint32_t get_buffer_state() = 0;
virtual void get_buffer_state(uint32_t& tx_queue, uint32_t& prio_tx_queue) = 0;
virtual void reestablish() = 0;
virtual void empty_queue() = 0;
virtual void discard_sdu(uint32_t pdcp_sn) = 0;
virtual bool sdu_queue_is_full() = 0;
virtual bool has_data() = 0;
virtual void stop() = 0;
void set_bsr_callback(bsr_callback_t callback);
int write_sdu(unique_byte_buffer_t sdu);
virtual uint32_t read_pdu(uint8_t* payload, uint32_t nof_bytes) = 0;
bool tx_enabled = false;
byte_buffer_pool* pool = nullptr;
srslog::basic_logger* logger;
std::string rb_name;
bsr_callback_t bsr_callback;
// Tx SDU buffers
byte_buffer_queue tx_sdu_queue;
// Mutexes
std::mutex mutex;
};
/*******************************************************
* RLC AM RX entity
* This class is used for common code between the
* LTE and NR RX entitites
*******************************************************/
class rlc_am_base_rx
{
public:
explicit rlc_am_base_rx(rlc_am* parent_, srslog::basic_logger* logger_) : parent(parent_), logger(logger_) {}
virtual ~rlc_am_base_rx() = default;
virtual bool configure(const rlc_config_t& cfg_) = 0;
virtual void handle_data_pdu(uint8_t* payload, uint32_t nof_bytes) = 0;
virtual void reestablish() = 0;
virtual void stop() = 0;
virtual uint32_t get_sdu_rx_latency_ms() = 0;
virtual uint32_t get_rx_buffered_bytes() = 0;
void write_pdu(uint8_t* payload, uint32_t nof_bytes);
srslog::basic_logger* logger = nullptr;
byte_buffer_pool* pool = nullptr;
rlc_am* parent = nullptr;
};
protected:
std::unique_ptr<rlc_am_base_tx> tx_base = {};
std::unique_ptr<rlc_am_base_rx> rx_base = {};
};
} // namespace srsran
#endif // SRSRAN_RLC_AM_BASE_H #endif // SRSRAN_RLC_AM_BASE_H

@ -25,61 +25,139 @@
#include "srsran/adt/circular_buffer.h" #include "srsran/adt/circular_buffer.h"
#include "srsran/adt/circular_map.h" #include "srsran/adt/circular_map.h"
#include "srsran/adt/intrusive_list.h" #include "srsran/adt/intrusive_list.h"
#include "srsran/common/buffer_pool.h"
#include <array> #include <array>
#include <vector> #include <vector>
namespace srsran { namespace srsran {
template <typename HeaderType>
class rlc_amd_tx_pdu; class rlc_amd_tx_pdu;
template <typename HeaderType>
class pdcp_pdu_info; class pdcp_pdu_info;
/// Pool that manages the allocation of RLC AM PDU Segments to RLC PDUs and tracking of segments ACK state /// Pool that manages the allocation of RLC AM PDU Segments to RLC PDUs and tracking of segments ACK state
template <typename HeaderType>
struct rlc_am_pdu_segment_pool { struct rlc_am_pdu_segment_pool {
const static size_t MAX_POOL_SIZE = 16384; 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 /// RLC AM PDU Segment, containing the PDCP SN and RLC SN it has been assigned to, and its current ACK state
using rlc_list_tag = default_intrusive_tag;
struct free_list_tag {};
struct segment_resource : public intrusive_forward_list_element<rlc_list_tag>, struct segment_resource : public intrusive_forward_list_element<rlc_list_tag>,
public intrusive_forward_list_element<free_list_tag>, public intrusive_forward_list_element<free_list_tag>,
public intrusive_double_linked_list_element<> { public intrusive_double_linked_list_element<> {
const static uint32_t invalid_rlc_sn = std::numeric_limits<uint32_t>::max(); 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 const static uint32_t invalid_pdcp_sn = std::numeric_limits<uint32_t>::max() - 1; // -1 for Status Report
int id() const; int id() const { return std::distance(parent_pool->segments.cbegin(), this); }
void release_pdcp_sn();
void release_rlc_sn(); void release_pdcp_sn()
{
pdcp_sn_ = invalid_pdcp_sn;
if (empty()) {
parent_pool->free_list.push_front(this);
}
}
void release_rlc_sn()
{
rlc_sn_ = invalid_rlc_sn;
if (empty()) {
parent_pool->free_list.push_front(this);
}
}
uint32_t rlc_sn() const { return rlc_sn_; } uint32_t rlc_sn() const { return rlc_sn_; }
uint32_t pdcp_sn() const { return pdcp_sn_; } uint32_t pdcp_sn() const { return pdcp_sn_; }
bool empty() const { return rlc_sn_ == invalid_rlc_sn and pdcp_sn_ == invalid_pdcp_sn; } bool empty() const { return rlc_sn_ == invalid_rlc_sn and pdcp_sn_ == invalid_pdcp_sn; }
private: private:
friend struct rlc_am_pdu_segment_pool; friend struct rlc_am_pdu_segment_pool<HeaderType>;
uint32_t rlc_sn_ = invalid_rlc_sn; uint32_t rlc_sn_ = invalid_rlc_sn;
uint32_t pdcp_sn_ = invalid_pdcp_sn; uint32_t pdcp_sn_ = invalid_pdcp_sn;
rlc_am_pdu_segment_pool* parent_pool = nullptr; rlc_am_pdu_segment_pool<HeaderType>* parent_pool = nullptr;
}; };
rlc_am_pdu_segment_pool(); rlc_am_pdu_segment_pool()
{
for (segment_resource& s : segments) {
s.parent_pool = this;
free_list.push_front(&s);
}
}
rlc_am_pdu_segment_pool(const rlc_am_pdu_segment_pool&) = delete; 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(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=(const rlc_am_pdu_segment_pool&) = delete;
rlc_am_pdu_segment_pool& operator=(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); bool has_segments() const { return not free_list.empty(); }
bool make_segment(rlc_amd_tx_pdu<HeaderType>& rlc_list, pdcp_pdu_info<HeaderType>& 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;
}
private: private:
intrusive_forward_list<segment_resource, free_list_tag> free_list; intrusive_forward_list<rlc_am_pdu_segment_pool<HeaderType>::segment_resource, free_list_tag> free_list;
std::array<segment_resource, MAX_POOL_SIZE> segments; std::array<rlc_am_pdu_segment_pool<HeaderType>::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 /// Class that contains the parameters and state (e.g. segments) of a RLC PDU
using rlc_am_pdu_segment = rlc_am_pdu_segment_pool::segment_resource; template <typename HeaderType>
class rlc_amd_tx_pdu
{
using rlc_am_pdu_segment = typename rlc_am_pdu_segment_pool<HeaderType>::segment_resource;
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;
HeaderType header;
unique_byte_buffer_t buf;
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()
{
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();
}
}
// 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(); }
};
/// Class that contains the parameters and state (e.g. unACKed segments) of a PDCP PDU /// Class that contains the parameters and state (e.g. unACKed segments) of a PDCP PDU
template <typename HeaderType>
class pdcp_pdu_info class pdcp_pdu_info
{ {
using list_type = intrusive_double_linked_list<rlc_am_pdu_segment>; using rlc_am_pdu_segment = typename rlc_am_pdu_segment_pool<HeaderType>::segment_resource;
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. list_type list; // List of unACKed RLC PDUs that contain segments that belong to the PDCP PDU.
@ -106,7 +184,13 @@ public:
// Interface for list of unACKed RLC segments of the PDCP PDU // Interface for list of unACKed RLC segments of the PDCP PDU
void add_segment(rlc_am_pdu_segment& segment) { list.push_front(&segment); } void add_segment(rlc_am_pdu_segment& segment) { list.push_front(&segment); }
void ack_segment(rlc_am_pdu_segment& segment); void 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();
}
void clear() void clear()
{ {
sn = invalid_pdcp_sn; sn = invalid_pdcp_sn;
@ -115,6 +199,7 @@ public:
ack_segment(list.front()); ack_segment(list.front());
} }
} }
const_iterator begin() const { return list.begin(); } const_iterator begin() const { return list.begin(); }
const_iterator end() const { return list.end(); } const_iterator end() const { return list.end(); }
}; };
@ -155,6 +240,7 @@ private:
srsran::static_circular_map<uint32_t, T, WINDOW_SIZE> window; srsran::static_circular_map<uint32_t, T, WINDOW_SIZE> window;
}; };
template <typename HeaderType>
struct buffered_pdcp_pdu_list { struct buffered_pdcp_pdu_list {
public: public:
explicit buffered_pdcp_pdu_list() : buffered_pdus(buffered_pdcp_pdu_list::buffer_size) { clear(); } explicit buffered_pdcp_pdu_list() : buffered_pdus(buffered_pdcp_pdu_list::buffer_size) { clear(); }
@ -162,7 +248,7 @@ public:
void clear() void clear()
{ {
count = 0; count = 0;
for (pdcp_pdu_info& b : buffered_pdus) { for (pdcp_pdu_info<HeaderType>& b : buffered_pdus) {
b.clear(); b.clear();
} }
} }
@ -171,7 +257,7 @@ public:
{ {
srsran_expect(sn <= max_pdcp_sn or sn == status_report_sn, "Invalid PDCP SN=%d", sn); srsran_expect(sn <= max_pdcp_sn or sn == status_report_sn, "Invalid PDCP SN=%d", sn);
srsran_assert(not has_pdcp_sn(sn), "Cannot re-add same PDCP SN twice"); srsran_assert(not has_pdcp_sn(sn), "Cannot re-add same PDCP SN twice");
pdcp_pdu_info& pdu = get_pdu_(sn); pdcp_pdu_info<HeaderType>& pdu = get_pdu_(sn);
if (pdu.valid()) { if (pdu.valid()) {
pdu.clear(); pdu.clear();
count--; count--;
@ -179,9 +265,10 @@ public:
pdu.sn = sn; pdu.sn = sn;
count++; count++;
} }
void clear_pdcp_sdu(uint32_t sn) void clear_pdcp_sdu(uint32_t sn)
{ {
pdcp_pdu_info& pdu = get_pdu_(sn); pdcp_pdu_info<HeaderType>& pdu = get_pdu_(sn);
if (not pdu.valid()) { if (not pdu.valid()) {
return; return;
} }
@ -189,11 +276,12 @@ public:
count--; count--;
} }
pdcp_pdu_info& operator[](uint32_t sn) pdcp_pdu_info<HeaderType>& operator[](uint32_t sn)
{ {
srsran_expect(has_pdcp_sn(sn), "Invalid access to non-existent PDCP SN=%d", sn); srsran_expect(has_pdcp_sn(sn), "Invalid access to non-existent PDCP SN=%d", sn);
return get_pdu_(sn); return get_pdu_(sn);
} }
bool has_pdcp_sn(uint32_t pdcp_sn) const bool has_pdcp_sn(uint32_t pdcp_sn) const
{ {
srsran_expect(pdcp_sn <= max_pdcp_sn or pdcp_sn == status_report_sn, "Invalid PDCP SN=%d", pdcp_sn); srsran_expect(pdcp_sn <= max_pdcp_sn or pdcp_sn == status_report_sn, "Invalid PDCP SN=%d", pdcp_sn);
@ -204,21 +292,21 @@ public:
private: private:
const static size_t max_pdcp_sn = 262143u; const static size_t max_pdcp_sn = 262143u;
const static size_t buffer_size = 4096u; const static size_t buffer_size = 4096u;
const static uint32_t status_report_sn = pdcp_pdu_info::status_report_sn; const static uint32_t status_report_sn = pdcp_pdu_info<HeaderType>::status_report_sn;
pdcp_pdu_info& get_pdu_(uint32_t sn) pdcp_pdu_info<HeaderType>& get_pdu_(uint32_t sn)
{ {
return (sn == status_report_sn) ? status_report_pdu : buffered_pdus[static_cast<size_t>(sn % buffer_size)]; 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 const pdcp_pdu_info<HeaderType>& get_pdu_(uint32_t sn) const
{ {
return (sn == status_report_sn) ? status_report_pdu : buffered_pdus[static_cast<size_t>(sn % buffer_size)]; return (sn == status_report_sn) ? status_report_pdu : buffered_pdus[static_cast<size_t>(sn % buffer_size)];
} }
// size equal to buffer_size // size equal to buffer_size
std::vector<pdcp_pdu_info> buffered_pdus; std::vector<pdcp_pdu_info<HeaderType> > buffered_pdus;
pdcp_pdu_info status_report_pdu; pdcp_pdu_info<HeaderType> status_report_pdu;
uint32_t count = 0; uint32_t count = 0;
}; };
} // namespace srsran } // namespace srsran

@ -89,251 +89,198 @@ private:
size_t rpos = 0; size_t rpos = 0;
}; };
class rlc_am_lte : public rlc_common /******************************
*
* RLC AM LTE entity
*
*****************************/
/******************************
* RLC AM LTE TX entity
*****************************/
class rlc_am_lte_tx;
class rlc_am_lte_rx;
class rlc_am_lte_tx : public rlc_am::rlc_am_base_tx, timer_callback
{ {
public: public:
rlc_am_lte(srslog::basic_logger& logger, explicit rlc_am_lte_tx(rlc_am* parent_);
uint32_t lcid_, ~rlc_am_lte_tx() = default;
srsue::pdcp_interface_rlc* pdcp_,
srsue::rrc_interface_rlc* rrc_,
srsran::timer_handler* timers_);
void set_rx(rlc_am_lte_rx* rx_) { rx = rx_; };
bool configure(const rlc_config_t& cfg_); bool configure(const rlc_config_t& cfg_);
void empty_queue();
void reestablish(); void reestablish();
void stop(); void stop();
void empty_queue(); uint32_t read_pdu(uint8_t* payload, uint32_t nof_bytes);
void discard_sdu(uint32_t discard_sn);
rlc_mode_t get_mode(); bool sdu_queue_is_full();
uint32_t get_bearer();
// PDCP interface
void write_sdu(unique_byte_buffer_t sdu);
void discard_sdu(uint32_t pdcp_sn);
bool sdu_queue_is_full();
// MAC interface
bool has_data(); bool has_data();
uint32_t get_buffer_state(); uint32_t get_buffer_state();
void get_buffer_state(uint32_t& tx_queue, uint32_t& prio_tx_queue); void get_buffer_state(uint32_t& n_bytes_newtx, uint32_t& n_bytes_prio);
uint32_t read_pdu(uint8_t* payload, uint32_t nof_bytes);
void write_pdu(uint8_t* payload, uint32_t nof_bytes);
rlc_bearer_metrics_t get_metrics();
void reset_metrics();
void set_bsr_callback(bsr_callback_t callback);
private:
// Transmitter sub-class
class rlc_am_lte_tx : public timer_callback
{
public:
rlc_am_lte_tx(rlc_am_lte* parent_);
~rlc_am_lte_tx();
bool configure(const rlc_config_t& cfg_);
void empty_queue(); void empty_queue_nolock();
void reestablish(); void debug_state();
void stop();
int write_sdu(unique_byte_buffer_t sdu); // Timeout callback interface
uint32_t read_pdu(uint8_t* payload, uint32_t nof_bytes); void timer_expired(uint32_t timeout_id) final;
void discard_sdu(uint32_t discard_sn);
bool sdu_queue_is_full();
bool has_data(); // Interface for Rx subclass
uint32_t get_buffer_state(); void handle_control_pdu(uint8_t* payload, uint32_t nof_bytes);
void get_buffer_state(uint32_t& new_tx, uint32_t& prio_tx);
// Timeout callback interface private:
void timer_expired(uint32_t timeout_id); void stop_nolock();
// Interface for Rx subclass
void handle_control_pdu(uint8_t* payload, uint32_t nof_bytes);
void set_bsr_callback(bsr_callback_t callback);
private: int build_status_pdu(uint8_t* payload, uint32_t nof_bytes);
void stop_nolock(); 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(uint32_t rlc_sn);
int build_status_pdu(uint8_t* payload, uint32_t nof_bytes); int required_buffer_size(const rlc_amd_retx_t& retx);
int build_retx_pdu(uint8_t* payload, uint32_t nof_bytes); void retransmit_pdu(uint32_t sn);
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(uint32_t rlc_sn);
void debug_state(); // Helpers
void empty_queue_nolock(); bool poll_required();
bool do_status();
void check_sn_reached_max_retx(uint32_t sn);
void get_buffer_state_nolock(uint32_t& new_tx, uint32_t& prio_tx);
int required_buffer_size(const rlc_amd_retx_t& retx); rlc_am* parent = nullptr;
void retransmit_pdu(uint32_t sn); rlc_am_lte_rx* rx = nullptr;
byte_buffer_pool* pool = nullptr;
rlc_am_pdu_segment_pool<rlc_amd_pdu_header_t> segment_pool;
void get_buffer_state_nolock(uint32_t& new_tx, uint32_t& prio_tx); /****************************************************************************
* Configurable parameters
* Ref: 3GPP TS 36.322 v10.0.0 Section 7
***************************************************************************/
// Helpers rlc_am_config_t cfg = {};
bool poll_required();
bool do_status();
void check_sn_reached_max_retx(uint32_t sn);
rlc_am_lte* parent = nullptr; // TX SDU buffers
byte_buffer_pool* pool = nullptr; unique_byte_buffer_t tx_sdu;
srslog::basic_logger& logger;
rlc_am_pdu_segment_pool segment_pool;
/**************************************************************************** /****************************************************************************
* Configurable parameters * State variables and counters
* Ref: 3GPP TS 36.322 v10.0.0 Section 7 * Ref: 3GPP TS 36.322 v10.0.0 Section 7
***************************************************************************/ ***************************************************************************/
rlc_am_config_t cfg = {}; // Tx state variables
uint32_t vt_a = 0; // ACK state. SN of next PDU in sequence to be ACKed. Low edge of tx window.
uint32_t vt_ms = RLC_AM_WINDOW_SIZE; // Max send state. High edge of tx window. vt_a + window_size.
uint32_t vt_s = 0; // Send state. SN to be assigned for next PDU.
uint32_t poll_sn = 0; // Poll send state. SN of most recent PDU txed with poll bit set.
// TX SDU buffers // Tx counters
byte_buffer_queue tx_sdu_queue; uint32_t pdu_without_poll = 0;
unique_byte_buffer_t tx_sdu; uint32_t byte_without_poll = 0;
bool tx_enabled = false; rlc_status_pdu_t tx_status;
/**************************************************************************** /****************************************************************************
* State variables and counters * Timers
* Ref: 3GPP TS 36.322 v10.0.0 Section 7 * Ref: 3GPP TS 36.322 v10.0.0 Section 7
***************************************************************************/ ***************************************************************************/
// Tx state variables srsran::timer_handler::unique_timer poll_retx_timer;
uint32_t vt_a = 0; // ACK state. SN of next PDU in sequence to be ACKed. Low edge of tx window. srsran::timer_handler::unique_timer status_prohibit_timer;
uint32_t vt_ms = RLC_AM_WINDOW_SIZE; // Max send state. High edge of tx window. vt_a + window_size.
uint32_t vt_s = 0; // Send state. SN to be assigned for next PDU.
uint32_t poll_sn = 0; // Poll send state. SN of most recent PDU txed with poll bit set.
// Tx counters // SDU info for PDCP notifications
uint32_t pdu_without_poll = 0; buffered_pdcp_pdu_list<rlc_amd_pdu_header_t> undelivered_sdu_info_queue;
uint32_t byte_without_poll = 0;
rlc_status_pdu_t tx_status; // Tx windows
rlc_ringbuffer_t<rlc_amd_tx_pdu<rlc_amd_pdu_header_t>, RLC_AM_WINDOW_SIZE> tx_window;
pdu_retx_queue retx_queue;
pdcp_sn_vector_t notify_info_vec;
/**************************************************************************** // Mutexes
* Timers std::mutex mutex;
* Ref: 3GPP TS 36.322 v10.0.0 Section 7
***************************************************************************/
srsran::timer_handler::unique_timer poll_retx_timer; // default to RLC SDU queue length
srsran::timer_handler::unique_timer status_prohibit_timer; const uint32_t MAX_SDUS_PER_RLC_PDU = RLC_TX_QUEUE_LEN;
};
// SDU info for PDCP notifications /******************************
buffered_pdcp_pdu_list undelivered_sdu_info_queue; * RLC AM LTE RX entity
*****************************/
class rlc_am_lte_rx : public rlc_am::rlc_am_base_rx, public timer_callback
{
public:
explicit rlc_am_lte_rx(rlc_am* parent_);
~rlc_am_lte_rx() = default;
// Callback function for buffer status report void set_tx(rlc_am_lte_tx* tx_) { tx = tx_; };
bsr_callback_t bsr_callback; bool configure(const rlc_config_t& cfg_) final;
void reestablish() final;
void stop() final;
// Tx windows uint32_t get_rx_buffered_bytes() final; // returns sum of PDUs in rx_window
rlc_ringbuffer_t<rlc_amd_tx_pdu, RLC_AM_WINDOW_SIZE> tx_window; uint32_t get_sdu_rx_latency_ms() final;
pdu_retx_queue retx_queue;
pdcp_sn_vector_t notify_info_vec;
// Mutexes // Timeout callback interface
std::mutex mutex; void timer_expired(uint32_t timeout_id) final;
// default to RLC SDU queue length // Functions needed by Tx subclass to query rx state
const uint32_t MAX_SDUS_PER_RLC_PDU = RLC_TX_QUEUE_LEN; int get_status_pdu_length();
}; int get_status_pdu(rlc_status_pdu_t* status, uint32_t nof_bytes);
bool get_do_status();
// Receiver sub-class private:
class rlc_am_lte_rx : public timer_callback void handle_data_pdu(uint8_t* payload, uint32_t nof_bytes) final;
{ void handle_data_pdu_full(uint8_t* payload, uint32_t nof_bytes, rlc_amd_pdu_header_t& header);
public: void handle_data_pdu_segment(uint8_t* payload, uint32_t nof_bytes, rlc_amd_pdu_header_t& header);
rlc_am_lte_rx(rlc_am_lte* parent_); void reassemble_rx_sdus();
~rlc_am_lte_rx(); bool inside_rx_window(const int16_t sn);
void debug_state();
bool configure(rlc_am_config_t cfg_); void print_rx_segments();
void reestablish(); bool add_segment_and_check(rlc_amd_rx_pdu_segments_t* pdu, rlc_amd_rx_pdu* segment);
void stop(); void reset_status();
void write_pdu(uint8_t* payload, uint32_t nof_bytes); rlc_am* parent = nullptr;
rlc_am_lte_tx* tx = nullptr;
uint32_t get_rx_buffered_bytes(); // returns sum of PDUs in rx_window byte_buffer_pool* pool = nullptr;
uint32_t get_sdu_rx_latency_ms();
/****************************************************************************
// Timeout callback interface * Configurable parameters
void timer_expired(uint32_t timeout_id); * Ref: 3GPP TS 36.322 v10.0.0 Section 7
***************************************************************************/
// Functions needed by Tx subclass to query rx state rlc_am_config_t cfg = {};
int get_status_pdu_length();
int get_status_pdu(rlc_status_pdu_t* status, const uint32_t nof_bytes); // RX SDU buffers
bool get_do_status(); unique_byte_buffer_t rx_sdu;
private: /****************************************************************************
void handle_data_pdu(uint8_t* payload, uint32_t nof_bytes, rlc_amd_pdu_header_t& header); * State variables and counters
void handle_data_pdu_segment(uint8_t* payload, uint32_t nof_bytes, rlc_amd_pdu_header_t& header); * Ref: 3GPP TS 36.322 v10.0.0 Section 7
void reassemble_rx_sdus(); ***************************************************************************/
bool inside_rx_window(const int16_t sn);
void debug_state(); // Rx state variables
void print_rx_segments(); uint32_t vr_r = 0; // Receive state. SN following last in-sequence received PDU. Low edge of rx window
bool add_segment_and_check(rlc_amd_rx_pdu_segments_t* pdu, rlc_amd_rx_pdu* segment); uint32_t vr_mr = RLC_AM_WINDOW_SIZE; // Max acceptable receive state. High edge of rx window. vr_r + window size.
void reset_status(); uint32_t vr_x = 0; // t_reordering state. SN following PDU which triggered t_reordering.
uint32_t vr_ms = 0; // Max status tx state. Highest possible value of SN for ACK_SN in status PDU.
rlc_am_lte* parent = nullptr; uint32_t vr_h = 0; // Highest rx state. SN following PDU with highest SN among rxed PDUs.
byte_buffer_pool* pool = nullptr;
srslog::basic_logger& logger; // Mutex to protect members
std::mutex mutex;
/****************************************************************************
* Configurable parameters // Rx windows
* Ref: 3GPP TS 36.322 v10.0.0 Section 7 rlc_ringbuffer_t<rlc_amd_rx_pdu, RLC_AM_WINDOW_SIZE> rx_window;
***************************************************************************/ std::map<uint32_t, rlc_amd_rx_pdu_segments_t> rx_segments;
rlc_am_config_t cfg = {};
bool poll_received = false;
// RX SDU buffers std::atomic<bool> do_status = {false}; // light-weight access from Tx entity
unique_byte_buffer_t rx_sdu;
/****************************************************************************
/**************************************************************************** * Timers
* State variables and counters * Ref: 3GPP TS 36.322 v10.0.0 Section 7
* Ref: 3GPP TS 36.322 v10.0.0 Section 7 ***************************************************************************/
***************************************************************************/
srsran::timer_handler::unique_timer reordering_timer;
// Rx state variables
uint32_t vr_r = 0; // Receive state. SN following last in-sequence received PDU. Low edge of rx window srsran::rolling_average<double> sdu_rx_latency_ms;
uint32_t vr_mr = RLC_AM_WINDOW_SIZE; // Max acceptable receive state. High edge of rx window. vr_r + window size.
uint32_t vr_x = 0; // t_reordering state. SN following PDU which triggered t_reordering.
uint32_t vr_ms = 0; // Max status tx state. Highest possible value of SN for ACK_SN in status PDU.
uint32_t vr_h = 0; // Highest rx state. SN following PDU with highest SN among rxed PDUs.
// Mutex to protect members
std::mutex mutex;
// Rx windows
rlc_ringbuffer_t<rlc_amd_rx_pdu, RLC_AM_WINDOW_SIZE> rx_window;
std::map<uint32_t, rlc_amd_rx_pdu_segments_t> rx_segments;
bool poll_received = false;
std::atomic<bool> do_status = {false}; // light-weight access from Tx entity
/****************************************************************************
* Timers
* Ref: 3GPP TS 36.322 v10.0.0 Section 7
***************************************************************************/
srsran::timer_handler::unique_timer reordering_timer;
srsran::rolling_average<double> sdu_rx_latency_ms;
};
// Common variables needed/provided by parent class
srsue::rrc_interface_rlc* rrc = nullptr;
srslog::basic_logger& logger;
srsue::pdcp_interface_rlc* pdcp = nullptr;
srsran::timer_handler* timers = nullptr;
uint32_t lcid = 0;
rlc_config_t cfg = {};
std::string rb_name;
static const int poll_periodicity = 8; // After how many data PDUs a status PDU shall be requested
// Rx and Tx objects
rlc_am_lte_tx tx;
rlc_am_lte_rx rx;
std::mutex metrics_mutex;
rlc_bearer_metrics_t metrics = {};
}; };
} // namespace srsran } // namespace srsran

@ -29,38 +29,6 @@
namespace srsran { namespace srsran {
/// 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;
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 { struct rlc_amd_retx_t {
uint32_t sn; uint32_t sn;
bool is_segment; bool is_segment;
@ -99,17 +67,18 @@ void rlc_am_read_status_pdu(uint8_t* payload, uint32_t nof_bytes, rlc_status_pdu
void rlc_am_write_status_pdu(rlc_status_pdu_t* status, byte_buffer_t* pdu); void rlc_am_write_status_pdu(rlc_status_pdu_t* status, byte_buffer_t* pdu);
int rlc_am_write_status_pdu(rlc_status_pdu_t* status, uint8_t* payload); int rlc_am_write_status_pdu(rlc_status_pdu_t* status, uint8_t* payload);
uint32_t rlc_am_packed_length(rlc_amd_pdu_header_t* header); uint32_t rlc_am_packed_length(rlc_amd_pdu_header_t* header);
uint32_t rlc_am_packed_length(rlc_status_pdu_t* status); uint32_t rlc_am_packed_length(rlc_status_pdu_t* status);
uint32_t rlc_am_packed_length(rlc_amd_retx_t retx); uint32_t rlc_am_packed_length(rlc_amd_retx_t retx);
bool rlc_am_is_pdu_segment(uint8_t* payload); bool rlc_am_is_pdu_segment(uint8_t* payload);
bool rlc_am_is_valid_status_pdu(const rlc_status_pdu_t& status, uint32_t rx_win_min = 0); bool rlc_am_is_valid_status_pdu(const rlc_status_pdu_t& status, uint32_t rx_win_min = 0);
std::string rlc_am_undelivered_sdu_info_to_string(const std::map<uint32_t, pdcp_pdu_info>& info_queue); std::string
void log_rlc_amd_pdu_header_to_string(srslog::log_channel& log_ch, const rlc_amd_pdu_header_t& header); rlc_am_undelivered_sdu_info_to_string(const std::map<uint32_t, pdcp_pdu_info<rlc_amd_pdu_header_t> >& info_queue);
bool rlc_am_start_aligned(const uint8_t fi); void log_rlc_amd_pdu_header_to_string(srslog::log_channel& log_ch, const rlc_amd_pdu_header_t& header);
bool rlc_am_end_aligned(const uint8_t fi); bool rlc_am_start_aligned(const uint8_t fi);
bool rlc_am_is_unaligned(const uint8_t fi); bool rlc_am_end_aligned(const uint8_t fi);
bool rlc_am_not_start_aligned(const uint8_t fi); bool rlc_am_is_unaligned(const uint8_t fi);
bool rlc_am_not_start_aligned(const uint8_t fi);
/** /**
* Logs Status PDU into provided log channel, using fmt_str as format string * Logs Status PDU into provided log channel, using fmt_str as format string

@ -26,6 +26,8 @@
#include "srsran/common/common.h" #include "srsran/common/common.h"
#include "srsran/common/timers.h" #include "srsran/common/timers.h"
#include "srsran/rlc/rlc_am_base.h" #include "srsran/rlc/rlc_am_base.h"
#include "srsran/rlc/rlc_am_data_structs.h"
#include "srsran/rlc/rlc_am_nr_packing.h"
#include "srsran/upper/byte_buffer_queue.h" #include "srsran/upper/byte_buffer_queue.h"
#include <map> #include <map>
#include <mutex> #include <mutex>
@ -34,114 +36,93 @@
namespace srsran { namespace srsran {
class rlc_am_nr : public rlc_common /******************************
*
* RLC AM NR entity
*
*****************************/
class rlc_am_nr_tx;
class rlc_am_nr_rx;
// Transmitter sub-class
class rlc_am_nr_tx : public rlc_am::rlc_am_base_tx
{ {
public: public:
rlc_am_nr(srslog::basic_logger& logger, explicit rlc_am_nr_tx(rlc_am* parent_);
uint32_t lcid_, ~rlc_am_nr_tx() = default;
srsue::pdcp_interface_rlc* pdcp_,
srsue::rrc_interface_rlc* rrc_,
srsran::timer_handler* timers_);
bool configure(const rlc_config_t& cfg_) final;
void stop() final;
rlc_mode_t get_mode() final;
uint32_t get_bearer() final;
void reestablish() final; void set_rx(rlc_am_nr_rx* rx_) { rx = rx_; }
void empty_queue() final; bool configure(const rlc_config_t& cfg_) final;
void set_bsr_callback(bsr_callback_t callback) final; uint32_t read_pdu(uint8_t* payload, uint32_t nof_bytes) final;
void handle_control_pdu(uint8_t* payload, uint32_t nof_bytes) final;
// PDCP interface void discard_sdu(uint32_t discard_sn) final;
void write_sdu(unique_byte_buffer_t sdu) final;
void discard_sdu(uint32_t pdcp_sn) final;
bool sdu_queue_is_full() final; bool sdu_queue_is_full() final;
void reestablish() final;
// MAC interface int write_sdu(unique_byte_buffer_t sdu);
void empty_queue() final;
bool has_data() final; bool has_data() final;
uint32_t get_buffer_state() final; uint32_t get_buffer_state() final;
void get_buffer_state(uint32_t& tx_queue, uint32_t& prio_tx_queue) final; void get_buffer_state(uint32_t& tx_queue, uint32_t& prio_tx_queue);
uint32_t read_pdu(uint8_t* payload, uint32_t nof_bytes) final;
void write_pdu(uint8_t* payload, uint32_t nof_bytes) final;
rlc_bearer_metrics_t get_metrics() final; void stop() final;
void reset_metrics() final;
private: private:
// Transmitter sub-class rlc_am* parent = nullptr;
class rlc_am_nr_tx rlc_am_nr_rx* rx = nullptr;
{
public: /****************************************************************************
explicit rlc_am_nr_tx(rlc_am_nr* parent_); * Configurable parameters
~rlc_am_nr_tx() = default; * Ref: 3GPP TS 38.322 v10.0.0 Section 7.4
***************************************************************************/
bool configure(const rlc_am_config_t& cfg_); rlc_am_config_t cfg = {};
void stop();
/****************************************************************************
int write_sdu(unique_byte_buffer_t sdu); * Tx state variables
uint32_t read_pdu(uint8_t* payload, uint32_t nof_bytes); * Ref: 3GPP TS 38.322 v10.0.0 Section 7.1
void discard_sdu(uint32_t discard_sn); ***************************************************************************/
bool sdu_queue_is_full(); struct rlc_nr_tx_state_t {
uint32_t tx_next_ack;
bool has_data(); uint32_t tx_next;
uint32_t get_buffer_state(); uint32_t poll_sn;
uint32_t pdu_without_poll;
rlc_am_nr* parent = nullptr; uint32_t byte_without_poll;
srslog::basic_logger& logger; } st = {};
private: using rlc_amd_tx_pdu_nr = rlc_amd_tx_pdu<rlc_am_nr_pdu_header_t>;
byte_buffer_pool* pool = nullptr; rlc_ringbuffer_t<rlc_amd_tx_pdu_nr, RLC_AM_WINDOW_SIZE> tx_window;
/****************************************************************************
* Configurable parameters
* Ref: 3GPP TS 38.322 v10.0.0 Section 7.4
***************************************************************************/
rlc_am_config_t cfg = {};
};
// Receiver sub-class
class rlc_am_nr_rx
{
public:
explicit rlc_am_nr_rx(rlc_am_nr* parent_);
~rlc_am_nr_rx() = default;
bool configure(const rlc_am_config_t& cfg_);
void stop();
void write_pdu(uint8_t* payload, uint32_t nof_bytes);
rlc_am_nr* parent = nullptr;
srslog::basic_logger& logger;
private:
byte_buffer_pool* pool = nullptr;
/****************************************************************************
* Configurable parameters
* Ref: 3GPP TS 38.322 v10.0.0 Section 7.4
***************************************************************************/
rlc_am_config_t cfg = {};
};
// Common variables needed/provided by parent class
srsue::rrc_interface_rlc* rrc = nullptr;
srslog::basic_logger& logger;
srsue::pdcp_interface_rlc* pdcp = nullptr;
srsran::timer_handler* timers = nullptr;
uint32_t lcid = 0;
rlc_config_t cfg = {};
std::string rb_name;
static const int poll_periodicity = 8; // After how many data PDUs a status PDU shall be requested
// Rx and Tx objects
rlc_am_nr_tx tx;
rlc_am_nr_rx rx;
rlc_bearer_metrics_t metrics = {};
}; };
} // namespace srsran // Receiver sub-class
class rlc_am_nr_rx : public rlc_am::rlc_am_base_rx
{
public:
explicit rlc_am_nr_rx(rlc_am* parent_);
~rlc_am_nr_rx() = default;
void set_tx(rlc_am_nr_tx* tx_) { tx = tx_; }
bool configure(const rlc_config_t& cfg_) final;
void handle_data_pdu(uint8_t* payload, uint32_t nof_bytes) final;
void stop();
void reestablish();
uint32_t get_sdu_rx_latency_ms();
uint32_t get_rx_buffered_bytes();
private:
rlc_am* parent = nullptr;
rlc_am_nr_tx* tx = nullptr;
byte_buffer_pool* pool = nullptr;
/****************************************************************************
* Configurable parameters
* Ref: 3GPP TS 38.322 v10.0.0 Section 7.4
***************************************************************************/
rlc_am_config_t cfg = {};
};
} // namespace srsran
#endif // SRSRAN_RLC_AM_NR_H #endif // SRSRAN_RLC_AM_NR_H

@ -23,10 +23,13 @@
#define SRSRAN_RLC_COMMON_H #define SRSRAN_RLC_COMMON_H
#include "srsran/adt/circular_buffer.h" #include "srsran/adt/circular_buffer.h"
#include "srsran/adt/circular_map.h"
#include "srsran/adt/intrusive_list.h"
#include "srsran/interfaces/rlc_interface_types.h" #include "srsran/interfaces/rlc_interface_types.h"
#include "srsran/rlc/bearer_mem_pool.h" #include "srsran/rlc/bearer_mem_pool.h"
#include "srsran/rlc/rlc_metrics.h" #include "srsran/rlc/rlc_metrics.h"
#include <stdlib.h> #include <cstdlib>
#include <list>
namespace srsran { namespace srsran {
@ -247,8 +250,8 @@ public:
} }
} }
virtual rlc_mode_t get_mode() = 0; virtual rlc_mode_t get_mode() = 0;
virtual uint32_t get_bearer() = 0; virtual uint32_t get_lcid() = 0;
virtual rlc_bearer_metrics_t get_metrics() = 0; virtual rlc_bearer_metrics_t get_metrics() = 0;
virtual void reset_metrics() = 0; virtual void reset_metrics() = 0;

@ -50,7 +50,7 @@ public:
void empty_queue() override; void empty_queue() override;
rlc_mode_t get_mode() override; rlc_mode_t get_mode() override;
uint32_t get_bearer() override; uint32_t get_lcid() override;
rlc_bearer_metrics_t get_metrics() override; rlc_bearer_metrics_t get_metrics() override;
void reset_metrics() override; void reset_metrics() override;

@ -57,7 +57,7 @@ public:
bool is_mrb(); bool is_mrb();
rlc_mode_t get_mode(); rlc_mode_t get_mode();
uint32_t get_bearer(); uint32_t get_lcid() final;
// PDCP interface // PDCP interface
void write_sdu(unique_byte_buffer_t sdu); void write_sdu(unique_byte_buffer_t sdu);

@ -111,8 +111,8 @@ private:
uint32_t RX_Next_Highest = 0; // the SN following the SN of the UMD PDU with the highest SN among uint32_t RX_Next_Highest = 0; // the SN following the SN of the UMD PDU with the highest SN among
// received UMD PDUs. It serves as the higher edge of the reassembly window. // received UMD PDUs. It serves as the higher edge of the reassembly window.
uint32_t UM_Window_Size; uint32_t UM_Window_Size = 0;
uint32_t mod; // Rx counter modulus uint32_t mod = 0; // Rx counter modulus
// Rx window // Rx window
typedef struct { typedef struct {

@ -1,52 +0,0 @@
/**
* Copyright 2013-2021 Software Radio Systems Limited
*
* This file is part of srsRAN.
*
* srsRAN 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.
*
* srsRAN 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_RRC_NR_CFG_UTILS_H
#define SRSRAN_RRC_NR_CFG_UTILS_H
#include "srsran/asn1/rrc_nr.h"
#include "srsran/interfaces/gnb_rrc_nr_interfaces.h"
namespace srsran {
struct basic_cell_args_t {
uint32_t cell_id = 0x19B01;
uint32_t nof_prbs = 52;
uint32_t scs = 15;
bool is_standalone = true;
bool is_fdd = true;
std::string plmn = "90170";
uint32_t tac = 7;
};
void generate_default_pdcch_cfg_common(asn1::rrc_nr::pdcch_cfg_common_s& cfg, const basic_cell_args_t& args = {});
void generate_default_init_dl_bwp(asn1::rrc_nr::bwp_dl_common_s& cfg, const basic_cell_args_t& args = {});
void generate_default_dl_cfg_common(asn1::rrc_nr::dl_cfg_common_s& cfg, const basic_cell_args_t& args = {});
void generate_default_mib(const basic_cell_args_t& args, asn1::rrc_nr::mib_s& cfg);
void generate_default_serv_cell_cfg_common_sib(const basic_cell_args_t& args,
asn1::rrc_nr::serving_cell_cfg_common_sib_s& cfg);
void generate_default_sib1(const basic_cell_args_t& args, asn1::rrc_nr::sib1_s& cfg);
} // namespace srsran
#endif // SRSRAN_RRC_NR_CFG_UTILS_H

@ -23,7 +23,6 @@ add_subdirectory(common)
add_subdirectory(mac) add_subdirectory(mac)
add_subdirectory(phy) add_subdirectory(phy)
add_subdirectory(radio) add_subdirectory(radio)
add_subdirectory(rrc)
add_subdirectory(rlc) add_subdirectory(rlc)
add_subdirectory(pdcp) add_subdirectory(pdcp)
add_subdirectory(gtpu) add_subdirectory(gtpu)

@ -20,6 +20,7 @@
*/ */
#include "srsran/asn1/rrc_nr_utils.h" #include "srsran/asn1/rrc_nr_utils.h"
#include "srsran/asn1/obj_id_cmp_utils.h"
#include "srsran/asn1/rrc_nr.h" #include "srsran/asn1/rrc_nr.h"
#include "srsran/common/band_helper.h" #include "srsran/common/band_helper.h"
#include "srsran/config.h" #include "srsran/config.h"
@ -1489,6 +1490,24 @@ bool make_phy_ssb_cfg(const srsran_carrier_nr_t& carrier,
return true; return true;
} }
bool make_phy_mib(const asn1::rrc_nr::mib_s& mib_cfg, srsran_mib_nr_t* mib)
{
mib->sfn = 0;
mib->ssb_idx = 0;
mib->hrf = 0;
mib->scs_common =
mib_cfg.sub_carrier_spacing_common.value == asn1::rrc_nr::mib_s::sub_carrier_spacing_common_opts::scs15or60
? srsran_subcarrier_spacing_15kHz
: srsran_subcarrier_spacing_30kHz;
mib->ssb_offset = mib_cfg.ssb_subcarrier_offset;
mib->dmrs_typeA_pos = (srsran_dmrs_sch_typeA_pos_t)mib_cfg.dmrs_type_a_position.value;
mib->coreset0_idx = mib_cfg.pdcch_cfg_sib1.ctrl_res_set_zero;
mib->ss0_idx = mib_cfg.pdcch_cfg_sib1.search_space_zero;
mib->cell_barred = mib_cfg.cell_barred.value == asn1::rrc_nr::mib_s::cell_barred_opts::barred;
mib->intra_freq_reselection = mib_cfg.intra_freq_resel.value == asn1::rrc_nr::mib_s::intra_freq_resel_opts::allowed;
return true;
}
bool make_pdsch_cfg_from_serv_cell(const asn1::rrc_nr::serving_cell_cfg_s& serv_cell, srsran_sch_hl_cfg_nr_t* sch_hl) bool make_pdsch_cfg_from_serv_cell(const asn1::rrc_nr::serving_cell_cfg_s& serv_cell, srsran_sch_hl_cfg_nr_t* sch_hl)
{ {
if (serv_cell.csi_meas_cfg_present and if (serv_cell.csi_meas_cfg_present and
@ -1603,4 +1622,40 @@ bool fill_phy_pdcch_cfg_common(const asn1::rrc_nr::pdcch_cfg_common_s& pdcch_cfg
return true; return true;
} }
/**************************
* Asn1 Obj Id
*************************/
ASN1_OBJ_ID_DEFINE(asn1::rrc_nr::srb_to_add_mod_s, srb_id);
ASN1_OBJ_ID_DEFINE(asn1::rrc_nr::drb_to_add_mod_s, drb_id);
ASN1_OBJ_ID_DEFINE(asn1::rrc_nr::meas_obj_to_add_mod_s, meas_obj_id);
ASN1_OBJ_ID_DEFINE(asn1::rrc_nr::report_cfg_to_add_mod_s, report_cfg_id);
ASN1_OBJ_ID_DEFINE(asn1::rrc_nr::meas_id_to_add_mod_s, meas_id);
} // namespace srsran } // namespace srsran
namespace asn1 {
namespace rrc_nr {
bool operator==(const srb_to_add_mod_s& lhs, const srb_to_add_mod_s& rhs)
{
if (lhs.srb_id != rhs.srb_id or lhs.pdcp_cfg_present != rhs.pdcp_cfg_present) {
return false;
}
// TODO: check remaining fields
return true;
}
bool operator==(const drb_to_add_mod_s& lhs, const drb_to_add_mod_s& rhs)
{
if (lhs.drb_id != rhs.drb_id or lhs.pdcp_cfg_present != rhs.pdcp_cfg_present or
lhs.cn_assoc_present != rhs.cn_assoc_present) {
return false;
}
// TODO: check remaining fields
return true;
}
} // namespace rrc_nr
} // namespace asn1

@ -20,6 +20,7 @@
*/ */
#include "srsran/asn1/rrc_utils.h" #include "srsran/asn1/rrc_utils.h"
#include "srsran/asn1/obj_id_cmp_utils.h"
#include "srsran/asn1/rrc.h" #include "srsran/asn1/rrc.h"
#include "srsran/config.h" #include "srsran/config.h"
#include <algorithm> #include <algorithm>
@ -138,12 +139,12 @@ srsran::rlc_config_t make_rlc_config_t(const asn1::rrc::rlc_cfg_c& asn1_type)
srsran::rlc_config_t rlc_cfg; srsran::rlc_config_t rlc_cfg;
switch (asn1_type.type().value) { switch (asn1_type.type().value) {
case asn1::rrc::rlc_cfg_c::types_opts::am: case asn1::rrc::rlc_cfg_c::types_opts::am:
rlc_cfg.rlc_mode = rlc_mode_t::am; rlc_cfg.rlc_mode = rlc_mode_t::am;
rlc_cfg.am.t_poll_retx = asn1_type.am().ul_am_rlc.t_poll_retx.to_number(); rlc_cfg.am.t_poll_retx = asn1_type.am().ul_am_rlc.t_poll_retx.to_number();
rlc_cfg.am.poll_pdu = asn1_type.am().ul_am_rlc.poll_pdu.to_number(); rlc_cfg.am.poll_pdu = asn1_type.am().ul_am_rlc.poll_pdu.to_number();
rlc_cfg.am.poll_byte = asn1_type.am().ul_am_rlc.poll_byte.to_number() < 0 rlc_cfg.am.poll_byte = asn1_type.am().ul_am_rlc.poll_byte.to_number() < 0
? -1 ? -1
: asn1_type.am().ul_am_rlc.poll_byte.to_number() * 1000; // KB : asn1_type.am().ul_am_rlc.poll_byte.to_number() * 1000; // KB
rlc_cfg.am.max_retx_thresh = asn1_type.am().ul_am_rlc.max_retx_thres.to_number(); rlc_cfg.am.max_retx_thresh = asn1_type.am().ul_am_rlc.max_retx_thres.to_number();
rlc_cfg.am.t_reordering = asn1_type.am().dl_am_rlc.t_reordering.to_number(); rlc_cfg.am.t_reordering = asn1_type.am().dl_am_rlc.t_reordering.to_number();
rlc_cfg.am.t_status_prohibit = asn1_type.am().dl_am_rlc.t_status_prohibit.to_number(); rlc_cfg.am.t_status_prohibit = asn1_type.am().dl_am_rlc.t_status_prohibit.to_number();
@ -1096,88 +1097,18 @@ sib13_t make_sib13(const asn1::rrc::sib_type13_r9_s& asn1_type)
return sib13; return sib13;
} }
} // namespace srsran
namespace asn1 {
namespace rrc {
/************************** /**************************
* RRC Obj Id * Asn1 Obj Id
*************************/ *************************/
uint8_t get_rrc_obj_id(const srb_to_add_mod_s& srb) ASN1_OBJ_ID_DEFINE(asn1::rrc::srb_to_add_mod_s, srb_id);
{ ASN1_OBJ_ID_DEFINE(asn1::rrc::drb_to_add_mod_s, drb_id);
return srb.srb_id; ASN1_OBJ_ID_DEFINE(asn1::rrc::black_cells_to_add_mod_s, cell_idx);
} ASN1_OBJ_ID_DEFINE(asn1::rrc::cells_to_add_mod_s, cell_idx);
uint8_t get_rrc_obj_id(const drb_to_add_mod_s& drb) ASN1_OBJ_ID_DEFINE(asn1::rrc::cells_to_add_mod_nr_r15_s, cell_idx_r15);
{ ASN1_OBJ_ID_DEFINE(asn1::rrc::meas_obj_to_add_mod_s, meas_obj_id);
return drb.drb_id; ASN1_OBJ_ID_DEFINE(asn1::rrc::report_cfg_to_add_mod_s, report_cfg_id);
} ASN1_OBJ_ID_DEFINE(asn1::rrc::meas_id_to_add_mod_s, meas_id);
uint8_t get_rrc_obj_id(const black_cells_to_add_mod_s& obj) ASN1_OBJ_ID_DEFINE(asn1::rrc::scell_to_add_mod_r10_s, scell_idx_r10);
{
return obj.cell_idx;
}
uint8_t get_rrc_obj_id(const cells_to_add_mod_s& obj)
{
return obj.cell_idx;
}
uint8_t get_rrc_obj_id(const cells_to_add_mod_nr_r15_s& obj)
{
return obj.cell_idx_r15;
}
uint8_t get_rrc_obj_id(const meas_obj_to_add_mod_s& obj)
{
return obj.meas_obj_id;
}
uint8_t get_rrc_obj_id(const report_cfg_to_add_mod_s& obj)
{
return obj.report_cfg_id;
}
uint8_t get_rrc_obj_id(const meas_id_to_add_mod_s& obj)
{
return obj.meas_id;
}
uint8_t get_rrc_obj_id(const scell_to_add_mod_r10_s& obj)
{
return obj.scell_idx_r10;
}
void set_rrc_obj_id(srb_to_add_mod_s& srb, uint8_t id) } // namespace srsran
{
srb.srb_id = id;
}
void set_rrc_obj_id(drb_to_add_mod_s& drb, uint8_t id)
{
drb.drb_id = id;
}
void set_rrc_obj_id(black_cells_to_add_mod_s& obj, uint8_t id)
{
obj.cell_idx = id;
}
void set_rrc_obj_id(cells_to_add_mod_s& obj, uint8_t id)
{
obj.cell_idx = id;
}
void set_rrc_obj_id(cells_to_add_mod_nr_r15_s& obj, uint8_t id)
{
obj.cell_idx_r15 = id;
}
void set_rrc_obj_id(meas_obj_to_add_mod_s& obj, uint8_t id)
{
obj.meas_obj_id = id;
}
void set_rrc_obj_id(report_cfg_to_add_mod_s& obj, uint8_t id)
{
obj.report_cfg_id = id;
}
void set_rrc_obj_id(meas_id_to_add_mod_s& obj, uint8_t id)
{
obj.meas_id = id;
}
void set_rrc_obj_id(scell_to_add_mod_r10_s& obj, uint8_t id)
{
obj.scell_idx_r10 = id;
}
} // namespace rrc
} // namespace asn1

@ -142,23 +142,21 @@ double srsran_band_helper::get_abs_freq_point_a_from_center_freq(uint32_t nof_pr
SRSRAN_NRE); SRSRAN_NRE);
} }
uint32_t uint32_t srsran_band_helper::find_lower_bound_abs_freq_ssb(uint16_t band,
srsran_band_helper::get_abs_freq_ssb_arfcn(uint16_t band, srsran_subcarrier_spacing_t scs, uint32_t freq_point_a_arfcn) srsran_subcarrier_spacing_t scs,
uint32_t min_center_freq_hz)
{ {
sync_raster_t sync_raster = get_sync_raster(band, scs); sync_raster_t sync_raster = get_sync_raster(band, scs);
if (!sync_raster.valid()) { if (!sync_raster.valid()) {
return 0; return 0;
} }
// double abs_freq_ssb_hz = sync_raster.get_frequency(); double ssb_bw_hz = SRSRAN_SSB_BW_SUBC * SRSRAN_SUBC_SPACING_NR(scs);
double freq_point_a_hz = nr_arfcn_to_freq(freq_point_a_arfcn);
double ssb_bw_hz = SRSRAN_SSB_BW_SUBC * SRSRAN_SUBC_SPACING_NR(scs);
while (!sync_raster.end()) { while (!sync_raster.end()) {
double abs_freq_ssb_hz = sync_raster.get_frequency(); double abs_freq_ssb_hz = sync_raster.get_frequency();
if ((abs_freq_ssb_hz > (freq_point_a_hz + ssb_bw_hz / 2)) and if ((abs_freq_ssb_hz > min_center_freq_hz + ssb_bw_hz / 2) and
((uint32_t)std::round(abs_freq_ssb_hz - freq_point_a_hz) % SRSRAN_SUBC_SPACING_NR(scs) == 0)) { ((uint32_t)std::round(abs_freq_ssb_hz - min_center_freq_hz) % SRSRAN_SUBC_SPACING_NR(scs) == 0)) {
return freq_to_nr_arfcn(abs_freq_ssb_hz); return freq_to_nr_arfcn(abs_freq_ssb_hz);
} }
@ -167,6 +165,16 @@ srsran_band_helper::get_abs_freq_ssb_arfcn(uint16_t band, srsran_subcarrier_spac
return 0; return 0;
} }
uint32_t srsran_band_helper::get_abs_freq_ssb_arfcn(uint16_t band,
srsran_subcarrier_spacing_t scs,
uint32_t freq_point_a_arfcn,
uint32_t coreset0_offset_rb)
{
double freq_point_a_hz = nr_arfcn_to_freq(freq_point_a_arfcn);
double coreset0_offset_hz = coreset0_offset_rb * SRSRAN_NRE * SRSRAN_SUBC_SPACING_NR(scs);
return find_lower_bound_abs_freq_ssb(band, scs, freq_point_a_hz + coreset0_offset_hz);
}
srsran_ssb_patern_t srsran_band_helper::get_ssb_pattern(uint16_t band, srsran_subcarrier_spacing_t scs) const srsran_ssb_patern_t srsran_band_helper::get_ssb_pattern(uint16_t band, srsran_subcarrier_spacing_t scs) const
{ {
// Look for the given band and SCS // Look for the given band and SCS

@ -78,4 +78,4 @@ void srsran_debug_handle_crash(int argc, char** argv)
signal(SIGPIPE, crash_handler); signal(SIGPIPE, crash_handler);
} }
#endif // HAVE_BACKWARD #endif // HAVE_BACKWARD

@ -56,9 +56,11 @@ int bands_test_nr()
TESTASSERT(bands.nr_arfcn_to_freq(342000) == 1710.0e6); TESTASSERT(bands.nr_arfcn_to_freq(342000) == 1710.0e6);
TESTASSERT(bands.nr_arfcn_to_freq(348000) == 1740.0e6); TESTASSERT(bands.nr_arfcn_to_freq(348000) == 1740.0e6);
TESTASSERT(bands.nr_arfcn_to_freq(361000) == 1805.0e6); TESTASSERT(bands.nr_arfcn_to_freq(361000) == 1805.0e6);
TESTASSERT_EQ(1842.5e6, bands.nr_arfcn_to_freq(368500));
TESTASSERT(bands.nr_arfcn_to_freq(376000) == 1880.0e6); TESTASSERT(bands.nr_arfcn_to_freq(376000) == 1880.0e6);
TESTASSERT(bands.get_abs_freq_point_a_arfcn(52, 368500) == 367564); TESTASSERT(bands.get_abs_freq_point_a_arfcn(52, 368500) == 367564);
TESTASSERT(bands.get_abs_freq_ssb_arfcn(3, srsran_subcarrier_spacing_15kHz, 367564) > 367924); TESTASSERT(bands.get_abs_freq_ssb_arfcn(3, srsran_subcarrier_spacing_15kHz, 367564) > 367924);
TESTASSERT_EQ(368410, bands.get_abs_freq_ssb_arfcn(3, srsran_subcarrier_spacing_15kHz, 367564, 12));
// n5 // n5
TESTASSERT(bands.get_duplex_mode(5) == SRSRAN_DUPLEX_MODE_FDD); TESTASSERT(bands.get_duplex_mode(5) == SRSRAN_DUPLEX_MODE_FDD);
TESTASSERT(bands.nr_arfcn_to_freq(176300) == 881.5e6); TESTASSERT(bands.nr_arfcn_to_freq(176300) == 881.5e6);

@ -89,7 +89,9 @@ bool threads_new_rt_cpu(pthread_t* thread, void* (*start_routine)(void*), void*
#else #else
// All threads have normal priority except prio_offset=0,1,2,3,4 // All threads have normal priority except prio_offset=0,1,2,3,4
if (prio_offset >= 0 && prio_offset < 5) { if (prio_offset >= 0 && prio_offset < 5) {
param.sched_priority = sched_get_priority_max(SCHED_FIFO) - prio_offset; // Subtract one to the priority offset to avoid scheduling threads with the highest priority that could contend with
// OS critical tasks.
param.sched_priority = sched_get_priority_max(SCHED_FIFO) - prio_offset - 1;
if (pthread_attr_init(&attr)) { if (pthread_attr_init(&attr)) {
perror("pthread_attr_init"); perror("pthread_attr_init");
} else { } else {

@ -225,7 +225,8 @@ static int srsran_dmrs_sch_put_symbol(srsran_dmrs_sch_t* q,
// ... save first consecutive PRB in the group // ... save first consecutive PRB in the group
prb_start = prb_idx; prb_start = prb_idx;
// ... discard unused pilots and reset counter // ... discard unused pilots and reset counter unless the PDSCH transmission carries SIB
prb_skip = SRSRAN_MAX(0, (int)prb_skip - (int)dmrs_cfg->reference_point_k_rb);
srsran_sequence_state_advance(&sequence_state, prb_skip * nof_pilots_x_prb * 2); srsran_sequence_state_advance(&sequence_state, prb_skip * nof_pilots_x_prb * 2);
prb_skip = 0; prb_skip = 0;
} }
@ -713,7 +714,8 @@ static int srsran_dmrs_sch_get_symbol(srsran_dmrs_sch_t* q,
// ... save first consecutive PRB in the group // ... save first consecutive PRB in the group
prb_start = prb_idx; prb_start = prb_idx;
// ... discard unused pilots and reset counter // ... discard unused pilots and reset counter unless the PDSCH transmission carries SIB
prb_skip = SRSRAN_MAX(0, (int)prb_skip - (int)dmrs_cfg->reference_point_k_rb);
srsran_sequence_state_advance(&sequence_state, prb_skip * nof_pilots_x_prb * 2); srsran_sequence_state_advance(&sequence_state, prb_skip * nof_pilots_x_prb * 2);
prb_skip = 0; prb_skip = 0;
} }

@ -347,9 +347,9 @@ int srsran_symbol_sz_power2(uint32_t nof_prb)
return 256; return 256;
} else if (nof_prb <= 25) { } else if (nof_prb <= 25) {
return 512; return 512;
} else if (nof_prb <= 50) { } else if (nof_prb <= 52) {
return 1024; return 1024;
} else if (nof_prb <= 75) { } else if (nof_prb <= 79) {
return 1536; return 1536;
} else if (nof_prb <= 110) { } else if (nof_prb <= 110) {
return 2048; return 2048;

@ -537,6 +537,19 @@ void srsran_combine_csi_trs_measurements(const srsran_csi_trs_measurements_t* a,
dst->nof_re = nof_re_sum; dst->nof_re = nof_re_sum;
} }
uint32_t pdcch_nr_bundle_size(srsran_coreset_bundle_size_t x)
{
switch (x) {
case srsran_coreset_bundle_size_n2:
return 2;
case srsran_coreset_bundle_size_n3:
return 3;
case srsran_coreset_bundle_size_n6:
return 6;
}
return 0;
}
typedef struct { typedef struct {
uint32_t mux_pattern; uint32_t mux_pattern;
uint32_t nof_prb; uint32_t nof_prb;
@ -605,6 +618,44 @@ static const coreset_zero_entry_t coreset_zero_30_15[16] = {
{}, {},
}; };
int srsran_coreset_to_str(srsran_coreset_t* coreset, char* str, uint32_t str_len)
{
if (coreset == NULL || str == NULL || str_len == 0) {
return 0;
}
char freq_res_str[SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE] = {};
srsran_vec_sprint_bin(
freq_res_str, sizeof(freq_res_str), (uint8_t*)coreset->freq_resources, SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE);
return srsran_print_check(
str,
str_len,
0,
"\n"
" - coreset_id=%d\n"
" - mapping_type=%s\n"
" - duration=%d\n"
" - freq_res=%s\n"
" - dmrs_scrambling_present=%s (id=%d)\n"
" - precoder_granularity=%s\n"
" - interleaver_size=%d\n"
" - reg_bundle_size=%d\n"
" - shift_index=%d\n"
" - offset_rb=%d\n",
coreset->id,
coreset->mapping_type == srsran_coreset_mapping_type_non_interleaved ? "non-interleaved" : "interleaved",
coreset->duration,
freq_res_str,
coreset->dmrs_scrambling_id_present ? "true" : "false",
coreset->dmrs_scrambling_id,
coreset->precoder_granularity == srsran_coreset_precoder_granularity_contiguous ? "contiguous" : "reg_bundle",
pdcch_nr_bundle_size(coreset->interleaver_size),
pdcch_nr_bundle_size(coreset->reg_bundle_size),
coreset->shift_index,
coreset->offset_rb);
}
int srsran_coreset_zero(uint32_t n_cell_id, int srsran_coreset_zero(uint32_t n_cell_id,
uint32_t ssb_pointA_freq_offset_Hz, uint32_t ssb_pointA_freq_offset_Hz,
srsran_subcarrier_spacing_t ssb_scs, srsran_subcarrier_spacing_t ssb_scs,
@ -691,6 +742,48 @@ int srsran_coreset_zero(uint32_t n_cell_id,
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
int srsran_coreset0_ssb_offset(uint32_t idx, srsran_subcarrier_spacing_t ssb_scs, srsran_subcarrier_spacing_t pdcch_scs)
{
// Verify inputs
if (idx >= 16) {
ERROR("Invalid CORESET Zero input. idx=%d", idx);
return SRSRAN_ERROR_INVALID_INPUTS;
}
// Default entry to NULL
const coreset_zero_entry_t* entry = NULL;
// Table 13-1: Set of resource blocks and slot symbols of CORESET for Type0-PDCCH search space set
// when {SS/PBCH block, PDCCH} SCS is {15, 15} kHz for frequency bands with minimum channel
// bandwidth 5 MHz or 10 MHz
if (ssb_scs == srsran_subcarrier_spacing_15kHz && pdcch_scs == srsran_subcarrier_spacing_15kHz) {
entry = &coreset_zero_15_15[idx];
}
// Table 13-2: Set of resource blocks and slot symbols of CORESET for Type0-PDCCH search space set
// when {SS/PBCH block, PDCCH} SCS is {15, 30} kHz for frequency bands with minimum channel
// bandwidth 5 MHz or 10 MHz
if (ssb_scs == srsran_subcarrier_spacing_15kHz && pdcch_scs == srsran_subcarrier_spacing_30kHz) {
entry = &coreset_zero_15_30[idx];
}
// Table 13-3: Set of resource blocks and slot symbols of CORESET for Type0-PDCCH search space set
// when {SS/PBCH block, PDCCH} SCS is {30, 15} kHz for frequency bands with minimum channel
// bandwidth 5 MHz or 10 MHz
if (ssb_scs == srsran_subcarrier_spacing_30kHz && pdcch_scs == srsran_subcarrier_spacing_15kHz) {
entry = &coreset_zero_30_15[idx];
}
// Check a valid entry has been selected
if (entry == NULL) {
ERROR("Unhandled case ssb_scs=%s, pdcch_scs=%s",
srsran_subcarrier_spacing_to_str(ssb_scs),
srsran_subcarrier_spacing_to_str(pdcch_scs));
return SRSRAN_ERROR;
}
return entry->offset_rb;
}
const char* srsran_ssb_pattern_to_str(srsran_ssb_patern_t pattern) const char* srsran_ssb_pattern_to_str(srsran_ssb_patern_t pattern)
{ {
switch (pattern) { switch (pattern) {

@ -1282,6 +1282,7 @@ static uint32_t dci_nr_format_1_0_to_str(const srsran_dci_dl_nr_t* dci, char* st
// System information indicator 1 bit // System information indicator 1 bit
if (rnti_type == srsran_rnti_type_si) { if (rnti_type == srsran_rnti_type_si) {
len = srsran_print_check(str, str_len, len, "sii=%d ", dci->sii); len = srsran_print_check(str, str_len, len, "sii=%d ", dci->sii);
len = srsran_print_check(str, str_len, len, "coreset0_bw=%d ", dci->coreset0_bw);
} }
// Downlink assignment index 2 bits // Downlink assignment index 2 bits

@ -313,19 +313,6 @@ int srsran_pdcch_nr_set_carrier(srsran_pdcch_nr_t* q,
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
static uint32_t pdcch_nr_bundle_size(srsran_coreset_bundle_size_t x)
{
switch (x) {
case srsran_coreset_bundle_size_n2:
return 2;
case srsran_coreset_bundle_size_n3:
return 3;
case srsran_coreset_bundle_size_n6:
return 6;
}
return 0;
}
static int pdcch_nr_cce_to_reg_mapping_non_interleaved(const srsran_coreset_t* coreset, static int pdcch_nr_cce_to_reg_mapping_non_interleaved(const srsran_coreset_t* coreset,
const srsran_dci_location_t* dci_location, const srsran_dci_location_t* dci_location,
bool rb_mask[SRSRAN_MAX_PRB_NR]) bool rb_mask[SRSRAN_MAX_PRB_NR])

@ -568,6 +568,14 @@ static int ra_dl_dmrs(const srsran_sch_hl_cfg_nr_t* hl_cfg, const srsran_dci_dl_
(cfg->grant.mapping == srsran_sch_mapping_type_A) ? hl_cfg->dmrs_typeA.present : hl_cfg->dmrs_typeB.present; (cfg->grant.mapping == srsran_sch_mapping_type_A) ? hl_cfg->dmrs_typeA.present : hl_cfg->dmrs_typeB.present;
if (dci->ctx.format == srsran_dci_format_nr_1_0 || !dedicated_dmrs_present) { if (dci->ctx.format == srsran_dci_format_nr_1_0 || !dedicated_dmrs_present) {
// The reference point for k is
// - for PDSCH transmission carrying SIB1, subcarrier 0 of the lowest-numbered common resource block in the
// CORESET configured by the PBCH
//- otherwise, subcarrier 0 in common resource block 0
if (dci->ctx.rnti_type == srsran_rnti_type_si) {
cfg->dmrs.reference_point_k_rb = dci->ctx.coreset_start_rb;
}
if (cfg->grant.mapping == srsran_sch_mapping_type_A) { if (cfg->grant.mapping == srsran_sch_mapping_type_A) {
// Absent default values are defined is TS 38.331 - DMRS-DownlinkConfig // Absent default values are defined is TS 38.331 - DMRS-DownlinkConfig
cfg->dmrs.additional_pos = srsran_dmrs_sch_add_pos_2; cfg->dmrs.additional_pos = srsran_dmrs_sch_add_pos_2;

@ -100,8 +100,10 @@ static int test_52prb_base()
TESTASSERT(srsran_dci_nr_size(&dci, srsran_search_space_type_ue, srsran_dci_format_nr_0_1) == 36); TESTASSERT(srsran_dci_nr_size(&dci, srsran_search_space_type_ue, srsran_dci_format_nr_0_1) == 36);
TESTASSERT(srsran_dci_nr_size(&dci, srsran_search_space_type_ue, srsran_dci_format_nr_1_1) == 41); TESTASSERT(srsran_dci_nr_size(&dci, srsran_search_space_type_ue, srsran_dci_format_nr_1_1) == 41);
TESTASSERT(srsran_dci_nr_size(&dci, srsran_search_space_type_rar, srsran_dci_format_nr_rar) == 27); TESTASSERT(srsran_dci_nr_size(&dci, srsran_search_space_type_rar, srsran_dci_format_nr_rar) == 27);
TESTASSERT(srsran_dci_nr_size(&dci, srsran_search_space_type_common_0, srsran_dci_format_nr_1_0) == 39);
srsran_dci_ctx_t ctx = {}; srsran_dci_ctx_t ctx = {};
ctx.rnti = 0x1234; ctx.rnti = 0x1234;
ctx.ss_type = srsran_search_space_type_common_3; ctx.ss_type = srsran_search_space_type_common_3;
ctx.rnti_type = srsran_rnti_type_c; ctx.rnti_type = srsran_rnti_type_c;
@ -358,6 +360,43 @@ static int test_52prb_base()
TESTASSERT(memcmp(&dci_tx, &dci_rx, sizeof(srsran_dci_dl_nr_t)) == 0); TESTASSERT(memcmp(&dci_tx, &dci_rx, sizeof(srsran_dci_dl_nr_t)) == 0);
} }
// Test DL DCI 1_0 Packing/Unpacking and info for SI-RNTI
ctx.format = srsran_dci_format_nr_1_0;
ctx.rnti = 0xffff;
ctx.ss_type = srsran_search_space_type_common_0;
ctx.rnti_type = srsran_rnti_type_si;
dci.cfg.coreset0_bw = 48;
for (uint32_t i = 0; i < nof_repetitions; i++) {
srsran_dci_dl_nr_t dci_tx = {};
dci_tx.ctx = ctx;
dci_tx.freq_domain_assigment = 0x120;
dci_tx.time_domain_assigment = 0;
dci_tx.vrb_to_prb_mapping = 0;
dci_tx.mcs = srsran_random_uniform_int_dist(random_gen, 0, 31);
dci_tx.rv = srsran_random_uniform_int_dist(random_gen, 0, 3);
dci_tx.sii = 1; // bit set to 1 indicates SI message other than SIB1
dci_tx.coreset0_bw = 48;
// Pack
srsran_dci_msg_nr_t dci_msg = {};
TESTASSERT(srsran_dci_nr_dl_pack(&dci, &dci_tx, &dci_msg) == SRSRAN_SUCCESS);
// Unpack
srsran_dci_dl_nr_t dci_rx = {};
TESTASSERT(srsran_dci_nr_dl_unpack(&dci, &dci_msg, &dci_rx) == SRSRAN_SUCCESS);
// To string
char str[512];
TESTASSERT(srsran_dci_dl_nr_to_str(&dci, &dci_tx, str, (uint32_t)sizeof(str)) != 0);
INFO("Tx: %s", str);
TESTASSERT(srsran_dci_dl_nr_to_str(&dci, &dci_rx, str, (uint32_t)sizeof(str)) != 0);
INFO("Rx: %s", str);
// Assert
TESTASSERT(memcmp(&dci_tx, &dci_rx, sizeof(srsran_dci_dl_nr_t)) == 0);
}
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }

@ -71,12 +71,12 @@ if(RF_FOUND)
list(APPEND SOURCES_RF rf_zmq_imp.c rf_zmq_imp_tx.c rf_zmq_imp_rx.c) list(APPEND SOURCES_RF rf_zmq_imp.c rf_zmq_imp_tx.c rf_zmq_imp_rx.c)
endif (ZEROMQ_FOUND) endif (ZEROMQ_FOUND)
add_library(srsran_rf SHARED ${SOURCES_RF}) add_library(srsran_rf STATIC ${SOURCES_RF})
target_link_libraries(srsran_rf srsran_rf_utils srsran_phy) target_link_libraries(srsran_rf srsran_rf_utils srsran_phy)
set_target_properties(srsran_rf PROPERTIES VERSION ${SRSRAN_VERSION_STRING} SOVERSION ${SRSRAN_SOVERSION}) set_target_properties(srsran_rf PROPERTIES VERSION ${SRSRAN_VERSION_STRING} SOVERSION ${SRSRAN_SOVERSION})
if (UHD_FOUND) if (UHD_FOUND)
target_link_libraries(srsran_rf ${UHD_LIBRARIES}) target_link_libraries(srsran_rf ${UHD_LIBRARIES} ${Boost_LIBRARIES}) # Ubuntu 18.04 requires 'system' from Boost_LIBRARIES
endif (UHD_FOUND) endif (UHD_FOUND)
if (BLADERF_FOUND) if (BLADERF_FOUND)

@ -218,7 +218,13 @@ int rf_skiq_card_init(rf_skiq_card_t* q, uint8_t card, uint8_t nof_ports, const
// Launch thread // Launch thread
if (pthread_create(&q->thread, &attr, reader_thread, q)) { if (pthread_create(&q->thread, &attr, reader_thread, q)) {
ERROR("Error creating reader thread with attributes (Did you miss sudo?). Trying without attributes.\n"); ERROR("Error creating reader thread with attributes (Did you miss sudo?). Trying without attributes.\n");
return SRSRAN_ERROR;
// try to create thread without attributes
pthread_attr_destroy(&attr);
if (pthread_create(&q->thread, NULL, reader_thread, q)) {
ERROR("Error creating reader thread, even without thread attributes. Exiting.\n");
return SRSRAN_ERROR;
}
} }
// Rename thread // Rename thread

@ -231,7 +231,13 @@ int rf_skiq_tx_port_init(rf_skiq_tx_port_t* q, uint8_t card, skiq_tx_hdl_t hdl,
// Launch thread // Launch thread
if (pthread_create(&q->thread, &attr, writer_thread, q)) { if (pthread_create(&q->thread, &attr, writer_thread, q)) {
ERROR("Error creating writer thread with attributes (Did you miss sudo?). Trying without attributes.\n"); ERROR("Error creating writer thread with attributes (Did you miss sudo?). Trying without attributes.\n");
return SRSRAN_ERROR;
// try to create thread without attributes
pthread_attr_destroy(&attr);
if (pthread_create(&q->thread, NULL, writer_thread, q)) {
ERROR("Error creating writer thread, even without thread attributes. Exiting.\n");
return SRSRAN_ERROR;
}
} }
// Rename thread // Rename thread

@ -176,4 +176,6 @@ target_link_libraries(ssb_file_test srsran_phy)
# File test 1 # File test 1
# Captured with command: lib/examples/usrp_capture -a type=x300,clock=external,sampling_rate=46.08e6,rx_subdev_spec=B:0 -g 20 -r 46.08e6 -n 460800 -f 3502.8e6 -o /tmp/n78.fo35028.fs2304M.data # Captured with command: lib/examples/usrp_capture -a type=x300,clock=external,sampling_rate=46.08e6,rx_subdev_spec=B:0 -g 20 -r 46.08e6 -n 460800 -f 3502.8e6 -o /tmp/n78.fo35028.fs2304M.data
add_nr_test(ssb_file_test ssb_file_test -i ${CMAKE_CURRENT_SOURCE_DIR}/n78.fo35028.fs4608M.data -v -r 46.08e6 -f 3502.8e6 -F 3512.64e6 -n 460800 -A 500 357802 2 0 1 0) add_nr_test(ssb_file_test_tdd ssb_file_test -i ${CMAKE_CURRENT_SOURCE_DIR}/n78.fo35028.fs4608M.data -v -r 46.08e6 -f 3502.8e6 -F 3512.64e6 -n 460800 -A 500 357802 2 0 1 0)
# Capture with third-party gNB on band n3 (FDD) 15kHz SSB SCS, f_s=15.36e6, f_c=1842.5e6, f_c_ssb=1842.05e6, PCI=500
add_nr_test(ssb_file_test_fdd ssb_file_test -i ${CMAKE_CURRENT_SOURCE_DIR}/../../ue/test/ue_dl_nr_pci500_rb52_si_coreset0_idx6_s15.36e6.dat -v -r 15.36e6 -f 1842.5e6 -F 1842.05e6 -n 15360 -d fdd -s 15 -A 500 2200 0 0 0 0)

@ -38,7 +38,7 @@ static char* filename = NULL;
static double srate_hz = 23.04e6; // Base-band sampling rate in Hz static double srate_hz = 23.04e6; // Base-band sampling rate in Hz
static double center_freq_hz = NAN; // Center frequency in Hz static double center_freq_hz = NAN; // Center frequency in Hz
static double ssb_freq_hz = NAN; // SSB frequency in Hz static double ssb_freq_hz = NAN; // SSB frequency in Hz
static uint32_t nof_samples = 0; // Number of half-frames static uint32_t nof_samples = 0; // Number of samples
// Assertion // Assertion
static bool assert = false; static bool assert = false;
@ -53,9 +53,11 @@ static void usage(char* prog)
{ {
printf("Usage: %s -i filename [rv]\n", prog); printf("Usage: %s -i filename [rv]\n", prog);
printf("\t-r sampling rate in Hz [Default %.2f MHz]\n", srate_hz / 1e6); printf("\t-r sampling rate in Hz [Default %.2f MHz]\n", srate_hz / 1e6);
printf("\t-n number of samples [Default %d]\n", nof_samples);
printf("\t-s SSB subcarrier spacing (15, 30) [Default %s]\n", srsran_subcarrier_spacing_to_str(ssb_scs));
printf("\t-d duplex mode [Default %s]\n", duplex_mode == SRSRAN_DUPLEX_MODE_FDD ? "FDD" : "TDD");
printf("\t-f absolute baseband center frequency in Hz [Default %.2f MHz]\n", center_freq_hz / 1e3); printf("\t-f absolute baseband center frequency in Hz [Default %.2f MHz]\n", center_freq_hz / 1e3);
printf("\t-F absolute SSB center freuqency in Hz [Default %.2f MHz]\n", ssb_freq_hz / 1e3); printf("\t-F absolute SSB center freuqency in Hz [Default %.2f MHz]\n", ssb_freq_hz / 1e3);
printf("\t-F absolute SSB center freuqency in Hz [Default %.2f MHz]\n", ssb_freq_hz / 1e3);
printf("\t-A Assert: PCI t_offset sfn_lsb ssb_idx ssb_k hrf"); printf("\t-A Assert: PCI t_offset sfn_lsb ssb_idx ssb_k hrf");
printf("\t-v [set srsran_verbose to debug, default none]\n"); printf("\t-v [set srsran_verbose to debug, default none]\n");
} }
@ -63,7 +65,7 @@ static void usage(char* prog)
static void parse_args(int argc, char** argv) static void parse_args(int argc, char** argv)
{ {
int opt; int opt;
while ((opt = getopt(argc, argv, "inrfFAv")) != -1) { while ((opt = getopt(argc, argv, "insdrfFAv")) != -1) {
switch (opt) { switch (opt) {
case 'i': case 'i':
filename = argv[optind]; filename = argv[optind];
@ -71,6 +73,24 @@ static void parse_args(int argc, char** argv)
case 'n': case 'n':
nof_samples = (uint32_t)strtol(argv[optind], NULL, 10); nof_samples = (uint32_t)strtol(argv[optind], NULL, 10);
break; break;
case 's':
if ((uint32_t)strtol(argv[optind], NULL, 10) == 15) {
ssb_scs = srsran_subcarrier_spacing_15kHz;
} else {
ssb_scs = srsran_subcarrier_spacing_30kHz;
}
break;
case 'd':
if (strcmp(argv[optind], "tdd") == 0) {
duplex_mode = SRSRAN_DUPLEX_MODE_TDD;
} else if (strcmp(argv[optind], "fdd") == 0) {
duplex_mode = SRSRAN_DUPLEX_MODE_FDD;
} else {
printf("Invalid duplex mode '%s'\n", argv[optind]);
usage(argv[0]);
exit(-1);
}
break;
case 'r': case 'r':
srate_hz = strtod(argv[optind], NULL); srate_hz = strtod(argv[optind], NULL);
break; break;
@ -204,6 +224,17 @@ int main(int argc, char** argv)
str, str,
search_res.pbch_msg.crc ? "OK" : "KO"); search_res.pbch_msg.crc ? "OK" : "KO");
// unpack MIB
srsran_mib_nr_t mib = {};
if (srsran_pbch_msg_nr_mib_unpack(&search_res.pbch_msg, &mib) < SRSRAN_SUCCESS) {
ERROR("Error unpacking PBCH-MIB");
goto clean_exit;
}
char mib_info[512] = {};
srsran_pbch_msg_nr_mib_info(&mib, mib_info, sizeof(mib_info));
INFO("PBCH-MIB: %s", mib_info);
// Assert search // Assert search
if (assert) { if (assert) {
if (assert_search(&search_res)) { if (assert_search(&search_res)) {

@ -56,14 +56,17 @@ if(RF_FOUND)
endif(SRSGUI_FOUND) endif(SRSGUI_FOUND)
endif(RF_FOUND) endif(RF_FOUND)
add_executable(ue_dl_nr_file_test ue_dl_nr_file_test.c) add_executable(ue_dl_nr_file_test ue_dl_nr_file_test.cc)
target_link_libraries(ue_dl_nr_file_test srsran_phy pthread) target_link_libraries(ue_dl_nr_file_test srsran_phy srsran_common pthread)
foreach (n RANGE 0 9) foreach (n RANGE 0 9)
add_test(ue_dl_nr_pci1_rb25_n${n}_common_L1_ncce0 ue_dl_nr_file_test -f ${CMAKE_CURRENT_SOURCE_DIR}/ue_dl_nr_pci1_rb25_n${n}_common_L1_ncce0.dat -i 1 -P 25 -n ${n} -R 1234) #add_test(ue_dl_nr_pci1_rb25_n${n}_common_L1_ncce0 ue_dl_nr_file_test -f ${CMAKE_CURRENT_SOURCE_DIR}/ue_dl_nr_pci1_rb25_n${n}_common_L1_ncce0.dat -i 1 -P 25 -n ${n} -R 1234 -l 2)
add_test(ue_dl_nr_pci1_rb25_n${n}_common_L1_ncce0 ue_dl_nr_file_test -f ${CMAKE_CURRENT_SOURCE_DIR}/ue_dl_nr_pci1_rb25_n${n}_common_L1_ncce0.dat -i 1 -P 25 -n ${n} -R 1234) #add_test(ue_dl_nr_pci1_rb25_n${n}_common_L1_ncce0 ue_dl_nr_file_test -f ${CMAKE_CURRENT_SOURCE_DIR}/ue_dl_nr_pci1_rb25_n${n}_common_L1_ncce0.dat -i 1 -P 25 -n ${n} -R 1234 -l 2)
add_test(ue_dl_nr_pci1_rb25_n${n}_common_L1_ncce0 ue_dl_nr_file_test -f ${CMAKE_CURRENT_SOURCE_DIR}/ue_dl_nr_pci1_rb25_n${n}_common_L1_ncce0.dat -i 1 -P 25 -n ${n} -R 1234) #add_test(ue_dl_nr_pci1_rb25_n${n}_common_L1_ncce0 ue_dl_nr_file_test -f ${CMAKE_CURRENT_SOURCE_DIR}/ue_dl_nr_pci1_rb25_n${n}_common_L1_ncce0.dat -i 1 -P 25 -n ${n} -R 1234 -l 2)
add_test(ue_dl_nr_pci1_rb25_n${n}_common_L1_ncce0 ue_dl_nr_file_test -f ${CMAKE_CURRENT_SOURCE_DIR}/ue_dl_nr_pci1_rb25_n${n}_common_L1_ncce0.dat -i 1 -P 25 -n ${n} -R 1234) #add_test(ue_dl_nr_pci1_rb25_n${n}_common_L1_ncce0 ue_dl_nr_file_test -f ${CMAKE_CURRENT_SOURCE_DIR}/ue_dl_nr_pci1_rb25_n${n}_common_L1_ncce0.dat -i 1 -P 25 -n ${n} -R 1234 -l 2)
add_test(ue_dl_nr_pci1_rb25_n${n}_common_L1_ncce0 ue_dl_nr_file_test -f ${CMAKE_CURRENT_SOURCE_DIR}/ue_dl_nr_pci1_rb25_n${n}_common_L1_ncce0.dat -i 1 -P 25 -n ${n} -R 1234) #add_test(ue_dl_nr_pci1_rb25_n${n}_common_L1_ncce0 ue_dl_nr_file_test -f ${CMAKE_CURRENT_SOURCE_DIR}/ue_dl_nr_pci1_rb25_n${n}_common_L1_ncce0.dat -i 1 -P 25 -n ${n} -R 1234 -l 2)
add_test(ue_dl_nr_pci1_rb25_n${n}_common_L1_ncce0 ue_dl_nr_file_test -f ${CMAKE_CURRENT_SOURCE_DIR}/ue_dl_nr_pci1_rb25_n${n}_common_L1_ncce0.dat -i 1 -P 25 -n ${n} -R 1234) #add_test(ue_dl_nr_pci1_rb25_n${n}_common_L1_ncce0 ue_dl_nr_file_test -f ${CMAKE_CURRENT_SOURCE_DIR}/ue_dl_nr_pci1_rb25_n${n}_common_L1_ncce0.dat -i 1 -P 25 -n ${n} -R 1234 -l 2)
endforeach () endforeach ()
add_test(ue_dl_nr_pci500_rb52_n4_ra_L2_ncce0 ue_dl_nr_file_test -f ${CMAKE_CURRENT_SOURCE_DIR}/ue_dl_nr_pci500_rb52_n4_ra_L2_ncce0.dat -i 1 -P 52 -n 4 -R 7f) #add_test(ue_dl_nr_pci500_rb52_n4_ra_L2_ncce0 ue_dl_nr_file_test -f ${CMAKE_CURRENT_SOURCE_DIR}/ue_dl_nr_pci500_rb52_n4_ra_L2_ncce0.dat -i 1 -P 52 -n 4 -R 7f)
add_test(ue_dl_nr_pci500_rb52_si_coreset0_idx6 ue_dl_nr_file_test -f ${CMAKE_CURRENT_SOURCE_DIR}/ue_dl_nr_pci500_rb52_si_coreset0_idx6_s15.36e6.dat -S -i 500 -P 52 -n 0 -R ffff -T si -c 6 -s common0 -A 368500 -a 368410)
#add_test(ue_dl_nr_pci500_rb52_si_coreset0_idx7 ue_dl_nr_file_test -f ${CMAKE_CURRENT_SOURCE_DIR}/ue_dl_nr_pci500_rb52_si_coreset0_idx7_s15.36e6.dat -S -i 500 -P 52 -n 0 -R ffff -T si -c 7 -s common0 -A 161200 -a 161290)
#add_test(ue_dl_nr_pci500_rb52_pdsch ue_dl_nr_file_test -f ${CMAKE_CURRENT_SOURCE_DIR}/ue_dl_nr_pci500_rb52_rnti0x100_s15.36e6.dat -S -i 500 -P 52 -n 0 -R ffff -T si -o 2 -s common3)

@ -19,10 +19,17 @@
* *
*/ */
#ifdef __cplusplus
#include <complex.h>
extern "C" {
#include "srsran/phy/io/filesource.h" #include "srsran/phy/io/filesource.h"
#include "srsran/phy/phch/ra_nr.h" #include "srsran/phy/phch/ra_nr.h"
#include "srsran/phy/ue/ue_dl_nr.h" #include "srsran/phy/ue/ue_dl_nr.h"
#include "srsran/phy/utils/debug.h" #include "srsran/phy/utils/debug.h"
}
#endif // __cplusplus
#include "srsran/common/band_helper.h"
#include <getopt.h> #include <getopt.h>
static srsran_carrier_nr_t carrier = SRSRAN_DEFAULT_CARRIER_NR; static srsran_carrier_nr_t carrier = SRSRAN_DEFAULT_CARRIER_NR;
@ -34,8 +41,21 @@ static uint16_t rnti = 0x1234;
static srsran_rnti_type_t rnti_type = srsran_rnti_type_c; static srsran_rnti_type_t rnti_type = srsran_rnti_type_c;
static srsran_slot_cfg_t slot_cfg = {}; static srsran_slot_cfg_t slot_cfg = {};
static srsran_softbuffer_rx_t softbuffer = {}; static srsran_filesource_t filesource = {};
static uint8_t* data = NULL; static srsran_ue_dl_nr_t ue_dl = {};
static cf_t* buffer[SRSRAN_MAX_PORTS] = {};
static srsran_softbuffer_rx_t softbuffer = {};
static uint8_t* data = NULL;
static uint32_t coreset0_idx = 0; // if ss_type=si coreset0 is used and this is the index
static uint32_t coreset_offset_rb = 0;
static uint32_t dl_arfcn = 161200; // center of the NR carrier (default at 806e6 Hz)
static uint32_t ssb_arfcn = 161290; // center of the SSB within the carrier (default at 806.45e6)
static uint32_t coreset_n_rb = 48;
static uint32_t coreset_len = 1;
static srsran_search_space_type_t ss_type = srsran_search_space_type_common_0;
static void usage(char* prog) static void usage(char* prog)
{ {
@ -45,7 +65,16 @@ static void usage(char* prog)
printf("\t-i Physical cell identifier [Default %d]\n", carrier.pci); printf("\t-i Physical cell identifier [Default %d]\n", carrier.pci);
printf("\t-n Slot index [Default %d]\n", slot_cfg.idx); printf("\t-n Slot index [Default %d]\n", slot_cfg.idx);
printf("\t-R RNTI in hexadecimal [Default 0x%x]\n", rnti); printf("\t-R RNTI in hexadecimal [Default 0x%x]\n", rnti);
printf("\t-T RNTI type (c, ra) [Default %s]\n", srsran_rnti_type_str(rnti_type)); printf("\t-T RNTI type (c, ra, si) [Default %s]\n", srsran_rnti_type_str(rnti_type));
printf("\t-s Search space type (common0, common3) [Default %s]\n", srsran_ss_type_str(ss_type));
printf("\t-c Coreset0 index (only used if SS type is common0 for SIB) [Default %d]\n", coreset0_idx);
printf("\t-o Coreset RB offset [Default %d]\n", coreset_offset_rb);
printf("\t-N Coreset N_RB [Default %d]\n", coreset_n_rb);
printf("\t-l Coreset duration in symbols [Default %d]\n", coreset_len);
printf("\t-A ARFCN of the NR carrier (center) [Default %d]\n", dl_arfcn);
printf("\t-a center of the SSB within the carrier [Default %d]\n", ssb_arfcn);
printf("\t-S Use standard rates [Default %s]\n", srsran_symbol_size_is_standard() ? "yes" : "no"); printf("\t-S Use standard rates [Default %s]\n", srsran_symbol_size_is_standard() ? "yes" : "no");
printf("\t-v [set srsran_verbose to debug, default none]\n"); printf("\t-v [set srsran_verbose to debug, default none]\n");
@ -54,7 +83,7 @@ static void usage(char* prog)
static int parse_args(int argc, char** argv) static int parse_args(int argc, char** argv)
{ {
int opt; int opt;
while ((opt = getopt(argc, argv, "fPivnSRT")) != -1) { while ((opt = getopt(argc, argv, "fPivnSRTscoNlAa")) != -1) {
switch (opt) { switch (opt) {
case 'f': case 'f':
filename = argv[optind]; filename = argv[optind];
@ -79,12 +108,47 @@ static int parse_args(int argc, char** argv)
rnti_type = srsran_rnti_type_c; rnti_type = srsran_rnti_type_c;
} else if (strcmp(argv[optind], "ra") == 0) { } else if (strcmp(argv[optind], "ra") == 0) {
rnti_type = srsran_rnti_type_ra; rnti_type = srsran_rnti_type_ra;
} else if (strcmp(argv[optind], "si") == 0) {
rnti_type = srsran_rnti_type_si;
} else { } else {
printf("Invalid RNTI type '%s'\n", argv[optind]); printf("Invalid RNTI type '%s'\n", argv[optind]);
usage(argv[0]); usage(argv[0]);
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
break; break;
case 's':
if (strcmp(argv[optind], "common0") == 0) {
ss_type = srsran_search_space_type_common_0;
} else if (strcmp(argv[optind], "common1") == 0) {
ss_type = srsran_search_space_type_common_1;
} else if (strcmp(argv[optind], "common3") == 0) {
ss_type = srsran_search_space_type_common_3;
} else if (strcmp(argv[optind], "ue") == 0) {
ss_type = srsran_search_space_type_ue;
} else {
printf("Invalid SS type '%s'\n", argv[optind]);
usage(argv[0]);
return SRSRAN_ERROR;
}
break;
case 'c':
coreset0_idx = (uint16_t)strtol(argv[optind], NULL, 10);
break;
case 'o':
coreset_offset_rb = (uint16_t)strtol(argv[optind], NULL, 10);
break;
case 'N':
coreset_n_rb = (uint16_t)strtol(argv[optind], NULL, 10);
break;
case 'l':
coreset_len = (uint16_t)strtol(argv[optind], NULL, 10);
break;
case 'A':
dl_arfcn = (uint32_t)strtol(argv[optind], NULL, 10);
break;
case 'a':
ssb_arfcn = (uint32_t)strtol(argv[optind], NULL, 10);
break;
case 'S': case 'S':
srsran_use_standard_symbol_size(true); srsran_use_standard_symbol_size(true);
break; break;
@ -130,7 +194,7 @@ static int work_ue_dl(srsran_ue_dl_nr_t* ue_dl, srsran_slot_cfg_t* slot)
if (nof_found_dci < 1) { if (nof_found_dci < 1) {
printf("No DCI found :'(\n"); printf("No DCI found :'(\n");
return SRSRAN_SUCCESS; return SRSRAN_ERROR;
} }
char str[1024] = {}; char str[1024] = {};
@ -161,34 +225,74 @@ static int work_ue_dl(srsran_ue_dl_nr_t* ue_dl, srsran_slot_cfg_t* slot)
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
if (!pdsch_res.tb[0].crc) {
ERROR("Error decoding PDSCH");
return SRSRAN_ERROR;
}
printf("Decoded PDSCH (%d B)\n", pdsch_cfg.grant.tb[0].tbs / 8);
srsran_vec_fprint_byte(stdout, pdsch_res.tb[0].payload, pdsch_cfg.grant.tb[0].tbs / 8);
// check payload is not all null
bool all_zero = true;
for (int i = 0; i < pdsch_cfg.grant.tb[0].tbs / 8; ++i) {
if (pdsch_res.tb[0].payload[i] != 0x0) {
all_zero = false;
break;
}
}
if (all_zero) {
ERROR("PDSCH payload is all zeros");
return SRSRAN_ERROR;
}
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
// helper to avoid goto in C++
int clean_exit(int ret)
{
if (buffer[0] != NULL) {
free(buffer[0]);
}
if (data != NULL) {
free(data);
}
srsran_ue_dl_nr_free(&ue_dl);
srsran_filesource_free(&filesource);
srsran_softbuffer_rx_free(&softbuffer);
return ret;
}
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
int ret = SRSRAN_ERROR; int ret = SRSRAN_ERROR;
srsran_ue_dl_nr_t ue_dl = {};
cf_t* buffer[SRSRAN_MAX_PORTS] = {}; // parse args
if (parse_args(argc, argv) < SRSRAN_SUCCESS) {
return clean_exit(ret);
}
uint32_t sf_len = SRSRAN_SF_LEN_PRB(carrier.nof_prb); uint32_t sf_len = SRSRAN_SF_LEN_PRB(carrier.nof_prb);
buffer[0] = srsran_vec_cf_malloc(sf_len); buffer[0] = srsran_vec_cf_malloc(sf_len);
if (buffer[0] == NULL) { if (buffer[0] == NULL) {
ERROR("Error malloc"); ERROR("Error malloc");
goto clean_exit; return clean_exit(ret);
} }
if (srsran_softbuffer_rx_init_guru(&softbuffer, SRSRAN_SCH_NR_MAX_NOF_CB_LDPC, SRSRAN_LDPC_MAX_LEN_ENCODED_CB) < if (srsran_softbuffer_rx_init_guru(&softbuffer, SRSRAN_SCH_NR_MAX_NOF_CB_LDPC, SRSRAN_LDPC_MAX_LEN_ENCODED_CB) <
SRSRAN_SUCCESS) { SRSRAN_SUCCESS) {
ERROR("Error init soft-buffer"); ERROR("Error init soft-buffer");
goto clean_exit; return clean_exit(ret);
} }
data = srsran_vec_u8_malloc(SRSRAN_SLOT_MAX_NOF_BITS_NR); data = srsran_vec_u8_malloc(SRSRAN_SLOT_MAX_NOF_BITS_NR);
if (data == NULL) { if (data == NULL) {
ERROR("Error malloc"); ERROR("Error malloc");
goto clean_exit; return clean_exit(ret);
} }
// Set default PDSCH configuration
srsran_ue_dl_nr_args_t ue_dl_args = {}; srsran_ue_dl_nr_args_t ue_dl_args = {};
ue_dl_args.nof_rx_antennas = 1; ue_dl_args.nof_rx_antennas = 1;
ue_dl_args.pdsch.sch.disable_simd = false; ue_dl_args.pdsch.sch.disable_simd = false;
@ -198,38 +302,83 @@ int main(int argc, char** argv)
ue_dl_args.pdcch.measure_evm = true; ue_dl_args.pdcch.measure_evm = true;
ue_dl_args.nof_max_prb = carrier.nof_prb; ue_dl_args.nof_max_prb = carrier.nof_prb;
// Set default PDSCH configuration
if (parse_args(argc, argv) < SRSRAN_SUCCESS) {
goto clean_exit;
}
// Check for filename // Check for filename
if (filename == NULL) { if (filename == NULL) {
ERROR("Filename was not provided"); ERROR("Filename was not provided");
goto clean_exit; return clean_exit(ret);
} }
// Open filesource // Open filesource
srsran_filesource_t filesource = {};
if (srsran_filesource_init(&filesource, filename, SRSRAN_COMPLEX_FLOAT_BIN) < SRSRAN_SUCCESS) { if (srsran_filesource_init(&filesource, filename, SRSRAN_COMPLEX_FLOAT_BIN) < SRSRAN_SUCCESS) {
ERROR("Error opening filesource"); ERROR("Error opening filesource");
goto clean_exit; return clean_exit(ret);
} }
// initial DCI config
srsran_dci_cfg_nr_t dci_cfg = {};
dci_cfg.bwp_dl_initial_bw = carrier.nof_prb;
dci_cfg.bwp_ul_initial_bw = carrier.nof_prb;
dci_cfg.monitor_common_0_0 = true;
srsran_coreset_t* coreset = NULL;
// Configure CORESET // Configure CORESET
srsran_coreset_t* coreset = &pdcch_cfg.coreset[1]; if (rnti_type == srsran_rnti_type_si) {
pdcch_cfg.coreset_present[1] = true; // configure to use coreset0
coreset->duration = 2; coreset = &pdcch_cfg.coreset[0];
for (uint32_t i = 0; i < SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE; i++) { pdcch_cfg.coreset_present[0] = true;
coreset->freq_resources[i] = i < carrier.nof_prb / 6;
// derive absolute frequencies from ARFCNs
srsran::srsran_band_helper band_helper;
carrier.ssb_center_freq_hz = band_helper.nr_arfcn_to_freq(ssb_arfcn);
carrier.dl_center_frequency_hz = band_helper.nr_arfcn_to_freq(dl_arfcn);
// Get pointA and SSB absolute frequencies
double pointA_abs_freq_Hz =
carrier.dl_center_frequency_hz - carrier.nof_prb * SRSRAN_NRE * SRSRAN_SUBC_SPACING_NR(carrier.scs) / 2;
double ssb_abs_freq_Hz = carrier.ssb_center_freq_hz;
// Calculate integer SSB to pointA frequency offset in Hz
uint32_t ssb_pointA_freq_offset_Hz =
(ssb_abs_freq_Hz > pointA_abs_freq_Hz) ? (uint32_t)(ssb_abs_freq_Hz - pointA_abs_freq_Hz) : 0;
// derive coreset0 parameters
if (srsran_coreset_zero(carrier.pci, ssb_pointA_freq_offset_Hz, carrier.scs, carrier.scs, coreset0_idx, coreset) !=
SRSRAN_SUCCESS) {
printf("Not possible to create CORESET Zero (ssb_scs=%s, pdcch_scs=%s, idx=%d)",
srsran_subcarrier_spacing_to_str(carrier.scs),
srsran_subcarrier_spacing_to_str(carrier.scs),
coreset0_idx);
return clean_exit(ret);
}
// Setup PDSCH DMRS (also signaled through MIB)
pdsch_hl_cfg.typeA_pos = srsran_dmrs_sch_typeA_pos_2;
// set coreset0 bandwidth
dci_cfg.coreset0_bw = srsran_coreset_get_bw(coreset);
} else {
// configure to use coreset1
coreset = &pdcch_cfg.coreset[1];
coreset->id = 1;
pdcch_cfg.coreset_present[1] = true;
coreset->duration = coreset_len;
coreset->offset_rb = coreset_offset_rb;
for (uint32_t i = 0; i < SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE; i++) {
coreset->freq_resources[i] = i < coreset_n_rb / 6;
}
pdsch_hl_cfg.nof_common_time_ra = 1;
} }
char coreset_info[512] = {};
srsran_coreset_to_str(coreset, coreset_info, sizeof(coreset_info));
INFO("Coreset parameter: %s", coreset_info);
// Configure Search Space // Configure Search Space
srsran_search_space_t* search_space = &pdcch_cfg.search_space[0]; srsran_search_space_t* search_space = &pdcch_cfg.search_space[0];
pdcch_cfg.search_space_present[0] = true; pdcch_cfg.search_space_present[0] = true;
search_space->id = 0; search_space->id = 0;
search_space->coreset_id = 1; search_space->coreset_id = (rnti_type == srsran_rnti_type_si) ? 0 : 1;
search_space->type = srsran_search_space_type_common_3; search_space->type = ss_type;
search_space->formats[0] = srsran_dci_format_nr_0_0; search_space->formats[0] = srsran_dci_format_nr_0_0;
search_space->formats[1] = srsran_dci_format_nr_1_0; search_space->formats[1] = srsran_dci_format_nr_1_0;
search_space->nof_formats = 2; search_space->nof_formats = 2;
@ -244,44 +393,28 @@ int main(int argc, char** argv)
if (srsran_ue_dl_nr_init(&ue_dl, buffer, &ue_dl_args)) { if (srsran_ue_dl_nr_init(&ue_dl, buffer, &ue_dl_args)) {
ERROR("Error UE DL"); ERROR("Error UE DL");
goto clean_exit; return clean_exit(ret);
} }
if (srsran_ue_dl_nr_set_carrier(&ue_dl, &carrier)) { if (srsran_ue_dl_nr_set_carrier(&ue_dl, &carrier)) {
ERROR("Error setting SCH NR carrier"); ERROR("Error setting SCH NR carrier");
goto clean_exit; return clean_exit(ret);
} }
// Read baseband from file // Read baseband from file
if (srsran_filesource_read(&filesource, buffer[0], (int)ue_dl.fft->sf_sz) < SRSRAN_SUCCESS) { if (srsran_filesource_read(&filesource, buffer[0], (int)ue_dl.fft->sf_sz) < SRSRAN_SUCCESS) {
ERROR("Error reading baseband"); ERROR("Error reading baseband");
goto clean_exit; return clean_exit(ret);
} }
srsran_dci_cfg_nr_t dci_cfg = {};
dci_cfg.bwp_dl_initial_bw = carrier.nof_prb;
dci_cfg.bwp_ul_initial_bw = carrier.nof_prb;
dci_cfg.monitor_common_0_0 = true;
if (srsran_ue_dl_nr_set_pdcch_config(&ue_dl, &pdcch_cfg, &dci_cfg)) { if (srsran_ue_dl_nr_set_pdcch_config(&ue_dl, &pdcch_cfg, &dci_cfg)) {
ERROR("Error setting CORESET"); ERROR("Error setting CORESET");
goto clean_exit; return clean_exit(ret);
} }
// Actual decode // Actual decode
work_ue_dl(&ue_dl, &slot_cfg); ret = work_ue_dl(&ue_dl, &slot_cfg);
ret = SRSRAN_SUCCESS;
clean_exit:
if (buffer[0] != NULL) {
free(buffer[0]);
}
if (data != NULL) {
free(data);
}
srsran_ue_dl_nr_free(&ue_dl);
srsran_filesource_free(&filesource);
srsran_softbuffer_rx_free(&softbuffer);
return ret; // free memory and return last value of ret
return clean_exit(ret);
} }

@ -302,6 +302,16 @@ static int ue_dl_nr_find_dci_ncce(srsran_ue_dl_nr_t* q,
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
#if 0
static uint32_t num_pdcch = 0;
char tmpstr[64];
snprintf(tmpstr, 64, "pdcch_symbols%d.dat", num_pdcch);
printf("save %d syms to %s\n", q->pdcch.M / 4, tmpstr);
srsran_vec_save_file(tmpstr, q->pdcch.symbols, q->pdcch.M / 4 * sizeof(cf_t));
// srsran_vec_fprint_c(stdout, q->pdcch.symbols, q->pdcch.M/4);
num_pdcch++;
#endif
// Save information // Save information
pdcch_info->result = *pdcch_res; pdcch_info->result = *pdcch_res;

@ -22,6 +22,8 @@
#include "srsran/rlc/bearer_mem_pool.h" #include "srsran/rlc/bearer_mem_pool.h"
#include "srsran/adt/pool/batch_mem_pool.h" #include "srsran/adt/pool/batch_mem_pool.h"
#include "srsran/rlc/rlc_am_lte.h" #include "srsran/rlc/rlc_am_lte.h"
#include "srsran/rlc/rlc_am_nr.h"
#include "srsran/rlc/rlc_tm.h"
#include "srsran/rlc/rlc_um_lte.h" #include "srsran/rlc/rlc_um_lte.h"
#include "srsran/rlc/rlc_um_nr.h" #include "srsran/rlc/rlc_um_nr.h"
@ -30,7 +32,11 @@ namespace srsran {
srsran::background_mem_pool* get_bearer_pool() srsran::background_mem_pool* get_bearer_pool()
{ {
static background_mem_pool pool( static background_mem_pool pool(
4, std::max(std::max(sizeof(rlc_am_lte), sizeof(rlc_um_lte)), sizeof(rlc_um_nr)), 8, 8); 4,
std::max(std::max(std::max(std::max(sizeof(rlc_am), sizeof(rlc_am)), sizeof(rlc_um_lte)), sizeof(rlc_um_nr)),
sizeof(rlc_tm)),
8,
8);
return &pool; return &pool;
} }

@ -405,7 +405,7 @@ int rlc::add_bearer(uint32_t lcid, const rlc_config_t& cnfg)
case rlc_mode_t::am: case rlc_mode_t::am:
switch (cnfg.rat) { switch (cnfg.rat) {
case srsran_rat_t::lte: case srsran_rat_t::lte:
rlc_entity = std::unique_ptr<rlc_common>(new rlc_am_lte(logger, lcid, pdcp, rrc, timers)); rlc_entity = std::unique_ptr<rlc_common>(new rlc_am(cnfg.rat, logger, lcid, pdcp, rrc, timers));
break; break;
default: default:
logger.error("AM not supported for this RAT"); logger.error("AM not supported for this RAT");

@ -20,6 +20,8 @@
*/ */
#include "srsran/rlc/rlc_am_base.h" #include "srsran/rlc/rlc_am_base.h"
#include "srsran/rlc/rlc_am_lte.h"
#include "srsran/rlc/rlc_am_nr.h"
#include <sstream> #include <sstream>
namespace srsran { namespace srsran {
@ -34,4 +36,234 @@ bool rlc_am_is_control_pdu(byte_buffer_t* pdu)
return rlc_am_is_control_pdu(pdu->msg); return rlc_am_is_control_pdu(pdu->msg);
} }
/*******************************************************
* RLC AM entity
* This entity is common between LTE and NR
* and only the TX/RX entities change between them
*******************************************************/
rlc_am::rlc_am(srsran_rat_t rat,
srslog::basic_logger& logger,
uint32_t lcid_,
srsue::pdcp_interface_rlc* pdcp_,
srsue::rrc_interface_rlc* rrc_,
srsran::timer_handler* timers_) :
logger(logger), rrc(rrc_), pdcp(pdcp_), timers(timers_), lcid(lcid_)
{
if (rat == srsran_rat_t::lte) {
rlc_am_lte_tx* tx = new rlc_am_lte_tx(this);
rlc_am_lte_rx* rx = new rlc_am_lte_rx(this);
tx_base = std::unique_ptr<rlc_am_base_tx>(tx);
rx_base = std::unique_ptr<rlc_am_base_rx>(rx);
tx->set_rx(rx);
rx->set_tx(tx);
} else if (rat == srsran_rat_t::nr) {
rlc_am_nr_tx* tx = new rlc_am_nr_tx(this);
rlc_am_nr_rx* rx = new rlc_am_nr_rx(this);
tx_base = std::unique_ptr<rlc_am_base_tx>(tx);
rx_base = std::unique_ptr<rlc_am_base_rx>(rx);
tx->set_rx(rx);
rx->set_tx(tx);
} else {
logger.error("Invalid RAT at entity initialization");
}
}
bool rlc_am::configure(const rlc_config_t& cfg_)
{
// determine bearer name and configure Rx/Tx objects
rb_name = rrc->get_rb_name(lcid);
// store config
cfg = cfg_;
if (not rx_base->configure(cfg)) {
logger.error("Error configuring bearer (RX)");
return false;
}
if (not tx_base->configure(cfg)) {
logger.error("Error configuring bearer (TX)");
return false;
}
logger.info("%s configured: t_poll_retx=%d, poll_pdu=%d, poll_byte=%d, max_retx_thresh=%d, "
"t_reordering=%d, t_status_prohibit=%d",
rb_name.c_str(),
cfg.am.t_poll_retx,
cfg.am.poll_pdu,
cfg.am.poll_byte,
cfg.am.max_retx_thresh,
cfg.am.t_reordering,
cfg.am.t_status_prohibit);
return true;
}
void rlc_am::stop()
{
logger.debug("Stopped bearer %s", rb_name.c_str());
tx_base->stop();
rx_base->stop();
}
void rlc_am::reestablish()
{
logger.debug("Reestablished bearer %s", rb_name.c_str());
tx_base->reestablish(); // calls stop and enables tx again
rx_base->reestablish(); // calls only stop
}
/****************************************************************************
* PDCP interface
***************************************************************************/
void rlc_am::write_sdu(unique_byte_buffer_t sdu)
{
if (tx_base->write_sdu(std::move(sdu)) == SRSRAN_SUCCESS) {
std::lock_guard<std::mutex> lock(metrics_mutex);
metrics.num_tx_sdus++;
}
}
void rlc_am::discard_sdu(uint32_t discard_sn)
{
tx_base->discard_sdu(discard_sn);
std::lock_guard<std::mutex> lock(metrics_mutex);
metrics.num_lost_sdus++;
}
bool rlc_am::sdu_queue_is_full()
{
return tx_base->sdu_queue_is_full();
}
/****************************************************************************
* MAC interface
***************************************************************************/
bool rlc_am::has_data()
{
return tx_base->has_data();
}
uint32_t rlc_am::get_buffer_state()
{
return tx_base->get_buffer_state();
}
void rlc_am::get_buffer_state(uint32_t& n_bytes_newtx, uint32_t& n_bytes_prio)
{
tx_base->get_buffer_state(n_bytes_newtx, n_bytes_prio);
return;
}
uint32_t rlc_am::read_pdu(uint8_t* payload, uint32_t nof_bytes)
{
uint32_t read_bytes = tx_base->read_pdu(payload, nof_bytes);
std::lock_guard<std::mutex> lock(metrics_mutex);
metrics.num_tx_pdus++;
metrics.num_tx_pdu_bytes += read_bytes;
return read_bytes;
}
void rlc_am::write_pdu(uint8_t* payload, uint32_t nof_bytes)
{
rx_base->write_pdu(payload, nof_bytes);
std::lock_guard<std::mutex> lock(metrics_mutex);
metrics.num_rx_pdus++;
metrics.num_rx_pdu_bytes += nof_bytes;
}
/****************************************************************************
* Metrics
***************************************************************************/
rlc_bearer_metrics_t rlc_am::get_metrics()
{
// update values that aren't calculated on the fly
uint32_t latency = rx_base->get_sdu_rx_latency_ms();
uint32_t buffered_bytes = rx_base->get_rx_buffered_bytes();
std::lock_guard<std::mutex> lock(metrics_mutex);
metrics.rx_latency_ms = latency;
metrics.rx_buffered_bytes = buffered_bytes;
return metrics;
}
void rlc_am::reset_metrics()
{
std::lock_guard<std::mutex> lock(metrics_mutex);
metrics = {};
}
/****************************************************************************
* BSR callback
***************************************************************************/
void rlc_am::set_bsr_callback(bsr_callback_t callback)
{
tx_base->set_bsr_callback(callback);
}
/*******************************************************
* RLC AM TX entity
* This class is used for common code between the
* LTE and NR TX entitites
*******************************************************/
int rlc_am::rlc_am_base_tx::write_sdu(unique_byte_buffer_t sdu)
{
std::lock_guard<std::mutex> lock(mutex);
if (!tx_enabled) {
return SRSRAN_ERROR;
}
if (sdu.get() == nullptr) {
srslog::fetch_basic_logger("RLC").warning("NULL SDU pointer in write_sdu()");
return SRSRAN_ERROR;
}
// Get SDU info
uint32_t sdu_pdcp_sn = sdu->md.pdcp_sn;
// Store SDU
uint8_t* msg_ptr = sdu->msg;
uint32_t nof_bytes = sdu->N_bytes;
srsran::error_type<unique_byte_buffer_t> ret = tx_sdu_queue.try_write(std::move(sdu));
if (ret) {
srslog::fetch_basic_logger("RLC").info(
msg_ptr, nof_bytes, "%s Tx SDU (%d B, tx_sdu_queue_len=%d)", rb_name, nof_bytes, tx_sdu_queue.size());
} else {
// in case of fail, the try_write returns back the sdu
srslog::fetch_basic_logger("RLC").warning(ret.error()->msg,
ret.error()->N_bytes,
"[Dropped SDU] %s Tx SDU (%d B, tx_sdu_queue_len=%d)",
rb_name,
ret.error()->N_bytes,
tx_sdu_queue.size());
return SRSRAN_ERROR;
}
return SRSRAN_SUCCESS;
}
void rlc_am::rlc_am_base_tx::set_bsr_callback(bsr_callback_t callback)
{
bsr_callback = callback;
}
/*******************************************************
* RLC AM RX entity
* This class is used for common code between the
* LTE and NR TX entitites
*******************************************************/
void rlc_am::rlc_am_base_rx::write_pdu(uint8_t* payload, const uint32_t nof_bytes)
{
if (nof_bytes < 1) {
return;
}
if (rlc_am_is_control_pdu(payload)) {
parent->tx_base->handle_control_pdu(payload, nof_bytes);
} else {
handle_data_pdu(payload, nof_bytes);
}
}
} // namespace srsran } // namespace srsran

File diff suppressed because it is too large Load Diff

@ -285,7 +285,8 @@ bool rlc_am_is_valid_status_pdu(const rlc_status_pdu_t& status, uint32_t rx_win_
return true; return true;
} }
void rlc_am_undelivered_sdu_info_to_string(fmt::memory_buffer& buffer, const std::vector<pdcp_pdu_info>& info_queue) void rlc_am_undelivered_sdu_info_to_string(fmt::memory_buffer& buffer,
const std::vector<pdcp_pdu_info<rlc_amd_pdu_header_t> >& info_queue)
{ {
fmt::format_to(buffer, "\n"); fmt::format_to(buffer, "\n");
for (const auto& pdcp_pdu : info_queue) { for (const auto& pdcp_pdu : info_queue) {

@ -28,138 +28,20 @@
namespace srsran { namespace srsran {
/*******************************
* RLC AM NR class
******************************/
rlc_am_nr::rlc_am_nr(srslog::basic_logger& logger,
uint32_t lcid_,
srsue::pdcp_interface_rlc* pdcp_,
srsue::rrc_interface_rlc* rrc_,
srsran::timer_handler* timers_) :
logger(logger), rrc(rrc_), pdcp(pdcp_), timers(timers_), lcid(lcid_), tx(this), rx(this)
{}
// Applies new configuration. Must be just reestablished or initiated
bool rlc_am_nr::configure(const rlc_config_t& cfg_)
{
// determine bearer name and configure Rx/Tx objects
rb_name = rrc->get_rb_name(lcid);
// store config
cfg = cfg_;
if (not rx.configure(cfg.am)) {
logger.error("Error configuring bearer (RX)");
return false;
}
if (not tx.configure(cfg.am)) {
logger.error("Error configuring bearer (TX)");
return false;
}
logger.info("%s configured: t_poll_retx=%d, poll_pdu=%d, poll_byte=%d, max_retx_thresh=%d, "
"t_reordering=%d, t_status_prohibit=%d",
rb_name.c_str(),
cfg.am.t_poll_retx,
cfg.am.poll_pdu,
cfg.am.poll_byte,
cfg.am.max_retx_thresh,
cfg.am.t_reordering,
cfg.am.t_status_prohibit);
return true;
}
void rlc_am_nr::stop() {}
rlc_mode_t rlc_am_nr::get_mode()
{
return rlc_mode_t::am;
}
uint32_t rlc_am_nr::get_bearer()
{
return 0;
}
void rlc_am_nr::reestablish() {}
void rlc_am_nr::empty_queue() {}
void rlc_am_nr::set_bsr_callback(bsr_callback_t callback) {}
rlc_bearer_metrics_t rlc_am_nr::get_metrics()
{
return {};
}
void rlc_am_nr::reset_metrics() {}
/**************************************************************************** /****************************************************************************
* PDCP interface * RLC AM NR entity
***************************************************************************/ ***************************************************************************/
void rlc_am_nr::write_sdu(unique_byte_buffer_t sdu)
{
if (tx.write_sdu(std::move(sdu)) == SRSRAN_SUCCESS) {
metrics.num_tx_sdus++;
}
}
void rlc_am_nr::discard_sdu(uint32_t pdcp_sn)
{
tx.discard_sdu(pdcp_sn);
metrics.num_lost_sdus++;
}
bool rlc_am_nr::sdu_queue_is_full()
{
return tx.sdu_queue_is_full();
}
/**************************************************************************** /***************************************************************************
* MAC interface * Tx subclass implementation
***************************************************************************/ ***************************************************************************/
rlc_am_nr_tx::rlc_am_nr_tx(rlc_am* parent_) : parent(parent_), rlc_am_base_tx(&parent_->logger)
bool rlc_am_nr::has_data()
{
return tx.has_data();
}
uint32_t rlc_am_nr::get_buffer_state()
{ {
return tx.get_buffer_state(); parent->logger.debug("Initializing RLC AM NR TX: Tx_Next: %d",
st.tx_next); // Temporarly silence unused variable warning
} }
void rlc_am_nr::get_buffer_state(uint32_t& tx_queue, uint32_t& prio_tx_queue) bool rlc_am_nr_tx::configure(const rlc_config_t& cfg_)
{
// TODO
tx_queue = tx.get_buffer_state();
prio_tx_queue = 0;
}
uint32_t rlc_am_nr::read_pdu(uint8_t* payload, uint32_t nof_bytes)
{
uint32_t read_bytes = tx.read_pdu(payload, nof_bytes);
metrics.num_tx_pdus++;
metrics.num_tx_pdu_bytes += read_bytes;
return read_bytes;
}
void rlc_am_nr::write_pdu(uint8_t* payload, uint32_t nof_bytes)
{
rx.write_pdu(payload, nof_bytes);
metrics.num_rx_pdus++;
metrics.num_rx_pdu_bytes += nof_bytes;
}
/****************************************************************************
* Tx subclass implementation
***************************************************************************/
rlc_am_nr::rlc_am_nr_tx::rlc_am_nr_tx(rlc_am_nr* parent_) :
parent(parent_), logger(parent_->logger), pool(byte_buffer_pool::get_instance())
{}
bool rlc_am_nr::rlc_am_nr_tx::configure(const rlc_am_config_t& cfg_)
{ {
/* /*
if (cfg_.tx_queue_length > MAX_SDUS_PER_RLC_PDU) { if (cfg_.tx_queue_length > MAX_SDUS_PER_RLC_PDU) {
@ -169,57 +51,83 @@ bool rlc_am_nr::rlc_am_nr_tx::configure(const rlc_am_config_t& cfg_)
return false; return false;
} }
*/ */
cfg = cfg_; cfg = cfg_.am;
return true; return true;
} }
int rlc_am_nr::rlc_am_nr_tx::write_sdu(unique_byte_buffer_t sdu) bool rlc_am_nr_tx::has_data()
{ {
return 0; return true;
} }
void rlc_am_nr::rlc_am_nr_tx::discard_sdu(uint32_t sn) uint32_t rlc_am_nr_tx::read_pdu(uint8_t* payload, uint32_t nof_bytes)
{ {
return; return 0;
} }
bool rlc_am_nr::rlc_am_nr_tx::sdu_queue_is_full() void rlc_am_nr_tx::handle_control_pdu(uint8_t* payload, uint32_t nof_bytes) {}
uint32_t rlc_am_nr_tx::get_buffer_state()
{ {
return false; return 0;
} }
bool rlc_am_nr::rlc_am_nr_tx::has_data() void rlc_am_nr_tx::get_buffer_state(uint32_t& tx_queue, uint32_t& prio_tx_queue) {}
int rlc_am_nr_tx::write_sdu(unique_byte_buffer_t sdu)
{ {
return true; return 0;
} }
uint32_t rlc_am_nr::rlc_am_nr_tx::read_pdu(uint8_t* payload, uint32_t nof_bytes) void rlc_am_nr_tx::reestablish()
{ {
return 0; stop();
} }
uint32_t rlc_am_nr::rlc_am_nr_tx::get_buffer_state() void rlc_am_nr_tx::discard_sdu(uint32_t discard_sn) {}
bool rlc_am_nr_tx::sdu_queue_is_full()
{ {
return 0; return false;
} }
void rlc_am_nr_tx::empty_queue() {}
void rlc_am_nr_tx::stop() {}
/**************************************************************************** /****************************************************************************
* Rx subclass implementation * Rx subclass implementation
***************************************************************************/ ***************************************************************************/
rlc_am_nr::rlc_am_nr_rx::rlc_am_nr_rx(rlc_am_nr* parent_) : rlc_am_nr_rx::rlc_am_nr_rx(rlc_am* parent_) :
parent(parent_), pool(byte_buffer_pool::get_instance()), logger(parent_->logger) parent(parent_), pool(byte_buffer_pool::get_instance()), rlc_am_base_rx(parent_, &parent_->logger)
{} {
parent->logger.debug("Initializing RLC AM NR RX"); // Temporarly silence unused variable warning
}
bool rlc_am_nr::rlc_am_nr_rx::configure(const rlc_am_config_t& cfg_) bool rlc_am_nr_rx::configure(const rlc_config_t& cfg_)
{ {
cfg = cfg_; cfg = cfg_.am;
return true; return true;
} }
void rlc_am_nr::rlc_am_nr_rx::stop() {} void rlc_am_nr_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_bytes) {}
void rlc_am_nr::rlc_am_nr_rx::write_pdu(uint8_t* payload, uint32_t nof_bytes) {} void rlc_am_nr_rx::stop() {}
void rlc_am_nr_rx::reestablish()
{
stop();
}
uint32_t rlc_am_nr_rx::get_sdu_rx_latency_ms()
{
return 0;
}
uint32_t rlc_am_nr_rx::get_rx_buffered_bytes()
{
return 0;
}
} // namespace srsran } // namespace srsran

@ -73,7 +73,7 @@ rlc_mode_t rlc_tm::get_mode()
return rlc_mode_t::tm; return rlc_mode_t::tm;
} }
uint32_t rlc_tm::get_bearer() uint32_t rlc_tm::get_lcid()
{ {
return lcid; return lcid;
} }

@ -51,7 +51,7 @@ rlc_mode_t rlc_um_base::get_mode()
return rlc_mode_t::um; return rlc_mode_t::um;
} }
uint32_t rlc_um_base::get_bearer() uint32_t rlc_um_base::get_lcid()
{ {
return lcid; return lcid;
} }

@ -313,9 +313,10 @@ void rlc_um_nr::rlc_um_nr_rx::timer_expired(uint32_t timeout_id)
{ {
std::lock_guard<std::mutex> lock(mutex); std::lock_guard<std::mutex> lock(mutex);
if (reassembly_timer.id() == timeout_id) { if (reassembly_timer.id() == timeout_id) {
logger.info("%s reassembly timeout expiry - updating RX_Next_Reassembly and reassembling", rb_name.c_str()); logger.debug("%s reassembly timeout expiry for SN=%d - updating RX_Next_Reassembly and reassembling",
rb_name.c_str(),
RX_Next_Reassembly);
logger.info("Lost PDU SN=%d", RX_Next_Reassembly);
metrics.num_lost_pdus++; metrics.num_lost_pdus++;
if (rx_sdu != nullptr) { if (rx_sdu != nullptr) {
@ -331,7 +332,7 @@ void rlc_um_nr::rlc_um_nr_rx::timer_expired(uint32_t timeout_id)
// discard all segments with SN < updated RX_Next_Reassembly // discard all segments with SN < updated RX_Next_Reassembly
for (auto it = rx_window.begin(); it != rx_window.end();) { for (auto it = rx_window.begin(); it != rx_window.end();) {
if (it->first < RX_Next_Reassembly) { if (RX_MOD_NR_BASE(it->first) < RX_MOD_NR_BASE(RX_Next_Reassembly)) {
it = rx_window.erase(it); it = rx_window.erase(it);
} else { } else {
++it; ++it;
@ -342,6 +343,7 @@ void rlc_um_nr::rlc_um_nr_rx::timer_expired(uint32_t timeout_id)
if (RX_MOD_NR_BASE(RX_Next_Highest) > RX_MOD_NR_BASE(RX_Next_Reassembly + 1) || if (RX_MOD_NR_BASE(RX_Next_Highest) > RX_MOD_NR_BASE(RX_Next_Reassembly + 1) ||
((RX_MOD_NR_BASE(RX_Next_Highest) == RX_MOD_NR_BASE(RX_Next_Reassembly + 1) && ((RX_MOD_NR_BASE(RX_Next_Highest) == RX_MOD_NR_BASE(RX_Next_Reassembly + 1) &&
has_missing_byte_segment(RX_Next_Reassembly)))) { has_missing_byte_segment(RX_Next_Reassembly)))) {
logger.debug("%s starting reassembly timer for SN=%d", rb_name.c_str(), RX_Next_Reassembly);
reassembly_timer.run(); reassembly_timer.run();
RX_Timer_Trigger = RX_Next_Highest; RX_Timer_Trigger = RX_Next_Highest;
} }
@ -394,6 +396,8 @@ bool rlc_um_nr::rlc_um_nr_rx::has_missing_byte_segment(const uint32_t sn)
void rlc_um_nr::rlc_um_nr_rx::handle_rx_buffer_update(const uint32_t sn) void rlc_um_nr::rlc_um_nr_rx::handle_rx_buffer_update(const uint32_t sn)
{ {
if (rx_window.find(sn) != rx_window.end()) { if (rx_window.find(sn) != rx_window.end()) {
bool sdu_complete = false;
// iterate over received segments and try to assemble full SDU // iterate over received segments and try to assemble full SDU
auto& pdu = rx_window.at(sn); auto& pdu = rx_window.at(sn);
for (auto it = pdu.segments.begin(); it != pdu.segments.end();) { for (auto it = pdu.segments.begin(); it != pdu.segments.end();) {
@ -436,22 +440,9 @@ void rlc_um_nr::rlc_um_nr_rx::handle_rx_buffer_update(const uint32_t sn)
it = pdu.segments.erase(it); it = pdu.segments.erase(it);
if (pdu.next_expected_so == pdu.total_sdu_length) { if (pdu.next_expected_so == pdu.total_sdu_length) {
// deliver full SDU to upper layers // entire SDU has been received, it will be passed up the stack outside the loop
logger.info("Delivering %s SDU SN=%d (%d B)", rb_name.c_str(), sn, pdu.sdu->N_bytes); sdu_complete = true;
pdcp->write_pdu(lcid, std::move(pdu.sdu)); break;
// find next SN in rx buffer
if (sn == RX_Next_Reassembly) {
RX_Next_Reassembly = ((RX_Next_Reassembly + 1) % mod);
while (RX_MOD_NR_BASE(RX_Next_Reassembly) < RX_MOD_NR_BASE(RX_Next_Highest)) {
RX_Next_Reassembly = (RX_Next_Reassembly + 1) % mod;
}
logger.debug("Updating RX_Next_Reassembly=%d", RX_Next_Reassembly);
}
// delete PDU from rx_window
rx_window.erase(sn);
return;
} }
} }
} else { } else {
@ -460,10 +451,34 @@ void rlc_um_nr::rlc_um_nr_rx::handle_rx_buffer_update(const uint32_t sn)
} }
} }
// check for SN outside of rx window if (sdu_complete) {
if (not sn_in_reassembly_window(sn)) { // deliver full SDU to upper layers
// update RX_Next_highest logger.info("%s Rx SDU (%d B)", rb_name.c_str(), pdu.sdu->N_bytes);
RX_Next_Highest = sn + 1; pdcp->write_pdu(lcid, std::move(pdu.sdu));
// delete PDU from rx_window
rx_window.erase(sn);
// find next SN in rx buffer
if (sn == RX_Next_Reassembly) {
if (rx_window.empty()) {
// no further segments received
RX_Next_Reassembly = RX_Next_Highest;
} else {
for (auto it = rx_window.begin(); it != rx_window.end(); ++it) {
logger.debug("SN=%d has %zd segments", it->first, it->second.segments.size());
if (RX_MOD_NR_BASE(it->first) > RX_MOD_NR_BASE(RX_Next_Reassembly)) {
RX_Next_Reassembly = it->first;
break;
}
}
}
logger.debug("Updating RX_Next_Reassembly=%d", RX_Next_Reassembly);
}
} else if (not sn_in_reassembly_window(sn)) {
// SN outside of rx window
RX_Next_Highest = (sn + 1) % mod; // update RX_Next_highest
logger.debug("Updating RX_Next_Highest=%d", RX_Next_Highest); logger.debug("Updating RX_Next_Highest=%d", RX_Next_Highest);
// drop all SNs outside of new rx window // drop all SNs outside of new rx window
@ -486,29 +501,33 @@ void rlc_um_nr::rlc_um_nr_rx::handle_rx_buffer_update(const uint32_t sn)
for (const auto& rx_pdu : rx_window) { for (const auto& rx_pdu : rx_window) {
if (rx_pdu.first >= RX_MOD_NR_BASE(RX_Next_Highest - UM_Window_Size)) { if (rx_pdu.first >= RX_MOD_NR_BASE(RX_Next_Highest - UM_Window_Size)) {
RX_Next_Reassembly = rx_pdu.first; RX_Next_Reassembly = rx_pdu.first;
logger.debug("Updating RX_Next_Reassembly=%d", RX_Next_Reassembly); logger.debug("%s Updating RX_Next_Reassembly=%d", rb_name.c_str(), RX_Next_Reassembly);
break; break;
} }
} }
} }
}
if (reassembly_timer.is_running()) { if (reassembly_timer.is_running()) {
if (RX_Timer_Trigger <= RX_Next_Reassembly || if (RX_Timer_Trigger <= RX_Next_Reassembly ||
(not sn_in_reassembly_window(RX_Timer_Trigger) and RX_Timer_Trigger != RX_Next_Highest) || (not sn_in_reassembly_window(RX_Timer_Trigger) and RX_Timer_Trigger != RX_Next_Highest) ||
((RX_Next_Highest == RX_Next_Reassembly + 1) && not has_missing_byte_segment(sn))) { ((RX_Next_Highest == RX_Next_Reassembly + 1) && not has_missing_byte_segment(RX_Next_Reassembly))) {
reassembly_timer.stop(); logger.debug("%s stopping reassembly timer", rb_name.c_str());
} reassembly_timer.stop();
} }
}
if (not reassembly_timer.is_running() && has_missing_byte_segment(sn)) { if (not reassembly_timer.is_running()) {
if (RX_Next_Highest > RX_Next_Reassembly + 1) { if ((RX_MOD_NR_BASE(RX_Next_Highest) > RX_MOD_NR_BASE(RX_Next_Reassembly + 1)) ||
reassembly_timer.run(); ((RX_MOD_NR_BASE(RX_Next_Highest) == RX_MOD_NR_BASE(RX_Next_Reassembly + 1)) &&
RX_Timer_Trigger = RX_Next_Highest; has_missing_byte_segment(RX_Next_Reassembly))) {
} logger.debug("%s Starting reassembly timer for SN=%d", rb_name.c_str(), sn);
reassembly_timer.run();
RX_Timer_Trigger = RX_Next_Highest;
} }
} }
} else { } else {
logger.error("SN=%d does not exist in Rx buffer", sn); logger.error("%s SN=%d does not exist in Rx buffer", rb_name.c_str(), sn);
} }
} }
@ -517,10 +536,10 @@ inline void rlc_um_nr::rlc_um_nr_rx::update_total_sdu_length(rlc_umd_pdu_segment
{ {
if (rx_pdu.header.si == rlc_nr_si_field_t::last_segment) { if (rx_pdu.header.si == rlc_nr_si_field_t::last_segment) {
pdu_segments.total_sdu_length = rx_pdu.header.so + rx_pdu.buf->N_bytes; pdu_segments.total_sdu_length = rx_pdu.header.so + rx_pdu.buf->N_bytes;
logger.info("%s updating total SDU length for SN=%d to %d B", logger.debug("%s updating total SDU length for SN=%d to %d B",
rb_name.c_str(), rb_name.c_str(),
rx_pdu.header.sn, rx_pdu.header.sn,
pdu_segments.total_sdu_length); pdu_segments.total_sdu_length);
} }
}; };
@ -531,7 +550,7 @@ void rlc_um_nr::rlc_um_nr_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_byt
rlc_um_nr_pdu_header_t header = {}; rlc_um_nr_pdu_header_t header = {};
rlc_um_nr_read_data_pdu_header(payload, nof_bytes, cfg.um_nr.sn_field_length, &header); rlc_um_nr_read_data_pdu_header(payload, nof_bytes, cfg.um_nr.sn_field_length, &header);
logger.debug(payload, nof_bytes, "RX %s Rx data PDU (%d B)", rb_name.c_str(), nof_bytes); logger.debug(payload, nof_bytes, "%s Rx data PDU (%d B)", rb_name.c_str(), nof_bytes);
// check if PDU contains a SN // check if PDU contains a SN
if (header.si == rlc_nr_si_field_t::full_sdu) { if (header.si == rlc_nr_si_field_t::full_sdu) {
@ -539,7 +558,7 @@ void rlc_um_nr::rlc_um_nr_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_byt
unique_byte_buffer_t sdu = rlc_um_nr_strip_pdu_header(header, payload, nof_bytes); unique_byte_buffer_t sdu = rlc_um_nr_strip_pdu_header(header, payload, nof_bytes);
// deliver to PDCP // deliver to PDCP
logger.info("Delivering %s SDU (%d B)", rb_name.c_str(), sdu->N_bytes); logger.info("%s Rx SDU (%d B)", rb_name.c_str(), sdu->N_bytes);
pdcp->write_pdu(lcid, std::move(sdu)); pdcp->write_pdu(lcid, std::move(sdu));
} else if (sn_invalid_for_rx_buffer(header.sn)) { } else if (sn_invalid_for_rx_buffer(header.sn)) {
logger.info("%s Discarding SN=%d", rb_name.c_str(), header.sn); logger.info("%s Discarding SN=%d", rb_name.c_str(), header.sn);
@ -553,24 +572,26 @@ void rlc_um_nr::rlc_um_nr_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_byt
// check if this SN is already present in rx buffer // check if this SN is already present in rx buffer
if (rx_window.find(header.sn) == rx_window.end()) { if (rx_window.find(header.sn) == rx_window.end()) {
// first received segment of this SN, add to rx buffer // first received segment of this SN, add to rx buffer
logger.info(rx_pdu.buf->msg, logger.debug(rx_pdu.buf->msg,
rx_pdu.buf->N_bytes, rx_pdu.buf->N_bytes,
"%s placing %s segment of SN=%d (%d B) in Rx buffer", "%s placing %s segment of SN=%d (%d B) in Rx buffer",
rb_name.c_str(), rb_name.c_str(),
to_string_short(header.si).c_str(), to_string_short(header.si).c_str(),
header.sn, header.sn,
rx_pdu.buf->N_bytes); rx_pdu.buf->N_bytes);
rlc_umd_pdu_segments_nr_t pdu_segments = {}; rlc_umd_pdu_segments_nr_t pdu_segments = {};
update_total_sdu_length(pdu_segments, rx_pdu); update_total_sdu_length(pdu_segments, rx_pdu);
pdu_segments.segments.emplace(header.so, std::move(rx_pdu)); pdu_segments.segments.emplace(header.so, std::move(rx_pdu));
rx_window[header.sn] = std::move(pdu_segments); rx_window[header.sn] = std::move(pdu_segments);
} else { } else {
// other segment for this SN already present, update received data // other segment for this SN already present, update received data
logger.info("%s updating SN=%d at SO=%d with %d B", logger.debug(rx_pdu.buf->msg,
rb_name.c_str(), rx_pdu.buf->N_bytes,
rx_pdu.header.sn, "%s updating SN=%d at SO=%d with %d B",
rx_pdu.header.so, rb_name.c_str(),
rx_pdu.buf->N_bytes); rx_pdu.header.sn,
rx_pdu.header.so,
rx_pdu.buf->N_bytes);
auto& pdu_segments = rx_window.at(header.sn); auto& pdu_segments = rx_window.at(header.sn);

@ -1,22 +0,0 @@
#
# Copyright 2013-2021 Software Radio Systems Limited
#
# This file is part of srsRAN
#
# srsRAN 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.
#
# srsRAN 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/.
#
set(SOURCES nr/rrc_nr_cfg_utils.cc)
add_library(srsran_rrc_nr STATIC ${SOURCES})

@ -1,248 +0,0 @@
/**
* Copyright 2013-2021 Software Radio Systems Limited
*
* This file is part of srsRAN.
*
* srsRAN 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.
*
* srsRAN is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include "srsran/rrc/nr/rrc_nr_cfg_utils.h"
#include "srsran/asn1/rrc_nr.h"
#include "srsran/asn1/rrc_nr_utils.h"
using namespace asn1::rrc_nr;
namespace srsran {
void generate_default_pdcch_cfg_common(const basic_cell_args_t& args, pdcch_cfg_common_s& cfg)
{
cfg.ctrl_res_set_zero_present = true;
cfg.ctrl_res_set_zero = 0;
cfg.common_ctrl_res_set_present = false;
cfg.search_space_zero_present = true;
cfg.search_space_zero = 0;
cfg.common_search_space_list_present = true;
cfg.common_search_space_list.resize(1);
search_space_s& ss = cfg.common_search_space_list[0];
ss.search_space_id = 1;
ss.ctrl_res_set_id_present = true;
ss.ctrl_res_set_id = 0;
ss.monitoring_slot_periodicity_and_offset_present = true;
ss.monitoring_slot_periodicity_and_offset.set_sl1();
ss.monitoring_symbols_within_slot_present = true;
ss.monitoring_symbols_within_slot.from_number(0x2000);
ss.nrof_candidates_present = true;
ss.nrof_candidates.aggregation_level1.value = search_space_s::nrof_candidates_s_::aggregation_level1_opts::n0;
ss.nrof_candidates.aggregation_level2.value = search_space_s::nrof_candidates_s_::aggregation_level2_opts::n0;
ss.nrof_candidates.aggregation_level4.value = search_space_s::nrof_candidates_s_::aggregation_level4_opts::n1;
ss.nrof_candidates.aggregation_level8.value = search_space_s::nrof_candidates_s_::aggregation_level8_opts::n0;
ss.nrof_candidates.aggregation_level16.value = search_space_s::nrof_candidates_s_::aggregation_level16_opts::n0;
ss.search_space_type_present = true;
auto& common = ss.search_space_type.set_common();
common.dci_format0_minus0_and_format1_minus0_present = true;
cfg.search_space_sib1_present = true;
cfg.search_space_sib1 = 0;
cfg.search_space_other_sys_info_present = true;
cfg.search_space_other_sys_info = 1;
cfg.paging_search_space_present = true;
cfg.paging_search_space = 1;
cfg.ra_search_space_present = true;
cfg.ra_search_space = 1;
}
void generate_default_pdsch_cfg_common(const basic_cell_args_t& args, pdsch_cfg_common_s& cfg)
{
cfg.pdsch_time_domain_alloc_list_present = true;
cfg.pdsch_time_domain_alloc_list.resize(1);
cfg.pdsch_time_domain_alloc_list[0].map_type.value = pdsch_time_domain_res_alloc_s::map_type_opts::type_a;
cfg.pdsch_time_domain_alloc_list[0].start_symbol_and_len = 40;
}
void generate_default_init_dl_bwp(const basic_cell_args_t& args, bwp_dl_common_s& cfg)
{
cfg.generic_params.location_and_bw = 14025;
asn1::number_to_enum(cfg.generic_params.subcarrier_spacing, args.scs);
cfg.pdcch_cfg_common_present = true;
generate_default_pdcch_cfg_common(args, cfg.pdcch_cfg_common.set_setup());
cfg.pdsch_cfg_common_present = true;
generate_default_pdsch_cfg_common(args, cfg.pdsch_cfg_common.set_setup());
}
void generate_default_dl_cfg_common(dl_cfg_common_s& cfg, const basic_cell_args_t& args)
{
cfg.init_dl_bwp_present = true;
generate_default_init_dl_bwp(args, cfg.init_dl_bwp);
}
void generate_default_dl_cfg_common_sib(const basic_cell_args_t& args, dl_cfg_common_sib_s& cfg)
{
cfg.freq_info_dl.freq_band_list.resize(1);
cfg.freq_info_dl.freq_band_list[0].freq_band_ind_nr_present = true;
cfg.freq_info_dl.freq_band_list[0].freq_band_ind_nr = 20;
cfg.freq_info_dl.offset_to_point_a = 24;
cfg.freq_info_dl.scs_specific_carrier_list.resize(1);
cfg.freq_info_dl.scs_specific_carrier_list[0].offset_to_carrier = 0;
asn1::number_to_enum(cfg.freq_info_dl.scs_specific_carrier_list[0].subcarrier_spacing, args.scs);
cfg.freq_info_dl.scs_specific_carrier_list[0].carrier_bw = args.nof_prbs;
generate_default_init_dl_bwp(args, cfg.init_dl_bwp);
// disable InitialBWP-Only fields
cfg.init_dl_bwp.pdcch_cfg_common.setup().ctrl_res_set_zero_present = false;
cfg.init_dl_bwp.pdcch_cfg_common.setup().search_space_zero_present = false;
cfg.bcch_cfg.mod_period_coeff.value = bcch_cfg_s::mod_period_coeff_opts::n4;
cfg.pcch_cfg.default_paging_cycle.value = paging_cycle_opts::rf128;
cfg.pcch_cfg.nand_paging_frame_offset.set_one_t();
cfg.pcch_cfg.ns.value = pcch_cfg_s::ns_opts::one;
}
void generate_default_rach_cfg_common(const basic_cell_args_t& args, rach_cfg_common_s& cfg)
{
cfg.rach_cfg_generic.prach_cfg_idx = 16;
cfg.rach_cfg_generic.msg1_fdm.value = rach_cfg_generic_s::msg1_fdm_opts::one;
cfg.rach_cfg_generic.msg1_freq_start = 0;
cfg.rach_cfg_generic.zero_correlation_zone_cfg = 15;
cfg.rach_cfg_generic.preamb_rx_target_pwr = -110;
cfg.rach_cfg_generic.preamb_trans_max.value = rach_cfg_generic_s::preamb_trans_max_opts::n7;
cfg.rach_cfg_generic.pwr_ramp_step.value = rach_cfg_generic_s::pwr_ramp_step_opts::db4;
cfg.rach_cfg_generic.ra_resp_win.value = rach_cfg_generic_s::ra_resp_win_opts::sl10;
cfg.ssb_per_rach_occasion_and_cb_preambs_per_ssb_present = true;
cfg.ssb_per_rach_occasion_and_cb_preambs_per_ssb.set_one().value =
rach_cfg_common_s::ssb_per_rach_occasion_and_cb_preambs_per_ssb_c_::one_opts::n8;
cfg.ra_contention_resolution_timer.value = rach_cfg_common_s::ra_contention_resolution_timer_opts::sf64;
cfg.prach_root_seq_idx.set_l839() = 1;
cfg.restricted_set_cfg.value = rach_cfg_common_s::restricted_set_cfg_opts::unrestricted_set;
}
void generate_default_ul_cfg_common_sib(const basic_cell_args_t& args, ul_cfg_common_sib_s& cfg)
{
cfg.freq_info_ul.scs_specific_carrier_list.resize(1);
cfg.freq_info_ul.scs_specific_carrier_list[0].offset_to_carrier = 0;
asn1::number_to_enum(cfg.freq_info_ul.scs_specific_carrier_list[0].subcarrier_spacing, args.scs);
cfg.freq_info_ul.scs_specific_carrier_list[0].carrier_bw = args.nof_prbs;
cfg.init_ul_bwp.generic_params.location_and_bw = 14025;
asn1::number_to_enum(cfg.init_ul_bwp.generic_params.subcarrier_spacing, args.scs);
cfg.init_ul_bwp.rach_cfg_common_present = true;
generate_default_rach_cfg_common(args, cfg.init_ul_bwp.rach_cfg_common.set_setup());
cfg.init_ul_bwp.pusch_cfg_common_present = true;
pusch_cfg_common_s& pusch = cfg.init_ul_bwp.pusch_cfg_common.set_setup();
pusch.pusch_time_domain_alloc_list_present = true;
pusch.pusch_time_domain_alloc_list.resize(1);
pusch.pusch_time_domain_alloc_list[0].k2_present = true;
pusch.pusch_time_domain_alloc_list[0].k2 = 4;
pusch.pusch_time_domain_alloc_list[0].map_type.value = pusch_time_domain_res_alloc_s::map_type_opts::type_a;
pusch.pusch_time_domain_alloc_list[0].start_symbol_and_len = 27;
pusch.p0_nominal_with_grant_present = true;
pusch.p0_nominal_with_grant = -76;
cfg.init_ul_bwp.pucch_cfg_common_present = true;
pucch_cfg_common_s& pucch = cfg.init_ul_bwp.pucch_cfg_common.set_setup();
pucch.pucch_res_common_present = true;
pucch.pucch_res_common = 11;
pucch.pucch_group_hop.value = pucch_cfg_common_s::pucch_group_hop_opts::neither;
pucch.p0_nominal_present = true;
pucch.p0_nominal = -90;
cfg.time_align_timer_common.value = time_align_timer_opts::infinity;
}
void generate_default_serv_cell_cfg_common_sib(const basic_cell_args_t& args, serving_cell_cfg_common_sib_s& cfg)
{
generate_default_dl_cfg_common_sib(args, cfg.dl_cfg_common);
cfg.ul_cfg_common_present = true;
generate_default_ul_cfg_common_sib(args, cfg.ul_cfg_common);
cfg.ssb_positions_in_burst.in_one_group.from_number(0x80);
cfg.ssb_periodicity_serving_cell.value = serving_cell_cfg_common_sib_s::ssb_periodicity_serving_cell_opts::ms20;
cfg.ss_pbch_block_pwr = -16;
}
void generate_default_mib(const basic_cell_args_t& args, mib_s& cfg)
{
asn1::number_to_enum(cfg.sub_carrier_spacing_common, args.scs);
cfg.ssb_subcarrier_offset = 0;
cfg.intra_freq_resel.value = mib_s::intra_freq_resel_opts::allowed;
cfg.cell_barred.value = mib_s::cell_barred_opts::not_barred;
cfg.pdcch_cfg_sib1.search_space_zero = 0;
cfg.pdcch_cfg_sib1.ctrl_res_set_zero = 0;
cfg.dmrs_type_a_position.value = mib_s::dmrs_type_a_position_opts::pos2;
cfg.sys_frame_num.from_number(0);
}
void generate_default_sib1(const basic_cell_args_t& args, sib1_s& cfg)
{
cfg.cell_sel_info_present = true;
cfg.cell_sel_info.q_rx_lev_min = -70;
cfg.cell_sel_info.q_qual_min_present = true;
cfg.cell_sel_info.q_qual_min = -20;
cfg.cell_access_related_info.plmn_id_list.resize(1);
cfg.cell_access_related_info.plmn_id_list[0].plmn_id_list.resize(1);
srsran::plmn_id_t plmn;
plmn.from_string(args.plmn);
srsran::to_asn1(&cfg.cell_access_related_info.plmn_id_list[0].plmn_id_list[0], plmn);
cfg.cell_access_related_info.plmn_id_list[0].tac_present = true;
cfg.cell_access_related_info.plmn_id_list[0].tac.from_number(args.tac);
cfg.cell_access_related_info.plmn_id_list[0].cell_id.from_number(args.cell_id);
cfg.cell_access_related_info.plmn_id_list[0].cell_reserved_for_oper.value =
plmn_id_info_s::cell_reserved_for_oper_opts::not_reserved;
cfg.conn_est_fail_ctrl_present = true;
cfg.conn_est_fail_ctrl.conn_est_fail_count.value = conn_est_fail_ctrl_s::conn_est_fail_count_opts::n1;
cfg.conn_est_fail_ctrl.conn_est_fail_offset_validity.value =
conn_est_fail_ctrl_s::conn_est_fail_offset_validity_opts::s30;
cfg.conn_est_fail_ctrl.conn_est_fail_offset_present = true;
cfg.conn_est_fail_ctrl.conn_est_fail_offset = 1;
// cfg.si_sched_info_present = true;
// cfg.si_sched_info.si_request_cfg.rach_occasions_si_present = true;
// cfg.si_sched_info.si_request_cfg.rach_occasions_si.rach_cfg_si.ra_resp_win.value =
// rach_cfg_generic_s::ra_resp_win_opts::sl8;
// cfg.si_sched_info.si_win_len.value = si_sched_info_s::si_win_len_opts::s20;
// cfg.si_sched_info.sched_info_list.resize(1);
// cfg.si_sched_info.sched_info_list[0].si_broadcast_status.value =
// sched_info_s::si_broadcast_status_opts::broadcasting; cfg.si_sched_info.sched_info_list[0].si_periodicity.value =
// sched_info_s::si_periodicity_opts::rf16; cfg.si_sched_info.sched_info_list[0].sib_map_info.resize(1);
// // scheduling of SI messages
// cfg.si_sched_info.sched_info_list[0].sib_map_info[0].type.value = sib_type_info_s::type_opts::sib_type2;
// cfg.si_sched_info.sched_info_list[0].sib_map_info[0].value_tag_present = true;
// cfg.si_sched_info.sched_info_list[0].sib_map_info[0].value_tag = 0;
cfg.serving_cell_cfg_common_present = true;
generate_default_serv_cell_cfg_common_sib(args, cfg.serving_cell_cfg_common);
cfg.ue_timers_and_consts_present = true;
cfg.ue_timers_and_consts.t300.value = ue_timers_and_consts_s::t300_opts::ms1000;
cfg.ue_timers_and_consts.t301.value = ue_timers_and_consts_s::t301_opts::ms1000;
cfg.ue_timers_and_consts.t310.value = ue_timers_and_consts_s::t310_opts::ms1000;
cfg.ue_timers_and_consts.n310.value = ue_timers_and_consts_s::n310_opts::n1;
cfg.ue_timers_and_consts.t311.value = ue_timers_and_consts_s::t311_opts::ms30000;
cfg.ue_timers_and_consts.n311.value = ue_timers_and_consts_s::n311_opts::n1;
cfg.ue_timers_and_consts.t319.value = ue_timers_and_consts_s::t319_opts::ms1000;
}
} // namespace srsran

@ -38,7 +38,7 @@ using namespace srsran;
class ul_writer : public thread class ul_writer : public thread
{ {
public: public:
ul_writer(rlc_am_lte* rlc_) : rlc(rlc_), thread("UL_WRITER") {} ul_writer(rlc_am* rlc_) : rlc(rlc_), thread("UL_WRITER") {}
~ul_writer() { stop(); } ~ul_writer() { stop(); }
void stop() void stop()
{ {
@ -74,11 +74,11 @@ private:
running = false; running = false;
} }
rlc_am_lte* rlc = nullptr; rlc_am* rlc = nullptr;
std::atomic<bool> running = {false}; std::atomic<bool> running = {false};
}; };
int basic_test_tx(rlc_am_lte* rlc, byte_buffer_t pdu_bufs[NBUFS]) int basic_test_tx(rlc_am* rlc, byte_buffer_t pdu_bufs[NBUFS])
{ {
// Push 5 SDUs into RLC1 // Push 5 SDUs into RLC1
unique_byte_buffer_t sdu_bufs[NBUFS]; unique_byte_buffer_t sdu_bufs[NBUFS];
@ -109,8 +109,8 @@ int basic_test()
timer_handler timers(8); timer_handler timers(8);
byte_buffer_t pdu_bufs[NBUFS]; byte_buffer_t pdu_bufs[NBUFS];
rlc_am_lte rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
rlc_am_lte rlc2(srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers); rlc_am rlc2(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers);
// before configuring entity // before configuring entity
TESTASSERT(0 == rlc1.get_buffer_state()); TESTASSERT(0 == rlc1.get_buffer_state());
@ -167,8 +167,8 @@ int concat_test()
rlc_am_tester tester; rlc_am_tester tester;
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
rlc_am_lte rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
rlc_am_lte rlc2(srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers); rlc_am rlc2(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers);
if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) { if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) {
return -1; return -1;
@ -242,8 +242,8 @@ int segment_test(bool in_seq_rx)
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
int len = 0; int len = 0;
rlc_am_lte rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
rlc_am_lte rlc2(srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers); rlc_am rlc2(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers);
if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) { if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) {
return -1; return -1;
@ -337,8 +337,8 @@ int retx_test()
timer_handler timers(8); timer_handler timers(8);
int len = 0; int len = 0;
rlc_am_lte rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
rlc_am_lte rlc2(srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers); rlc_am rlc2(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers);
if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) { if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) {
return -1; return -1;
@ -473,7 +473,7 @@ int max_retx_test()
timer_handler timers(8); timer_handler timers(8);
int len = 0; int len = 0;
rlc_am_lte rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
const rlc_config_t rlc_cfg = rlc_config_t::default_rlc_am_config(); const rlc_config_t rlc_cfg = rlc_config_t::default_rlc_am_config();
if (not rlc1.configure(rlc_cfg)) { if (not rlc1.configure(rlc_cfg)) {
@ -536,8 +536,8 @@ int segment_retx_test()
timer_handler timers(8); timer_handler timers(8);
int len = 0; int len = 0;
rlc_am_lte rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
rlc_am_lte rlc2(srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers); rlc_am rlc2(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers);
if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) { if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) {
return -1; return -1;
@ -661,8 +661,8 @@ int resegment_test_1()
timer_handler timers(8); timer_handler timers(8);
int len = 0; int len = 0;
rlc_am_lte rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
rlc_am_lte rlc2(srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers); rlc_am rlc2(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers);
if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) { if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) {
return -1; return -1;
@ -818,8 +818,8 @@ int resegment_test_2()
rlc_am_tester tester; rlc_am_tester tester;
timer_handler timers(8); timer_handler timers(8);
rlc_am_lte rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
rlc_am_lte rlc2(srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers); rlc_am rlc2(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers);
if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) { if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) {
return -1; return -1;
@ -950,8 +950,8 @@ int resegment_test_3()
rlc_am_tester tester; rlc_am_tester tester;
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
rlc_am_lte rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
rlc_am_lte rlc2(srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers); rlc_am rlc2(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers);
if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) { if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) {
return -1; return -1;
@ -1080,8 +1080,8 @@ int resegment_test_4()
rlc_am_tester tester; rlc_am_tester tester;
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
rlc_am_lte rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
rlc_am_lte rlc2(srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers); rlc_am rlc2(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers);
if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) { if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) {
return -1; return -1;
@ -1212,8 +1212,8 @@ int resegment_test_5()
rlc_am_tester tester; rlc_am_tester tester;
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
rlc_am_lte rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
rlc_am_lte rlc2(srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers); rlc_am rlc2(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers);
if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) { if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) {
return -1; return -1;
@ -1339,8 +1339,8 @@ int resegment_test_6()
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
int len = 0; int len = 0;
rlc_am_lte rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
rlc_am_lte rlc2(srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers); rlc_am rlc2(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers);
if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) { if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) {
return -1; return -1;
@ -1508,8 +1508,8 @@ int resegment_test_7()
#endif #endif
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
rlc_am_lte rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
rlc_am_lte rlc2(srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers); rlc_am rlc2(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers);
if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) { if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) {
return -1; return -1;
@ -1693,8 +1693,8 @@ int resegment_test_8()
#endif #endif
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
rlc_am_lte rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
rlc_am_lte rlc2(srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers); rlc_am rlc2(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers);
if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) { if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) {
return -1; return -1;
@ -1845,8 +1845,8 @@ int resegment_test_9()
#endif #endif
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
rlc_am_lte rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
rlc_am_lte rlc2(srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers); rlc_am rlc2(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers);
if (not rlc1.configure(config)) { if (not rlc1.configure(config)) {
return SRSRAN_ERROR; return SRSRAN_ERROR;
@ -1987,8 +1987,8 @@ int resegment_test_10()
#endif #endif
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
rlc_am_lte rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
rlc_am_lte rlc2(srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers); rlc_am rlc2(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers);
if (not rlc1.configure(config)) { if (not rlc1.configure(config)) {
return SRSRAN_ERROR; return SRSRAN_ERROR;
@ -2136,8 +2136,8 @@ int resegment_test_11()
#endif #endif
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
rlc_am_lte rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
rlc_am_lte rlc2(srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers); rlc_am rlc2(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers);
if (not rlc1.configure(config)) { if (not rlc1.configure(config)) {
return SRSRAN_ERROR; return SRSRAN_ERROR;
@ -2294,8 +2294,8 @@ int resegment_test_12()
#endif #endif
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
rlc_am_lte rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
rlc_am_lte rlc2(srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers); rlc_am rlc2(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers);
if (not rlc1.configure(config)) { if (not rlc1.configure(config)) {
return SRSRAN_ERROR; return SRSRAN_ERROR;
@ -2438,7 +2438,7 @@ int header_reconstruction_test(srsran::log_sink_message_spy& spy)
#endif #endif
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
rlc_am_lte rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) { if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) {
return -1; return -1;
@ -2501,7 +2501,7 @@ int header_reconstruction_test2(srsran::log_sink_message_spy& spy)
#endif #endif
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
rlc_am_lte rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) { if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) {
return -1; return -1;
} }
@ -2565,7 +2565,7 @@ int header_reconstruction_test3(srsran::log_sink_message_spy& spy)
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
// configure RLC // configure RLC
rlc_am_lte rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) { if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) {
return -1; return -1;
} }
@ -2651,7 +2651,7 @@ int header_reconstruction_test4(srsran::log_sink_message_spy& spy)
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
// configure RLC // configure RLC
rlc_am_lte rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) { if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) {
return -1; return -1;
} }
@ -2728,7 +2728,7 @@ int header_reconstruction_test5(srsran::log_sink_message_spy& spy)
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
// configure RLC // configure RLC
rlc_am_lte rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) { if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) {
return -1; return -1;
} }
@ -2807,7 +2807,7 @@ int header_reconstruction_test6(srsran::log_sink_message_spy& spy)
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
// configure RLC // configure RLC
rlc_am_lte rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) { if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) {
return -1; return -1;
} }
@ -2906,7 +2906,7 @@ int header_reconstruction_test7(srsran::log_sink_message_spy& spy)
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
// configure RLC // configure RLC
rlc_am_lte rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) { if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) {
return -1; return -1;
} }
@ -3008,7 +3008,7 @@ int header_reconstruction_test8(srsran::log_sink_message_spy& spy)
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
// configure RLC // configure RLC
rlc_am_lte rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) { if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) {
return -1; return -1;
} }
@ -3039,7 +3039,7 @@ bool reset_test()
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
int len = 0; int len = 0;
rlc_am_lte rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) { if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) {
return -1; return -1;
@ -3081,7 +3081,7 @@ bool resume_test()
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
int len = 0; int len = 0;
rlc_am_lte rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) { if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) {
return -1; return -1;
@ -3122,7 +3122,7 @@ bool stop_test()
rlc_am_tester tester; rlc_am_tester tester;
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
rlc_am_lte rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) { if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) {
return -1; return -1;
@ -3149,8 +3149,8 @@ bool status_pdu_test()
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
int len = 0; int len = 0;
rlc_am_lte rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
rlc_am_lte rlc2(srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers); rlc_am rlc2(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers);
if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) { if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) {
return -1; return -1;
@ -3258,8 +3258,8 @@ bool incorrect_status_pdu_test()
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
int len = 0; int len = 0;
rlc_am_lte rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
rlc_am_lte rlc2(srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers); rlc_am rlc2(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers);
if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) { if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) {
return -1; return -1;
@ -3323,8 +3323,8 @@ bool incorrect_status_pdu_test2()
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
int len = 0; int len = 0;
rlc_am_lte rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
rlc_am_lte rlc2(srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers); rlc_am rlc2(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers);
if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) { if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) {
return -1; return -1;
@ -3437,8 +3437,8 @@ bool reestablish_test()
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
rlc_am_lte rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
rlc_am_lte rlc2(srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers); rlc_am rlc2(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers);
srslog::fetch_basic_logger("RLC_AM_1").set_hex_dump_max_size(100); srslog::fetch_basic_logger("RLC_AM_1").set_hex_dump_max_size(100);
srslog::fetch_basic_logger("RLC_AM_2").set_hex_dump_max_size(100); srslog::fetch_basic_logger("RLC_AM_2").set_hex_dump_max_size(100);
@ -3557,8 +3557,8 @@ bool discard_test()
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
rlc_am_lte rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
rlc_am_lte rlc2(srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers); rlc_am rlc2(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers);
srslog::fetch_basic_logger("RLC_AM_1").set_hex_dump_max_size(100); srslog::fetch_basic_logger("RLC_AM_1").set_hex_dump_max_size(100);
srslog::fetch_basic_logger("RLC_AM_2").set_hex_dump_max_size(100); srslog::fetch_basic_logger("RLC_AM_2").set_hex_dump_max_size(100);

@ -35,7 +35,7 @@
using namespace srsue; using namespace srsue;
using namespace srsran; using namespace srsran;
int basic_test_tx(rlc_am_nr* rlc, byte_buffer_t pdu_bufs[NBUFS]) int basic_test_tx(rlc_am* rlc, byte_buffer_t pdu_bufs[NBUFS])
{ {
// Push 5 SDUs into RLC1 // Push 5 SDUs into RLC1
unique_byte_buffer_t sdu_bufs[NBUFS]; unique_byte_buffer_t sdu_bufs[NBUFS];
@ -66,8 +66,8 @@ int basic_test()
timer_handler timers(8); timer_handler timers(8);
byte_buffer_t pdu_bufs[NBUFS]; byte_buffer_t pdu_bufs[NBUFS];
rlc_am_nr rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); rlc_am rlc1(srsran_rat_t::nr, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
rlc_am_nr rlc2(srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers); rlc_am rlc2(srsran_rat_t::nr, srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers);
// before configuring entity // before configuring entity
TESTASSERT(0 == rlc1.get_buffer_state()); TESTASSERT(0 == rlc1.get_buffer_state());

@ -561,7 +561,7 @@ int rlc_um_nr_test8()
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
// Similar to rlc_um_nr_test9() but out-of-order PDUs have SNs (from multiple SDUs) // Similar to rlc_um_nr_test8() but out-of-order PDUs have SNs (from multiple SDUs)
int rlc_um_nr_test9() int rlc_um_nr_test9()
{ {
rlc_um_nr_test_context1 ctxt; rlc_um_nr_test_context1 ctxt;
@ -621,6 +621,8 @@ int rlc_um_nr_test9()
TESTASSERT(*(ctxt.tester.sdus[i]->msg) == i); TESTASSERT(*(ctxt.tester.sdus[i]->msg) == i);
} }
TESTASSERT(ctxt.timers.nof_running_timers() == 0);
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
@ -676,13 +678,10 @@ int main(int argc, char** argv)
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
// temporarily disabling
#if 0
if (rlc_um_nr_test9()) { if (rlc_um_nr_test9()) {
fprintf(stderr, "rlc_um_nr_test9() failed.\n"); fprintf(stderr, "rlc_um_nr_test9() failed.\n");
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
#endif
#if PCAP #if PCAP
pcap_handle->close(); pcap_handle->close();

@ -361,6 +361,7 @@ enable = false
# ts1_reloc_overall_timeout: S1AP TS 36.413 TS1RelocOverall Expiry Timeout value in milliseconds # ts1_reloc_overall_timeout: S1AP TS 36.413 TS1RelocOverall Expiry Timeout value in milliseconds
# rlf_release_timer_ms: Time taken by eNB to release UE context after it detects a RLF # rlf_release_timer_ms: Time taken by eNB to release UE context after it detects a RLF
# rlf_min_ul_snr_estim: SNR threshold in dB below which the enb is notified with RLF ko # rlf_min_ul_snr_estim: SNR threshold in dB below which the enb is notified with RLF ko
# s1_setup_max_retries: Maximum amount of retries to setup the S1AP connection. If this value is exceeded, an alarm is written to the log. -1 means infinity.
# #
##################################################################### #####################################################################
[expert] [expert]
@ -397,3 +398,4 @@ enable = false
#ts1_reloc_overall_timeout = 10000 #ts1_reloc_overall_timeout = 10000
#rlf_release_timer_ms = 4000 #rlf_release_timer_ms = 4000
#rlf_min_ul_snr_estim = -2 #rlf_min_ul_snr_estim = -2
#s1_setup_max_retries = -1

@ -41,11 +41,10 @@ namespace srsenb {
class metrics_csv : public srsran::metrics_listener<enb_metrics_t> class metrics_csv : public srsran::metrics_listener<enb_metrics_t>
{ {
public: public:
metrics_csv(std::string filename); metrics_csv(std::string filename, enb_metrics_interface* enb_);
~metrics_csv(); ~metrics_csv();
void set_metrics(const enb_metrics_t& m, const uint32_t period_usec); void set_metrics(const enb_metrics_t& m, const uint32_t period_usec);
void set_handle(enb_metrics_interface* enb_);
void stop(); void stop();
private: private:

@ -100,8 +100,8 @@ public:
if (cc_idx < cell_list_lte.size()) { if (cc_idx < cell_list_lte.size()) {
ret = cell_list_lte[cc_idx].cell.nof_ports; ret = cell_list_lte[cc_idx].cell.nof_ports;
} else if (cc_idx == 1 && !cell_list_nr.empty()) { } else if ((cc_idx == 0 || cc_idx == 1) && !cell_list_nr.empty()) {
// one RF port for basic NSA config // one RF port for basic NSA/SA config
ret = 1; ret = 1;
} }

@ -22,6 +22,8 @@
#ifndef SRSENB_PHY_METRICS_H #ifndef SRSENB_PHY_METRICS_H
#define SRSENB_PHY_METRICS_H #define SRSENB_PHY_METRICS_H
#include <limits>
namespace srsenb { namespace srsenb {
// PHY metrics per user // PHY metrics per user
@ -29,7 +31,15 @@ namespace srsenb {
struct ul_metrics_t { struct ul_metrics_t {
float n; float n;
float pusch_sinr; float pusch_sinr;
float pucch_sinr; // Initialize this member with an invalid value as this field is optional.
float pusch_rssi = std::numeric_limits<float>::quiet_NaN();
// Initialize this member with an invalid value as this field is optional.
int64_t pusch_tpc = 0;
float pucch_sinr;
// Initialize this member with an invalid value as this field is optional.
float pucch_rssi = std::numeric_limits<float>::quiet_NaN();
// Initialize this member with an invalid value as this field is optional.
float pucch_ni = std::numeric_limits<float>::quiet_NaN();
float rssi; float rssi;
float turbo_iters; float turbo_iters;
float mcs; float mcs;
@ -39,7 +49,9 @@ struct ul_metrics_t {
struct dl_metrics_t { struct dl_metrics_t {
float mcs; float mcs;
int n_samples; // Initialize this member with an invalid value as this field is optional.
int64_t pucch_tpc = 0;
int n_samples;
}; };
struct phy_metrics_t { struct phy_metrics_t {

@ -30,6 +30,7 @@ namespace srsenb {
/// MAC metrics per user /// MAC metrics per user
struct mac_ue_metrics_t { struct mac_ue_metrics_t {
uint16_t rnti; uint16_t rnti;
uint32_t pci;
uint32_t nof_tti; uint32_t nof_tti;
uint32_t cc_idx; uint32_t cc_idx;
int tx_pkts; int tx_pkts;
@ -44,16 +45,18 @@ struct mac_ue_metrics_t {
float dl_ri; float dl_ri;
float dl_pmi; float dl_pmi;
float phr; float phr;
float dl_cqi_offset;
float ul_snr_offset;
// NR-only UL PHY metrics // NR-only UL PHY metrics
float pusch_sinr; float pusch_sinr;
float pucch_sinr; float pucch_sinr;
float ul_rssi; float ul_rssi;
float fec_iters; float fec_iters;
float dl_mcs; float dl_mcs;
int dl_mcs_samples; int dl_mcs_samples;
float ul_mcs; float ul_mcs;
int ul_mcs_samples; int ul_mcs_samples;
}; };
/// MAC misc information for each cc. /// MAC misc information for each cc.
struct mac_cc_info_t { struct mac_cc_info_t {

@ -86,6 +86,7 @@ public:
std::array<int, SRSRAN_MAX_CARRIERS> get_enb_ue_cc_map(uint16_t rnti) final; std::array<int, SRSRAN_MAX_CARRIERS> get_enb_ue_cc_map(uint16_t rnti) final;
std::array<int, SRSRAN_MAX_CARRIERS> get_enb_ue_activ_cc_map(uint16_t rnti) final; std::array<int, SRSRAN_MAX_CARRIERS> get_enb_ue_activ_cc_map(uint16_t rnti) final;
int ul_buffer_add(uint16_t rnti, uint32_t lcid, uint32_t bytes) final; int ul_buffer_add(uint16_t rnti, uint32_t lcid, uint32_t bytes) final;
int metrics_read(uint16_t rnti, mac_ue_metrics_t& metrics);
class carrier_sched; class carrier_sched;

@ -27,6 +27,7 @@
#include "sched_ue_ctrl/sched_ue_cell.h" #include "sched_ue_ctrl/sched_ue_cell.h"
#include "sched_ue_ctrl/tpc.h" #include "sched_ue_ctrl/tpc.h"
#include "srsenb/hdr/common/common_enb.h" #include "srsenb/hdr/common/common_enb.h"
#include "srsenb/hdr/stack/mac/common/mac_metrics.h"
#include "srsran/srslog/srslog.h" #include "srsran/srslog/srslog.h"
#include <bitset> #include <bitset>
#include <map> #include <map>
@ -82,6 +83,7 @@ public:
const ue_cfg_t& get_ue_cfg() const { return cfg; } const ue_cfg_t& get_ue_cfg() const { return cfg; }
uint32_t get_aggr_level(uint32_t enb_cc_idx, uint32_t nof_bits); uint32_t get_aggr_level(uint32_t enb_cc_idx, uint32_t nof_bits);
void ul_buffer_add(uint8_t lcid, uint32_t bytes); void ul_buffer_add(uint8_t lcid, uint32_t bytes);
void metrics_read(mac_ue_metrics_t& metrics);
/******************************************************* /*******************************************************
* Functions used by scheduler metric objects * Functions used by scheduler metric objects

@ -52,6 +52,8 @@ struct sched_ue_cell {
const ue_cc_cfg* get_ue_cc_cfg() const { return configured() ? &ue_cfg->supported_cc_list[ue_cc_idx] : nullptr; } const ue_cc_cfg* get_ue_cc_cfg() const { return configured() ? &ue_cfg->supported_cc_list[ue_cc_idx] : nullptr; }
const sched_interface::ue_cfg_t* get_ue_cfg() const { return configured() ? ue_cfg : nullptr; } const sched_interface::ue_cfg_t* get_ue_cfg() const { return configured() ? ue_cfg : nullptr; }
cc_st cc_state() const { return cc_state_; } cc_st cc_state() const { return cc_state_; }
float get_ul_snr_offset() const { return ul_snr_coeff; }
float get_dl_cqi_offset() const { return dl_cqi_coeff; }
int get_dl_cqi() const; int get_dl_cqi() const;
int get_dl_cqi(const rbgmask_t& rbgs) const; int get_dl_cqi(const rbgmask_t& rbgs) const;

@ -131,6 +131,7 @@ private:
rrc_interface_s1ap* rrc = nullptr; rrc_interface_s1ap* rrc = nullptr;
s1ap_args_t args; s1ap_args_t args;
srslog::basic_logger& logger; srslog::basic_logger& logger;
srslog::log_channel& alarms_channel;
srsran::task_sched_handle task_sched; srsran::task_sched_handle task_sched;
srsran::task_queue_handle mme_task_queue; srsran::task_queue_handle mme_task_queue;
srsran::socket_manager_itf* rx_socket_handler; srsran::socket_manager_itf* rx_socket_handler;
@ -338,8 +339,9 @@ private:
srsran::proc_outcome_t init(); srsran::proc_outcome_t init();
srsran::proc_outcome_t step() { return srsran::proc_outcome_t::yield; } srsran::proc_outcome_t step() { return srsran::proc_outcome_t::yield; }
srsran::proc_outcome_t react(const s1setupresult& event); srsran::proc_outcome_t react(const s1setupresult& event);
void then(const srsran::proc_state_t& result) const; void then(const srsran::proc_state_t& result);
const char* name() const { return "MME Connection"; } const char* name() const { return "MME Connection"; }
uint16_t connect_count = 0;
private: private:
srsran::proc_outcome_t start_mme_connection(); srsran::proc_outcome_t start_mme_connection();

@ -34,7 +34,7 @@ if (RPATH)
endif (RPATH) endif (RPATH)
add_library(enb_cfg_parser STATIC parser.cc enb_cfg_parser.cc) add_library(enb_cfg_parser STATIC parser.cc enb_cfg_parser.cc)
target_link_libraries(enb_cfg_parser srsran_common ${LIBCONFIGPP_LIBRARIES}) target_link_libraries(enb_cfg_parser srsran_common srsgnb_rrc_config_utils ${LIBCONFIGPP_LIBRARIES})
add_executable(srsenb main.cc enb.cc metrics_stdout.cc metrics_csv.cc metrics_json.cc) add_executable(srsenb main.cc enb.cc metrics_stdout.cc metrics_csv.cc metrics_json.cc)

@ -21,6 +21,7 @@
#include "enb_cfg_parser.h" #include "enb_cfg_parser.h"
#include "srsenb/hdr/enb.h" #include "srsenb/hdr/enb.h"
#include "srsgnb/hdr/stack/rrc/rrc_nr_config_utils.h"
#include "srsran/asn1/rrc_utils.h" #include "srsran/asn1/rrc_utils.h"
#include "srsran/common/band_helper.h" #include "srsran/common/band_helper.h"
#include "srsran/common/multiqueue.h" #include "srsran/common/multiqueue.h"
@ -970,8 +971,10 @@ static int parse_cell_list(all_args_t* args, rrc_cfg_t* rrc_cfg, Setting& root)
static int parse_nr_cell_list(all_args_t* args, rrc_nr_cfg_t* rrc_cfg_nr, rrc_cfg_t* rrc_cfg_eutra, Setting& root) static int parse_nr_cell_list(all_args_t* args, rrc_nr_cfg_t* rrc_cfg_nr, rrc_cfg_t* rrc_cfg_eutra, Setting& root)
{ {
for (uint32_t n = 0; n < (uint32_t)root.getLength(); ++n) { for (uint32_t n = 0; n < (uint32_t)root.getLength(); ++n) {
auto& cellroot = root[n];
rrc_cell_cfg_nr_t cell_cfg = {}; rrc_cell_cfg_nr_t cell_cfg = {};
auto& cellroot = root[n]; generate_default_nr_cell(cell_cfg);
parse_opt_field(cell_cfg.phy_cell.rf_port, cellroot, "rf_port"); parse_opt_field(cell_cfg.phy_cell.rf_port, cellroot, "rf_port");
HANDLEPARSERCODE(parse_required_field(cell_cfg.phy_cell.carrier.pci, cellroot, "pci")); HANDLEPARSERCODE(parse_required_field(cell_cfg.phy_cell.carrier.pci, cellroot, "pci"));
@ -1170,6 +1173,21 @@ int parse_cfg_files(all_args_t* args_, rrc_cfg_t* rrc_cfg_, rrc_nr_cfg_t* rrc_nr
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
// update number of NR cells
rrc_cfg_->num_nr_cells = rrc_nr_cfg_->cell_list.size();
args_->rf.nof_carriers = rrc_cfg_->cell_list.size() + rrc_nr_cfg_->cell_list.size();
ASSERT_VALID_CFG(args_->rf.nof_carriers > 0, "There must be at least one NR or LTE cell");
if (rrc_nr_cfg_->cell_list.size() > 0) {
// NR cells available.
if (rrc_cfg_->cell_list.size() == 0) {
// SA mode.
rrc_nr_cfg_->is_standalone = true;
} else {
// NSA mode.
rrc_nr_cfg_->is_standalone = false;
}
}
// Set fields derived from others, and check for correctness of the parsed configuration // Set fields derived from others, and check for correctness of the parsed configuration
if (enb_conf_sections::set_derived_args(args_, rrc_cfg_, phy_cfg_, cell_common_cfg) != SRSRAN_SUCCESS) { if (enb_conf_sections::set_derived_args(args_, rrc_cfg_, phy_cfg_, cell_common_cfg) != SRSRAN_SUCCESS) {
fprintf(stderr, "Error deriving EUTRA cell parameters\n"); fprintf(stderr, "Error deriving EUTRA cell parameters\n");
@ -1183,20 +1201,15 @@ int parse_cfg_files(all_args_t* args_, rrc_cfg_t* rrc_cfg_, rrc_nr_cfg_t* rrc_nr
} }
// update number of NR cells // update number of NR cells
rrc_cfg_->num_nr_cells = rrc_nr_cfg_->cell_list.size();
args_->rf.nof_carriers = rrc_cfg_->cell_list.size() + rrc_nr_cfg_->cell_list.size();
ASSERT_VALID_CFG(args_->rf.nof_carriers > 0, "There must be at least one NR or LTE cell");
if (rrc_nr_cfg_->cell_list.size() > 0) { if (rrc_nr_cfg_->cell_list.size() > 0) {
// NR cells available. // NR cells available.
if (rrc_cfg_->cell_list.size() == 0) { if (rrc_nr_cfg_->is_standalone) {
// SA mode. Update NGAP args // SA mode. Update NGAP args
rrc_nr_cfg_->is_standalone = true;
args_->nr_stack.ngap.gnb_id = args_->enb.enb_id; args_->nr_stack.ngap.gnb_id = args_->enb.enb_id;
args_->nr_stack.ngap.cell_id = rrc_nr_cfg_->cell_list[0].phy_cell.cell_id; args_->nr_stack.ngap.cell_id = rrc_nr_cfg_->cell_list[0].phy_cell.cell_id;
args_->nr_stack.ngap.tac = rrc_nr_cfg_->cell_list[0].tac; args_->nr_stack.ngap.tac = rrc_nr_cfg_->cell_list[0].tac;
} else { } else {
// NSA mode. // NSA mode.
rrc_nr_cfg_->is_standalone = false;
// update EUTRA RRC params for ENDC // update EUTRA RRC params for ENDC
rrc_cfg_->endc_cfg.abs_frequency_ssb = rrc_nr_cfg_->cell_list.at(0).ssb_absolute_freq_point; rrc_cfg_->endc_cfg.abs_frequency_ssb = rrc_nr_cfg_->cell_list.at(0).ssb_absolute_freq_point;
rrc_cfg_->endc_cfg.nr_band = rrc_nr_cfg_->cell_list.at(0).band; rrc_cfg_->endc_cfg.nr_band = rrc_nr_cfg_->cell_list.at(0).band;
@ -1529,7 +1542,8 @@ int set_derived_args_nr(all_args_t* args_, rrc_nr_cfg_t* rrc_nr_cfg_, phy_cfg_t*
// Create NR dedicated cell configuration from RRC configuration // Create NR dedicated cell configuration from RRC configuration
for (auto it = rrc_nr_cfg_->cell_list.begin(); it != rrc_nr_cfg_->cell_list.end(); ++it) { for (auto it = rrc_nr_cfg_->cell_list.begin(); it != rrc_nr_cfg_->cell_list.end(); ++it) {
auto& cfg = *it; auto& cfg = *it;
cfg.phy_cell.carrier.max_mimo_layers = args_->enb.nof_ports; cfg.phy_cell.carrier.max_mimo_layers = args_->enb.nof_ports;
// NR cells have the same bandwidth as EUTRA cells, adjust PRB sizes // NR cells have the same bandwidth as EUTRA cells, adjust PRB sizes
@ -1547,122 +1561,22 @@ int set_derived_args_nr(all_args_t* args_, rrc_nr_cfg_t* rrc_nr_cfg_, phy_cfg_t*
ERROR("The only accepted number of PRB is: 25, 50, 100"); ERROR("The only accepted number of PRB is: 25, 50, 100");
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
// phy_cell_cfg.root_seq_idx = cfg.root_seq_idx;
cfg.phy_cell.num_ra_preambles = 52; // FIXME: read from config
if (cfg.phy_cell.dl_freq_hz == 0) { // Derive cross-dependent cell params
cfg.phy_cell.dl_freq_hz = band_helper.nr_arfcn_to_freq(cfg.dl_arfcn); if (set_derived_nr_cell_params(rrc_nr_cfg_->is_standalone, cfg) != SRSRAN_SUCCESS) {
} ERROR("Failed to derive NR cell params.");
return SRSRAN_ERROR;
if (cfg.phy_cell.ul_freq_hz == 0) {
// auto-detect UL frequency
if (cfg.ul_arfcn == 0) {
// derive UL ARFCN from given DL ARFCN
cfg.ul_arfcn = band_helper.get_ul_arfcn_from_dl_arfcn(cfg.dl_arfcn);
if (cfg.ul_arfcn == 0) {
ERROR("Can't derive UL ARFCN from DL ARFCN %d", cfg.dl_arfcn);
return SRSRAN_ERROR;
}
}
cfg.phy_cell.ul_freq_hz = band_helper.nr_arfcn_to_freq(cfg.ul_arfcn);
} }
// duplex mode // phy_cell_cfg.root_seq_idx = cfg.root_seq_idx;
cfg.duplex_mode = band_helper.get_duplex_mode(cfg.band);
// PRACH // PRACH
cfg.phy_cell.prach.is_nr = true; cfg.phy_cell.prach.hs_flag = phy_cfg_->prach_cnfg.prach_cfg_info.high_speed_flag;
cfg.phy_cell.prach.config_idx = 8;
cfg.phy_cell.prach.root_seq_idx = 0;
cfg.phy_cell.prach.freq_offset = 1;
cfg.phy_cell.prach.num_ra_preambles = cfg.phy_cell.num_ra_preambles;
cfg.phy_cell.prach.hs_flag = phy_cfg_->prach_cnfg.prach_cfg_info.high_speed_flag;
cfg.phy_cell.prach.tdd_config.configured = (cfg.duplex_mode == SRSRAN_DUPLEX_MODE_TDD);
// PDCCH
// Configure CORESET ID 1
cfg.phy_cell.pdcch.coreset_present[1] = true;
cfg.phy_cell.pdcch.coreset[1].id = 1;
cfg.phy_cell.pdcch.coreset[1].duration = 1;
cfg.phy_cell.pdcch.coreset[1].mapping_type = srsran_coreset_mapping_type_non_interleaved;
cfg.phy_cell.pdcch.coreset[1].precoder_granularity = srsran_coreset_precoder_granularity_reg_bundle;
// Generate frequency resources for the full BW
for (uint32_t i = 0; i < SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE; i++) {
cfg.phy_cell.pdcch.coreset[1].freq_resources[i] = i < SRSRAN_FLOOR(cfg.phy_cell.carrier.nof_prb, 6);
}
// Configure Search Space 1 as common
cfg.phy_cell.pdcch.search_space_present[1] = true;
cfg.phy_cell.pdcch.search_space[1].id = 1;
cfg.phy_cell.pdcch.search_space[1].coreset_id = 1;
cfg.phy_cell.pdcch.search_space[1].duration = 1;
cfg.phy_cell.pdcch.search_space[1].formats[0] = srsran_dci_format_nr_0_0; // DCI format for PUSCH
cfg.phy_cell.pdcch.search_space[1].formats[1] = srsran_dci_format_nr_1_0; // DCI format for PDSCH
cfg.phy_cell.pdcch.search_space[1].nof_formats = 2;
cfg.phy_cell.pdcch.search_space[1].type = srsran_search_space_type_common_3;
// Generate 1 candidate for each aggregation level if possible
for (uint32_t L = 0; L < SRSRAN_SEARCH_SPACE_NOF_AGGREGATION_LEVELS_NR; L++) {
cfg.phy_cell.pdcch.search_space[1].nof_candidates[L] =
SRSRAN_MIN(2, srsran_pdcch_nr_max_candidates_coreset(&cfg.phy_cell.pdcch.coreset[1], L));
}
cfg.phy_cell.pdcch.ra_search_space_present = true;
cfg.phy_cell.pdcch.ra_search_space = cfg.phy_cell.pdcch.search_space[1];
cfg.phy_cell.pdcch.ra_search_space.type = srsran_search_space_type_common_1;
// PDSCH // PDSCH
cfg.phy_cell.pdsch.rs_power = phy_cfg_->pdsch_cnfg.ref_sig_pwr; cfg.phy_cell.pdsch.rs_power = phy_cfg_->pdsch_cnfg.ref_sig_pwr;
cfg.phy_cell.pdsch.p_b = phy_cfg_->pdsch_cnfg.p_b; cfg.phy_cell.pdsch.p_b = phy_cfg_->pdsch_cnfg.p_b;
// copy center frequencies
cfg.phy_cell.carrier.dl_center_frequency_hz = cfg.phy_cell.dl_freq_hz;
cfg.phy_cell.carrier.ul_center_frequency_hz = cfg.phy_cell.ul_freq_hz;
cfg.dl_absolute_freq_point_a = band_helper.get_abs_freq_point_a_arfcn(cfg.phy_cell.carrier.nof_prb, cfg.dl_arfcn);
cfg.ul_absolute_freq_point_a = band_helper.get_abs_freq_point_a_arfcn(cfg.phy_cell.carrier.nof_prb, cfg.ul_arfcn);
// Calculate SSB params depending on band/duplex
cfg.ssb_cfg.duplex_mode = band_helper.get_duplex_mode(cfg.band);
cfg.ssb_cfg.pattern = band_helper.get_ssb_pattern(cfg.band, srsran_subcarrier_spacing_15kHz);
if (cfg.ssb_cfg.pattern == SRSRAN_SSB_PATTERN_A) {
// 15kHz SSB SCS
cfg.ssb_cfg.scs = srsran_subcarrier_spacing_15kHz;
} else {
// try to optain SSB pattern for same band with 30kHz SCS
cfg.ssb_cfg.pattern = band_helper.get_ssb_pattern(cfg.band, srsran_subcarrier_spacing_30kHz);
if (cfg.ssb_cfg.pattern == SRSRAN_SSB_PATTERN_B || cfg.ssb_cfg.pattern == SRSRAN_SSB_PATTERN_C) {
// SSB SCS is 30 kHz
cfg.ssb_cfg.scs = srsran_subcarrier_spacing_30kHz;
} else {
ERROR("Can't derive SSB pattern for band %d", cfg.band);
return SRSRAN_ERROR;
}
}
// fill remaining SSB fields
cfg.ssb_absolute_freq_point =
band_helper.get_abs_freq_ssb_arfcn(cfg.band, cfg.ssb_cfg.scs, cfg.dl_absolute_freq_point_a);
if (cfg.ssb_absolute_freq_point == 0) {
ERROR("Can't derive SSB freq point for dl_arfcn %d and band %d", cfg.dl_arfcn, cfg.band);
return SRSRAN_ERROR;
}
// Convert to frequency for PHY
cfg.phy_cell.carrier.ssb_center_freq_hz = band_helper.nr_arfcn_to_freq(cfg.ssb_absolute_freq_point);
cfg.ssb_cfg.center_freq_hz = cfg.phy_cell.carrier.dl_center_frequency_hz;
cfg.ssb_cfg.ssb_freq_hz = cfg.phy_cell.carrier.ssb_center_freq_hz;
cfg.ssb_cfg.periodicity_ms = 10; // TODO: make a param
cfg.ssb_cfg.beta_pss = 0.0;
cfg.ssb_cfg.beta_sss = 0.0;
cfg.ssb_cfg.beta_pbch = 0.0;
cfg.ssb_cfg.beta_pbch_dmrs = 0.0;
// set by PHY layer in worker_pool::set_common_cfg
cfg.ssb_cfg.srate_hz = 0.0;
cfg.ssb_cfg.scaling = 0.0;
phy_cfg_->phy_cell_cfg_nr.push_back(cfg.phy_cell); phy_cfg_->phy_cell_cfg_nr.push_back(cfg.phy_cell);
} }

@ -256,6 +256,7 @@ void parse_args(all_args_t* args, int argc, char* argv[])
("expert.ts1_reloc_prep_timeout", bpo::value<uint32_t>(&args->stack.s1ap.ts1_reloc_prep_timeout)->default_value(10000), "S1AP TS 36.413 TS1RelocPrep Expiry Timeout value in milliseconds.") ("expert.ts1_reloc_prep_timeout", bpo::value<uint32_t>(&args->stack.s1ap.ts1_reloc_prep_timeout)->default_value(10000), "S1AP TS 36.413 TS1RelocPrep Expiry Timeout value in milliseconds.")
("expert.ts1_reloc_overall_timeout", bpo::value<uint32_t>(&args->stack.s1ap.ts1_reloc_overall_timeout)->default_value(10000), "S1AP TS 36.413 TS1RelocOverall Expiry Timeout value in milliseconds.") ("expert.ts1_reloc_overall_timeout", bpo::value<uint32_t>(&args->stack.s1ap.ts1_reloc_overall_timeout)->default_value(10000), "S1AP TS 36.413 TS1RelocOverall Expiry Timeout value in milliseconds.")
("expert.rlf_min_ul_snr_estim", bpo::value<int>(&args->stack.mac.rlf_min_ul_snr_estim)->default_value(-2), "SNR threshold in dB below which the eNB is notified with rlf ko.") ("expert.rlf_min_ul_snr_estim", bpo::value<int>(&args->stack.mac.rlf_min_ul_snr_estim)->default_value(-2), "SNR threshold in dB below which the eNB is notified with rlf ko.")
("expert.max_s1_setup_retries", bpo::value<int32_t>(&args->stack.s1ap.max_s1_setup_retries)->default_value(-1), "Max S1 setup retries")
// eMBMS section // eMBMS section
("embms.enable", bpo::value<bool>(&args->stack.embms.enable)->default_value(false), "Enables MBMS in the eNB") ("embms.enable", bpo::value<bool>(&args->stack.embms.enable)->default_value(false), "Enables MBMS in the eNB")
@ -641,10 +642,9 @@ int main(int argc, char* argv[])
metricshub.add_listener(&metrics_screen); metricshub.add_listener(&metrics_screen);
metrics_screen.set_handle(enb.get()); metrics_screen.set_handle(enb.get());
srsenb::metrics_csv metrics_file(args.general.metrics_csv_filename); srsenb::metrics_csv metrics_file(args.general.metrics_csv_filename, enb.get());
if (args.general.metrics_csv_enable) { if (args.general.metrics_csv_enable) {
metricshub.add_listener(&metrics_file); metricshub.add_listener(&metrics_file);
metrics_file.set_handle(enb.get());
} }
srsenb::metrics_json json_metrics(json_channel, enb.get()); srsenb::metrics_json json_metrics(json_channel, enb.get());

@ -36,7 +36,8 @@ using namespace std;
namespace srsenb { namespace srsenb {
metrics_csv::metrics_csv(std::string filename) : n_reports(0), metrics_report_period(1.0), enb(NULL) metrics_csv::metrics_csv(std::string filename, enb_metrics_interface* enb_) :
n_reports(0), metrics_report_period(1.0), enb(enb_)
{ {
file.open(filename.c_str(), std::ios_base::out); file.open(filename.c_str(), std::ios_base::out);
} }
@ -46,11 +47,6 @@ metrics_csv::~metrics_csv()
stop(); stop();
} }
void metrics_csv::set_handle(enb_metrics_interface* enb_)
{
enb = enb_;
}
void metrics_csv::stop() void metrics_csv::stop()
{ {
if (file.is_open()) { if (file.is_open()) {

@ -54,6 +54,13 @@ DECLARE_METRIC("dl_bitrate", metric_dl_bitrate, float, "");
DECLARE_METRIC("dl_bler", metric_dl_bler, float, ""); DECLARE_METRIC("dl_bler", metric_dl_bler, float, "");
DECLARE_METRIC("ul_snr", metric_ul_snr, float, ""); DECLARE_METRIC("ul_snr", metric_ul_snr, float, "");
DECLARE_METRIC("ul_mcs", metric_ul_mcs, float, ""); DECLARE_METRIC("ul_mcs", metric_ul_mcs, float, "");
DECLARE_METRIC("ul_pusch_rssi", metric_ul_pusch_rssi, float, "");
DECLARE_METRIC("ul_pucch_rssi", metric_ul_pucch_rssi, float, "");
DECLARE_METRIC("ul_pucch_ni", metric_ul_pucch_ni, float, "");
DECLARE_METRIC("ul_pusch_tpc", metric_ul_pusch_tpc, int64_t, "");
DECLARE_METRIC("ul_pucch_tpc", metric_ul_pucch_tpc, int64_t, "");
DECLARE_METRIC("dl_cqi_offset", metric_dl_cqi_offset, float, "");
DECLARE_METRIC("ul_snr_offset", metric_ul_snr_offset, float, "");
DECLARE_METRIC("ul_bitrate", metric_ul_bitrate, float, ""); DECLARE_METRIC("ul_bitrate", metric_ul_bitrate, float, "");
DECLARE_METRIC("ul_bler", metric_ul_bler, float, ""); DECLARE_METRIC("ul_bler", metric_ul_bler, float, "");
DECLARE_METRIC("ul_phr", metric_ul_phr, float, ""); DECLARE_METRIC("ul_phr", metric_ul_phr, float, "");
@ -64,6 +71,13 @@ DECLARE_METRIC_SET("ue_container",
metric_ue_rnti, metric_ue_rnti,
metric_dl_cqi, metric_dl_cqi,
metric_dl_mcs, metric_dl_mcs,
metric_ul_pusch_rssi,
metric_ul_pucch_rssi,
metric_ul_pucch_ni,
metric_ul_pusch_tpc,
metric_ul_pucch_tpc,
metric_dl_cqi_offset,
metric_ul_snr_offset,
metric_dl_bitrate, metric_dl_bitrate,
metric_dl_bler, metric_dl_bler,
metric_ul_snr, metric_ul_snr,
@ -97,24 +111,40 @@ static void fill_ue_metrics(mset_ue_container& ue, const enb_metrics_t& m, unsig
ue.write<metric_ue_rnti>(m.stack.mac.ues[i].rnti); ue.write<metric_ue_rnti>(m.stack.mac.ues[i].rnti);
ue.write<metric_dl_cqi>(std::max(0.1f, m.stack.mac.ues[i].dl_cqi)); ue.write<metric_dl_cqi>(std::max(0.1f, m.stack.mac.ues[i].dl_cqi));
if (!std::isnan(m.phy[i].dl.mcs)) { if (!std::isnan(m.phy[i].dl.mcs)) {
ue.write<metric_dl_mcs>(std::max(0.1f, m.phy[i].dl.mcs)); ue.write<metric_dl_mcs>(m.phy[i].dl.mcs);
} }
if (m.stack.mac.ues[i].tx_brate > 0 && m.stack.mac.ues[i].nof_tti > 0) { if (m.stack.mac.ues[i].tx_brate > 0 && m.stack.mac.ues[i].nof_tti > 0) {
ue.write<metric_dl_bitrate>( ue.write<metric_dl_bitrate>(
std::max(0.1f, (float)m.stack.mac.ues[i].tx_brate / (m.stack.mac.ues[i].nof_tti * 0.001f))); std::max(0.1f, (float)m.stack.mac.ues[i].tx_brate / (m.stack.mac.ues[i].nof_tti * 0.001f)));
} }
if (m.stack.mac.ues[i].tx_pkts > 0 && m.stack.mac.ues[i].tx_errors > 0) { if (m.stack.mac.ues[i].tx_pkts > 0 && m.stack.mac.ues[i].tx_errors > 0) {
ue.write<metric_dl_bler>(std::max(0.1f, (float)100 * m.stack.mac.ues[i].tx_errors / m.stack.mac.ues[i].tx_pkts)); ue.write<metric_dl_bler>((float)100 * m.stack.mac.ues[i].tx_errors / m.stack.mac.ues[i].tx_pkts);
} }
if (!std::isnan(m.phy[i].ul.pusch_sinr)) { if (!std::isnan(m.phy[i].ul.pusch_sinr)) {
ue.write<metric_ul_snr>(std::max(0.1f, m.phy[i].ul.pusch_sinr)); ue.write<metric_ul_snr>(m.phy[i].ul.pusch_sinr);
}
if (!std::isnan(m.phy[i].ul.pusch_rssi)) {
ue.write<metric_ul_pusch_rssi>(m.phy[i].ul.pusch_rssi);
}
if (!std::isnan(m.phy[i].ul.pucch_rssi)) {
ue.write<metric_ul_pucch_rssi>(m.phy[i].ul.pucch_rssi);
}
if (!std::isnan(m.phy[i].ul.pucch_ni)) {
ue.write<metric_ul_pucch_ni>(m.phy[i].ul.pucch_ni);
}
ue.write<metric_ul_pusch_tpc>(m.phy[i].ul.pusch_tpc);
ue.write<metric_ul_pucch_tpc>(m.phy[i].dl.pucch_tpc);
if (!std::isnan(m.stack.mac.ues[i].dl_cqi_offset)) {
ue.write<metric_dl_cqi_offset>(m.stack.mac.ues[i].dl_cqi_offset);
}
if (!std::isnan(m.stack.mac.ues[i].ul_snr_offset)) {
ue.write<metric_ul_snr_offset>(m.stack.mac.ues[i].ul_snr_offset);
} }
if (!std::isnan(m.phy[i].ul.mcs)) { if (!std::isnan(m.phy[i].ul.mcs)) {
ue.write<metric_ul_mcs>(std::max(0.1f, m.phy[i].ul.mcs)); ue.write<metric_ul_mcs>(m.phy[i].ul.mcs);
} }
if (m.stack.mac.ues[i].rx_brate > 0 && m.stack.mac.ues[i].nof_tti > 0) { if (m.stack.mac.ues[i].rx_brate > 0 && m.stack.mac.ues[i].nof_tti > 0) {
ue.write<metric_ul_bitrate>( ue.write<metric_ul_bitrate>((float)m.stack.mac.ues[i].rx_brate / (m.stack.mac.ues[i].nof_tti * 0.001f));
std::max(0.1f, (float)m.stack.mac.ues[i].rx_brate / (m.stack.mac.ues[i].nof_tti * 0.001f)));
} }
if (m.stack.mac.ues[i].rx_pkts > 0 && m.stack.mac.ues[i].rx_errors > 0) { if (m.stack.mac.ues[i].rx_pkts > 0 && m.stack.mac.ues[i].rx_errors > 0) {
ue.write<metric_ul_bler>(std::max(0.1f, (float)100 * m.stack.mac.ues[i].rx_errors / m.stack.mac.ues[i].rx_pkts)); ue.write<metric_ul_bler>(std::max(0.1f, (float)100 * m.stack.mac.ues[i].rx_errors / m.stack.mac.ues[i].rx_pkts));

@ -98,6 +98,7 @@ void metrics_stdout::set_metrics_helper(uint32_t num_ue
} }
fmt::print("{:>3.5}", (is_nr) ? "nr" : "lte"); fmt::print("{:>3.5}", (is_nr) ? "nr" : "lte");
fmt::print(" {:>4}", mac.ues[i].pci);
fmt::print("{:>5x}", mac.ues[i].rnti); fmt::print("{:>5x}", mac.ues[i].rnti);
if (not iszero(mac.ues[i].dl_cqi)) { if (not iszero(mac.ues[i].dl_cqi)) {
fmt::print(" {:>3}", int(mac.ues[i].dl_cqi)); fmt::print(" {:>3}", int(mac.ues[i].dl_cqi));
@ -194,8 +195,10 @@ void metrics_stdout::set_metrics(const enb_metrics_t& metrics, const uint32_t pe
if (++n_reports > 10) { if (++n_reports > 10) {
n_reports = 0; n_reports = 0;
fmt::print("\n"); fmt::print("\n");
fmt::print(" -----------------DL----------------|-------------------------UL-------------------------\n"); fmt::print(
fmt::print("rat rnti cqi ri mcs brate ok nok (%) | pusch pucch phr mcs brate ok nok (%) bsr\n"); " -----------------DL----------------|-------------------------UL-------------------------\n");
fmt::print(
"rat pci rnti cqi ri mcs brate ok nok (%) | pusch pucch phr mcs brate ok nok (%) bsr\n");
} }
set_metrics_helper(metrics.stack.rrc.ues.size(), metrics.stack.mac, metrics.phy, false); set_metrics_helper(metrics.stack.rrc.ues.size(), metrics.stack.mac, metrics.phy, false);

@ -23,6 +23,14 @@
#include "srsran/common/buffer_pool.h" #include "srsran/common/buffer_pool.h"
#include "srsran/common/common.h" #include "srsran/common/common.h"
//#define DEBUG_WRITE_FILE
#ifdef DEBUG_WRITE_FILE
FILE* f;
static uint32_t num_slots = 0;
static uint32_t slots_to_dump = 10;
#endif
namespace srsenb { namespace srsenb {
namespace nr { namespace nr {
slot_worker::slot_worker(srsran::phy_common_interface& common_, slot_worker::slot_worker(srsran::phy_common_interface& common_,
@ -95,6 +103,12 @@ bool slot_worker::init(const args_t& args)
return false; return false;
} }
#ifdef DEBUG_WRITE_FILE
const char* filename = "nr_baseband.dat";
printf("Opening %s to dump baseband\n", filename);
f = fopen(filename, "w");
#endif
return true; return true;
} }
@ -416,6 +430,16 @@ void slot_worker::work_imp()
} }
common.worker_end(context, true, tx_rf_buffer); common.worker_end(context, true, tx_rf_buffer);
#ifdef DEBUG_WRITE_FILE
if (num_slots++ < slots_to_dump) {
printf("Writing slot %d\n", dl_slot_cfg.idx);
fwrite(tx_rf_buffer.get(0), tx_rf_buffer.get_nof_samples() * sizeof(cf_t), 1, f);
} else if (num_slots == slots_to_dump) {
printf("Baseband signaled dump finished. Please close app.\n");
fclose(f);
}
#endif
} }
bool slot_worker::set_common_cfg(const srsran_carrier_nr_t& carrier, bool slot_worker::set_common_cfg(const srsran_carrier_nr_t& carrier,

@ -250,7 +250,11 @@ void mac::get_metrics(mac_metrics_t& metrics)
continue; continue;
} }
metrics.ues.emplace_back(); metrics.ues.emplace_back();
u.second->metrics_read(&metrics.ues.back()); auto& ue_metrics = metrics.ues.back();
u.second->metrics_read(&ue_metrics);
scheduler.metrics_read(u.first, ue_metrics);
ue_metrics.pci = (ue_metrics.cc_idx < cell_config.size()) ? cell_config[ue_metrics.cc_idx].cell.id : 0;
} }
metrics.cc_info.resize(detected_rachs.size()); metrics.cc_info.resize(detected_rachs.size());
for (unsigned cc = 0, e = detected_rachs.size(); cc != e; ++cc) { for (unsigned cc = 0, e = detected_rachs.size(); cc != e; ++cc) {
@ -579,11 +583,22 @@ void mac::rach_detected(uint32_t tti, uint32_t enb_cc_idx, uint32_t preamble_idx
// Trigger scheduler RACH // Trigger scheduler RACH
scheduler.dl_rach_info(enb_cc_idx, rar_info); scheduler.dl_rach_info(enb_cc_idx, rar_info);
logger.info( auto get_pci = [this, enb_cc_idx]() {
"RACH: tti=%d, cc=%d, preamble=%d, offset=%d, temp_crnti=0x%x", tti, enb_cc_idx, preamble_idx, time_adv, rnti); srsran::rwlock_read_guard lock(rwlock);
srsran::console("RACH: tti=%d, cc=%d, preamble=%d, offset=%d, temp_crnti=0x%x\n", return (enb_cc_idx < cell_config.size()) ? cell_config[enb_cc_idx].cell.id : 0;
};
uint32_t pci = get_pci();
logger.info("RACH: tti=%d, cc=%d, pci=%d, preamble=%d, offset=%d, temp_crnti=0x%x",
tti,
enb_cc_idx,
pci,
preamble_idx,
time_adv,
rnti);
srsran::console("RACH: tti=%d, cc=%d, pci=%d, preamble=%d, offset=%d, temp_crnti=0x%x\n",
tti, tti,
enb_cc_idx, enb_cc_idx,
pci,
preamble_idx, preamble_idx,
time_adv, time_adv,
rnti); rnti);
@ -840,9 +855,9 @@ int mac::get_mch_sched(uint32_t tti, bool is_mcch, dl_sched_list_t& dl_sched_res
int requested_bytes = (mcs_data.tbs / 8 > (int)mch.mtch_sched[mtch_index].lcid_buffer_size) int requested_bytes = (mcs_data.tbs / 8 > (int)mch.mtch_sched[mtch_index].lcid_buffer_size)
? (mch.mtch_sched[mtch_index].lcid_buffer_size) ? (mch.mtch_sched[mtch_index].lcid_buffer_size)
: ((mcs_data.tbs / 8) - 2); : ((mcs_data.tbs / 8) - 2);
int bytes_received = ue_db[SRSRAN_MRNTI]->read_pdu(current_lcid, mtch_payload_buffer, requested_bytes); int bytes_received = ue_db[SRSRAN_MRNTI]->read_pdu(current_lcid, mtch_payload_buffer, requested_bytes);
mch.pdu[0].lcid = current_lcid; mch.pdu[0].lcid = current_lcid;
mch.pdu[0].nbytes = bytes_received; mch.pdu[0].nbytes = bytes_received;
mch.mtch_sched[0].mtch_payload = mtch_payload_buffer; mch.mtch_sched[0].mtch_payload = mtch_payload_buffer;
dl_sched_res->pdsch[0].dci.rnti = SRSRAN_MRNTI; dl_sched_res->pdsch[0].dci.rnti = SRSRAN_MRNTI;
if (bytes_received) { if (bytes_received) {

@ -370,6 +370,12 @@ bool sched::is_generated(srsran::tti_point tti_rx, uint32_t enb_cc_idx) const
return sched_results.has_sf(tti_rx) and sched_results.get_sf(tti_rx)->is_generated(enb_cc_idx); return sched_results.has_sf(tti_rx) and sched_results.get_sf(tti_rx)->is_generated(enb_cc_idx);
} }
int sched::metrics_read(uint16_t rnti, mac_ue_metrics_t& metrics)
{
return ue_db_access_locked(
rnti, [&metrics](sched_ue& ue) { ue.metrics_read(metrics); }, "metrics_read");
}
// Common way to access ue_db elements in a read locking way // Common way to access ue_db elements in a read locking way
template <typename Func> template <typename Func>
int sched::ue_db_access_locked(uint16_t rnti, Func&& f, const char* func_name, bool log_fail) int sched::ue_db_access_locked(uint16_t rnti, Func&& f, const char* func_name, bool log_fail)

@ -87,8 +87,8 @@ void sf_grid_t::init(const sched_cell_params_t& cell_params_)
// Compute reserved PRBs for CQI, SR and HARQ-ACK, and store it in a bitmask // Compute reserved PRBs for CQI, SR and HARQ-ACK, and store it in a bitmask
pucch_mask.resize(cc_cfg->nof_prb()); pucch_mask.resize(cc_cfg->nof_prb());
pucch_nrb = (cc_cfg->cfg.nrb_pucch > 0) ? (uint32_t)cc_cfg->cfg.nrb_pucch : 0; pucch_nrb = (cc_cfg->cfg.nrb_pucch > 0) ? (uint32_t)cc_cfg->cfg.nrb_pucch : 0;
srsran_pucch_cfg_t pucch_cfg = cell_params_.pucch_cfg_common; srsran_pucch_cfg_t pucch_cfg = cell_params_.pucch_cfg_common;
uint32_t harq_pucch = 0; uint32_t harq_pucch = 0;
if (cc_cfg->sched_cfg->pucch_harq_max_rb > 0) { if (cc_cfg->sched_cfg->pucch_harq_max_rb > 0) {
harq_pucch = cc_cfg->sched_cfg->pucch_harq_max_rb; harq_pucch = cc_cfg->sched_cfg->pucch_harq_max_rb;
@ -831,13 +831,13 @@ void sf_sched::set_ul_sched_result(const sf_cch_allocator::alloc_result_t& dci_r
sched_interface::ul_sched_data_t& pusch = ul_result->pusch.back(); sched_interface::ul_sched_data_t& pusch = ul_result->pusch.back();
uint32_t total_data_before = user->get_pending_ul_data_total(get_tti_tx_ul(), cc_cfg->enb_cc_idx); uint32_t total_data_before = user->get_pending_ul_data_total(get_tti_tx_ul(), cc_cfg->enb_cc_idx);
int tbs = user->generate_format0(&pusch, int tbs = user->generate_format0(&pusch,
get_tti_tx_ul(), get_tti_tx_ul(),
cc_cfg->enb_cc_idx, cc_cfg->enb_cc_idx,
ul_alloc.alloc, ul_alloc.alloc,
ul_alloc.needs_pdcch(), ul_alloc.needs_pdcch(),
cce_range, cce_range,
ul_alloc.msg3_mcs, ul_alloc.msg3_mcs,
uci_type); uci_type);
ul_harq_proc* h = user->get_ul_harq(get_tti_tx_ul(), cc_cfg->enb_cc_idx); ul_harq_proc* h = user->get_ul_harq(get_tti_tx_ul(), cc_cfg->enb_cc_idx);
uint32_t new_pending_bytes = user->get_pending_ul_new_data(get_tti_tx_ul(), cc_cfg->enb_cc_idx); uint32_t new_pending_bytes = user->get_pending_ul_new_data(get_tti_tx_ul(), cc_cfg->enb_cc_idx);
@ -863,23 +863,24 @@ void sf_sched::set_ul_sched_result(const sf_cch_allocator::alloc_result_t& dci_r
uint32_t old_pending_bytes = user->get_pending_ul_old_data(); uint32_t old_pending_bytes = user->get_pending_ul_old_data();
if (logger.info.enabled()) { if (logger.info.enabled()) {
fmt::memory_buffer str_buffer; fmt::memory_buffer str_buffer;
fmt::format_to( fmt::format_to(str_buffer,
str_buffer, "SCHED: {} {} rnti=0x{:x}, cc={}, pid={}, dci=({},{}), prb={}, n_rtx={}, cfi={}, tbs={}, bsr={} "
"SCHED: {} {} rnti=0x{:x}, cc={}, pid={}, dci=({},{}), prb={}, n_rtx={}, cfi={}, tbs={}, bsr={} ({}-{})", "({}-{}), tti_tx_ul={}",
ul_alloc.is_msg3 ? "Msg3" : "UL", ul_alloc.is_msg3 ? "Msg3" : "UL",
ul_alloc.is_retx() ? "retx" : "tx", ul_alloc.is_retx() ? "retx" : "tx",
user->get_rnti(), user->get_rnti(),
cc_cfg->enb_cc_idx, cc_cfg->enb_cc_idx,
h->get_id(), h->get_id(),
pusch.dci.location.L, pusch.dci.location.L,
pusch.dci.location.ncce, pusch.dci.location.ncce,
ul_alloc.alloc, ul_alloc.alloc,
h->nof_retx(0), h->nof_retx(0),
tti_alloc.get_cfi(), tti_alloc.get_cfi(),
tbs, tbs,
new_pending_bytes, new_pending_bytes,
total_data_before, total_data_before,
old_pending_bytes); old_pending_bytes,
get_tti_tx_ul().to_uint());
logger.info("%s", srsran::to_c_str(str_buffer)); logger.info("%s", srsran::to_c_str(str_buffer));
} }

@ -173,6 +173,13 @@ void sched_ue::unset_sr()
sr = false; sr = false;
} }
void sched_ue::metrics_read(mac_ue_metrics_t& metrics)
{
sched_ue_cell& pcell = cells[cfg.supported_cc_list[0].enb_cc_idx];
metrics.ul_snr_offset = pcell.get_ul_snr_offset();
metrics.dl_cqi_offset = pcell.get_dl_cqi_offset();
}
tti_point prev_meas_gap_start(tti_point tti, uint32_t period, uint32_t offset) tti_point prev_meas_gap_start(tti_point tti, uint32_t period, uint32_t offset)
{ {
return tti_point{static_cast<uint32_t>(floor(static_cast<float>((tti - offset).to_uint()) / period)) * period + return tti_point{static_cast<uint32_t>(floor(static_cast<float>((tti - offset).to_uint()) / period)) * period +

@ -21,8 +21,8 @@
#include "srsenb/hdr/stack/rrc/rrc_bearer_cfg.h" #include "srsenb/hdr/stack/rrc/rrc_bearer_cfg.h"
#include "srsenb/hdr/common/common_enb.h" #include "srsenb/hdr/common/common_enb.h"
#include "srsran/asn1/obj_id_cmp_utils.h"
#include "srsran/asn1/rrc_utils.h" #include "srsran/asn1/rrc_utils.h"
#include "srsran/rrc/rrc_cfg_utils.h"
namespace srsenb { namespace srsenb {

@ -24,6 +24,7 @@
#include "srsenb/hdr/stack/rrc/rrc_cell_cfg.h" #include "srsenb/hdr/stack/rrc/rrc_cell_cfg.h"
#include "srsenb/hdr/stack/rrc/ue_meas_cfg.h" #include "srsenb/hdr/stack/rrc/ue_meas_cfg.h"
#include "srsenb/hdr/stack/rrc/ue_rr_cfg.h" #include "srsenb/hdr/stack/rrc/ue_rr_cfg.h"
#include "srsran/asn1/obj_id_cmp_utils.h"
#include "srsran/asn1/rrc_utils.h" #include "srsran/asn1/rrc_utils.h"
#include "srsran/common/bcd_helpers.h" #include "srsran/common/bcd_helpers.h"
#include "srsran/common/common.h" #include "srsran/common/common.h"
@ -34,7 +35,6 @@
#include "srsran/interfaces/enb_pdcp_interfaces.h" #include "srsran/interfaces/enb_pdcp_interfaces.h"
#include "srsran/interfaces/enb_rlc_interfaces.h" #include "srsran/interfaces/enb_rlc_interfaces.h"
#include "srsran/interfaces/enb_s1ap_interfaces.h" #include "srsran/interfaces/enb_s1ap_interfaces.h"
#include "srsran/rrc/rrc_cfg_utils.h"
#include <algorithm> #include <algorithm>
#include <cstdio> #include <cstdio>

@ -21,7 +21,8 @@
#include "srsenb/hdr/stack/rrc/ue_meas_cfg.h" #include "srsenb/hdr/stack/rrc/ue_meas_cfg.h"
#include "srsenb/hdr/stack/rrc/rrc_cell_cfg.h" #include "srsenb/hdr/stack/rrc/rrc_cell_cfg.h"
#include "srsran/rrc/rrc_cfg_utils.h" #include "srsran/asn1/obj_id_cmp_utils.h"
#include "srsran/asn1/rrc_utils.h"
using namespace asn1::rrc; using namespace asn1::rrc;

@ -23,8 +23,8 @@
#include "srsenb/hdr/stack/rrc/rrc_bearer_cfg.h" #include "srsenb/hdr/stack/rrc/rrc_bearer_cfg.h"
#include "srsenb/hdr/stack/rrc/rrc_cell_cfg.h" #include "srsenb/hdr/stack/rrc/rrc_cell_cfg.h"
#include "srsenb/hdr/stack/rrc/rrc_config.h" #include "srsenb/hdr/stack/rrc/rrc_config.h"
#include "srsran/asn1/obj_id_cmp_utils.h"
#include "srsran/asn1/rrc_utils.h" #include "srsran/asn1/rrc_utils.h"
#include "srsran/rrc/rrc_cfg_utils.h"
#define SET_OPT_FIELD(fieldname, out, in) \ #define SET_OPT_FIELD(fieldname, out, in) \
if (in.fieldname##_present) { \ if (in.fieldname##_present) { \

@ -229,6 +229,7 @@ void s1ap::ue::ho_prep_proc_t::then(const srsran::proc_state_t& result)
srsran::proc_outcome_t s1ap::s1_setup_proc_t::init() srsran::proc_outcome_t s1ap::s1_setup_proc_t::init()
{ {
procInfo("Starting new MME connection."); procInfo("Starting new MME connection.");
connect_count++;
return start_mme_connection(); return start_mme_connection();
} }
@ -274,7 +275,7 @@ srsran::proc_outcome_t s1ap::s1_setup_proc_t::react(const srsenb::s1ap::s1_setup
return srsran::proc_outcome_t::error; return srsran::proc_outcome_t::error;
} }
void s1ap::s1_setup_proc_t::then(const srsran::proc_state_t& result) const void s1ap::s1_setup_proc_t::then(const srsran::proc_state_t& result)
{ {
if (result.is_error()) { if (result.is_error()) {
procInfo("Failed to initiate S1 connection. Attempting reconnection in %d seconds", procInfo("Failed to initiate S1 connection. Attempting reconnection in %d seconds",
@ -285,7 +286,13 @@ void s1ap::s1_setup_proc_t::then(const srsran::proc_state_t& result) const
s1ap_ptr->mme_socket.close(); s1ap_ptr->mme_socket.close();
procInfo("S1AP socket closed."); procInfo("S1AP socket closed.");
s1ap_ptr->mme_connect_timer.run(); s1ap_ptr->mme_connect_timer.run();
if (s1ap_ptr->args.max_s1_setup_retries > 0 && connect_count > s1ap_ptr->args.max_s1_setup_retries) {
s1ap_ptr->alarms_channel("s1apError");
srsran_terminate("Error connecting to MME");
}
// Try again with in 10 seconds // Try again with in 10 seconds
} else {
connect_count = 0;
} }
} }
@ -296,7 +303,11 @@ void s1ap::s1_setup_proc_t::then(const srsran::proc_state_t& result) const
s1ap::s1ap(srsran::task_sched_handle task_sched_, s1ap::s1ap(srsran::task_sched_handle task_sched_,
srslog::basic_logger& logger, srslog::basic_logger& logger,
srsran::socket_manager_itf* rx_socket_handler_) : srsran::socket_manager_itf* rx_socket_handler_) :
s1setup_proc(this), logger(logger), task_sched(task_sched_), rx_socket_handler(rx_socket_handler_) s1setup_proc(this),
logger(logger),
task_sched(task_sched_),
rx_socket_handler(rx_socket_handler_),
alarms_channel(srslog::fetch_log_channel("alarms"))
{ {
mme_task_queue = task_sched.make_task_queue(); mme_task_queue = task_sched.make_task_queue();
} }
@ -312,7 +323,7 @@ int s1ap::init(const s1ap_args_t& args_, rrc_interface_s1ap* rrc_)
mme_connect_timer = task_sched.get_unique_timer(); mme_connect_timer = task_sched.get_unique_timer();
auto mme_connect_run = [this](uint32_t tid) { auto mme_connect_run = [this](uint32_t tid) {
if (s1setup_proc.is_busy()) { if (s1setup_proc.is_busy()) {
logger.error("Failed to initiate S1Setup procedure."); logger.error("Failed to initiate S1Setup procedure: procedure is busy.");
} }
s1setup_proc.launch(); s1setup_proc.launch();
}; };
@ -330,7 +341,7 @@ int s1ap::init(const s1ap_args_t& args_, rrc_interface_s1ap* rrc_)
running = true; running = true;
// starting MME connection // starting MME connection
if (not s1setup_proc.launch()) { if (not s1setup_proc.launch()) {
logger.error("Failed to initiate S1Setup procedure."); logger.error("Failed to initiate S1Setup procedure: error launching procedure.");
} }
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
@ -710,6 +721,13 @@ bool s1ap::handle_unsuccessfuloutcome(const unsuccessful_outcome_s& msg)
bool s1ap::handle_s1setupresponse(const asn1::s1ap::s1_setup_resp_s& msg) bool s1ap::handle_s1setupresponse(const asn1::s1ap::s1_setup_resp_s& msg)
{ {
if (s1setup_proc.is_idle()) {
asn1::s1ap::cause_c cause;
cause.set_protocol().value = cause_protocol_opts::msg_not_compatible_with_receiver_state;
send_error_indication(cause);
return false;
}
s1setupresponse = msg; s1setupresponse = msg;
mme_connected = true; mme_connected = true;
s1_setup_proc_t::s1setupresult res; s1_setup_proc_t::s1setupresult res;
@ -1084,6 +1102,13 @@ bool s1ap::handle_uectxtreleasecommand(const ue_context_release_cmd_s& msg)
bool s1ap::handle_s1setupfailure(const asn1::s1ap::s1_setup_fail_s& msg) bool s1ap::handle_s1setupfailure(const asn1::s1ap::s1_setup_fail_s& msg)
{ {
if (s1setup_proc.is_idle()) {
asn1::s1ap::cause_c cause;
cause.set_protocol().value = cause_protocol_opts::msg_not_compatible_with_receiver_state;
send_error_indication(cause);
return false;
}
std::string cause = get_cause(msg.protocol_ies.cause.value); std::string cause = get_cause(msg.protocol_ies.cause.value);
logger.error("S1 Setup Failure. Cause: %s", cause.c_str()); logger.error("S1 Setup Failure. Cause: %s", cause.c_str());
srsran::console("S1 Setup Failure. Cause: %s\n", cause.c_str()); srsran::console("S1 Setup Failure. Cause: %s\n", cause.c_str());
@ -1097,6 +1122,14 @@ bool s1ap::handle_handover_preparation_failure(const ho_prep_fail_s& msg)
if (u == nullptr) { if (u == nullptr) {
return false; return false;
} }
if (u->ho_prep_proc.is_idle()) {
asn1::s1ap::cause_c cause;
cause.set_protocol().value = cause_protocol_opts::msg_not_compatible_with_receiver_state;
send_error_indication(cause);
return false;
}
u->ho_prep_proc.trigger(msg); u->ho_prep_proc.trigger(msg);
return true; return true;
} }
@ -1108,6 +1141,13 @@ bool s1ap::handle_handover_command(const asn1::s1ap::ho_cmd_s& msg)
if (u == nullptr) { if (u == nullptr) {
return false; return false;
} }
if (u->ho_prep_proc.is_idle()) {
asn1::s1ap::cause_c cause;
cause.set_protocol().value = cause_protocol_opts::msg_not_compatible_with_receiver_state;
send_error_indication(cause);
return false;
}
u->ho_prep_proc.trigger(msg); u->ho_prep_proc.trigger(msg);
return true; return true;
} }

@ -84,14 +84,17 @@ void rlc::add_user(uint16_t rnti)
void rlc::rem_user(uint16_t rnti) void rlc::rem_user(uint16_t rnti)
{ {
pthread_rwlock_wrlock(&rwlock); pthread_rwlock_rdlock(&rwlock);
if (users.count(rnti)) { if (users.count(rnti)) {
users[rnti].rlc->stop(); users[rnti].rlc->stop();
users.erase(rnti);
} else { } else {
logger.error("Removing rnti=0x%x. Already removed", rnti); logger.error("Removing rnti=0x%x. Already removed", rnti);
} }
pthread_rwlock_unlock(&rwlock); pthread_rwlock_unlock(&rwlock);
pthread_rwlock_wrlock(&rwlock);
users.erase(rnti);
pthread_rwlock_unlock(&rwlock);
} }
void rlc::clear_buffer(uint16_t rnti) void rlc::clear_buffer(uint16_t rnti)

@ -62,8 +62,8 @@ public:
metrics[0].stack.mac.ues[0].dl_pmi = 1.0; metrics[0].stack.mac.ues[0].dl_pmi = 1.0;
metrics[0].stack.mac.ues[0].phr = 12.0; metrics[0].stack.mac.ues[0].phr = 12.0;
metrics[0].phy.resize(2); metrics[0].phy.resize(2);
metrics[0].phy[0].dl.mcs = 28.0; metrics[0].phy[0].dl.mcs = 28.0;
metrics[0].phy[0].ul.mcs = 20.2; metrics[0].phy[0].ul.mcs = 20.2;
metrics[0].phy[0].ul.pucch_sinr = 14.2; metrics[0].phy[0].ul.pucch_sinr = 14.2;
metrics[0].phy[0].ul.pusch_sinr = 14.2; metrics[0].phy[0].ul.pusch_sinr = 14.2;
@ -105,8 +105,8 @@ public:
metrics[1].stack.mac.ues[0].dl_pmi = 1.0; metrics[1].stack.mac.ues[0].dl_pmi = 1.0;
metrics[1].stack.mac.ues[0].phr = 99.1; metrics[1].stack.mac.ues[0].phr = 99.1;
metrics[1].phy.resize(1); metrics[1].phy.resize(1);
metrics[1].phy[0].dl.mcs = 6.2; metrics[1].phy[0].dl.mcs = 6.2;
metrics[1].phy[0].ul.mcs = 28.0; metrics[1].phy[0].ul.mcs = 28.0;
metrics[1].phy[0].ul.pucch_sinr = 22.2; metrics[1].phy[0].ul.pucch_sinr = 22.2;
metrics[1].phy[0].ul.pusch_sinr = 22.2; metrics[1].phy[0].ul.pusch_sinr = 22.2;
@ -128,8 +128,8 @@ public:
metrics[2].stack.mac.ues[0].dl_pmi = 1.0; metrics[2].stack.mac.ues[0].dl_pmi = 1.0;
metrics[2].stack.mac.ues[0].phr = 12.0; metrics[2].stack.mac.ues[0].phr = 12.0;
metrics[2].phy.resize(1); metrics[2].phy.resize(1);
metrics[2].phy[0].dl.mcs = 28.0; metrics[2].phy[0].dl.mcs = 28.0;
metrics[2].phy[0].ul.mcs = 20.2; metrics[2].phy[0].ul.mcs = 20.2;
metrics[2].phy[0].ul.pusch_sinr = 14.2; metrics[2].phy[0].ul.pusch_sinr = 14.2;
metrics[2].phy[0].ul.pucch_sinr = 14.2; metrics[2].phy[0].ul.pucch_sinr = 14.2;
@ -210,8 +210,7 @@ int main(int argc, char** argv)
metrics_screen.set_handle(&enb); metrics_screen.set_handle(&enb);
// the CSV file writer // the CSV file writer
metrics_csv metrics_file(csv_file_name); metrics_csv metrics_file(csv_file_name, &enb);
metrics_file.set_handle(&enb);
// create metrics hub and register metrics for stdout // create metrics hub and register metrics for stdout
srsran::metrics_hub<enb_metrics_t> metricshub; srsran::metrics_hub<enb_metrics_t> metricshub;

@ -21,10 +21,10 @@
#include "srsenb/hdr/enb.h" #include "srsenb/hdr/enb.h"
#include "srsenb/hdr/stack/rrc/ue_meas_cfg.h" #include "srsenb/hdr/stack/rrc/ue_meas_cfg.h"
#include "srsran/asn1/obj_id_cmp_utils.h"
#include "srsran/asn1/rrc_utils.h" #include "srsran/asn1/rrc_utils.h"
#include "srsran/common/test_common.h" #include "srsran/common/test_common.h"
#include "srsran/interfaces/enb_rrc_interface_types.h" #include "srsran/interfaces/enb_rrc_interface_types.h"
#include "srsran/rrc/rrc_cfg_utils.h"
#include "test_helpers.h" #include "test_helpers.h"
using namespace asn1::rrc; using namespace asn1::rrc;

@ -33,16 +33,16 @@ class ngap_dummy : public ngap_interface_rrc_nr
void initial_ue(uint16_t rnti, void initial_ue(uint16_t rnti,
uint32_t gnb_cc_idx, uint32_t gnb_cc_idx,
asn1::ngap_nr::rrcestablishment_cause_e cause, asn1::ngap_nr::rrcestablishment_cause_e cause,
srsran::unique_byte_buffer_t pdu) srsran::const_byte_span pdu)
{} {}
void initial_ue(uint16_t rnti, void initial_ue(uint16_t rnti,
uint32_t gnb_cc_idx, uint32_t gnb_cc_idx,
asn1::ngap_nr::rrcestablishment_cause_e cause, asn1::ngap_nr::rrcestablishment_cause_e cause,
srsran::unique_byte_buffer_t pdu, srsran::const_byte_span pdu,
uint32_t m_tmsi) uint32_t m_tmsi)
{} {}
void write_pdu(uint16_t rnti, srsran::unique_byte_buffer_t pdu) {} void write_pdu(uint16_t rnti, srsran::const_byte_span pdu) {}
bool user_exists(uint16_t rnti) { return true; } bool user_exists(uint16_t rnti) { return true; }
void user_mod(uint16_t old_rnti, uint16_t new_rnti) {} void user_mod(uint16_t old_rnti, uint16_t new_rnti) {}
bool user_release(uint16_t rnti, asn1::ngap_nr::cause_radio_network_e cause_radio) { return true; } bool user_release(uint16_t rnti, asn1::ngap_nr::cause_radio_network_e cause_radio) { return true; }

@ -84,6 +84,7 @@ public:
srsran_duplex_config_nr_t duplex = {}; srsran_duplex_config_nr_t duplex = {};
srsran::phy_cfg_nr_t::ssb_cfg_t ssb = {}; srsran::phy_cfg_nr_t::ssb_cfg_t ssb = {};
srsran::bounded_vector<bwp_cfg_t, SCHED_NR_MAX_BWP_PER_CELL> bwps{1}; // idx0 for BWP-common srsran::bounded_vector<bwp_cfg_t, SCHED_NR_MAX_BWP_PER_CELL> bwps{1}; // idx0 for BWP-common
srsran_mib_nr_t mib;
srsran::bounded_vector<cell_cfg_sib_t, MAX_SIBS> sibs; srsran::bounded_vector<cell_cfg_sib_t, MAX_SIBS> sibs;
}; };

@ -45,14 +45,18 @@ void sched_nzp_csi_rs(srsran::const_span<srsran_csi_rs_nzp_set_t> nzp_csi_rs_set
* *
* @param[in] sl_point Slot point carrying information about current slot. * @param[in] sl_point Slot point carrying information about current slot.
* @param[in] ssb_periodicity Periodicity of SSB in ms. * @param[in] ssb_periodicity Periodicity of SSB in ms.
* @param[out] ssb_list List of SSB messages to be sent to PHY. * @param[in] mib MIB message content
* @param[out] ssb_list List of SSB messages to be sent to PHY.
* *
* @remark This function a is basic scheduling function that uses the following simplified assumption: * @remark This function a is basic scheduling function that uses the following simplified assumption:
* 1) Subcarrier spacing: 15kHz * 1) Subcarrier spacing: 15kHz
* 2) Frequency below 3GHz * 2) Frequency below 3GHz
* 3) Position in Burst is 1000, i.e., Only the first SSB of the 4 opportunities gets scheduled * 3) Position in Burst is 1000, i.e., Only the first SSB of the 4 opportunities gets scheduled
*/ */
void sched_ssb_basic(const slot_point& sl_point, uint32_t ssb_periodicity, ssb_list& ssb_list); void sched_ssb_basic(const slot_point& sl_point,
uint32_t ssb_periodicity,
const srsran_mib_nr_t& mib,
ssb_list& ssb_list);
/// Fill DCI fields with SIB info /// Fill DCI fields with SIB info
bool fill_dci_sib(prb_interval interv, uint32_t sib_idx, const bwp_params_t& bwp_cfg, srsran_dci_dl_nr_t& dci); bool fill_dci_sib(prb_interval interv, uint32_t sib_idx, const bwp_params_t& bwp_cfg, srsran_dci_dl_nr_t& dci);

@ -59,14 +59,14 @@ public:
void initial_ue(uint16_t rnti, void initial_ue(uint16_t rnti,
uint32_t gnb_cc_idx, uint32_t gnb_cc_idx,
asn1::ngap_nr::rrcestablishment_cause_e cause, asn1::ngap_nr::rrcestablishment_cause_e cause,
srsran::unique_byte_buffer_t pdu); srsran::const_byte_span pdu);
void initial_ue(uint16_t rnti, void initial_ue(uint16_t rnti,
uint32_t gnb_cc_idx, uint32_t gnb_cc_idx,
asn1::ngap_nr::rrcestablishment_cause_e cause, asn1::ngap_nr::rrcestablishment_cause_e cause,
srsran::unique_byte_buffer_t pdu, srsran::const_byte_span pdu,
uint32_t s_tmsi); uint32_t s_tmsi);
void write_pdu(uint16_t rnti, srsran::unique_byte_buffer_t pdu); void write_pdu(uint16_t rnti, srsran::const_byte_span pdu);
bool user_exists(uint16_t rnti) { return true; }; bool user_exists(uint16_t rnti) { return true; };
void user_mod(uint16_t old_rnti, uint16_t new_rnti){}; void user_mod(uint16_t old_rnti, uint16_t new_rnti){};
bool user_release(uint16_t rnti, asn1::ngap_nr::cause_radio_network_e cause_radio) { return true; }; bool user_release(uint16_t rnti, asn1::ngap_nr::cause_radio_network_e cause_radio) { return true; };

@ -40,11 +40,11 @@ public:
virtual ~ue(); virtual ~ue();
// TS 38.413 - Section 9.2.5.1 - Initial UE Message // TS 38.413 - Section 9.2.5.1 - Initial UE Message
bool send_initial_ue_message(asn1::ngap_nr::rrcestablishment_cause_e cause, bool send_initial_ue_message(asn1::ngap_nr::rrcestablishment_cause_e cause,
srsran::unique_byte_buffer_t pdu, srsran::const_byte_span pdu,
bool has_tmsi, bool has_tmsi,
uint32_t s_tmsi = 0); uint32_t s_tmsi = 0);
// TS 38.413 - Section 9.2.5.3 - Uplink NAS Transport // TS 38.413 - Section 9.2.5.3 - Uplink NAS Transport
bool send_ul_nas_transport(srsran::unique_byte_buffer_t pdu); bool send_ul_nas_transport(srsran::const_byte_span pdu);
// TS 38.413 - Section 9.2.2.2 - Initial Context Setup Response // TS 38.413 - Section 9.2.2.2 - Initial Context Setup Response
bool send_initial_ctxt_setup_response(); bool send_initial_ctxt_setup_response();
// TS 38.413 - Section 9.2.2.3 - Initial Context Setup Failure // TS 38.413 - Section 9.2.2.3 - Initial Context Setup Failure
@ -86,4 +86,4 @@ private:
}; };
} // namespace srsenb } // namespace srsenb
#endif #endif

@ -22,15 +22,36 @@
#ifndef SRSRAN_CELL_ASN1_CONFIG_H #ifndef SRSRAN_CELL_ASN1_CONFIG_H
#define SRSRAN_CELL_ASN1_CONFIG_H #define SRSRAN_CELL_ASN1_CONFIG_H
#include "rrc_config_nr.h" #include "rrc_nr_config.h"
#include "srsran/asn1/rrc_nr.h" #include "srsran/asn1/rrc_nr.h"
#include "srsran/common/common_nr.h"
namespace srsenb { namespace srsenb {
using rlc_bearer_list_t = asn1::rrc_nr::cell_group_cfg_s::rlc_bearer_to_add_mod_list_l_;
// NSA helpers
int fill_sp_cell_cfg_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, asn1::rrc_nr::sp_cell_cfg_s& sp_cell); int fill_sp_cell_cfg_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, asn1::rrc_nr::sp_cell_cfg_s& sp_cell);
int fill_mib_from_enb_cfg(const rrc_nr_cfg_t& cfg, asn1::rrc_nr::mib_s& mib); // SA helpers
int fill_sib1_from_enb_cfg(const rrc_nr_cfg_t& cfg, asn1::rrc_nr::sib1_s& sib1); int fill_master_cell_cfg_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, asn1::rrc_nr::cell_group_cfg_s& out);
int fill_mib_from_enb_cfg(const rrc_cell_cfg_nr_t& cell_cfg, asn1::rrc_nr::mib_s& mib);
int fill_sib1_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, asn1::rrc_nr::sib1_s& sib1);
/**
* Based on the previous and new radio bearer config, generate ASN1 diff
* @return if a change was detected
*/
bool compute_diff_radio_bearer_cfg(const rrc_nr_cfg_t& cfg,
const asn1::rrc_nr::radio_bearer_cfg_s& prev_bearers,
const asn1::rrc_nr::radio_bearer_cfg_s& next_bearers,
asn1::rrc_nr::radio_bearer_cfg_s& diff);
/// Apply radioBearerConfig updates to CellGroupConfig
void fill_cellgroup_with_radio_bearer_cfg(const rrc_nr_cfg_t& cfg,
const asn1::rrc_nr::radio_bearer_cfg_s& bearers,
asn1::rrc_nr::cell_group_cfg_s& out);
} // namespace srsenb } // namespace srsenb

@ -25,7 +25,7 @@
#include "srsenb/hdr/stack/enb_stack_base.h" #include "srsenb/hdr/stack/enb_stack_base.h"
#include "srsenb/hdr/stack/rrc/rrc_config_common.h" #include "srsenb/hdr/stack/rrc/rrc_config_common.h"
#include "srsenb/hdr/stack/rrc/rrc_metrics.h" #include "srsenb/hdr/stack/rrc/rrc_metrics.h"
#include "srsgnb/hdr/stack/rrc/rrc_config_nr.h" #include "srsgnb/hdr/stack/rrc/rrc_nr_config.h"
#include "srsran/asn1/rrc_nr.h" #include "srsran/asn1/rrc_nr.h"
#include "srsran/common/block_queue.h" #include "srsran/common/block_queue.h"
#include "srsran/common/buffer_pool.h" #include "srsran/common/buffer_pool.h"
@ -147,11 +147,12 @@ private:
// vars // vars
struct cell_ctxt_t { struct cell_ctxt_t {
asn1::rrc_nr::mib_s mib; asn1::rrc_nr::mib_s mib;
asn1::rrc_nr::sib1_s sib1; asn1::rrc_nr::sib1_s sib1;
asn1::rrc_nr::sys_info_ies_s::sib_type_and_info_l_ sibs; asn1::rrc_nr::sys_info_ies_s::sib_type_and_info_l_ sibs;
srsran::unique_byte_buffer_t mib_buffer = nullptr; srsran::unique_byte_buffer_t mib_buffer = nullptr;
std::vector<srsran::unique_byte_buffer_t> sib_buffer; std::vector<srsran::unique_byte_buffer_t> sib_buffer;
std::unique_ptr<const asn1::rrc_nr::cell_group_cfg_s> master_cell_group;
}; };
std::unique_ptr<cell_ctxt_t> cell_ctxt; std::unique_ptr<cell_ctxt_t> cell_ctxt;
rnti_map_t<std::unique_ptr<ue> > users; rnti_map_t<std::unique_ptr<ue> > users;

@ -19,8 +19,8 @@
* *
*/ */
#ifndef SRSRAN_RRC_CONFIG_NR_H #ifndef SRSRAN_RRC_NR_CONFIG_H
#define SRSRAN_RRC_CONFIG_NR_H #define SRSRAN_RRC_NR_CONFIG_H
#include "srsenb/hdr/phy/phy_interfaces.h" #include "srsenb/hdr/phy/phy_interfaces.h"
#include "srsenb/hdr/stack/rrc/rrc_config_common.h" #include "srsenb/hdr/stack/rrc/rrc_config_common.h"
@ -49,6 +49,7 @@ struct rrc_cell_cfg_nr_t {
uint32_t ul_absolute_freq_point_a; // derived from UL ARFCN uint32_t ul_absolute_freq_point_a; // derived from UL ARFCN
uint32_t ssb_absolute_freq_point; // derived from DL ARFCN uint32_t ssb_absolute_freq_point; // derived from DL ARFCN
uint32_t band; uint32_t band;
uint32_t coreset0_idx; // Table 13-{1,...15} row index
srsran_duplex_mode_t duplex_mode; srsran_duplex_mode_t duplex_mode;
srsran_ssb_cfg_t ssb_cfg; srsran_ssb_cfg_t ssb_cfg;
}; };
@ -70,4 +71,4 @@ struct rrc_nr_cfg_t {
} // namespace srsenb } // namespace srsenb
#endif // SRSRAN_RRC_CONFIG_NR_H #endif // SRSRAN_RRC_NR_CONFIG_H

@ -0,0 +1,28 @@
/**
*
* \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 SRSRAN_RRC_NR_CONFIG_DEFAULT_H
#define SRSRAN_RRC_NR_CONFIG_DEFAULT_H
#include "rrc_nr_config.h"
namespace srsenb {
void generate_default_nr_cell(rrc_cell_cfg_nr_t& cell);
int set_derived_nr_cell_params(bool is_sa, rrc_cell_cfg_nr_t& cell);
int check_nr_cell_cfg_valid(const rrc_cell_cfg_nr_t& cell, bool is_sa);
} // namespace srsenb
#endif // SRSRAN_RRC_NR_CONFIG_DEFAULT_H

@ -40,8 +40,6 @@ public:
ue(rrc_nr* parent_, uint16_t rnti_, const sched_nr_ue_cfg_t& uecfg, bool start_msg3_timer = true); ue(rrc_nr* parent_, uint16_t rnti_, const sched_nr_ue_cfg_t& uecfg, bool start_msg3_timer = true);
~ue(); ~ue();
void send_dl_ccch(const asn1::rrc_nr::dl_ccch_msg_s& dl_dcch_msg);
int handle_sgnb_addition_request(uint16_t eutra_rnti, const sgnb_addition_req_params_t& params); int handle_sgnb_addition_request(uint16_t eutra_rnti, const sgnb_addition_req_params_t& params);
void crnti_ce_received(); void crnti_ce_received();
@ -67,14 +65,35 @@ public:
void handle_rrc_setup_request(const asn1::rrc_nr::rrc_setup_request_s& msg); void handle_rrc_setup_request(const asn1::rrc_nr::rrc_setup_request_s& msg);
void handle_rrc_setup_complete(const asn1::rrc_nr::rrc_setup_complete_s& msg); void handle_rrc_setup_complete(const asn1::rrc_nr::rrc_setup_complete_s& msg);
/* TS 38.331 - 5.3.4 Initial AS security activation */
void handle_security_mode_complete(const asn1::rrc_nr::security_mode_complete_s& msg);
/* TS 38.331 - 5.3.5 RRC reconfiguration */
void handle_rrc_reconfiguration_complete(const asn1::rrc_nr::rrc_recfg_complete_s& msg);
/* TS 38.331 - 5.7.1 DL information transfer */
void send_dl_information_transfer(srsran::unique_byte_buffer_t sdu);
/* TS 38.331 - 5.7.2 UL information transfer */
void handle_ul_information_transfer(const asn1::rrc_nr::ul_info_transfer_s& msg);
// NGAP interface
void establish_eps_bearer(uint32_t pdu_session_id, srsran::const_byte_span nas_pdu, uint32_t lcid);
private: private:
rrc_nr* parent = nullptr; void send_dl_ccch(const asn1::rrc_nr::dl_ccch_msg_s& dl_ccch_msg);
uint16_t rnti = SRSRAN_INVALID_RNTI; void send_dl_dcch(srsran::nr_srb srb, const asn1::rrc_nr::dl_dcch_msg_s& dl_dcch_msg);
/* TS 38.331 - 5.3.3 RRC connection establishment */ /* TS 38.331 - 5.3.3 RRC connection establishment */
void send_rrc_setup(); void send_rrc_setup();
void send_rrc_reject(uint8_t reject_wait_time_secs); void send_rrc_reject(uint8_t reject_wait_time_secs);
/* TS 38.331 - 5.3.4 Initial AS security activation */
void send_security_mode_command();
/* TS 38.331 - 5.3.5 RRC reconfiguration */
void send_rrc_reconfiguration();
int pack_rrc_reconfiguration(asn1::dyn_octstring& packed_rrc_reconfig); int pack_rrc_reconfiguration(asn1::dyn_octstring& packed_rrc_reconfig);
int pack_secondary_cell_group_cfg(asn1::dyn_octstring& packed_secondary_cell_config); int pack_secondary_cell_group_cfg(asn1::dyn_octstring& packed_secondary_cell_config);
@ -86,7 +105,6 @@ private:
int pack_sp_cell_cfg_ded(asn1::rrc_nr::cell_group_cfg_s& cell_group_cfg_pack); int pack_sp_cell_cfg_ded(asn1::rrc_nr::cell_group_cfg_s& cell_group_cfg_pack);
int pack_sp_cell_cfg_ded_init_dl_bwp(asn1::rrc_nr::cell_group_cfg_s& cell_group_cfg_pack); int pack_sp_cell_cfg_ded_init_dl_bwp(asn1::rrc_nr::cell_group_cfg_s& cell_group_cfg_pack);
int pack_sp_cell_cfg_ded_init_dl_bwp_pdsch_cfg(asn1::rrc_nr::cell_group_cfg_s& cell_group_cfg_pack);
int pack_sp_cell_cfg_ded_init_dl_bwp_radio_link_monitoring(asn1::rrc_nr::cell_group_cfg_s& cell_group_cfg_pack); int pack_sp_cell_cfg_ded_init_dl_bwp_radio_link_monitoring(asn1::rrc_nr::cell_group_cfg_s& cell_group_cfg_pack);
int pack_sp_cell_cfg_ded_ul_cfg(asn1::rrc_nr::cell_group_cfg_s& cell_group_cfg_pack); int pack_sp_cell_cfg_ded_ul_cfg(asn1::rrc_nr::cell_group_cfg_s& cell_group_cfg_pack);
@ -116,6 +134,8 @@ private:
int add_drb(); int add_drb();
bool init_pucch();
// logging helpers // logging helpers
template <class M> template <class M>
void log_rrc_message(srsran::nr_srb srb, void log_rrc_message(srsran::nr_srb srb,
@ -126,6 +146,11 @@ private:
template <class M> template <class M>
void log_rrc_container(const direction_t dir, srsran::const_byte_span pdu, const M& msg, const char* msg_type); void log_rrc_container(const direction_t dir, srsran::const_byte_span pdu, const M& msg, const char* msg_type);
// args
rrc_nr* parent = nullptr;
srslog::basic_logger& logger;
uint16_t rnti = SRSRAN_INVALID_RNTI;
// state // state
rrc_nr_state_t state = rrc_nr_state_t::RRC_IDLE; rrc_nr_state_t state = rrc_nr_state_t::RRC_IDLE;
uint8_t transaction_id = 0; uint8_t transaction_id = 0;
@ -133,13 +158,19 @@ private:
// RRC configs for UEs // RRC configs for UEs
asn1::rrc_nr::cell_group_cfg_s cell_group_cfg; asn1::rrc_nr::cell_group_cfg_s cell_group_cfg;
asn1::rrc_nr::radio_bearer_cfg_s radio_bearer_cfg; asn1::rrc_nr::radio_bearer_cfg_s radio_bearer_cfg, next_radio_bearer_cfg;
// MAC controller // MAC controller
sched_nr_interface::ue_cfg_t uecfg{}; sched_nr_interface::ue_cfg_t uecfg{};
const uint32_t drb1_lcid = 4; const uint32_t drb1_lcid = 4;
// SA specific variables
struct ctxt_t {
uint64_t setup_ue_id = -1;
asn1::rrc_nr::establishment_cause_opts connection_cause;
} ctxt;
// NSA specific variables // NSA specific variables
bool endc = false; bool endc = false;
uint16_t eutra_rnti = SRSRAN_INVALID_RNTI; uint16_t eutra_rnti = SRSRAN_INVALID_RNTI;

@ -29,6 +29,8 @@
#include "srsran/common/time_prof.h" #include "srsran/common/time_prof.h"
#include "srsran/mac/mac_rar_pdu_nr.h" #include "srsran/mac/mac_rar_pdu_nr.h"
//#define WRITE_SIB_PCAP
namespace srsenb { namespace srsenb {
class mac_nr_rx class mac_nr_rx
@ -493,6 +495,15 @@ mac_nr::dl_sched_t* mac_nr::get_dl_sched(const srsran_slot_cfg_t& slot_cfg)
} else if (pdsch.sch.grant.rnti_type == srsran_rnti_type_si) { } else if (pdsch.sch.grant.rnti_type == srsran_rnti_type_si) {
uint32_t sib_idx = dl_res->sib_idxs[si_count++]; uint32_t sib_idx = dl_res->sib_idxs[si_count++];
pdsch.data[0] = bcch_dlsch_payload[sib_idx].payload.get(); pdsch.data[0] = bcch_dlsch_payload[sib_idx].payload.get();
#ifdef WRITE_SIB_PCAP
if (pcap != nullptr) {
pcap->write_dl_si_rnti_nr(bcch_dlsch_payload[sib_idx].payload->msg,
bcch_dlsch_payload[sib_idx].payload->N_bytes,
SI_RNTI,
0,
slot_cfg.idx);
}
#endif
} }
} }
for (auto& u : ue_db) { for (auto& u : ue_db) {

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

Loading…
Cancel
Save