diff --git a/CMakeLists.txt b/CMakeLists.txt index 1f8c32dab..3d75d7407 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -280,6 +280,9 @@ endif(BUILD_STATIC) set(BOOST_REQUIRED_COMPONENTS 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") list(APPEND BOOST_LIBRARYDIR "/usr/lib64") #fedora 64-bit fix endif(UNIX AND EXISTS "/usr/lib64") diff --git a/lib/include/srsran/adt/circular_buffer.h b/lib/include/srsran/adt/circular_buffer.h index 67682b670..ddba67c34 100644 --- a/lib/include/srsran/adt/circular_buffer.h +++ b/lib/include/srsran/adt/circular_buffer.h @@ -300,7 +300,7 @@ public: } 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() { T obj; @@ -414,7 +414,7 @@ protected: 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 lock(mutex); if (not active) { diff --git a/lib/include/srsran/rrc/rrc_cfg_utils.h b/lib/include/srsran/asn1/obj_id_cmp_utils.h similarity index 77% rename from lib/include/srsran/rrc/rrc_cfg_utils.h rename to lib/include/srsran/asn1/obj_id_cmp_utils.h index 69faa5191..dc6000ea3 100644 --- a/lib/include/srsran/rrc/rrc_cfg_utils.h +++ b/lib/include/srsran/asn1/obj_id_cmp_utils.h @@ -19,18 +19,37 @@ * */ -#ifndef SRSRAN_RRC_CFG_UTILS_H -#define SRSRAN_RRC_CFG_UTILS_H +#ifndef SRSRAN_OBJ_ID_CMP_UTILS_H +#define SRSRAN_OBJ_ID_CMP_UTILS_H -#include "srsran/asn1/rrc_utils.h" #include "srsran/common/common.h" #include #include namespace srsran { -template -using rrc_obj_id_t = decltype(asn1::rrc::get_rrc_obj_id(std::declval())); +using asn1_obj_id_t = uint8_t; + +/// Template function to generically obtain id of asn1 object (e.g. srb_id of srbs, drb_id of drbs, etc.) +template +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 +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(const Asn1ObjType& obj) \ + { \ + return obj.member; \ + } \ + template <> \ + void set_asn1_obj_id(Asn1ObjType & obj, uint8_t id) \ + { \ + obj.member = id; \ + } //! Functor to compare RRC config elements (e.g. SRB/measObj/Rep) based on ID struct rrc_obj_id_cmp { @@ -38,27 +57,27 @@ struct rrc_obj_id_cmp { typename std::enable_if::value and not std::is_integral::value, bool>::type 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 - bool operator()(const T& lhs, rrc_obj_id_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 - bool operator()(rrc_obj_id_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 struct unary_rrc_obj_id { - rrc_obj_id_t id; + asn1_obj_id_t id; template 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 @@ -78,13 +97,13 @@ template 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{}); - 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::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{}); - 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 @@ -95,7 +114,7 @@ bool equal_rrc_obj_ids(const Container& c, const Container2& c2) c2.begin(), c2.end(), [](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()) { c.push_back({}); 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{}); 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::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()) { c.push_back(v); 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 { *it = v; } @@ -145,21 +164,21 @@ bool rem_rrc_obj_id(Container& c, IdType id) * @return id value */ template -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{}; assert(std::is_sorted(c.begin(), c.end(), id_cmp_op)); 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; 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; } } } - 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; - 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 mod_func = [&add_diff_list](it_t src_it, it_t target_it) { if (not(*src_it == *target_it)) { @@ -328,4 +347,4 @@ void compute_cfg_diff(const toAddModList& src_list, } // namespace srsran -#endif // SRSRAN_RRC_CFG_UTILS_H +#endif // SRSRAN_OBJ_ID_CMP_UTILS_H diff --git a/lib/include/srsran/asn1/rrc_nr_utils.h b/lib/include/srsran/asn1/rrc_nr_utils.h index abe9c1501..c43a7e9fd 100644 --- a/lib/include/srsran/asn1/rrc_nr_utils.h +++ b/lib/include/srsran/asn1/rrc_nr_utils.h @@ -67,6 +67,10 @@ struct serving_cell_cfg_common_s; struct serving_cell_cfg_s; struct pdcch_cfg_common_s; struct pdcch_cfg_s; +struct mib_s; + +struct srb_to_add_mod_s; +struct drb_to_add_mod_s; } // namespace rrc_nr } // 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, const asn1::rrc_nr::serving_cell_cfg_common_s& serv_cell_cfg, 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_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, @@ -151,4 +156,16 @@ pdcp_config_t make_drb_pdcp_config_t(const uint8_t bearer_id, bool is_ue, const } // 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 diff --git a/lib/include/srsran/asn1/rrc_utils.h b/lib/include/srsran/asn1/rrc_utils.h index 3dd44ec10..fda826ee0 100644 --- a/lib/include/srsran/asn1/rrc_utils.h +++ b/lib/include/srsran/asn1/rrc_utils.h @@ -150,37 +150,4 @@ sib13_t make_sib13(const asn1::rrc::sib_type13_r9_s& asn1_type); } // 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 diff --git a/lib/include/srsran/common/band_helper.h b/lib/include/srsran/common/band_helper.h index 617cfdb92..35750935b 100644 --- a/lib/include/srsran/common/band_helper.h +++ b/lib/include/srsran/common/band_helper.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 + * 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 - * 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 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. */ - 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 diff --git a/lib/include/srsran/common/block_queue.h b/lib/include/srsran/common/block_queue.h index 076b496a6..8823e98f9 100644 --- a/lib/include/srsran/common/block_queue.h +++ b/lib/include/srsran/common/block_queue.h @@ -104,6 +104,8 @@ public: return value; } + bool timedwait_pop(myobj* value, const struct timespec* abstime) { return pop_(value, true, abstime); } + bool empty() { // queue is empty? pthread_mutex_lock(&mutex); @@ -139,7 +141,7 @@ public: } private: - bool pop_(myobj* value, bool block) + bool pop_(myobj* value, bool block, const struct timespec* abstime = nullptr) { if (!enable) { return false; @@ -151,7 +153,13 @@ private: goto exit; } 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) { goto exit; diff --git a/lib/include/srsran/common/test_common.h b/lib/include/srsran/common/test_common.h index c27277a5c..251ef9b05 100644 --- a/lib/include/srsran/common/test_common.h +++ b/lib/include/srsran/common/test_common.h @@ -163,6 +163,12 @@ inline void copy_msg_to_buffer(unique_byte_buffer_t& pdu, const_byte_span msg) pdu->N_bytes = msg.size(); } +/** + * Delimits beginning/ending of a test with the following console output: + * ============= [Test ] =============== + * + * ======================================================= + */ class test_delimit_logger { const size_t delimiter_length = 128; diff --git a/lib/include/srsran/interfaces/enb_s1ap_interfaces.h b/lib/include/srsran/interfaces/enb_s1ap_interfaces.h index 7b9112dc9..cc4a45807 100644 --- a/lib/include/srsran/interfaces/enb_s1ap_interfaces.h +++ b/lib/include/srsran/interfaces/enb_s1ap_interfaces.h @@ -41,6 +41,7 @@ struct s1ap_args_t { std::string enb_name; uint32_t ts1_reloc_prep_timeout; uint32_t ts1_reloc_overall_timeout; + int32_t max_s1_setup_retries; }; // S1AP interface for RRC diff --git a/lib/include/srsran/interfaces/gnb_ngap_interfaces.h b/lib/include/srsran/interfaces/gnb_ngap_interfaces.h index 20662f800..5ef04b827 100644 --- a/lib/include/srsran/interfaces/gnb_ngap_interfaces.h +++ b/lib/include/srsran/interfaces/gnb_ngap_interfaces.h @@ -46,14 +46,14 @@ public: virtual void initial_ue(uint16_t rnti, uint32_t gnb_cc_idx, 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, uint32_t gnb_cc_idx, asn1::ngap_nr::rrcestablishment_cause_e cause, - srsran::unique_byte_buffer_t pdu, - uint32_t m_tmsi) = 0; + srsran::const_byte_span pdu, + 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 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; @@ -63,4 +63,4 @@ public: } // namespace srsenb -#endif // SRSRAN_GNB_NGAP_INTERFACES_H \ No newline at end of file +#endif // SRSRAN_GNB_NGAP_INTERFACES_H diff --git a/lib/include/srsran/phy/common/phy_common_nr.h b/lib/include/srsran/phy/common/phy_common_nr.h index 310aa7272..bfac21fe4 100644 --- a/lib/include/srsran/phy/common/phy_common_nr.h +++ b/lib/include/srsran/phy/common/phy_common_nr.h @@ -221,6 +221,8 @@ typedef enum SRSRAN_API { srsran_coreset_bundle_size_n6, } srsran_coreset_bundle_size_t; +uint32_t pdcch_nr_bundle_size(srsran_coreset_bundle_size_t x); + typedef enum SRSRAN_API { srsran_coreset_precoder_granularity_contiguous = 0, srsran_coreset_precoder_granularity_reg_bundle @@ -713,6 +715,26 @@ SRSRAN_API int srsran_coreset_zero(uint32_t n_cell_id, uint32_t idx, 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 * @param pattern diff --git a/lib/include/srsran/phy/phch/phch_cfg_nr.h b/lib/include/srsran/phy/phch/phch_cfg_nr.h index 5e1a40789..eb8ed4818 100644 --- a/lib/include/srsran/phy/phch/phch_cfg_nr.h +++ b/lib/include/srsran/phy/phch/phch_cfg_nr.h @@ -86,6 +86,8 @@ typedef struct { srsran_dmrs_sch_typeA_pos_t typeA_pos; bool lte_CRS_to_match_around; + uint32_t reference_point_k_rb; + /// Parameters provided by FeatureSetDownlink-v1540 bool additional_DMRS_DL_Alt; diff --git a/lib/include/srsran/rlc/rlc_am_base.h b/lib/include/srsran/rlc/rlc_am_base.h index 8997c295e..ae722546f 100644 --- a/lib/include/srsran/rlc/rlc_am_base.h +++ b/lib/include/srsran/rlc/rlc_am_base.h @@ -24,6 +24,8 @@ #include "srsran/common/buffer_pool.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/upper/byte_buffer_queue.h" #include @@ -31,20 +33,172 @@ #include #include -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(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; -class rrc_interface_rlc; + 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_); -} // 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 tx_base = {}; + std::unique_ptr rx_base = {}; +}; + +} // namespace srsran #endif // SRSRAN_RLC_AM_BASE_H diff --git a/lib/include/srsran/rlc/rlc_am_data_structs.h b/lib/include/srsran/rlc/rlc_am_data_structs.h index af6eb62bd..90b844d5a 100644 --- a/lib/include/srsran/rlc/rlc_am_data_structs.h +++ b/lib/include/srsran/rlc/rlc_am_data_structs.h @@ -25,61 +25,139 @@ #include "srsran/adt/circular_buffer.h" #include "srsran/adt/circular_map.h" #include "srsran/adt/intrusive_list.h" +#include "srsran/common/buffer_pool.h" #include #include namespace srsran { +template class rlc_amd_tx_pdu; +template class pdcp_pdu_info; /// Pool that manages the allocation of RLC AM PDU Segments to RLC PDUs and tracking of segments ACK state +template struct rlc_am_pdu_segment_pool { const static size_t MAX_POOL_SIZE = 16384; - using rlc_list_tag = default_intrusive_tag; - struct free_list_tag {}; /// RLC AM PDU Segment, containing the PDCP SN and RLC SN it has been assigned to, and its current ACK state + using rlc_list_tag = default_intrusive_tag; + struct free_list_tag {}; struct segment_resource : public intrusive_forward_list_element, public intrusive_forward_list_element, public intrusive_double_linked_list_element<> { const static uint32_t invalid_rlc_sn = std::numeric_limits::max(); const static uint32_t invalid_pdcp_sn = std::numeric_limits::max() - 1; // -1 for Status Report - int id() const; - void release_pdcp_sn(); - void release_rlc_sn(); + int id() const { return std::distance(parent_pool->segments.cbegin(), this); } + + 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 pdcp_sn() const { return pdcp_sn_; } bool empty() const { return rlc_sn_ == invalid_rlc_sn and pdcp_sn_ == invalid_pdcp_sn; } private: - friend struct rlc_am_pdu_segment_pool; - uint32_t rlc_sn_ = invalid_rlc_sn; - uint32_t pdcp_sn_ = invalid_pdcp_sn; - rlc_am_pdu_segment_pool* parent_pool = nullptr; + friend struct rlc_am_pdu_segment_pool; + uint32_t rlc_sn_ = invalid_rlc_sn; + uint32_t pdcp_sn_ = invalid_pdcp_sn; + rlc_am_pdu_segment_pool* parent_pool = nullptr; }; - rlc_am_pdu_segment_pool(); + rlc_am_pdu_segment_pool() + { + 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(rlc_am_pdu_segment_pool&&) = delete; rlc_am_pdu_segment_pool& operator=(const rlc_am_pdu_segment_pool&) = delete; rlc_am_pdu_segment_pool& operator=(rlc_am_pdu_segment_pool&&) = delete; - bool has_segments() const { return not free_list.empty(); } - bool make_segment(rlc_amd_tx_pdu& rlc_list, pdcp_pdu_info& pdcp_info); + + bool has_segments() const { return not free_list.empty(); } + bool make_segment(rlc_amd_tx_pdu& rlc_list, pdcp_pdu_info& pdcp_list) + { + if (not has_segments()) { + return false; + } + segment_resource* segment = free_list.pop_front(); + segment->rlc_sn_ = rlc_list.rlc_sn; + segment->pdcp_sn_ = pdcp_list.sn; + rlc_list.add_segment(*segment); + pdcp_list.add_segment(*segment); + return true; + } private: - intrusive_forward_list free_list; - std::array segments; + intrusive_forward_list::segment_resource, free_list_tag> free_list; + std::array::segment_resource, MAX_POOL_SIZE> segments; }; -/// RLC AM PDU Segment, containing the PDCP SN and RLC SN it has been assigned to, and its current ACK state -using rlc_am_pdu_segment = rlc_am_pdu_segment_pool::segment_resource; +/// Class that contains the parameters and state (e.g. segments) of a RLC PDU +template +class rlc_amd_tx_pdu +{ + using rlc_am_pdu_segment = typename rlc_am_pdu_segment_pool::segment_resource; + using list_type = intrusive_forward_list; + const static uint32_t invalid_rlc_sn = std::numeric_limits::max(); + + list_type list; + +public: + using iterator = typename list_type::iterator; + using const_iterator = typename list_type::const_iterator; + + const uint32_t rlc_sn = invalid_rlc_sn; + uint32_t retx_count = 0; + 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 +template class pdcp_pdu_info { - using list_type = intrusive_double_linked_list; + using rlc_am_pdu_segment = typename rlc_am_pdu_segment_pool::segment_resource; + using list_type = intrusive_double_linked_list; 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 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() { sn = invalid_pdcp_sn; @@ -115,6 +199,7 @@ public: ack_segment(list.front()); } } + const_iterator begin() const { return list.begin(); } const_iterator end() const { return list.end(); } }; @@ -155,6 +240,7 @@ private: srsran::static_circular_map window; }; +template struct buffered_pdcp_pdu_list { public: explicit buffered_pdcp_pdu_list() : buffered_pdus(buffered_pdcp_pdu_list::buffer_size) { clear(); } @@ -162,7 +248,7 @@ public: void clear() { count = 0; - for (pdcp_pdu_info& b : buffered_pdus) { + for (pdcp_pdu_info& b : buffered_pdus) { b.clear(); } } @@ -171,7 +257,7 @@ public: { 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"); - pdcp_pdu_info& pdu = get_pdu_(sn); + pdcp_pdu_info& pdu = get_pdu_(sn); if (pdu.valid()) { pdu.clear(); count--; @@ -179,9 +265,10 @@ public: pdu.sn = sn; count++; } + void clear_pdcp_sdu(uint32_t sn) { - pdcp_pdu_info& pdu = get_pdu_(sn); + pdcp_pdu_info& pdu = get_pdu_(sn); if (not pdu.valid()) { return; } @@ -189,11 +276,12 @@ public: count--; } - pdcp_pdu_info& operator[](uint32_t sn) + pdcp_pdu_info& operator[](uint32_t sn) { srsran_expect(has_pdcp_sn(sn), "Invalid access to non-existent PDCP SN=%d", sn); return get_pdu_(sn); } + bool has_pdcp_sn(uint32_t pdcp_sn) const { 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: const static size_t max_pdcp_sn = 262143u; 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::status_report_sn; - pdcp_pdu_info& get_pdu_(uint32_t sn) + pdcp_pdu_info& get_pdu_(uint32_t sn) { return (sn == status_report_sn) ? status_report_pdu : buffered_pdus[static_cast(sn % buffer_size)]; } - const pdcp_pdu_info& get_pdu_(uint32_t sn) const + const pdcp_pdu_info& get_pdu_(uint32_t sn) const { return (sn == status_report_sn) ? status_report_pdu : buffered_pdus[static_cast(sn % buffer_size)]; } // size equal to buffer_size - std::vector buffered_pdus; - pdcp_pdu_info status_report_pdu; - uint32_t count = 0; + std::vector > buffered_pdus; + pdcp_pdu_info status_report_pdu; + uint32_t count = 0; }; } // namespace srsran diff --git a/lib/include/srsran/rlc/rlc_am_lte.h b/lib/include/srsran/rlc/rlc_am_lte.h index 1dfd95172..0e2797c45 100644 --- a/lib/include/srsran/rlc/rlc_am_lte.h +++ b/lib/include/srsran/rlc/rlc_am_lte.h @@ -89,251 +89,198 @@ private: 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: - rlc_am_lte(srslog::basic_logger& logger, - uint32_t lcid_, - srsue::pdcp_interface_rlc* pdcp_, - srsue::rrc_interface_rlc* rrc_, - srsran::timer_handler* timers_); + explicit rlc_am_lte_tx(rlc_am* parent_); + ~rlc_am_lte_tx() = default; + void set_rx(rlc_am_lte_rx* rx_) { rx = rx_; }; bool configure(const rlc_config_t& cfg_); + void empty_queue(); void reestablish(); void stop(); - void empty_queue(); - - rlc_mode_t get_mode(); - 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(); + uint32_t read_pdu(uint8_t* payload, uint32_t nof_bytes); + void discard_sdu(uint32_t discard_sn); + bool sdu_queue_is_full(); - // MAC interface bool has_data(); uint32_t get_buffer_state(); - void get_buffer_state(uint32_t& tx_queue, uint32_t& prio_tx_queue); - 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 get_buffer_state(uint32_t& n_bytes_newtx, uint32_t& n_bytes_prio); - void empty_queue(); - void reestablish(); - void stop(); + void empty_queue_nolock(); + void debug_state(); - int write_sdu(unique_byte_buffer_t sdu); - uint32_t read_pdu(uint8_t* payload, uint32_t nof_bytes); - void discard_sdu(uint32_t discard_sn); - bool sdu_queue_is_full(); + // Timeout callback interface + void timer_expired(uint32_t timeout_id) final; - bool has_data(); - uint32_t get_buffer_state(); - void get_buffer_state(uint32_t& new_tx, uint32_t& prio_tx); + // Interface for Rx subclass + void handle_control_pdu(uint8_t* payload, uint32_t nof_bytes); - // Timeout callback interface - void timer_expired(uint32_t timeout_id); - - // Interface for Rx subclass - void handle_control_pdu(uint8_t* payload, uint32_t nof_bytes); - - void set_bsr_callback(bsr_callback_t callback); +private: + void stop_nolock(); - private: - void stop_nolock(); + int build_status_pdu(uint8_t* payload, uint32_t nof_bytes); + int build_retx_pdu(uint8_t* payload, uint32_t nof_bytes); + int build_segment(uint8_t* payload, uint32_t nof_bytes, rlc_amd_retx_t retx); + int build_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 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 required_buffer_size(const rlc_amd_retx_t& retx); + void retransmit_pdu(uint32_t sn); - void debug_state(); - void empty_queue_nolock(); + // Helpers + 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); - void retransmit_pdu(uint32_t sn); + rlc_am* parent = nullptr; + rlc_am_lte_rx* rx = nullptr; + byte_buffer_pool* pool = nullptr; + rlc_am_pdu_segment_pool 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 - bool poll_required(); - bool do_status(); - void check_sn_reached_max_retx(uint32_t sn); + rlc_am_config_t cfg = {}; - rlc_am_lte* parent = nullptr; - byte_buffer_pool* pool = nullptr; - srslog::basic_logger& logger; - rlc_am_pdu_segment_pool segment_pool; + // TX SDU buffers + unique_byte_buffer_t tx_sdu; - /**************************************************************************** - * Configurable parameters - * Ref: 3GPP TS 36.322 v10.0.0 Section 7 - ***************************************************************************/ + /**************************************************************************** + * State variables and counters + * 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 - byte_buffer_queue tx_sdu_queue; - unique_byte_buffer_t tx_sdu; + // Tx counters + uint32_t pdu_without_poll = 0; + uint32_t byte_without_poll = 0; - bool tx_enabled = false; + rlc_status_pdu_t tx_status; - /**************************************************************************** - * State variables and counters - * Ref: 3GPP TS 36.322 v10.0.0 Section 7 - ***************************************************************************/ + /**************************************************************************** + * Timers + * Ref: 3GPP TS 36.322 v10.0.0 Section 7 + ***************************************************************************/ - // 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. + srsran::timer_handler::unique_timer poll_retx_timer; + srsran::timer_handler::unique_timer status_prohibit_timer; - // Tx counters - uint32_t pdu_without_poll = 0; - uint32_t byte_without_poll = 0; + // SDU info for PDCP notifications + buffered_pdcp_pdu_list undelivered_sdu_info_queue; - rlc_status_pdu_t tx_status; + // Tx windows + rlc_ringbuffer_t, RLC_AM_WINDOW_SIZE> tx_window; + pdu_retx_queue retx_queue; + pdcp_sn_vector_t notify_info_vec; - /**************************************************************************** - * Timers - * Ref: 3GPP TS 36.322 v10.0.0 Section 7 - ***************************************************************************/ + // Mutexes + std::mutex mutex; - srsran::timer_handler::unique_timer poll_retx_timer; - srsran::timer_handler::unique_timer status_prohibit_timer; + // default to RLC SDU queue length + 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 - bsr_callback_t bsr_callback; + void set_tx(rlc_am_lte_tx* tx_) { tx = tx_; }; + bool configure(const rlc_config_t& cfg_) final; + void reestablish() final; + void stop() final; - // Tx windows - rlc_ringbuffer_t tx_window; - pdu_retx_queue retx_queue; - pdcp_sn_vector_t notify_info_vec; + uint32_t get_rx_buffered_bytes() final; // returns sum of PDUs in rx_window + uint32_t get_sdu_rx_latency_ms() final; - // Mutexes - std::mutex mutex; + // Timeout callback interface + void timer_expired(uint32_t timeout_id) final; - // default to RLC SDU queue length - const uint32_t MAX_SDUS_PER_RLC_PDU = RLC_TX_QUEUE_LEN; - }; + // Functions needed by Tx subclass to query rx state + 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 - class rlc_am_lte_rx : public timer_callback - { - public: - rlc_am_lte_rx(rlc_am_lte* parent_); - ~rlc_am_lte_rx(); - - bool configure(rlc_am_config_t cfg_); - void reestablish(); - void stop(); - - void write_pdu(uint8_t* payload, uint32_t nof_bytes); - - uint32_t get_rx_buffered_bytes(); // returns sum of PDUs in rx_window - uint32_t get_sdu_rx_latency_ms(); - - // Timeout callback interface - void timer_expired(uint32_t timeout_id); - - // Functions needed by Tx subclass to query rx state - int get_status_pdu_length(); - int get_status_pdu(rlc_status_pdu_t* status, const uint32_t nof_bytes); - bool get_do_status(); - - private: - void handle_data_pdu(uint8_t* payload, uint32_t nof_bytes, rlc_amd_pdu_header_t& header); - void handle_data_pdu_segment(uint8_t* payload, uint32_t nof_bytes, rlc_amd_pdu_header_t& header); - void reassemble_rx_sdus(); - bool inside_rx_window(const int16_t sn); - void debug_state(); - void print_rx_segments(); - bool add_segment_and_check(rlc_amd_rx_pdu_segments_t* pdu, rlc_amd_rx_pdu* segment); - void reset_status(); - - rlc_am_lte* parent = nullptr; - byte_buffer_pool* pool = nullptr; - srslog::basic_logger& logger; - - /**************************************************************************** - * Configurable parameters - * Ref: 3GPP TS 36.322 v10.0.0 Section 7 - ***************************************************************************/ - rlc_am_config_t cfg = {}; - - // RX SDU buffers - unique_byte_buffer_t rx_sdu; - - /**************************************************************************** - * State variables and counters - * Ref: 3GPP TS 36.322 v10.0.0 Section 7 - ***************************************************************************/ - - // Rx state variables - uint32_t vr_r = 0; // Receive state. SN following last in-sequence received PDU. Low edge of rx window - 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 rx_window; - std::map rx_segments; - - bool poll_received = false; - std::atomic 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 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 = {}; +private: + 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); + void handle_data_pdu_segment(uint8_t* payload, uint32_t nof_bytes, rlc_amd_pdu_header_t& header); + void reassemble_rx_sdus(); + bool inside_rx_window(const int16_t sn); + void debug_state(); + void print_rx_segments(); + bool add_segment_and_check(rlc_amd_rx_pdu_segments_t* pdu, rlc_amd_rx_pdu* segment); + void reset_status(); + + rlc_am* parent = nullptr; + rlc_am_lte_tx* tx = nullptr; + byte_buffer_pool* pool = nullptr; + + /**************************************************************************** + * Configurable parameters + * Ref: 3GPP TS 36.322 v10.0.0 Section 7 + ***************************************************************************/ + rlc_am_config_t cfg = {}; + + // RX SDU buffers + unique_byte_buffer_t rx_sdu; + + /**************************************************************************** + * State variables and counters + * Ref: 3GPP TS 36.322 v10.0.0 Section 7 + ***************************************************************************/ + + // Rx state variables + uint32_t vr_r = 0; // Receive state. SN following last in-sequence received PDU. Low edge of rx window + 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 rx_window; + std::map rx_segments; + + bool poll_received = false; + std::atomic 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 sdu_rx_latency_ms; }; } // namespace srsran diff --git a/lib/include/srsran/rlc/rlc_am_lte_packing.h b/lib/include/srsran/rlc/rlc_am_lte_packing.h index cc7fa71a7..20a24479f 100644 --- a/lib/include/srsran/rlc/rlc_am_lte_packing.h +++ b/lib/include/srsran/rlc/rlc_am_lte_packing.h @@ -29,38 +29,6 @@ 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; - const static uint32_t invalid_rlc_sn = std::numeric_limits::max(); - - list_type list; - -public: - using iterator = typename list_type::iterator; - using const_iterator = typename list_type::const_iterator; - - const uint32_t rlc_sn = invalid_rlc_sn; - uint32_t retx_count = 0; - rlc_amd_pdu_header_t header; - unique_byte_buffer_t buf; - - 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 { uint32_t sn; 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); 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_status_pdu_t* status); -uint32_t rlc_am_packed_length(rlc_amd_retx_t retx); -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); -std::string rlc_am_undelivered_sdu_info_to_string(const std::map& info_queue); -void log_rlc_amd_pdu_header_to_string(srslog::log_channel& log_ch, const rlc_amd_pdu_header_t& header); -bool rlc_am_start_aligned(const uint8_t fi); -bool rlc_am_end_aligned(const uint8_t fi); -bool rlc_am_is_unaligned(const uint8_t fi); -bool rlc_am_not_start_aligned(const uint8_t fi); +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_amd_retx_t retx); +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); +std::string + rlc_am_undelivered_sdu_info_to_string(const std::map >& info_queue); +void log_rlc_amd_pdu_header_to_string(srslog::log_channel& log_ch, const rlc_amd_pdu_header_t& header); +bool rlc_am_start_aligned(const uint8_t fi); +bool rlc_am_end_aligned(const uint8_t fi); +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 diff --git a/lib/include/srsran/rlc/rlc_am_nr.h b/lib/include/srsran/rlc/rlc_am_nr.h index 1cfea4e16..4ac6d26da 100644 --- a/lib/include/srsran/rlc/rlc_am_nr.h +++ b/lib/include/srsran/rlc/rlc_am_nr.h @@ -26,6 +26,8 @@ #include "srsran/common/common.h" #include "srsran/common/timers.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 #include @@ -34,114 +36,93 @@ 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: - rlc_am_nr(srslog::basic_logger& logger, - uint32_t lcid_, - 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; + explicit rlc_am_nr_tx(rlc_am* parent_); + ~rlc_am_nr_tx() = default; - void reestablish() final; - void empty_queue() final; - void set_bsr_callback(bsr_callback_t callback) final; + void set_rx(rlc_am_nr_rx* rx_) { rx = rx_; } + bool configure(const rlc_config_t& cfg_) 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 write_sdu(unique_byte_buffer_t sdu) final; - void discard_sdu(uint32_t pdcp_sn) final; + void discard_sdu(uint32_t discard_sn) 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; uint32_t get_buffer_state() final; - void get_buffer_state(uint32_t& tx_queue, uint32_t& prio_tx_queue) final; - uint32_t read_pdu(uint8_t* payload, uint32_t nof_bytes) final; - void write_pdu(uint8_t* payload, uint32_t nof_bytes) final; + void get_buffer_state(uint32_t& tx_queue, uint32_t& prio_tx_queue); - rlc_bearer_metrics_t get_metrics() final; - void reset_metrics() final; + void stop() final; private: - // Transmitter sub-class - class rlc_am_nr_tx - { - public: - explicit rlc_am_nr_tx(rlc_am_nr* parent_); - ~rlc_am_nr_tx() = default; - - bool configure(const rlc_am_config_t& cfg_); - void stop(); - - int write_sdu(unique_byte_buffer_t sdu); - uint32_t read_pdu(uint8_t* payload, uint32_t nof_bytes); - void discard_sdu(uint32_t discard_sn); - bool sdu_queue_is_full(); - - bool has_data(); - uint32_t get_buffer_state(); - - 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 = {}; - }; - - // 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 = {}; + rlc_am* parent = nullptr; + rlc_am_nr_rx* rx = nullptr; + + /**************************************************************************** + * Configurable parameters + * Ref: 3GPP TS 38.322 v10.0.0 Section 7.4 + ***************************************************************************/ + rlc_am_config_t cfg = {}; + + /**************************************************************************** + * Tx state variables + * Ref: 3GPP TS 38.322 v10.0.0 Section 7.1 + ***************************************************************************/ + struct rlc_nr_tx_state_t { + uint32_t tx_next_ack; + uint32_t tx_next; + uint32_t poll_sn; + uint32_t pdu_without_poll; + uint32_t byte_without_poll; + } st = {}; + + using rlc_amd_tx_pdu_nr = rlc_amd_tx_pdu; + rlc_ringbuffer_t tx_window; }; -} // 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 diff --git a/lib/include/srsran/rlc/rlc_common.h b/lib/include/srsran/rlc/rlc_common.h index ed6d51cc4..f6f1a361e 100644 --- a/lib/include/srsran/rlc/rlc_common.h +++ b/lib/include/srsran/rlc/rlc_common.h @@ -23,10 +23,13 @@ #define SRSRAN_RLC_COMMON_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/rlc/bearer_mem_pool.h" #include "srsran/rlc/rlc_metrics.h" -#include +#include +#include namespace srsran { @@ -247,8 +250,8 @@ public: } } - virtual rlc_mode_t get_mode() = 0; - virtual uint32_t get_bearer() = 0; + virtual rlc_mode_t get_mode() = 0; + virtual uint32_t get_lcid() = 0; virtual rlc_bearer_metrics_t get_metrics() = 0; virtual void reset_metrics() = 0; diff --git a/lib/include/srsran/rlc/rlc_tm.h b/lib/include/srsran/rlc/rlc_tm.h index 333b8339d..60d19b87c 100644 --- a/lib/include/srsran/rlc/rlc_tm.h +++ b/lib/include/srsran/rlc/rlc_tm.h @@ -50,7 +50,7 @@ public: void empty_queue() override; rlc_mode_t get_mode() override; - uint32_t get_bearer() override; + uint32_t get_lcid() override; rlc_bearer_metrics_t get_metrics() override; void reset_metrics() override; diff --git a/lib/include/srsran/rlc/rlc_um_base.h b/lib/include/srsran/rlc/rlc_um_base.h index cb558c816..538d97aa7 100644 --- a/lib/include/srsran/rlc/rlc_um_base.h +++ b/lib/include/srsran/rlc/rlc_um_base.h @@ -57,7 +57,7 @@ public: bool is_mrb(); rlc_mode_t get_mode(); - uint32_t get_bearer(); + uint32_t get_lcid() final; // PDCP interface void write_sdu(unique_byte_buffer_t sdu); diff --git a/lib/include/srsran/rlc/rlc_um_nr.h b/lib/include/srsran/rlc/rlc_um_nr.h index a6adf25c1..2c5f80f19 100644 --- a/lib/include/srsran/rlc/rlc_um_nr.h +++ b/lib/include/srsran/rlc/rlc_um_nr.h @@ -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 // received UMD PDUs. It serves as the higher edge of the reassembly window. - uint32_t UM_Window_Size; - uint32_t mod; // Rx counter modulus + uint32_t UM_Window_Size = 0; + uint32_t mod = 0; // Rx counter modulus // Rx window typedef struct { diff --git a/lib/include/srsran/rrc/nr/rrc_nr_cfg_utils.h b/lib/include/srsran/rrc/nr/rrc_nr_cfg_utils.h deleted file mode 100644 index 753801354..000000000 --- a/lib/include/srsran/rrc/nr/rrc_nr_cfg_utils.h +++ /dev/null @@ -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 diff --git a/lib/src/CMakeLists.txt b/lib/src/CMakeLists.txt index 4539d7f83..aa9940faf 100644 --- a/lib/src/CMakeLists.txt +++ b/lib/src/CMakeLists.txt @@ -23,7 +23,6 @@ add_subdirectory(common) add_subdirectory(mac) add_subdirectory(phy) add_subdirectory(radio) -add_subdirectory(rrc) add_subdirectory(rlc) add_subdirectory(pdcp) add_subdirectory(gtpu) diff --git a/lib/src/asn1/rrc_nr_utils.cc b/lib/src/asn1/rrc_nr_utils.cc index 0231c5938..f1f35c231 100644 --- a/lib/src/asn1/rrc_nr_utils.cc +++ b/lib/src/asn1/rrc_nr_utils.cc @@ -20,6 +20,7 @@ */ #include "srsran/asn1/rrc_nr_utils.h" +#include "srsran/asn1/obj_id_cmp_utils.h" #include "srsran/asn1/rrc_nr.h" #include "srsran/common/band_helper.h" #include "srsran/config.h" @@ -1489,6 +1490,24 @@ bool make_phy_ssb_cfg(const srsran_carrier_nr_t& carrier, 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) { 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; } +/************************** + * 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 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 diff --git a/lib/src/asn1/rrc_utils.cc b/lib/src/asn1/rrc_utils.cc index b08a54e1e..dbb655eae 100644 --- a/lib/src/asn1/rrc_utils.cc +++ b/lib/src/asn1/rrc_utils.cc @@ -20,6 +20,7 @@ */ #include "srsran/asn1/rrc_utils.h" +#include "srsran/asn1/obj_id_cmp_utils.h" #include "srsran/asn1/rrc.h" #include "srsran/config.h" #include @@ -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; switch (asn1_type.type().value) { case asn1::rrc::rlc_cfg_c::types_opts::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.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 - ? -1 - : asn1_type.am().ul_am_rlc.poll_byte.to_number() * 1000; // KB + 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.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 + ? -1 + : 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.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(); @@ -1096,88 +1097,18 @@ sib13_t make_sib13(const asn1::rrc::sib_type13_r9_s& asn1_type) 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) -{ - return srb.srb_id; -} -uint8_t get_rrc_obj_id(const drb_to_add_mod_s& drb) -{ - return drb.drb_id; -} -uint8_t get_rrc_obj_id(const black_cells_to_add_mod_s& obj) -{ - 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; -} +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); +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); +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); +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); +ASN1_OBJ_ID_DEFINE(asn1::rrc::scell_to_add_mod_r10_s, scell_idx_r10); -void set_rrc_obj_id(srb_to_add_mod_s& srb, uint8_t id) -{ - 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 +} // namespace srsran diff --git a/lib/src/common/band_helper.cc b/lib/src/common/band_helper.cc index d9c48ef98..87644d24b 100644 --- a/lib/src/common/band_helper.cc +++ b/lib/src/common/band_helper.cc @@ -142,23 +142,21 @@ double srsran_band_helper::get_abs_freq_point_a_from_center_freq(uint32_t nof_pr SRSRAN_NRE); } -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 srsran_band_helper::find_lower_bound_abs_freq_ssb(uint16_t band, + srsran_subcarrier_spacing_t scs, + uint32_t min_center_freq_hz) { sync_raster_t sync_raster = get_sync_raster(band, scs); if (!sync_raster.valid()) { return 0; } - // double abs_freq_ssb_hz = sync_raster.get_frequency(); - 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); - + double ssb_bw_hz = SRSRAN_SSB_BW_SUBC * SRSRAN_SUBC_SPACING_NR(scs); while (!sync_raster.end()) { double abs_freq_ssb_hz = sync_raster.get_frequency(); - if ((abs_freq_ssb_hz > (freq_point_a_hz + ssb_bw_hz / 2)) and - ((uint32_t)std::round(abs_freq_ssb_hz - freq_point_a_hz) % SRSRAN_SUBC_SPACING_NR(scs) == 0)) { + if ((abs_freq_ssb_hz > min_center_freq_hz + ssb_bw_hz / 2) and + ((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); } @@ -167,6 +165,16 @@ srsran_band_helper::get_abs_freq_ssb_arfcn(uint16_t band, srsran_subcarrier_spac 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 { // Look for the given band and SCS diff --git a/lib/src/common/crash_handler.cc b/lib/src/common/crash_handler.cc index 2899aa23a..ba7714f4d 100644 --- a/lib/src/common/crash_handler.cc +++ b/lib/src/common/crash_handler.cc @@ -78,4 +78,4 @@ void srsran_debug_handle_crash(int argc, char** argv) signal(SIGPIPE, crash_handler); } -#endif // HAVE_BACKWARD \ No newline at end of file +#endif // HAVE_BACKWARD diff --git a/lib/src/common/test/band_helper_test.cc b/lib/src/common/test/band_helper_test.cc index a89b4c80d..9082e6ba5 100644 --- a/lib/src/common/test/band_helper_test.cc +++ b/lib/src/common/test/band_helper_test.cc @@ -56,9 +56,11 @@ int bands_test_nr() TESTASSERT(bands.nr_arfcn_to_freq(342000) == 1710.0e6); TESTASSERT(bands.nr_arfcn_to_freq(348000) == 1740.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.get_abs_freq_point_a_arfcn(52, 368500) == 367564); 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 TESTASSERT(bands.get_duplex_mode(5) == SRSRAN_DUPLEX_MODE_FDD); TESTASSERT(bands.nr_arfcn_to_freq(176300) == 881.5e6); diff --git a/lib/src/common/threads.c b/lib/src/common/threads.c index a56df7818..49d488586 100644 --- a/lib/src/common/threads.c +++ b/lib/src/common/threads.c @@ -89,7 +89,9 @@ bool threads_new_rt_cpu(pthread_t* thread, void* (*start_routine)(void*), void* #else // All threads have normal priority except prio_offset=0,1,2,3,4 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)) { perror("pthread_attr_init"); } else { diff --git a/lib/src/phy/ch_estimation/dmrs_sch.c b/lib/src/phy/ch_estimation/dmrs_sch.c index 70603ad07..89ec59ad1 100644 --- a/lib/src/phy/ch_estimation/dmrs_sch.c +++ b/lib/src/phy/ch_estimation/dmrs_sch.c @@ -225,7 +225,8 @@ static int srsran_dmrs_sch_put_symbol(srsran_dmrs_sch_t* q, // ... save first consecutive PRB in the group 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); 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 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); prb_skip = 0; } diff --git a/lib/src/phy/common/phy_common.c b/lib/src/phy/common/phy_common.c index 9dc2c4de3..c6c24aca7 100644 --- a/lib/src/phy/common/phy_common.c +++ b/lib/src/phy/common/phy_common.c @@ -347,9 +347,9 @@ int srsran_symbol_sz_power2(uint32_t nof_prb) return 256; } else if (nof_prb <= 25) { return 512; - } else if (nof_prb <= 50) { + } else if (nof_prb <= 52) { return 1024; - } else if (nof_prb <= 75) { + } else if (nof_prb <= 79) { return 1536; } else if (nof_prb <= 110) { return 2048; diff --git a/lib/src/phy/common/phy_common_nr.c b/lib/src/phy/common/phy_common_nr.c index 7e8547dbe..4d7d204b1 100644 --- a/lib/src/phy/common/phy_common_nr.c +++ b/lib/src/phy/common/phy_common_nr.c @@ -537,6 +537,19 @@ void srsran_combine_csi_trs_measurements(const srsran_csi_trs_measurements_t* a, 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 { uint32_t mux_pattern; 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, uint32_t ssb_pointA_freq_offset_Hz, srsran_subcarrier_spacing_t ssb_scs, @@ -691,6 +742,48 @@ int srsran_coreset_zero(uint32_t n_cell_id, 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) { switch (pattern) { diff --git a/lib/src/phy/phch/dci_nr.c b/lib/src/phy/phch/dci_nr.c index 5646d7557..339a2bb6f 100644 --- a/lib/src/phy/phch/dci_nr.c +++ b/lib/src/phy/phch/dci_nr.c @@ -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 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, "coreset0_bw=%d ", dci->coreset0_bw); } // Downlink assignment index – 2 bits diff --git a/lib/src/phy/phch/pdcch_nr.c b/lib/src/phy/phch/pdcch_nr.c index e8f6afc93..5feef000b 100644 --- a/lib/src/phy/phch/pdcch_nr.c +++ b/lib/src/phy/phch/pdcch_nr.c @@ -313,19 +313,6 @@ int srsran_pdcch_nr_set_carrier(srsran_pdcch_nr_t* q, 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, const srsran_dci_location_t* dci_location, bool rb_mask[SRSRAN_MAX_PRB_NR]) diff --git a/lib/src/phy/phch/ra_nr.c b/lib/src/phy/phch/ra_nr.c index 35680f3c3..934c9301d 100644 --- a/lib/src/phy/phch/ra_nr.c +++ b/lib/src/phy/phch/ra_nr.c @@ -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; 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) { // Absent default values are defined is TS 38.331 - DMRS-DownlinkConfig cfg->dmrs.additional_pos = srsran_dmrs_sch_add_pos_2; diff --git a/lib/src/phy/phch/test/dci_nr_test.c b/lib/src/phy/phch/test/dci_nr_test.c index 3e3495468..dfb9548de 100644 --- a/lib/src/phy/phch/test/dci_nr_test.c +++ b/lib/src/phy/phch/test/dci_nr_test.c @@ -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_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_common_0, srsran_dci_format_nr_1_0) == 39); srsran_dci_ctx_t ctx = {}; + ctx.rnti = 0x1234; ctx.ss_type = srsran_search_space_type_common_3; 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); } + // 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; } diff --git a/lib/src/phy/rf/CMakeLists.txt b/lib/src/phy/rf/CMakeLists.txt index 8bd3f899b..38b0de186 100644 --- a/lib/src/phy/rf/CMakeLists.txt +++ b/lib/src/phy/rf/CMakeLists.txt @@ -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) 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) set_target_properties(srsran_rf PROPERTIES VERSION ${SRSRAN_VERSION_STRING} SOVERSION ${SRSRAN_SOVERSION}) 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) if (BLADERF_FOUND) diff --git a/lib/src/phy/rf/rf_skiq_imp_card.c b/lib/src/phy/rf/rf_skiq_imp_card.c index 749a53c55..b6fbd1400 100644 --- a/lib/src/phy/rf/rf_skiq_imp_card.c +++ b/lib/src/phy/rf/rf_skiq_imp_card.c @@ -218,7 +218,13 @@ int rf_skiq_card_init(rf_skiq_card_t* q, uint8_t card, uint8_t nof_ports, const // Launch thread if (pthread_create(&q->thread, &attr, reader_thread, q)) { 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 diff --git a/lib/src/phy/rf/rf_skiq_imp_port.c b/lib/src/phy/rf/rf_skiq_imp_port.c index 41b438d61..4f1025e42 100644 --- a/lib/src/phy/rf/rf_skiq_imp_port.c +++ b/lib/src/phy/rf/rf_skiq_imp_port.c @@ -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 if (pthread_create(&q->thread, &attr, writer_thread, q)) { 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 diff --git a/lib/src/phy/sync/test/CMakeLists.txt b/lib/src/phy/sync/test/CMakeLists.txt index 331e7b445..5518066e4 100644 --- a/lib/src/phy/sync/test/CMakeLists.txt +++ b/lib/src/phy/sync/test/CMakeLists.txt @@ -176,4 +176,6 @@ target_link_libraries(ssb_file_test srsran_phy) # 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 -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) \ No newline at end of file diff --git a/lib/src/phy/sync/test/ssb_file_test.c b/lib/src/phy/sync/test/ssb_file_test.c index de34c90a9..e112b56b4 100644 --- a/lib/src/phy/sync/test/ssb_file_test.c +++ b/lib/src/phy/sync/test/ssb_file_test.c @@ -38,7 +38,7 @@ static char* filename = NULL; static double srate_hz = 23.04e6; // Base-band sampling rate in Hz static double center_freq_hz = NAN; // Center 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 static bool assert = false; @@ -53,9 +53,11 @@ static void usage(char* 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-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 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-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) { int opt; - while ((opt = getopt(argc, argv, "inrfFAv")) != -1) { + while ((opt = getopt(argc, argv, "insdrfFAv")) != -1) { switch (opt) { case 'i': filename = argv[optind]; @@ -71,6 +73,24 @@ static void parse_args(int argc, char** argv) case 'n': nof_samples = (uint32_t)strtol(argv[optind], NULL, 10); 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': srate_hz = strtod(argv[optind], NULL); break; @@ -204,6 +224,17 @@ int main(int argc, char** argv) str, 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 if (assert) { if (assert_search(&search_res)) { diff --git a/lib/src/phy/ue/test/CMakeLists.txt b/lib/src/phy/ue/test/CMakeLists.txt index 7c6c43959..3a3d53804 100644 --- a/lib/src/phy/ue/test/CMakeLists.txt +++ b/lib/src/phy/ue/test/CMakeLists.txt @@ -56,14 +56,17 @@ if(RF_FOUND) endif(SRSGUI_FOUND) endif(RF_FOUND) -add_executable(ue_dl_nr_file_test ue_dl_nr_file_test.c) -target_link_libraries(ue_dl_nr_file_test srsran_phy pthread) +add_executable(ue_dl_nr_file_test ue_dl_nr_file_test.cc) +target_link_libraries(ue_dl_nr_file_test srsran_phy srsran_common pthread) 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) - 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) - 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) + #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 -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 -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 -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 -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 -l 2) 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) \ No newline at end of file diff --git a/lib/src/phy/ue/test/ue_dl_nr_file_test.c b/lib/src/phy/ue/test/ue_dl_nr_file_test.cc similarity index 55% rename from lib/src/phy/ue/test/ue_dl_nr_file_test.c rename to lib/src/phy/ue/test/ue_dl_nr_file_test.cc index f52c53cf7..8ad1db77b 100644 --- a/lib/src/phy/ue/test/ue_dl_nr_file_test.c +++ b/lib/src/phy/ue/test/ue_dl_nr_file_test.cc @@ -19,10 +19,17 @@ * */ +#ifdef __cplusplus +#include +extern "C" { #include "srsran/phy/io/filesource.h" #include "srsran/phy/phch/ra_nr.h" #include "srsran/phy/ue/ue_dl_nr.h" #include "srsran/phy/utils/debug.h" +} +#endif // __cplusplus + +#include "srsran/common/band_helper.h" #include 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_slot_cfg_t slot_cfg = {}; -static srsran_softbuffer_rx_t softbuffer = {}; -static uint8_t* data = NULL; +static srsran_filesource_t filesource = {}; +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) { @@ -45,7 +65,16 @@ static void usage(char* prog) printf("\t-i Physical cell identifier [Default %d]\n", carrier.pci); printf("\t-n Slot index [Default %d]\n", slot_cfg.idx); 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-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) { int opt; - while ((opt = getopt(argc, argv, "fPivnSRT")) != -1) { + while ((opt = getopt(argc, argv, "fPivnSRTscoNlAa")) != -1) { switch (opt) { case 'f': filename = argv[optind]; @@ -79,12 +108,47 @@ static int parse_args(int argc, char** argv) rnti_type = srsran_rnti_type_c; } else if (strcmp(argv[optind], "ra") == 0) { rnti_type = srsran_rnti_type_ra; + } else if (strcmp(argv[optind], "si") == 0) { + rnti_type = srsran_rnti_type_si; } else { printf("Invalid RNTI type '%s'\n", argv[optind]); usage(argv[0]); return SRSRAN_ERROR; } 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': srsran_use_standard_symbol_size(true); 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) { printf("No DCI found :'(\n"); - return SRSRAN_SUCCESS; + return SRSRAN_ERROR; } 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; } + 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; } +// 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 ret = SRSRAN_ERROR; - srsran_ue_dl_nr_t ue_dl = {}; - cf_t* buffer[SRSRAN_MAX_PORTS] = {}; + int ret = SRSRAN_ERROR; + + // parse args + if (parse_args(argc, argv) < SRSRAN_SUCCESS) { + return clean_exit(ret); + } uint32_t sf_len = SRSRAN_SF_LEN_PRB(carrier.nof_prb); buffer[0] = srsran_vec_cf_malloc(sf_len); if (buffer[0] == NULL) { 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) < SRSRAN_SUCCESS) { ERROR("Error init soft-buffer"); - goto clean_exit; + return clean_exit(ret); } data = srsran_vec_u8_malloc(SRSRAN_SLOT_MAX_NOF_BITS_NR); if (data == NULL) { ERROR("Error malloc"); - goto clean_exit; + return clean_exit(ret); } + // Set default PDSCH configuration srsran_ue_dl_nr_args_t ue_dl_args = {}; ue_dl_args.nof_rx_antennas = 1; 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.nof_max_prb = carrier.nof_prb; - // Set default PDSCH configuration - if (parse_args(argc, argv) < SRSRAN_SUCCESS) { - goto clean_exit; - } - // Check for filename if (filename == NULL) { ERROR("Filename was not provided"); - goto clean_exit; + return clean_exit(ret); } // Open filesource - srsran_filesource_t filesource = {}; if (srsran_filesource_init(&filesource, filename, SRSRAN_COMPLEX_FLOAT_BIN) < SRSRAN_SUCCESS) { 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 - srsran_coreset_t* coreset = &pdcch_cfg.coreset[1]; - pdcch_cfg.coreset_present[1] = true; - coreset->duration = 2; - for (uint32_t i = 0; i < SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE; i++) { - coreset->freq_resources[i] = i < carrier.nof_prb / 6; + if (rnti_type == srsran_rnti_type_si) { + // configure to use coreset0 + coreset = &pdcch_cfg.coreset[0]; + pdcch_cfg.coreset_present[0] = true; + + // 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 srsran_search_space_t* search_space = &pdcch_cfg.search_space[0]; pdcch_cfg.search_space_present[0] = true; search_space->id = 0; - search_space->coreset_id = 1; - search_space->type = srsran_search_space_type_common_3; + search_space->coreset_id = (rnti_type == srsran_rnti_type_si) ? 0 : 1; + search_space->type = ss_type; search_space->formats[0] = srsran_dci_format_nr_0_0; search_space->formats[1] = srsran_dci_format_nr_1_0; 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)) { ERROR("Error UE DL"); - goto clean_exit; + return clean_exit(ret); } if (srsran_ue_dl_nr_set_carrier(&ue_dl, &carrier)) { ERROR("Error setting SCH NR carrier"); - goto clean_exit; + return clean_exit(ret); } // Read baseband from file if (srsran_filesource_read(&filesource, buffer[0], (int)ue_dl.fft->sf_sz) < SRSRAN_SUCCESS) { 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)) { ERROR("Error setting CORESET"); - goto clean_exit; + return clean_exit(ret); } // Actual decode - 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); + ret = work_ue_dl(&ue_dl, &slot_cfg); - return ret; + // free memory and return last value of ret + return clean_exit(ret); } diff --git a/lib/src/phy/ue/test/ue_dl_nr_pci500_rb52_rnti0x100_s15.36e6.dat b/lib/src/phy/ue/test/ue_dl_nr_pci500_rb52_rnti0x100_s15.36e6.dat new file mode 100644 index 000000000..848f5bada Binary files /dev/null and b/lib/src/phy/ue/test/ue_dl_nr_pci500_rb52_rnti0x100_s15.36e6.dat differ diff --git a/lib/src/phy/ue/test/ue_dl_nr_pci500_rb52_si_coreset0_idx6_s15.36e6.dat b/lib/src/phy/ue/test/ue_dl_nr_pci500_rb52_si_coreset0_idx6_s15.36e6.dat new file mode 100644 index 000000000..9c35a565f Binary files /dev/null and b/lib/src/phy/ue/test/ue_dl_nr_pci500_rb52_si_coreset0_idx6_s15.36e6.dat differ diff --git a/lib/src/phy/ue/test/ue_dl_nr_pci500_rb52_si_coreset0_idx7_s15.36e6.dat b/lib/src/phy/ue/test/ue_dl_nr_pci500_rb52_si_coreset0_idx7_s15.36e6.dat new file mode 100644 index 000000000..e7afecae3 Binary files /dev/null and b/lib/src/phy/ue/test/ue_dl_nr_pci500_rb52_si_coreset0_idx7_s15.36e6.dat differ diff --git a/lib/src/phy/ue/ue_dl_nr.c b/lib/src/phy/ue/ue_dl_nr.c index 3752cf1b6..9cb32cf96 100644 --- a/lib/src/phy/ue/ue_dl_nr.c +++ b/lib/src/phy/ue/ue_dl_nr.c @@ -302,6 +302,16 @@ static int ue_dl_nr_find_dci_ncce(srsran_ue_dl_nr_t* q, 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 pdcch_info->result = *pdcch_res; diff --git a/lib/src/rlc/bearer_mem_pool.cc b/lib/src/rlc/bearer_mem_pool.cc index d3a17d3e9..7eb77bbe8 100644 --- a/lib/src/rlc/bearer_mem_pool.cc +++ b/lib/src/rlc/bearer_mem_pool.cc @@ -22,6 +22,8 @@ #include "srsran/rlc/bearer_mem_pool.h" #include "srsran/adt/pool/batch_mem_pool.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_nr.h" @@ -30,7 +32,11 @@ namespace srsran { srsran::background_mem_pool* get_bearer_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; } diff --git a/lib/src/rlc/rlc.cc b/lib/src/rlc/rlc.cc index 07b4c3cde..e121a7830 100644 --- a/lib/src/rlc/rlc.cc +++ b/lib/src/rlc/rlc.cc @@ -405,7 +405,7 @@ int rlc::add_bearer(uint32_t lcid, const rlc_config_t& cnfg) case rlc_mode_t::am: switch (cnfg.rat) { case srsran_rat_t::lte: - rlc_entity = std::unique_ptr(new rlc_am_lte(logger, lcid, pdcp, rrc, timers)); + rlc_entity = std::unique_ptr(new rlc_am(cnfg.rat, logger, lcid, pdcp, rrc, timers)); break; default: logger.error("AM not supported for this RAT"); diff --git a/lib/src/rlc/rlc_am_base.cc b/lib/src/rlc/rlc_am_base.cc index c63b4776e..d543c2ab9 100644 --- a/lib/src/rlc/rlc_am_base.cc +++ b/lib/src/rlc/rlc_am_base.cc @@ -20,6 +20,8 @@ */ #include "srsran/rlc/rlc_am_base.h" +#include "srsran/rlc/rlc_am_lte.h" +#include "srsran/rlc/rlc_am_nr.h" #include namespace srsran { @@ -34,4 +36,234 @@ bool rlc_am_is_control_pdu(byte_buffer_t* pdu) 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(tx); + rx_base = std::unique_ptr(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(tx); + rx_base = std::unique_ptr(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 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 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 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 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 lock(metrics_mutex); + metrics.rx_latency_ms = latency; + metrics.rx_buffered_bytes = buffered_bytes; + return metrics; +} + +void rlc_am::reset_metrics() +{ + std::lock_guard 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 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 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 diff --git a/lib/src/rlc/rlc_am_lte.cc b/lib/src/rlc/rlc_am_lte.cc index 09681dd73..5c485f92e 100644 --- a/lib/src/rlc/rlc_am_lte.cc +++ b/lib/src/rlc/rlc_am_lte.cc @@ -34,257 +34,30 @@ namespace srsran { -/******************************* - * RLC AM Segments - ******************************/ - -int rlc_am_pdu_segment_pool::segment_resource::id() const -{ - return std::distance(parent_pool->segments.cbegin(), this); -} - -void rlc_am_pdu_segment_pool::segment_resource::release_pdcp_sn() -{ - pdcp_sn_ = invalid_pdcp_sn; - if (empty()) { - parent_pool->free_list.push_front(this); - } -} - -void rlc_am_pdu_segment_pool::segment_resource::release_rlc_sn() -{ - rlc_sn_ = invalid_rlc_sn; - if (empty()) { - parent_pool->free_list.push_front(this); - } -} - -rlc_am_pdu_segment_pool::rlc_am_pdu_segment_pool() -{ - for (segment_resource& s : segments) { - s.parent_pool = this; - free_list.push_front(&s); - } -} - -bool rlc_am_pdu_segment_pool::make_segment(rlc_amd_tx_pdu& rlc_list, pdcp_pdu_info& pdcp_list) -{ - if (not has_segments()) { - return false; - } - segment_resource* segment = free_list.pop_front(); - segment->rlc_sn_ = rlc_list.rlc_sn; - segment->pdcp_sn_ = pdcp_list.sn; - rlc_list.add_segment(*segment); - pdcp_list.add_segment(*segment); - return true; -} - -void pdcp_pdu_info::ack_segment(rlc_am_pdu_segment& segment) -{ - // remove from list - list.pop(&segment); - // signal pool that the pdcp handle is released - segment.release_pdcp_sn(); -} - -rlc_amd_tx_pdu::~rlc_amd_tx_pdu() -{ - while (not list.empty()) { - // remove from list - rlc_am_pdu_segment* segment = list.pop_front(); - // deallocate if also removed from PDCP - segment->release_rlc_sn(); - } -} - -/******************************* - * rlc_am_lte class - ******************************/ - -rlc_am_lte::rlc_am_lte(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_lte::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)) { - 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_lte::set_bsr_callback(bsr_callback_t callback) -{ - tx.set_bsr_callback(callback); -} - -void rlc_am_lte::empty_queue() -{ - // Drop all messages in TX SDU queue - tx.empty_queue(); -} - -void rlc_am_lte::reestablish() -{ - logger.debug("Reestablished bearer %s", rb_name.c_str()); - tx.reestablish(); // calls stop and enables tx again - rx.reestablish(); // calls only stop -} - -void rlc_am_lte::stop() -{ - logger.debug("Stopped bearer %s", rb_name.c_str()); - tx.stop(); - rx.stop(); -} - -rlc_mode_t rlc_am_lte::get_mode() -{ - return rlc_mode_t::am; -} - -uint32_t rlc_am_lte::get_bearer() -{ - return lcid; -} - -rlc_bearer_metrics_t rlc_am_lte::get_metrics() -{ - // update values that aren't calculated on the fly - uint32_t latency = rx.get_sdu_rx_latency_ms(); - uint32_t buffered_bytes = rx.get_rx_buffered_bytes(); - - std::lock_guard lock(metrics_mutex); - metrics.rx_latency_ms = latency; - metrics.rx_buffered_bytes = buffered_bytes; - - return metrics; -} - -void rlc_am_lte::reset_metrics() -{ - std::lock_guard lock(metrics_mutex); - metrics = {}; -} - -/**************************************************************************** - * PDCP interface - ***************************************************************************/ - -void rlc_am_lte::write_sdu(unique_byte_buffer_t sdu) -{ - if (tx.write_sdu(std::move(sdu)) == SRSRAN_SUCCESS) { - std::lock_guard lock(metrics_mutex); - metrics.num_tx_sdus++; - } -} - -void rlc_am_lte::discard_sdu(uint32_t discard_sn) -{ - tx.discard_sdu(discard_sn); - - std::lock_guard lock(metrics_mutex); - metrics.num_lost_sdus++; -} - -bool rlc_am_lte::sdu_queue_is_full() -{ - return tx.sdu_queue_is_full(); -} - -/**************************************************************************** - * MAC interface - ***************************************************************************/ - -bool rlc_am_lte::has_data() -{ - return tx.has_data(); -} - -uint32_t rlc_am_lte::get_buffer_state() -{ - return tx.get_buffer_state(); -} - -void rlc_am_lte::get_buffer_state(uint32_t& tx_queue, uint32_t& prio_tx_queue) -{ - tx.get_buffer_state(tx_queue, prio_tx_queue); -} - -uint32_t rlc_am_lte::read_pdu(uint8_t* payload, uint32_t nof_bytes) -{ - uint32_t read_bytes = tx.read_pdu(payload, nof_bytes); - - std::lock_guard lock(metrics_mutex); - metrics.num_tx_pdus++; - metrics.num_tx_pdu_bytes += read_bytes; - - return read_bytes; -} - -void rlc_am_lte::write_pdu(uint8_t* payload, uint32_t nof_bytes) -{ - rx.write_pdu(payload, nof_bytes); - - std::lock_guard lock(metrics_mutex); - metrics.num_rx_pdus++; - metrics.num_rx_pdu_bytes += nof_bytes; -} +using pdcp_pdu_info_lte = pdcp_pdu_info; +using rlc_amd_tx_pdu_lte = rlc_amd_tx_pdu; +using rlc_am_pdu_segment = rlc_am_pdu_segment_pool::segment_resource; /**************************************************************************** * Tx subclass implementation ***************************************************************************/ - -rlc_am_lte::rlc_am_lte_tx::rlc_am_lte_tx(rlc_am_lte* parent_) : +rlc_am_lte_tx::rlc_am_lte_tx(rlc_am* parent_) : parent(parent_), - logger(parent_->logger), pool(byte_buffer_pool::get_instance()), poll_retx_timer(parent_->timers->get_unique_timer()), - status_prohibit_timer(parent_->timers->get_unique_timer()) -{} - -rlc_am_lte::rlc_am_lte_tx::~rlc_am_lte_tx() {} - -void rlc_am_lte::rlc_am_lte_tx::set_bsr_callback(bsr_callback_t callback) + status_prohibit_timer(parent_->timers->get_unique_timer()), + rlc_am_base_tx(&parent_->logger) { - bsr_callback = callback; + rx = dynamic_cast(parent->rx_base.get()); } -bool rlc_am_lte::rlc_am_lte_tx::configure(const rlc_config_t& cfg_) +bool rlc_am_lte_tx::configure(const rlc_config_t& cfg_) { std::lock_guard lock(mutex); if (cfg_.tx_queue_length > MAX_SDUS_PER_RLC_PDU) { - logger.error("Configuring Tx queue length of %d PDUs too big. Maximum value is %d.", - cfg_.tx_queue_length, - MAX_SDUS_PER_RLC_PDU); + logger->error("Configuring Tx queue length of %d PDUs too big. Maximum value is %d.", + cfg_.tx_queue_length, + MAX_SDUS_PER_RLC_PDU); return false; } @@ -293,7 +66,7 @@ bool rlc_am_lte::rlc_am_lte_tx::configure(const rlc_config_t& cfg_) // check timers if (not poll_retx_timer.is_valid() or not status_prohibit_timer.is_valid()) { - logger.error("Configuring RLC AM TX: timers not configured"); + logger->error("Configuring RLC AM TX: timers not configured"); return false; } @@ -316,13 +89,13 @@ bool rlc_am_lte::rlc_am_lte_tx::configure(const rlc_config_t& cfg_) return true; } -void rlc_am_lte::rlc_am_lte_tx::stop() +void rlc_am_lte_tx::stop() { std::lock_guard lock(mutex); stop_nolock(); } -void rlc_am_lte::rlc_am_lte_tx::stop_nolock() +void rlc_am_lte_tx::stop_nolock() { empty_queue_nolock(); @@ -354,13 +127,13 @@ void rlc_am_lte::rlc_am_lte_tx::stop_nolock() undelivered_sdu_info_queue.clear(); } -void rlc_am_lte::rlc_am_lte_tx::empty_queue() +void rlc_am_lte_tx::empty_queue() { std::lock_guard lock(mutex); empty_queue_nolock(); } -void rlc_am_lte::rlc_am_lte_tx::empty_queue_nolock() +void rlc_am_lte_tx::empty_queue_nolock() { // deallocate all SDUs in transmit queue while (tx_sdu_queue.size() > 0) { @@ -374,20 +147,20 @@ void rlc_am_lte::rlc_am_lte_tx::empty_queue_nolock() tx_sdu.reset(); } -void rlc_am_lte::rlc_am_lte_tx::reestablish() +void rlc_am_lte_tx::reestablish() { std::lock_guard lock(mutex); stop_nolock(); tx_enabled = true; } -bool rlc_am_lte::rlc_am_lte_tx::do_status() +bool rlc_am_lte_tx::do_status() { - return parent->rx.get_do_status(); + return rx->get_do_status(); } // Function is supposed to return as fast as possible -bool rlc_am_lte::rlc_am_lte_tx::has_data() +bool rlc_am_lte_tx::has_data() { return (((do_status() && not status_prohibit_timer.is_running())) || // if we have a status PDU to transmit (not retx_queue.empty()) || // if we have a retransmission @@ -404,10 +177,10 @@ bool rlc_am_lte::rlc_am_lte_tx::has_data() * * @param sn The SN of the PDU to check */ -void rlc_am_lte::rlc_am_lte_tx::check_sn_reached_max_retx(uint32_t sn) +void rlc_am_lte_tx::check_sn_reached_max_retx(uint32_t sn) { if (tx_window[sn].retx_count == cfg.max_retx_thresh) { - logger.warning("%s Signaling max number of reTx=%d for SN=%d", RB_NAME, tx_window[sn].retx_count, sn); + logger->warning("%s Signaling max number of reTx=%d for SN=%d", RB_NAME, tx_window[sn].retx_count, sn); parent->rrc->max_retx_attempted(); srsran::pdcp_sn_vector_t pdcp_sns; for (const rlc_am_pdu_segment& segment : tx_window[sn]) { @@ -420,55 +193,59 @@ void rlc_am_lte::rlc_am_lte_tx::check_sn_reached_max_retx(uint32_t sn) } } -uint32_t rlc_am_lte::rlc_am_lte_tx::get_buffer_state() +uint32_t rlc_am_lte_tx::get_buffer_state() { uint32_t new_tx_queue = 0, prio_tx_queue = 0; get_buffer_state(new_tx_queue, prio_tx_queue); return new_tx_queue + prio_tx_queue; } -void rlc_am_lte::rlc_am_lte_tx::get_buffer_state(uint32_t& n_bytes_newtx, uint32_t& n_bytes_prio) +void rlc_am_lte_tx::get_buffer_state(uint32_t& n_bytes_newtx, uint32_t& n_bytes_prio) { std::lock_guard lock(mutex); get_buffer_state_nolock(n_bytes_newtx, n_bytes_prio); } -void rlc_am_lte::rlc_am_lte_tx::get_buffer_state_nolock(uint32_t& n_bytes_newtx, uint32_t& n_bytes_prio) +void rlc_am_lte_tx::get_buffer_state_nolock(uint32_t& n_bytes_newtx, uint32_t& n_bytes_prio) { n_bytes_newtx = 0; n_bytes_prio = 0; uint32_t n_sdus = 0; - logger.debug("%s Buffer state - do_status=%s, status_prohibit_running=%s (%d/%d)", - RB_NAME, - do_status() ? "yes" : "no", - status_prohibit_timer.is_running() ? "yes" : "no", - status_prohibit_timer.time_elapsed(), - status_prohibit_timer.duration()); + if (not tx_enabled) { + return; + } + + logger->debug("%s Buffer state - do_status=%s, status_prohibit_running=%s (%d/%d)", + parent->rb_name, + do_status() ? "yes" : "no", + status_prohibit_timer.is_running() ? "yes" : "no", + status_prohibit_timer.time_elapsed(), + status_prohibit_timer.duration()); // Bytes needed for status report if (do_status() && not status_prohibit_timer.is_running()) { - n_bytes_prio += parent->rx.get_status_pdu_length(); - logger.debug("%s Buffer state - total status report: %d bytes", RB_NAME, n_bytes_prio); + n_bytes_prio += rx->get_status_pdu_length(); + logger->debug("%s Buffer state - total status report: %d bytes", RB_NAME, n_bytes_prio); } // Bytes needed for retx if (not retx_queue.empty()) { rlc_amd_retx_t& retx = retx_queue.front(); - logger.debug("%s Buffer state - retx - SN=%d, Segment: %s, %d:%d", - RB_NAME, - retx.sn, - retx.is_segment ? "true" : "false", - retx.so_start, - retx.so_end); + logger->debug("%s Buffer state - retx - SN=%d, Segment: %s, %d:%d", + RB_NAME, + retx.sn, + retx.is_segment ? "true" : "false", + retx.so_start, + retx.so_end); if (tx_window.has_sn(retx.sn)) { int req_bytes = required_buffer_size(retx); if (req_bytes < 0) { - logger.error("In get_buffer_state(): Removing retx.sn=%d from queue", retx.sn); + logger->error("In get_buffer_state(): Removing retx.sn=%d from queue", retx.sn); retx_queue.pop(); } else { n_bytes_prio += req_bytes; - logger.debug("Buffer state - retx: %d bytes", n_bytes_prio); + logger->debug("Buffer state - retx: %d bytes", n_bytes_prio); } } } @@ -491,51 +268,16 @@ void rlc_am_lte::rlc_am_lte_tx::get_buffer_state_nolock(uint32_t& n_bytes_newtx, // Room needed for fixed header of data PDUs if (n_bytes_newtx > 0 && n_sdus > 0) { n_bytes_newtx += 2; // Two bytes for fixed header with SN length = 10 - logger.debug("%s Total buffer state - %d SDUs (%d B)", RB_NAME, n_sdus, n_bytes_newtx); + logger->debug("%s Total buffer state - %d SDUs (%d B)", RB_NAME, n_sdus, n_bytes_newtx); } if (bsr_callback) { + logger->debug("%s Calling BSR callback - %d new_tx, %d prio bytes", RB_NAME, n_bytes_newtx, n_bytes_prio); bsr_callback(parent->lcid, n_bytes_newtx, n_bytes_prio); } } -int rlc_am_lte::rlc_am_lte_tx::write_sdu(unique_byte_buffer_t sdu) -{ - std::lock_guard lock(mutex); - - if (!tx_enabled) { - return SRSRAN_ERROR; - } - - if (sdu.get() == nullptr) { - logger.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 ret = tx_sdu_queue.try_write(std::move(sdu)); - if (ret) { - logger.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 - logger.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_lte::rlc_am_lte_tx::discard_sdu(uint32_t discard_sn) +void rlc_am_lte_tx::discard_sdu(uint32_t discard_sn) { if (!tx_enabled) { return; @@ -550,15 +292,15 @@ void rlc_am_lte::rlc_am_lte_tx::discard_sdu(uint32_t discard_sn) }); // Discard fails when the PDCP PDU is already in Tx window. - logger.info("%s PDU with PDCP_SN=%d", discarded ? "Discarding" : "Couldn't discard", discard_sn); + logger->info("%s PDU with PDCP_SN=%d", discarded ? "Discarding" : "Couldn't discard", discard_sn); } -bool rlc_am_lte::rlc_am_lte_tx::sdu_queue_is_full() +bool rlc_am_lte_tx::sdu_queue_is_full() { return tx_sdu_queue.is_full(); } -uint32_t rlc_am_lte::rlc_am_lte_tx::read_pdu(uint8_t* payload, uint32_t nof_bytes) +uint32_t rlc_am_lte_tx::read_pdu(uint8_t* payload, uint32_t nof_bytes) { std::lock_guard lock(mutex); @@ -566,11 +308,11 @@ uint32_t rlc_am_lte::rlc_am_lte_tx::read_pdu(uint8_t* payload, uint32_t nof_byte return 0; } - logger.debug("MAC opportunity - %d bytes", nof_bytes); - logger.debug("tx_window size - %zu PDUs", tx_window.size()); + logger->debug("MAC opportunity - %d bytes", nof_bytes); + logger->debug("tx_window size - %zu PDUs", tx_window.size()); if (not tx_enabled) { - logger.debug("RLC entity not active. Not generating PDU."); + logger->debug("RLC entity not active. Not generating PDU."); return 0; } @@ -596,11 +338,11 @@ uint32_t rlc_am_lte::rlc_am_lte_tx::read_pdu(uint8_t* payload, uint32_t nof_byte return build_data_pdu(payload, nof_bytes); } -void rlc_am_lte::rlc_am_lte_tx::timer_expired(uint32_t timeout_id) +void rlc_am_lte_tx::timer_expired(uint32_t timeout_id) { std::unique_lock lock(mutex); if (poll_retx_timer.is_valid() && poll_retx_timer.id() == timeout_id) { - logger.debug("%s Poll reTx timer expired after %dms", RB_NAME, poll_retx_timer.duration()); + logger->debug("%s Poll reTx timer expired after %dms", RB_NAME, poll_retx_timer.duration()); // Section 5.2.2.3 in TS 36.322, schedule PDU for retransmission if // (a) both tx and retx buffer are empty (excluding tx'ed PDU waiting for ack), or // (b) no new data PDU can be transmitted (tx window is full) @@ -608,7 +350,7 @@ void rlc_am_lte::rlc_am_lte_tx::timer_expired(uint32_t timeout_id) retransmit_pdu(vt_a); // TODO: TS says to send vt_s - 1 here } } else if (status_prohibit_timer.is_valid() && status_prohibit_timer.id() == timeout_id) { - logger.debug("%s Status prohibit timer expired after %dms", RB_NAME, status_prohibit_timer.duration()); + logger->debug("%s Status prohibit timer expired after %dms", RB_NAME, status_prohibit_timer.duration()); } if (bsr_callback) { @@ -617,26 +359,27 @@ void rlc_am_lte::rlc_am_lte_tx::timer_expired(uint32_t timeout_id) } } -void rlc_am_lte::rlc_am_lte_tx::retransmit_pdu(uint32_t sn) +void rlc_am_lte_tx::retransmit_pdu(uint32_t sn) { if (tx_window.empty()) { - logger.warning("%s No PDU to retransmit", RB_NAME); + logger->warning("%s No PDU to retransmit", RB_NAME); return; } if (not tx_window.has_sn(sn)) { - logger.warning("%s Can't retransmit unexisting SN=%d", RB_NAME, sn); + logger->warning("%s Can't retransmit unexisting SN=%d", RB_NAME, sn); return; } // select first PDU in tx window for retransmission - rlc_amd_tx_pdu& pdu = tx_window[sn]; + rlc_amd_tx_pdu_lte& pdu = tx_window[sn]; // increment retx counter and inform upper layers pdu.retx_count++; check_sn_reached_max_retx(sn); - logger.info("%s Schedule SN=%d for reTx", RB_NAME, pdu.rlc_sn); + logger->info("%s Schedule SN=%d for reTx", RB_NAME, pdu.rlc_sn); + rlc_amd_retx_t& retx = retx_queue.push(); retx.is_segment = false; retx.so_start = 0; @@ -656,7 +399,7 @@ void rlc_am_lte::rlc_am_lte_tx::retransmit_pdu(uint32_t sn) * * @return True if a status PDU needs to be requested, false otherwise. */ -bool rlc_am_lte::rlc_am_lte_tx::poll_required() +bool rlc_am_lte_tx::poll_required() { if (cfg.poll_pdu > 0 && pdu_without_poll > static_cast(cfg.poll_pdu)) { return true; @@ -684,21 +427,22 @@ bool rlc_am_lte::rlc_am_lte_tx::poll_required() * However, it seems more appropiate to request more often if polling * is disabled otherwise, e.g. every N PDUs. */ - if (cfg.poll_pdu == 0 && cfg.poll_byte == 0 && vt_s % poll_periodicity == 0) { + if (cfg.poll_pdu == 0 && cfg.poll_byte == 0 && vt_s % rlc_am::poll_periodicity == 0) { return true; } return false; } -int rlc_am_lte::rlc_am_lte_tx::build_status_pdu(uint8_t* payload, uint32_t nof_bytes) +int rlc_am_lte_tx::build_status_pdu(uint8_t* payload, uint32_t nof_bytes) { - int pdu_len = parent->rx.get_status_pdu(&tx_status, nof_bytes); + logger->debug("%s Generating status PDU. Nof bytes %d", RB_NAME, nof_bytes); + int pdu_len = rx->get_status_pdu(&tx_status, nof_bytes); if (pdu_len == SRSRAN_ERROR) { - logger.debug("%s Deferred Status PDU. Cause: Failed to acquire Rx lock", RB_NAME); + logger->debug("%s Deferred Status PDU. Cause: Failed to acquire Rx lock", RB_NAME); pdu_len = 0; } else if (pdu_len > 0 && nof_bytes >= static_cast(pdu_len)) { - log_rlc_am_status_pdu_to_string(logger.info, "%s Tx status PDU - %s", &tx_status, RB_NAME); + log_rlc_am_status_pdu_to_string(logger->info, "%s Tx status PDU - %s", &tx_status, RB_NAME); if (cfg.t_status_prohibit > 0 && status_prohibit_timer.is_valid()) { // re-arm timer status_prohibit_timer.run(); @@ -706,18 +450,18 @@ int rlc_am_lte::rlc_am_lte_tx::build_status_pdu(uint8_t* payload, uint32_t nof_b debug_state(); pdu_len = rlc_am_write_status_pdu(&tx_status, payload); } else { - logger.info("%s Cannot tx status PDU - %d bytes available, %d bytes required", RB_NAME, nof_bytes, pdu_len); + logger->info("%s Cannot tx status PDU - %d bytes available, %d bytes required", RB_NAME, nof_bytes, pdu_len); pdu_len = 0; } return pdu_len; } -int rlc_am_lte::rlc_am_lte_tx::build_retx_pdu(uint8_t* payload, uint32_t nof_bytes) +int rlc_am_lte_tx::build_retx_pdu(uint8_t* payload, uint32_t nof_bytes) { // Check there is at least 1 element before calling front() if (retx_queue.empty()) { - logger.error("In build_retx_pdu(): retx_queue is empty"); + logger->error("In build_retx_pdu(): retx_queue is empty"); return -1; } @@ -729,7 +473,7 @@ int rlc_am_lte::rlc_am_lte_tx::build_retx_pdu(uint8_t* payload, uint32_t nof_byt if (!retx_queue.empty()) { retx = retx_queue.front(); } else { - logger.info("%s SN=%d not in Tx window. Ignoring retx.", RB_NAME, retx.sn); + logger->info("%s SN=%d not in Tx window. Ignoring retx.", RB_NAME, retx.sn); if (tx_window.has_sn(vt_a)) { // schedule next SN for retx retransmit_pdu(vt_a); @@ -744,13 +488,13 @@ int rlc_am_lte::rlc_am_lte_tx::build_retx_pdu(uint8_t* payload, uint32_t nof_byt // Is resegmentation needed? int req_size = required_buffer_size(retx); if (req_size < 0) { - logger.error("In build_retx_pdu(): Removing retx.sn=%d from queue", retx.sn); + logger->error("In build_retx_pdu(): Removing retx.sn=%d from queue", retx.sn); retx_queue.pop(); return -1; } if (retx.is_segment || req_size > static_cast(nof_bytes)) { - logger.debug("%s build_retx_pdu - resegmentation required", RB_NAME); + logger->debug("%s build_retx_pdu - resegmentation required", RB_NAME); return build_segment(payload, nof_bytes, retx); } @@ -761,8 +505,8 @@ int rlc_am_lte::rlc_am_lte_tx::build_retx_pdu(uint8_t* payload, uint32_t nof_byt // Set poll bit pdu_without_poll++; byte_without_poll += (tx_window[retx.sn].buf->N_bytes + rlc_am_packed_length(&new_header)); - logger.info("%s pdu_without_poll: %d", RB_NAME, pdu_without_poll); - logger.info("%s byte_without_poll: %d", RB_NAME, byte_without_poll); + logger->info("%s pdu_without_poll: %d", RB_NAME, pdu_without_poll); + logger->info("%s byte_without_poll: %d", RB_NAME, byte_without_poll); if (poll_required()) { new_header.p = 1; // vt_s won't change for reTx, so don't update poll_sn @@ -780,24 +524,24 @@ int rlc_am_lte::rlc_am_lte_tx::build_retx_pdu(uint8_t* payload, uint32_t nof_byt retx_queue.pop(); - logger.info(payload, - tx_window[retx.sn].buf->N_bytes, - "%s Tx PDU SN=%d (%d B) (attempt %d/%d)", - RB_NAME, - retx.sn, - tx_window[retx.sn].buf->N_bytes, - tx_window[retx.sn].retx_count + 1, - cfg.max_retx_thresh); - log_rlc_amd_pdu_header_to_string(logger.debug, new_header); + logger->info(payload, + tx_window[retx.sn].buf->N_bytes, + "%s Tx PDU SN=%d (%d B) (attempt %d/%d)", + RB_NAME, + retx.sn, + tx_window[retx.sn].buf->N_bytes, + tx_window[retx.sn].retx_count + 1, + cfg.max_retx_thresh); + log_rlc_amd_pdu_header_to_string(logger->debug, new_header); debug_state(); return (ptr - payload) + tx_window[retx.sn].buf->N_bytes; } -int rlc_am_lte::rlc_am_lte_tx::build_segment(uint8_t* payload, uint32_t nof_bytes, rlc_amd_retx_t retx) +int rlc_am_lte_tx::build_segment(uint8_t* payload, uint32_t nof_bytes, rlc_amd_retx_t retx) { if (tx_window[retx.sn].buf == NULL) { - logger.error("In build_segment: retx.sn=%d has null buffer", retx.sn); + logger->error("In build_segment: retx.sn=%d has null buffer", retx.sn); return 0; } if (!retx.is_segment) { @@ -811,8 +555,8 @@ int rlc_am_lte::rlc_am_lte_tx::build_segment(uint8_t* payload, uint32_t nof_byte pdu_without_poll++; byte_without_poll += (tx_window[retx.sn].buf->N_bytes + rlc_am_packed_length(&new_header)); - logger.info("%s pdu_without_poll: %d", RB_NAME, pdu_without_poll); - logger.info("%s byte_without_poll: %d", RB_NAME, byte_without_poll); + logger->info("%s pdu_without_poll: %d", RB_NAME, pdu_without_poll); + logger->info("%s byte_without_poll: %d", RB_NAME, byte_without_poll); new_header.dc = RLC_DC_FIELD_DATA_PDU; new_header.rf = 1; @@ -823,7 +567,7 @@ int rlc_am_lte::rlc_am_lte_tx::build_segment(uint8_t* payload, uint32_t nof_byte new_header.N_li = 0; new_header.p = 0; if (poll_required()) { - logger.debug("%s setting poll bit to request status", RB_NAME); + logger->debug("%s setting poll bit to request status", RB_NAME); new_header.p = 1; // vt_s won't change for reTx, so don't update poll_sn pdu_without_poll = 0; @@ -843,10 +587,10 @@ int rlc_am_lte::rlc_am_lte_tx::build_segment(uint8_t* payload, uint32_t nof_byte } if (nof_bytes <= head_len) { - logger.info("%s Cannot build a PDU segment - %d bytes available, %d bytes required for header", - RB_NAME, - nof_bytes, - head_len); + logger->info("%s Cannot build a PDU segment - %d bytes available, %d bytes required for header", + RB_NAME, + nof_bytes, + head_len); return 0; } @@ -947,46 +691,46 @@ int rlc_am_lte::rlc_am_lte_tx::build_segment(uint8_t* payload, uint32_t nof_byte debug_state(); int pdu_len = (ptr - payload) + len; if (pdu_len > static_cast(nof_bytes)) { - logger.error("%s Retx PDU segment length error. Available: %d, Used: %d", RB_NAME, nof_bytes, pdu_len); + logger->error("%s Retx PDU segment length error. Available: %d, Used: %d", RB_NAME, nof_bytes, pdu_len); int header_len = (ptr - payload); - logger.debug("%s Retx PDU segment length error. Actual header len: %d, Payload len: %d, N_li: %d", - RB_NAME, - header_len, - len, - new_header.N_li); + logger->debug("%s Retx PDU segment length error. Actual header len: %d, Payload len: %d, N_li: %d", + RB_NAME, + header_len, + len, + new_header.N_li); } - logger.info(payload, - pdu_len, - "%s Retx PDU segment SN=%d [so=%d] (%d B) (attempt %d/%d)", - RB_NAME, - retx.sn, - retx.so_start, - pdu_len, - tx_window[retx.sn].retx_count + 1, - cfg.max_retx_thresh); + logger->info(payload, + pdu_len, + "%s Retx PDU segment SN=%d [so=%d] (%d B) (attempt %d/%d)", + RB_NAME, + retx.sn, + retx.so_start, + pdu_len, + tx_window[retx.sn].retx_count + 1, + cfg.max_retx_thresh); return pdu_len; } -int rlc_am_lte::rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_bytes) +int rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_bytes) { if (tx_sdu == NULL && tx_sdu_queue.is_empty()) { - logger.info("No data available to be sent"); + logger->info("No data available to be sent"); return 0; } // do not build any more PDU if window is already full if (tx_sdu == NULL && tx_window.size() >= RLC_AM_WINDOW_SIZE) { - logger.info("Tx window full."); + logger->info("Tx window full."); return 0; } if (nof_bytes < RLC_AM_MIN_DATA_PDU_SIZE) { - logger.info("%s Cannot build data PDU - %d bytes available but at least %d bytes are required ", - RB_NAME, - nof_bytes, - RLC_AM_MIN_DATA_PDU_SIZE); + logger->info("%s Cannot build data PDU - %d bytes available but at least %d bytes are required ", + RB_NAME, + nof_bytes, + RLC_AM_MIN_DATA_PDU_SIZE); return 0; } @@ -1003,7 +747,7 @@ int rlc_am_lte::rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_byt } exit(-1); #else - logger.error("Fatal Error: Couldn't allocate PDU in build_data_pdu()."); + logger->error("Fatal Error: Couldn't allocate PDU in build_data_pdu()."); return 0; #endif } @@ -1013,13 +757,13 @@ int rlc_am_lte::rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_byt header.sn = vt_s; if (not segment_pool.has_segments()) { - logger.info("Can't build a PDU - No segments available"); + logger->info("Can't build a PDU - No segments available"); return 0; } // insert newly assigned SN into window and use reference for in-place operations // NOTE: from now on, we can't return from this function anymore before increasing vt_s - rlc_amd_tx_pdu& tx_pdu = tx_window.add_pdu(header.sn); + rlc_amd_tx_pdu_lte& tx_pdu = tx_window.add_pdu(header.sn); uint32_t head_len = rlc_am_packed_length(&header); uint32_t to_move = 0; @@ -1027,7 +771,7 @@ int rlc_am_lte::rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_byt uint32_t pdu_space = SRSRAN_MIN(nof_bytes, pdu->get_tailroom()); uint8_t* pdu_ptr = pdu->msg; - logger.debug("%s Building PDU - pdu_space: %d, head_len: %d ", RB_NAME, pdu_space, head_len); + logger->debug("%s Building PDU - pdu_space: %d, head_len: %d ", RB_NAME, pdu_space, head_len); // Check for SDU segment if (tx_sdu != nullptr) { @@ -1039,18 +783,18 @@ int rlc_am_lte::rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_byt tx_sdu->N_bytes -= to_move; tx_sdu->msg += to_move; if (undelivered_sdu_info_queue.has_pdcp_sn(tx_sdu->md.pdcp_sn)) { - pdcp_pdu_info& pdcp_pdu = undelivered_sdu_info_queue[tx_sdu->md.pdcp_sn]; + pdcp_pdu_info_lte& pdcp_pdu = undelivered_sdu_info_queue[tx_sdu->md.pdcp_sn]; segment_pool.make_segment(tx_pdu, pdcp_pdu); if (tx_sdu->N_bytes == 0) { pdcp_pdu.fully_txed = true; } } else { // PDCP SNs for the RLC SDU has been removed from the queue - logger.warning("Couldn't find PDCP_SN=%d in SDU info queue (segment)", tx_sdu->md.pdcp_sn); + logger->warning("Couldn't find PDCP_SN=%d in SDU info queue (segment)", tx_sdu->md.pdcp_sn); } if (tx_sdu->N_bytes == 0) { - logger.debug("%s Complete SDU scheduled for tx.", RB_NAME); + logger->debug("%s Complete SDU scheduled for tx.", RB_NAME); tx_sdu.reset(); } if (pdu_space > to_move) { @@ -1060,7 +804,7 @@ int rlc_am_lte::rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_byt } header.fi |= RLC_FI_FIELD_NOT_START_ALIGNED; // First byte does not correspond to first byte of SDU - logger.debug( + logger->debug( "%s Building PDU - added SDU segment from previous PDU (len:%d) - pdu_space: %d, head_len: %d header_sn=%d", RB_NAME, to_move, @@ -1072,7 +816,7 @@ int rlc_am_lte::rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_byt // Pull SDUs from queue while (pdu_space > head_len && tx_sdu_queue.get_n_sdus() > 0 && header.N_li < MAX_SDUS_PER_PDU) { if (not segment_pool.has_segments()) { - logger.info("Can't build a PDU segment - No segment resources available"); + logger->info("Can't build a PDU segment - No segment resources available"); if (pdu_ptr != pdu->msg) { break; // continue with the segments created up to this point } @@ -1103,14 +847,14 @@ int rlc_am_lte::rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_byt // store sdu info if (undelivered_sdu_info_queue.has_pdcp_sn(tx_sdu->md.pdcp_sn)) { - logger.warning("PDCP_SN=%d already marked as undelivered", tx_sdu->md.pdcp_sn); + logger->warning("PDCP_SN=%d already marked as undelivered", tx_sdu->md.pdcp_sn); } else { - logger.debug("marking pdcp_sn=%d as undelivered (queue_len=%ld)", - tx_sdu->md.pdcp_sn, - undelivered_sdu_info_queue.nof_sdus()); + logger->debug("marking pdcp_sn=%d as undelivered (queue_len=%ld)", + tx_sdu->md.pdcp_sn, + undelivered_sdu_info_queue.nof_sdus()); undelivered_sdu_info_queue.add_pdcp_sdu(tx_sdu->md.pdcp_sn); } - pdcp_pdu_info& pdcp_pdu = undelivered_sdu_info_queue[tx_sdu->md.pdcp_sn]; + pdcp_pdu_info_lte& pdcp_pdu = undelivered_sdu_info_queue[tx_sdu->md.pdcp_sn]; to_move = ((pdu_space - head_len) >= tx_sdu->N_bytes) ? tx_sdu->N_bytes : pdu_space - head_len; memcpy(pdu_ptr, tx_sdu->msg, to_move); @@ -1125,7 +869,7 @@ int rlc_am_lte::rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_byt } if (tx_sdu->N_bytes == 0) { - logger.debug("%s Complete SDU scheduled for tx. PDCP SN=%d", RB_NAME, tx_sdu->md.pdcp_sn); + logger->debug("%s Complete SDU scheduled for tx. PDCP SN=%d", RB_NAME, tx_sdu->md.pdcp_sn); tx_sdu.reset(); } if (pdu_space > to_move) { @@ -1134,16 +878,16 @@ int rlc_am_lte::rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_byt pdu_space = 0; } - logger.debug("%s Building PDU - added SDU segment (len:%d) - pdu_space: %d, head_len: %d ", - RB_NAME, - to_move, - pdu_space, - head_len); + logger->debug("%s Building PDU - added SDU segment (len:%d) - pdu_space: %d, head_len: %d ", + RB_NAME, + to_move, + pdu_space, + head_len); } // Make sure, at least one SDU (segment) has been added until this point if (pdu->N_bytes == 0) { - logger.error("Generated empty RLC PDU."); + logger->error("Generated empty RLC PDU."); } if (tx_sdu != NULL) { @@ -1153,10 +897,10 @@ int rlc_am_lte::rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_byt // Set Poll bit pdu_without_poll++; byte_without_poll += (pdu->N_bytes + head_len); - logger.debug("%s pdu_without_poll: %d", RB_NAME, pdu_without_poll); - logger.debug("%s byte_without_poll: %d", RB_NAME, byte_without_poll); + logger->debug("%s pdu_without_poll: %d", RB_NAME, pdu_without_poll); + logger->debug("%s byte_without_poll: %d", RB_NAME, byte_without_poll); if (poll_required()) { - logger.debug("%s setting poll bit to request status", RB_NAME); + logger->debug("%s setting poll bit to request status", RB_NAME); header.p = 1; poll_sn = vt_s; pdu_without_poll = 0; @@ -1178,14 +922,14 @@ int rlc_am_lte::rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_byt rlc_am_write_data_pdu_header(&header, &ptr); memcpy(ptr, buffer_ptr->msg, buffer_ptr->N_bytes); int total_len = (ptr - payload) + buffer_ptr->N_bytes; - logger.info(payload, total_len, "%s Tx PDU SN=%d (%d B)", RB_NAME, header.sn, total_len); - log_rlc_amd_pdu_header_to_string(logger.debug, header); + logger->info(payload, total_len, "%s Tx PDU SN=%d (%d B)", RB_NAME, header.sn, total_len); + log_rlc_amd_pdu_header_to_string(logger->debug, header); debug_state(); return total_len; } -void rlc_am_lte::rlc_am_lte_tx::handle_control_pdu(uint8_t* payload, uint32_t nof_bytes) +void rlc_am_lte_tx::handle_control_pdu(uint8_t* payload, uint32_t nof_bytes) { if (not tx_enabled) { return; @@ -1199,27 +943,27 @@ void rlc_am_lte::rlc_am_lte_tx::handle_control_pdu(uint8_t* payload, uint32_t no { std::lock_guard lock(mutex); - logger.debug(payload, nof_bytes, "%s Rx control PDU", RB_NAME); + logger->debug(payload, nof_bytes, "%s Rx control PDU", RB_NAME); rlc_am_read_status_pdu(payload, nof_bytes, &status); - log_rlc_am_status_pdu_to_string(logger.info, "%s Rx Status PDU: %s", &status, RB_NAME); + log_rlc_am_status_pdu_to_string(logger->info, "%s Rx Status PDU: %s", &status, RB_NAME); // make sure ACK_SN is within our Tx window if (((MOD + status.ack_sn - vt_a) % MOD > RLC_AM_WINDOW_SIZE) || ((MOD + vt_s - status.ack_sn) % MOD > RLC_AM_WINDOW_SIZE)) { - logger.warning("%s Received invalid status PDU (ack_sn=%d, vt_a=%d, vt_s=%d). Dropping PDU.", - RB_NAME, - status.ack_sn, - vt_a, - vt_s); + logger->warning("%s Received invalid status PDU (ack_sn=%d, vt_a=%d, vt_s=%d). Dropping PDU.", + RB_NAME, + status.ack_sn, + vt_a, + vt_s); return; } // Sec 5.2.2.2, stop poll reTx timer if status PDU comprises a positive _or_ negative acknowledgement // for the RLC data PDU with sequence number poll_sn if (poll_retx_timer.is_valid() && (TX_MOD_BASE(poll_sn) < TX_MOD_BASE(status.ack_sn))) { - logger.debug("%s Stopping pollRetx timer", RB_NAME); + logger->debug("%s Stopping pollRetx timer", RB_NAME); poll_retx_timer.stop(); } @@ -1260,7 +1004,7 @@ void rlc_am_lte::rlc_am_lte_tx::handle_control_pdu(uint8_t* payload, uint32_t no // sanity check if (status.nacks[j].so_start >= pdu.buf->N_bytes) { // print error but try to send original PDU again - logger.info( + logger->info( "SO_start is larger than original PDU (%d >= %d)", status.nacks[j].so_start, pdu.buf->N_bytes); status.nacks[j].so_start = 0; } @@ -1276,19 +1020,19 @@ void rlc_am_lte::rlc_am_lte_tx::handle_control_pdu(uint8_t* payload, uint32_t no retx.is_segment = true; retx.so_start = status.nacks[j].so_start; } else { - logger.warning("%s invalid segment NACK received for SN %d. so_start: %d, so_end: %d, N_bytes: %d", - RB_NAME, - i, - status.nacks[j].so_start, - status.nacks[j].so_end, - pdu.buf->N_bytes); + logger->warning("%s invalid segment NACK received for SN %d. so_start: %d, so_end: %d, N_bytes: %d", + RB_NAME, + i, + status.nacks[j].so_start, + status.nacks[j].so_end, + pdu.buf->N_bytes); } } } else { - logger.info("%s NACKed SN=%d already considered for retransmission", RB_NAME, i); + logger->info("%s NACKed SN=%d already considered for retransmission", RB_NAME, i); } } else { - logger.error("%s NACKed SN=%d already removed from Tx window", RB_NAME, i); + logger->error("%s NACKed SN=%d already removed from Tx window", RB_NAME, i); } } } @@ -1298,7 +1042,7 @@ void rlc_am_lte::rlc_am_lte_tx::handle_control_pdu(uint8_t* payload, uint32_t no std::lock_guard lock(mutex); if (tx_window.has_sn(i)) { update_notification_ack_info(i); - logger.debug("Tx PDU SN=%zd being removed from tx window", i); + logger->debug("Tx PDU SN=%zd being removed from tx window", i); tx_window.remove_pdu(i); } // Advance window if possible @@ -1314,7 +1058,7 @@ void rlc_am_lte::rlc_am_lte_tx::handle_control_pdu(uint8_t* payload, uint32_t no // Make sure vt_a points to valid SN std::lock_guard lock(mutex); if (not tx_window.empty() && not tx_window.has_sn(vt_a)) { - logger.error("%s vt_a=%d points to invalid position in Tx window.", RB_NAME, vt_a); + logger->error("%s vt_a=%d points to invalid position in Tx window.", RB_NAME, vt_a); parent->rrc->protocol_failure(); } } @@ -1333,12 +1077,12 @@ void rlc_am_lte::rlc_am_lte_tx::handle_control_pdu(uint8_t* payload, uint32_t no * @tx_pdu: RLC PDU that was ack'ed. * @notify_info_vec: Vector which will keep track of the PDCP PDU SNs that have been fully ack'ed. */ -void rlc_am_lte::rlc_am_lte_tx::update_notification_ack_info(uint32_t rlc_sn) +void rlc_am_lte_tx::update_notification_ack_info(uint32_t rlc_sn) { - logger.debug("Updating ACK info: RLC SN=%d, number of notified SDU=%ld, number of undelivered SDUs=%ld", - rlc_sn, - notify_info_vec.size(), - undelivered_sdu_info_queue.nof_sdus()); + logger->debug("Updating ACK info: RLC SN=%d, number of notified SDU=%ld, number of undelivered SDUs=%ld", + rlc_sn, + notify_info_vec.size(), + undelivered_sdu_info_queue.nof_sdus()); // Iterate over all undelivered SDUs if (not tx_window.has_sn(rlc_sn)) { return; @@ -1348,10 +1092,10 @@ void rlc_am_lte::rlc_am_lte_tx::update_notification_ack_info(uint32_t rlc_sn) for (rlc_am_pdu_segment& acked_segment : acked_pdu) { uint32_t pdcp_sn = acked_segment.pdcp_sn(); if (pdcp_sn == rlc_am_pdu_segment::invalid_pdcp_sn) { - logger.debug("ACKed segment in RLC_SN=%d already discarded in PDCP. No need to notify the PDCP.", rlc_sn); + logger->debug("ACKed segment in RLC_SN=%d already discarded in PDCP. No need to notify the PDCP.", rlc_sn); continue; } - pdcp_pdu_info& info = undelivered_sdu_info_queue[pdcp_sn]; + pdcp_pdu_info_lte& info = undelivered_sdu_info_queue[pdcp_sn]; // Remove RLC SN from PDCP PDU undelivered list info.ack_segment(acked_segment); @@ -1362,31 +1106,31 @@ void rlc_am_lte::rlc_am_lte_tx::update_notification_ack_info(uint32_t rlc_sn) if (not notify_info_vec.full()) { notify_info_vec.push_back(pdcp_sn); } else { - logger.warning("Can't notify delivery of PDCP_SN=%d.", pdcp_sn); + logger->warning("Can't notify delivery of PDCP_SN=%d.", pdcp_sn); } - logger.debug("Erasing SDU info: PDCP_SN=%d", pdcp_sn); + logger->debug("Erasing SDU info: PDCP_SN=%d", pdcp_sn); undelivered_sdu_info_queue.clear_pdcp_sdu(pdcp_sn); } } } -void rlc_am_lte::rlc_am_lte_tx::debug_state() +void rlc_am_lte_tx::debug_state() { - logger.debug("%s vt_a = %d, vt_ms = %d, vt_s = %d, poll_sn = %d", RB_NAME, vt_a, vt_ms, vt_s, poll_sn); + logger->debug("%s vt_a = %d, vt_ms = %d, vt_s = %d, poll_sn = %d", RB_NAME, vt_a, vt_ms, vt_s, poll_sn); } -int rlc_am_lte::rlc_am_lte_tx::required_buffer_size(const rlc_amd_retx_t& retx) +int rlc_am_lte_tx::required_buffer_size(const rlc_amd_retx_t& retx) { if (!retx.is_segment) { if (tx_window.has_sn(retx.sn)) { if (tx_window[retx.sn].buf) { return rlc_am_packed_length(&tx_window[retx.sn].header) + tx_window[retx.sn].buf->N_bytes; } else { - logger.warning("retx.sn=%d has null ptr in required_buffer_size()", retx.sn); + logger->warning("retx.sn=%d has null ptr in required_buffer_size()", retx.sn); return -1; } } else { - logger.warning("retx.sn=%d does not exist in required_buffer_size()", retx.sn); + logger->warning("retx.sn=%d does not exist in required_buffer_size()", retx.sn); return -1; } } @@ -1451,24 +1195,21 @@ int rlc_am_lte::rlc_am_lte_tx::required_buffer_size(const rlc_amd_retx_t& retx) /**************************************************************************** * Rx subclass implementation ***************************************************************************/ - -rlc_am_lte::rlc_am_lte_rx::rlc_am_lte_rx(rlc_am_lte* parent_) : +rlc_am_lte_rx::rlc_am_lte_rx(rlc_am* parent_) : parent(parent_), pool(byte_buffer_pool::get_instance()), - logger(parent_->logger), - reordering_timer(parent_->timers->get_unique_timer()) + reordering_timer(parent_->timers->get_unique_timer()), + rlc_am_base_rx(parent_, &parent_->logger) {} -rlc_am_lte::rlc_am_lte_rx::~rlc_am_lte_rx() {} - -bool rlc_am_lte::rlc_am_lte_rx::configure(rlc_am_config_t cfg_) +bool rlc_am_lte_rx::configure(const rlc_config_t& cfg_) { // TODO: add config checks - cfg = cfg_; + cfg = cfg_.am; // check timers if (not reordering_timer.is_valid()) { - logger.error("Configuring RLC AM TX: timers not configured"); + logger->error("Configuring RLC AM TX: timers not configured"); return false; } @@ -1480,12 +1221,12 @@ bool rlc_am_lte::rlc_am_lte_rx::configure(rlc_am_config_t cfg_) return true; } -void rlc_am_lte::rlc_am_lte_rx::reestablish() +void rlc_am_lte_rx::reestablish() { stop(); } -void rlc_am_lte::rlc_am_lte_rx::stop() +void rlc_am_lte_rx::stop() { std::lock_guard lock(mutex); @@ -1511,18 +1252,41 @@ void rlc_am_lte::rlc_am_lte_rx::stop() rx_window.clear(); } +/** Called from stack thread when MAC has received a new RLC PDU + * + * @param payload Pointer to payload + * @param nof_bytes Payload length + */ +void rlc_am_lte_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_bytes) +{ + std::lock_guard lock(mutex); + + rlc_amd_pdu_header_t header = {}; + uint32_t payload_len = nof_bytes; + rlc_am_read_data_pdu_header(&payload, &payload_len, &header); + if (payload_len > nof_bytes) { + logger->info("Dropping corrupted PDU (%d B). Remaining length after header %d B.", nof_bytes, payload_len); + return; + } + if (header.rf != 0) { + handle_data_pdu_segment(payload, payload_len, header); + } else { + handle_data_pdu_full(payload, payload_len, header); + } +} + /** Called from stack thread when MAC has received a new RLC PDU * * @param payload Pointer to payload * @param nof_bytes Payload length * @param header Reference to PDU header (unpacked by caller) */ -void rlc_am_lte::rlc_am_lte_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_bytes, rlc_amd_pdu_header_t& header) +void rlc_am_lte_rx::handle_data_pdu_full(uint8_t* payload, uint32_t nof_bytes, rlc_amd_pdu_header_t& header) { std::map::iterator it; - logger.info(payload, nof_bytes, "%s Rx data PDU SN=%d (%d B)", RB_NAME, header.sn, nof_bytes); - log_rlc_amd_pdu_header_to_string(logger.debug, header); + logger->info(payload, nof_bytes, "%s Rx data PDU SN=%d (%d B)", RB_NAME, header.sn, nof_bytes); + log_rlc_amd_pdu_header_to_string(logger->debug, header); // sanity check for segments not exceeding PDU length if (header.N_li > 0) { @@ -1530,7 +1294,7 @@ void rlc_am_lte::rlc_am_lte_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_b for (uint32_t i = 0; i < header.N_li; i++) { segments_len += header.li[i]; if (segments_len > nof_bytes) { - logger.info("Dropping corrupted PDU (segments_len=%d > pdu_len=%d)", segments_len, nof_bytes); + logger->info("Dropping corrupted PDU (segments_len=%d > pdu_len=%d)", segments_len, nof_bytes); return; } } @@ -1538,19 +1302,19 @@ void rlc_am_lte::rlc_am_lte_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_b if (!inside_rx_window(header.sn)) { if (header.p) { - logger.info("%s Status packet requested through polling bit", RB_NAME); + logger->info("%s Status packet requested through polling bit", RB_NAME); do_status = true; } - logger.info("%s SN=%d outside rx window [%d:%d] - discarding", RB_NAME, header.sn, vr_r, vr_mr); + logger->info("%s SN=%d outside rx window [%d:%d] - discarding", RB_NAME, header.sn, vr_r, vr_mr); return; } if (rx_window.has_sn(header.sn)) { if (header.p) { - logger.info("%s Status packet requested through polling bit", RB_NAME); + logger->info("%s Status packet requested through polling bit", RB_NAME); do_status = true; } - logger.info("%s Discarding duplicate SN=%d", RB_NAME, header.sn); + logger->info("%s Discarding duplicate SN=%d", RB_NAME, header.sn); return; } @@ -1562,7 +1326,7 @@ void rlc_am_lte::rlc_am_lte_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_b srsran::console("Fatal Error: Couldn't allocate PDU in handle_data_pdu().\n"); exit(-1); #else - logger.error("Fatal Error: Couldn't allocate PDU in handle_data_pdu()."); + logger->error("Fatal Error: Couldn't allocate PDU in handle_data_pdu()."); rx_window.remove_pdu(header.sn); return; #endif @@ -1571,11 +1335,11 @@ void rlc_am_lte::rlc_am_lte_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_b // check available space for payload if (nof_bytes > pdu.buf->get_tailroom()) { - logger.error("%s Discarding SN=%d of size %d B (available space %d B)", - RB_NAME, - header.sn, - nof_bytes, - pdu.buf->get_tailroom()); + logger->error("%s Discarding SN=%d of size %d B (available space %d B)", + RB_NAME, + header.sn, + nof_bytes, + pdu.buf->get_tailroom()); return; } memcpy(pdu.buf->msg, payload, nof_bytes); @@ -1594,7 +1358,7 @@ void rlc_am_lte::rlc_am_lte_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_b // Check poll bit if (header.p) { - logger.info("%s Status packet requested through polling bit", RB_NAME); + logger->info("%s Status packet requested through polling bit", RB_NAME); poll_received = true; // 36.322 v10 Section 5.2.3 @@ -1611,21 +1375,21 @@ void rlc_am_lte::rlc_am_lte_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_b if (reordering_timer.is_valid()) { if (reordering_timer.is_running()) { if (vr_x == vr_r || (!inside_rx_window(vr_x) && vr_x != vr_mr)) { - logger.debug("Stopping reordering timer."); + logger->debug("Stopping reordering timer."); reordering_timer.stop(); } else { - logger.debug("Leave reordering timer running."); + logger->debug("Leave reordering timer running."); } debug_state(); } if (not reordering_timer.is_running()) { if (RX_MOD_BASE(vr_h) > RX_MOD_BASE(vr_r)) { - logger.debug("Starting reordering timer."); + logger->debug("Starting reordering timer."); reordering_timer.run(); vr_x = vr_h; } else { - logger.debug("Leave reordering timer stopped."); + logger->debug("Leave reordering timer stopped."); } debug_state(); } @@ -1634,29 +1398,27 @@ void rlc_am_lte::rlc_am_lte_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_b debug_state(); } -void rlc_am_lte::rlc_am_lte_rx::handle_data_pdu_segment(uint8_t* payload, - uint32_t nof_bytes, - rlc_amd_pdu_header_t& header) +void rlc_am_lte_rx::handle_data_pdu_segment(uint8_t* payload, uint32_t nof_bytes, rlc_amd_pdu_header_t& header) { std::map::iterator it; - logger.info(payload, - nof_bytes, - "%s Rx data PDU segment of SN=%d (%d B), SO=%d, N_li=%d", - RB_NAME, - header.sn, - nof_bytes, - header.so, - header.N_li); - log_rlc_amd_pdu_header_to_string(logger.debug, header); + logger->info(payload, + nof_bytes, + "%s Rx data PDU segment of SN=%d (%d B), SO=%d, N_li=%d", + RB_NAME, + header.sn, + nof_bytes, + header.so, + header.N_li); + log_rlc_amd_pdu_header_to_string(logger->debug, header); // Check inside rx window if (!inside_rx_window(header.sn)) { if (header.p) { - logger.info("%s Status packet requested through polling bit", RB_NAME); + logger->info("%s Status packet requested through polling bit", RB_NAME); do_status = true; } - logger.info("%s SN=%d outside rx window [%d:%d] - discarding", RB_NAME, header.sn, vr_r, vr_mr); + logger->info("%s SN=%d outside rx window [%d:%d] - discarding", RB_NAME, header.sn, vr_r, vr_mr); return; } @@ -1667,13 +1429,13 @@ void rlc_am_lte::rlc_am_lte_rx::handle_data_pdu_segment(uint8_t* pa srsran::console("Fatal Error: Couldn't allocate PDU in handle_data_pdu_segment().\n"); exit(-1); #else - logger.error("Fatal Error: Couldn't allocate PDU in handle_data_pdu_segment()."); + logger->error("Fatal Error: Couldn't allocate PDU in handle_data_pdu_segment()."); return; #endif } if (segment.buf->get_tailroom() < nof_bytes) { - logger.info("Dropping corrupted segment SN=%d, not enough space to fit %d B", header.sn, nof_bytes); + logger->info("Dropping corrupted segment SN=%d, not enough space to fit %d B", header.sn, nof_bytes); return; } @@ -1685,7 +1447,7 @@ void rlc_am_lte::rlc_am_lte_rx::handle_data_pdu_segment(uint8_t* pa it = rx_segments.find(header.sn); if (rx_segments.end() != it) { if (header.p) { - logger.info("%s Status packet requested through polling bit", RB_NAME); + logger->info("%s Status packet requested through polling bit", RB_NAME); do_status = true; } @@ -1708,7 +1470,7 @@ void rlc_am_lte::rlc_am_lte_rx::handle_data_pdu_segment(uint8_t* pa // Check poll bit if (header.p) { - logger.info("%s Status packet requested through polling bit", RB_NAME); + logger->info("%s Status packet requested through polling bit", RB_NAME); poll_received = true; // 36.322 v10 Section 5.2.3 @@ -1724,7 +1486,7 @@ void rlc_am_lte::rlc_am_lte_rx::handle_data_pdu_segment(uint8_t* pa debug_state(); } -void rlc_am_lte::rlc_am_lte_rx::reassemble_rx_sdus() +void rlc_am_lte_rx::reassemble_rx_sdus() { uint32_t len = 0; if (rx_sdu == NULL) { @@ -1734,7 +1496,7 @@ void rlc_am_lte::rlc_am_lte_rx::reassemble_rx_sdus() srsran::console("Fatal Error: Could not allocate PDU in reassemble_rx_sdus() (1)\n"); exit(-1); #else - logger.error("Fatal Error: Could not allocate PDU in reassemble_rx_sdus() (1)"); + logger->error("Fatal Error: Could not allocate PDU in reassemble_rx_sdus() (1)"); return; #endif } @@ -1746,13 +1508,13 @@ void rlc_am_lte::rlc_am_lte_rx::reassemble_rx_sdus() for (uint32_t i = 0; i < rx_window[vr_r].header.N_li; i++) { len = rx_window[vr_r].header.li[i]; - logger.debug(rx_window[vr_r].buf->msg, - len, - "Handling segment %d/%d of length %d B of SN=%d", - i + 1, - rx_window[vr_r].header.N_li, - len, - vr_r); + logger->debug(rx_window[vr_r].buf->msg, + len, + "Handling segment %d/%d of length %d B of SN=%d", + i + 1, + rx_window[vr_r].header.N_li, + len, + vr_r); // sanity check to avoid zero-size SDUs if (len == 0) { @@ -1762,7 +1524,7 @@ void rlc_am_lte::rlc_am_lte_rx::reassemble_rx_sdus() if (rx_sdu->get_tailroom() >= len) { if ((rx_window[vr_r].buf->msg - rx_window[vr_r].buf->buffer) + len < SRSRAN_MAX_BUFFER_SIZE_BYTES) { if (rx_window[vr_r].buf->N_bytes < len) { - logger.error("Dropping corrupted SN=%d", vr_r); + logger->error("Dropping corrupted SN=%d", vr_r); rx_sdu.reset(); goto exit; } @@ -1776,7 +1538,7 @@ void rlc_am_lte::rlc_am_lte_rx::reassemble_rx_sdus() rx_window[vr_r].buf->msg += len; rx_window[vr_r].buf->N_bytes -= len; - logger.info(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU (%d B)", RB_NAME, rx_sdu->N_bytes); + logger->info(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU (%d B)", RB_NAME, rx_sdu->N_bytes); sdu_rx_latency_ms.push(std::chrono::duration_cast( std::chrono::high_resolution_clock::now() - rx_sdu->get_timestamp()) .count()); @@ -1792,18 +1554,18 @@ void rlc_am_lte::rlc_am_lte_rx::reassemble_rx_sdus() srsran::console("Fatal Error: Could not allocate PDU in reassemble_rx_sdus() (2)\n"); exit(-1); #else - logger.error("Fatal Error: Could not allocate PDU in reassemble_rx_sdus() (2)"); + logger->error("Fatal Error: Could not allocate PDU in reassemble_rx_sdus() (2)"); return; #endif } } else { int buf_len = rx_window[vr_r].buf->msg - rx_window[vr_r].buf->buffer; - logger.error("Cannot read %d bytes from rx_window. vr_r=%d, msg-buffer=%d B", len, vr_r, buf_len); + logger->error("Cannot read %d bytes from rx_window. vr_r=%d, msg-buffer=%d B", len, vr_r, buf_len); rx_sdu.reset(); goto exit; } } else { - logger.error("Cannot fit RLC PDU in SDU buffer, dropping both."); + logger->error("Cannot fit RLC PDU in SDU buffer, dropping both."); rx_sdu.reset(); goto exit; } @@ -1811,7 +1573,7 @@ void rlc_am_lte::rlc_am_lte_rx::reassemble_rx_sdus() // Handle last segment len = rx_window[vr_r].buf->N_bytes; - logger.debug(rx_window[vr_r].buf->msg, len, "Handling last segment of length %d B of SN=%d", len, vr_r); + logger->debug(rx_window[vr_r].buf->msg, len, "Handling last segment of length %d B of SN=%d", len, vr_r); if (rx_sdu->get_tailroom() >= len) { // store timestamp of the first segment when starting to assemble SDUs if (rx_sdu->N_bytes == 0) { @@ -1829,7 +1591,7 @@ void rlc_am_lte::rlc_am_lte_rx::reassemble_rx_sdus() } if (rlc_am_end_aligned(rx_window[vr_r].header.fi)) { - logger.info(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU (%d B)", RB_NAME, rx_sdu->N_bytes); + logger->info(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU (%d B)", RB_NAME, rx_sdu->N_bytes); sdu_rx_latency_ms.push(std::chrono::duration_cast( std::chrono::high_resolution_clock::now() - rx_sdu->get_timestamp()) .count()); @@ -1845,7 +1607,7 @@ void rlc_am_lte::rlc_am_lte_rx::reassemble_rx_sdus() srsran::console("Fatal Error: Could not allocate PDU in reassemble_rx_sdus() (3)\n"); exit(-1); #else - logger.error("Fatal Error: Could not allocate PDU in reassemble_rx_sdus() (3)"); + logger->error("Fatal Error: Could not allocate PDU in reassemble_rx_sdus() (3)"); return; #endif } @@ -1853,19 +1615,19 @@ void rlc_am_lte::rlc_am_lte_rx::reassemble_rx_sdus() exit: // Move the rx_window - logger.debug("Erasing SN=%d.", vr_r); + logger->debug("Erasing SN=%d.", vr_r); // also erase any segments of this SN std::map::iterator it; it = rx_segments.find(vr_r); if (rx_segments.end() != it) { - logger.debug("Erasing segments of SN=%d", vr_r); + logger->debug("Erasing segments of SN=%d", vr_r); std::list::iterator segit; for (segit = it->second.segments.begin(); segit != it->second.segments.end(); ++segit) { - logger.debug(" Erasing segment of SN=%d SO=%d Len=%d N_li=%d", - segit->header.sn, - segit->header.so, - segit->buf->N_bytes, - segit->header.N_li); + logger->debug(" Erasing segment of SN=%d SO=%d Len=%d N_li=%d", + segit->header.sn, + segit->header.so, + segit->buf->N_bytes, + segit->header.N_li); } it->second.segments.clear(); } @@ -1875,49 +1637,24 @@ void rlc_am_lte::rlc_am_lte_rx::reassemble_rx_sdus() } } -void rlc_am_lte::rlc_am_lte_rx::reset_status() +void rlc_am_lte_rx::reset_status() { do_status = false; poll_received = false; } -bool rlc_am_lte::rlc_am_lte_rx::get_do_status() +bool rlc_am_lte_rx::get_do_status() { return do_status.load(std::memory_order_relaxed); } -void rlc_am_lte::rlc_am_lte_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.handle_control_pdu(payload, nof_bytes); - } else { - std::lock_guard lock(mutex); - rlc_amd_pdu_header_t header = {}; - uint32_t payload_len = nof_bytes; - rlc_am_read_data_pdu_header(&payload, &payload_len, &header); - if (payload_len > nof_bytes) { - logger.info("Dropping corrupted PDU (%d B). Remaining length after header %d B.", nof_bytes, payload_len); - return; - } - if (header.rf) { - handle_data_pdu_segment(payload, payload_len, header); - } else { - handle_data_pdu(payload, payload_len, header); - } - } -} - -uint32_t rlc_am_lte::rlc_am_lte_rx::get_rx_buffered_bytes() +uint32_t rlc_am_lte_rx::get_rx_buffered_bytes() { std::lock_guard lock(mutex); return rx_window.get_buffered_bytes(); } -uint32_t rlc_am_lte::rlc_am_lte_rx::get_sdu_rx_latency_ms() +uint32_t rlc_am_lte_rx::get_sdu_rx_latency_ms() { std::lock_guard lock(mutex); return sdu_rx_latency_ms.value(); @@ -1928,11 +1665,11 @@ uint32_t rlc_am_lte::rlc_am_lte_rx::get_sdu_rx_latency_ms() * * @param timeout_id */ -void rlc_am_lte::rlc_am_lte_rx::timer_expired(uint32_t timeout_id) +void rlc_am_lte_rx::timer_expired(uint32_t timeout_id) { std::lock_guard lock(mutex); if (reordering_timer.is_valid() and reordering_timer.id() == timeout_id) { - logger.debug("%s reordering timeout expiry - updating vr_ms (was %d)", RB_NAME, vr_ms); + logger->debug("%s reordering timeout expiry - updating vr_ms (was %d)", RB_NAME, vr_ms); // 36.322 v10 Section 5.1.3.2.4 vr_ms = vr_x; @@ -1955,7 +1692,7 @@ void rlc_am_lte::rlc_am_lte_rx::timer_expired(uint32_t timeout_id) // Called from Tx object to pack status PDU that doesn't exceed a given size // If lock-acquisition fails, return -1. Otherwise it returns the length of the generated PDU. -int rlc_am_lte::rlc_am_lte_rx::get_status_pdu(rlc_status_pdu_t* status, const uint32_t max_pdu_size) +int rlc_am_lte_rx::get_status_pdu(rlc_status_pdu_t* status, const uint32_t max_pdu_size) { std::unique_lock lock(mutex, std::try_to_lock); if (not lock.owns_lock()) { @@ -1978,22 +1715,23 @@ int rlc_am_lte::rlc_am_lte_rx::get_status_pdu(rlc_status_pdu_t* status, const ui // make sure we don't exceed grant size if (rlc_am_packed_length(status) > max_pdu_size) { - logger.debug("Status PDU too big (%d > %d)", rlc_am_packed_length(status), max_pdu_size); + logger->debug("Status PDU too big (%d > %d)", rlc_am_packed_length(status), max_pdu_size); if (status->N_nack >= 1 && status->N_nack < RLC_AM_WINDOW_SIZE) { - logger.debug("Removing last NACK SN=%d", status->nacks[status->N_nack].nack_sn); + logger->debug("Removing last NACK SN=%d", status->nacks[status->N_nack].nack_sn); status->N_nack--; // make sure we don't have the current ACK_SN in the NACK list if (rlc_am_is_valid_status_pdu(*status, vr_r) == false) { // No space to send any NACKs, play safe and just ack lower edge - logger.warning("Resetting ACK_SN and N_nack to initial state"); + logger->warning("Resetting ACK_SN and N_nack to initial state"); status->ack_sn = vr_r; status->N_nack = 0; } } else { - logger.warning("Failed to generate small enough status PDU (packed_len=%d, max_pdu_size=%d, status->N_nack=%d)", - rlc_am_packed_length(status), - max_pdu_size, - status->N_nack); + logger->warning( + "Failed to generate small enough status PDU (packed_len=%d, max_pdu_size=%d, status->N_nack=%d)", + rlc_am_packed_length(status), + max_pdu_size, + status->N_nack); return 0; } break; @@ -2008,7 +1746,7 @@ int rlc_am_lte::rlc_am_lte_rx::get_status_pdu(rlc_status_pdu_t* status, const ui } // Called from Tx object to obtain length of the full status PDU -int rlc_am_lte::rlc_am_lte_rx::get_status_pdu_length() +int rlc_am_lte_rx::get_status_pdu_length() { std::unique_lock lock(mutex, std::try_to_lock); if (not lock.owns_lock()) { @@ -2026,7 +1764,7 @@ int rlc_am_lte::rlc_am_lte_rx::get_status_pdu_length() return rlc_am_packed_length(&status); } -void rlc_am_lte::rlc_am_lte_rx::print_rx_segments() +void rlc_am_lte_rx::print_rx_segments() { std::map::iterator it; std::stringstream ss; @@ -2038,11 +1776,11 @@ void rlc_am_lte::rlc_am_lte_rx::print_rx_segments() << " N_li: " << segit->header.N_li << std::endl; } } - logger.debug("%s", ss.str().c_str()); + logger->debug("%s", ss.str().c_str()); } // NOTE: Preference would be to capture by value, and then move; but header is stack allocated -bool rlc_am_lte::rlc_am_lte_rx::add_segment_and_check(rlc_amd_rx_pdu_segments_t* pdu, rlc_amd_rx_pdu* segment) +bool rlc_am_lte_rx::add_segment_and_check(rlc_amd_rx_pdu_segments_t* pdu, rlc_amd_rx_pdu* segment) { // Find segment insertion point in the list of segments auto it1 = pdu->segments.begin(); @@ -2112,7 +1850,7 @@ bool rlc_am_lte::rlc_am_lte_rx::add_segment_and_check(rlc_amd_rx_pdu_segments_t* header.fi |= (pdu->segments.front().header.fi & RLC_FI_FIELD_NOT_START_ALIGNED); header.fi |= (pdu->segments.back().header.fi & RLC_FI_FIELD_NOT_END_ALIGNED); - logger.debug("Starting header reconstruction of %zd segments", pdu->segments.size()); + logger->debug("Starting header reconstruction of %zd segments", pdu->segments.size()); // Reconstruct li fields uint16_t count = 0; @@ -2120,7 +1858,7 @@ bool rlc_am_lte::rlc_am_lte_rx::add_segment_and_check(rlc_amd_rx_pdu_segments_t* uint16_t consumed_bytes = 0; // rolling sum of all allocated LIs during segment reconstruction for (it = pdu->segments.begin(); it != pdu->segments.end(); ++it) { - logger.debug(" Handling %d PDU segments", it->header.N_li); + logger->debug(" Handling %d PDU segments", it->header.N_li); for (uint32_t i = 0; i < it->header.N_li; i++) { // variable marks total offset of each _processed_ LI of this segment uint32_t total_pdu_offset = it->header.so; @@ -2128,28 +1866,28 @@ bool rlc_am_lte::rlc_am_lte_rx::add_segment_and_check(rlc_amd_rx_pdu_segments_t* total_pdu_offset += it->header.li[k]; } - logger.debug(" - (total_pdu_offset=%d, consumed_bytes=%d, header.li[i]=%d)", - total_pdu_offset, - consumed_bytes, - header.li[i]); + logger->debug(" - (total_pdu_offset=%d, consumed_bytes=%d, header.li[i]=%d)", + total_pdu_offset, + consumed_bytes, + header.li[i]); if (total_pdu_offset > header.li[i] && total_pdu_offset > consumed_bytes) { header.li[header.N_li] = total_pdu_offset - consumed_bytes; consumed_bytes = total_pdu_offset; - logger.debug(" - adding segment %d/%d (%d B, SO=%d, carryover=%d, count=%d)", - i + 1, - it->header.N_li, - header.li[header.N_li], - header.so, - carryover, - count); + logger->debug(" - adding segment %d/%d (%d B, SO=%d, carryover=%d, count=%d)", + i + 1, + it->header.N_li, + header.li[header.N_li], + header.so, + carryover, + count); header.N_li++; count += it->header.li[i]; carryover = 0; } else { - logger.debug(" - Skipping segment in reTx PDU segment which is already included (%d B, SO=%d)", - it->header.li[i], - header.so); + logger->debug(" - Skipping segment in reTx PDU segment which is already included (%d B, SO=%d)", + it->header.li[i], + header.so); } } @@ -2159,24 +1897,24 @@ bool rlc_am_lte::rlc_am_lte_rx::add_segment_and_check(rlc_amd_rx_pdu_segments_t* for (uint32_t k = 0; k < header.N_li; ++k) { carryover -= header.li[k]; } - logger.debug("Incremented carryover (it->buf->N_bytes=%d, count=%d). New carryover=%d", - it->buf->N_bytes, - count, - carryover); + logger->debug("Incremented carryover (it->buf->N_bytes=%d, count=%d). New carryover=%d", + it->buf->N_bytes, + count, + carryover); } else { // Next segment would be too long, recalculate carryover header.N_li--; carryover = it->buf->N_bytes - (count - header.li[header.N_li]); - logger.debug("Recalculated carryover=%d (it->buf->N_bytes=%d, count=%d, header.li[header.N_li]=%d)", - carryover, - it->buf->N_bytes, - count, - header.li[header.N_li]); + logger->debug("Recalculated carryover=%d (it->buf->N_bytes=%d, count=%d, header.li[header.N_li]=%d)", + carryover, + it->buf->N_bytes, + count, + header.li[header.N_li]); } tmpit = it; if (rlc_am_end_aligned(it->header.fi) && ++tmpit != pdu->segments.end()) { - logger.debug("Header is end-aligned, overwrite header.li[%d]=%d", header.N_li, carryover); + logger->debug("Header is end-aligned, overwrite header.li[%d]=%d", header.N_li, carryover); header.li[header.N_li] = carryover; header.N_li++; consumed_bytes += carryover; @@ -2188,7 +1926,7 @@ bool rlc_am_lte::rlc_am_lte_rx::add_segment_and_check(rlc_amd_rx_pdu_segments_t* header.p |= it->header.p; } - logger.debug("Finished header reconstruction of %zd segments", pdu->segments.size()); + logger->debug("Finished header reconstruction of %zd segments", pdu->segments.size()); // Copy data unique_byte_buffer_t full_pdu = srsran::make_byte_buffer(); @@ -2197,7 +1935,7 @@ bool rlc_am_lte::rlc_am_lte_rx::add_segment_and_check(rlc_amd_rx_pdu_segments_t* srsran::console("Fatal Error: Could not allocate PDU in add_segment_and_check()\n"); exit(-1); #else - logger.error("Fatal Error: Could not allocate PDU in add_segment_and_check()"); + logger->error("Fatal Error: Could not allocate PDU in add_segment_and_check()"); return false; #endif } @@ -2218,11 +1956,11 @@ bool rlc_am_lte::rlc_am_lte_rx::add_segment_and_check(rlc_amd_rx_pdu_segments_t* full_pdu->N_bytes += n; } - handle_data_pdu(full_pdu->msg, full_pdu->N_bytes, header); + handle_data_pdu_full(full_pdu->msg, full_pdu->N_bytes, header); return true; } -bool rlc_am_lte::rlc_am_lte_rx::inside_rx_window(const int16_t sn) +bool rlc_am_lte_rx::inside_rx_window(const int16_t sn) { if (RX_MOD_BASE(sn) >= RX_MOD_BASE(static_cast(vr_r)) && RX_MOD_BASE(sn) < RX_MOD_BASE(vr_mr)) { return true; @@ -2231,9 +1969,9 @@ bool rlc_am_lte::rlc_am_lte_rx::inside_rx_window(const int16_t sn) } } -void rlc_am_lte::rlc_am_lte_rx::debug_state() +void rlc_am_lte_rx::debug_state() { - logger.debug("%s vr_r = %d, vr_mr = %d, vr_x = %d, vr_ms = %d, vr_h = %d", RB_NAME, vr_r, vr_mr, vr_x, vr_ms, vr_h); + logger->debug("%s vr_r = %d, vr_mr = %d, vr_x = %d, vr_ms = %d, vr_h = %d", RB_NAME, vr_r, vr_mr, vr_x, vr_ms, vr_h); } } // namespace srsran diff --git a/lib/src/rlc/rlc_am_lte_packing.cc b/lib/src/rlc/rlc_am_lte_packing.cc index 3c5820478..5c1d1baa8 100644 --- a/lib/src/rlc/rlc_am_lte_packing.cc +++ b/lib/src/rlc/rlc_am_lte_packing.cc @@ -285,7 +285,8 @@ bool rlc_am_is_valid_status_pdu(const rlc_status_pdu_t& status, uint32_t rx_win_ return true; } -void rlc_am_undelivered_sdu_info_to_string(fmt::memory_buffer& buffer, const std::vector& info_queue) +void rlc_am_undelivered_sdu_info_to_string(fmt::memory_buffer& buffer, + const std::vector >& info_queue) { fmt::format_to(buffer, "\n"); for (const auto& pdcp_pdu : info_queue) { diff --git a/lib/src/rlc/rlc_am_nr.cc b/lib/src/rlc/rlc_am_nr.cc index 42cd7abf0..55b750d77 100644 --- a/lib/src/rlc/rlc_am_nr.cc +++ b/lib/src/rlc/rlc_am_nr.cc @@ -28,138 +28,20 @@ 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 ***************************************************************************/ - -bool rlc_am_nr::has_data() -{ - return tx.has_data(); -} - -uint32_t rlc_am_nr::get_buffer_state() +rlc_am_nr_tx::rlc_am_nr_tx(rlc_am* parent_) : parent(parent_), rlc_am_base_tx(&parent_->logger) { - 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) -{ - // 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_) +bool rlc_am_nr_tx::configure(const rlc_config_t& cfg_) { /* 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; } */ - cfg = cfg_; + cfg = cfg_.am; 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 ***************************************************************************/ -rlc_am_nr::rlc_am_nr_rx::rlc_am_nr_rx(rlc_am_nr* parent_) : - parent(parent_), pool(byte_buffer_pool::get_instance()), logger(parent_->logger) -{} +rlc_am_nr_rx::rlc_am_nr_rx(rlc_am* parent_) : + 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; } -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 diff --git a/lib/src/rlc/rlc_tm.cc b/lib/src/rlc/rlc_tm.cc index 219ca36b1..0cfd9e3e6 100644 --- a/lib/src/rlc/rlc_tm.cc +++ b/lib/src/rlc/rlc_tm.cc @@ -73,7 +73,7 @@ rlc_mode_t rlc_tm::get_mode() return rlc_mode_t::tm; } -uint32_t rlc_tm::get_bearer() +uint32_t rlc_tm::get_lcid() { return lcid; } diff --git a/lib/src/rlc/rlc_um_base.cc b/lib/src/rlc/rlc_um_base.cc index faaf08ab3..e3256ce87 100644 --- a/lib/src/rlc/rlc_um_base.cc +++ b/lib/src/rlc/rlc_um_base.cc @@ -51,7 +51,7 @@ rlc_mode_t rlc_um_base::get_mode() return rlc_mode_t::um; } -uint32_t rlc_um_base::get_bearer() +uint32_t rlc_um_base::get_lcid() { return lcid; } diff --git a/lib/src/rlc/rlc_um_nr.cc b/lib/src/rlc/rlc_um_nr.cc index 39eea94fe..5c746b68d 100644 --- a/lib/src/rlc/rlc_um_nr.cc +++ b/lib/src/rlc/rlc_um_nr.cc @@ -313,9 +313,10 @@ void rlc_um_nr::rlc_um_nr_rx::timer_expired(uint32_t timeout_id) { std::lock_guard lock(mutex); 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++; 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 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); } else { ++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) || ((RX_MOD_NR_BASE(RX_Next_Highest) == RX_MOD_NR_BASE(RX_Next_Reassembly + 1) && 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(); 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) { if (rx_window.find(sn) != rx_window.end()) { + bool sdu_complete = false; + // iterate over received segments and try to assemble full SDU auto& pdu = rx_window.at(sn); 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); if (pdu.next_expected_so == pdu.total_sdu_length) { - // deliver full SDU to upper layers - logger.info("Delivering %s SDU SN=%d (%d B)", rb_name.c_str(), sn, pdu.sdu->N_bytes); - pdcp->write_pdu(lcid, std::move(pdu.sdu)); - - // 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; + // entire SDU has been received, it will be passed up the stack outside the loop + sdu_complete = true; + break; } } } 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 (not sn_in_reassembly_window(sn)) { - // update RX_Next_highest - RX_Next_Highest = sn + 1; + if (sdu_complete) { + // deliver full SDU to upper layers + logger.info("%s Rx SDU (%d B)", rb_name.c_str(), pdu.sdu->N_bytes); + 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); // 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) { if (rx_pdu.first >= RX_MOD_NR_BASE(RX_Next_Highest - UM_Window_Size)) { 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; } } } + } - if (reassembly_timer.is_running()) { - if (RX_Timer_Trigger <= RX_Next_Reassembly || - (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))) { - reassembly_timer.stop(); - } + if (reassembly_timer.is_running()) { + if (RX_Timer_Trigger <= RX_Next_Reassembly || + (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(RX_Next_Reassembly))) { + 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 (RX_Next_Highest > RX_Next_Reassembly + 1) { - reassembly_timer.run(); - RX_Timer_Trigger = RX_Next_Highest; - } + if (not reassembly_timer.is_running()) { + 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)) && + 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 { - 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) { 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", - rb_name.c_str(), - rx_pdu.header.sn, - pdu_segments.total_sdu_length); + logger.debug("%s updating total SDU length for SN=%d to %d B", + rb_name.c_str(), + rx_pdu.header.sn, + 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_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 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); // 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)); } else if (sn_invalid_for_rx_buffer(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 if (rx_window.find(header.sn) == rx_window.end()) { // first received segment of this SN, add to rx buffer - logger.info(rx_pdu.buf->msg, - rx_pdu.buf->N_bytes, - "%s placing %s segment of SN=%d (%d B) in Rx buffer", - rb_name.c_str(), - to_string_short(header.si).c_str(), - header.sn, - rx_pdu.buf->N_bytes); + logger.debug(rx_pdu.buf->msg, + rx_pdu.buf->N_bytes, + "%s placing %s segment of SN=%d (%d B) in Rx buffer", + rb_name.c_str(), + to_string_short(header.si).c_str(), + header.sn, + rx_pdu.buf->N_bytes); rlc_umd_pdu_segments_nr_t pdu_segments = {}; update_total_sdu_length(pdu_segments, rx_pdu); pdu_segments.segments.emplace(header.so, std::move(rx_pdu)); rx_window[header.sn] = std::move(pdu_segments); } else { // other segment for this SN already present, update received data - logger.info("%s updating SN=%d at SO=%d with %d B", - rb_name.c_str(), - rx_pdu.header.sn, - rx_pdu.header.so, - rx_pdu.buf->N_bytes); + logger.debug(rx_pdu.buf->msg, + rx_pdu.buf->N_bytes, + "%s updating SN=%d at SO=%d with %d B", + rb_name.c_str(), + rx_pdu.header.sn, + rx_pdu.header.so, + rx_pdu.buf->N_bytes); auto& pdu_segments = rx_window.at(header.sn); diff --git a/lib/src/rrc/CMakeLists.txt b/lib/src/rrc/CMakeLists.txt deleted file mode 100644 index d7f27f4f5..000000000 --- a/lib/src/rrc/CMakeLists.txt +++ /dev/null @@ -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}) diff --git a/lib/src/rrc/nr/rrc_nr_cfg_utils.cc b/lib/src/rrc/nr/rrc_nr_cfg_utils.cc deleted file mode 100644 index 040f1eaa0..000000000 --- a/lib/src/rrc/nr/rrc_nr_cfg_utils.cc +++ /dev/null @@ -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 diff --git a/lib/test/rlc/rlc_am_lte_test.cc b/lib/test/rlc/rlc_am_lte_test.cc index 0d7f433cf..542547f4f 100644 --- a/lib/test/rlc/rlc_am_lte_test.cc +++ b/lib/test/rlc/rlc_am_lte_test.cc @@ -38,7 +38,7 @@ using namespace srsran; class ul_writer : public thread { 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(); } void stop() { @@ -74,11 +74,11 @@ private: running = false; } - rlc_am_lte* rlc = nullptr; + rlc_am* rlc = nullptr; std::atomic 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 unique_byte_buffer_t sdu_bufs[NBUFS]; @@ -109,8 +109,8 @@ int basic_test() timer_handler timers(8); byte_buffer_t pdu_bufs[NBUFS]; - rlc_am_lte rlc1(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 rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 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 TESTASSERT(0 == rlc1.get_buffer_state()); @@ -167,8 +167,8 @@ int concat_test() rlc_am_tester tester; srsran::timer_handler timers(8); - rlc_am_lte rlc1(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 rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 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())) { return -1; @@ -242,8 +242,8 @@ int segment_test(bool in_seq_rx) srsran::timer_handler timers(8); int len = 0; - rlc_am_lte rlc1(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 rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 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())) { return -1; @@ -337,8 +337,8 @@ int retx_test() timer_handler timers(8); int len = 0; - rlc_am_lte rlc1(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 rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 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())) { return -1; @@ -473,7 +473,7 @@ int max_retx_test() timer_handler timers(8); 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(); if (not rlc1.configure(rlc_cfg)) { @@ -536,8 +536,8 @@ int segment_retx_test() timer_handler timers(8); int len = 0; - rlc_am_lte rlc1(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 rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 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())) { return -1; @@ -661,8 +661,8 @@ int resegment_test_1() timer_handler timers(8); int len = 0; - rlc_am_lte rlc1(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 rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 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())) { return -1; @@ -818,8 +818,8 @@ int resegment_test_2() rlc_am_tester tester; timer_handler timers(8); - rlc_am_lte rlc1(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 rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 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())) { return -1; @@ -950,8 +950,8 @@ int resegment_test_3() rlc_am_tester tester; srsran::timer_handler timers(8); - rlc_am_lte rlc1(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 rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 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())) { return -1; @@ -1080,8 +1080,8 @@ int resegment_test_4() rlc_am_tester tester; srsran::timer_handler timers(8); - rlc_am_lte rlc1(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 rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 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())) { return -1; @@ -1212,8 +1212,8 @@ int resegment_test_5() rlc_am_tester tester; srsran::timer_handler timers(8); - rlc_am_lte rlc1(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 rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 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())) { return -1; @@ -1339,8 +1339,8 @@ int resegment_test_6() srsran::timer_handler timers(8); int len = 0; - rlc_am_lte rlc1(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 rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 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())) { return -1; @@ -1508,8 +1508,8 @@ int resegment_test_7() #endif srsran::timer_handler timers(8); - rlc_am_lte rlc1(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 rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 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())) { return -1; @@ -1693,8 +1693,8 @@ int resegment_test_8() #endif srsran::timer_handler timers(8); - rlc_am_lte rlc1(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 rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 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())) { return -1; @@ -1845,8 +1845,8 @@ int resegment_test_9() #endif srsran::timer_handler timers(8); - rlc_am_lte rlc1(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 rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 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)) { return SRSRAN_ERROR; @@ -1987,8 +1987,8 @@ int resegment_test_10() #endif srsran::timer_handler timers(8); - rlc_am_lte rlc1(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 rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 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)) { return SRSRAN_ERROR; @@ -2136,8 +2136,8 @@ int resegment_test_11() #endif srsran::timer_handler timers(8); - rlc_am_lte rlc1(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 rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 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)) { return SRSRAN_ERROR; @@ -2294,8 +2294,8 @@ int resegment_test_12() #endif srsran::timer_handler timers(8); - rlc_am_lte rlc1(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 rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 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)) { return SRSRAN_ERROR; @@ -2438,7 +2438,7 @@ int header_reconstruction_test(srsran::log_sink_message_spy& spy) #endif 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())) { return -1; @@ -2501,7 +2501,7 @@ int header_reconstruction_test2(srsran::log_sink_message_spy& spy) #endif 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())) { return -1; } @@ -2565,7 +2565,7 @@ int header_reconstruction_test3(srsran::log_sink_message_spy& spy) srsran::timer_handler timers(8); // 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())) { return -1; } @@ -2651,7 +2651,7 @@ int header_reconstruction_test4(srsran::log_sink_message_spy& spy) srsran::timer_handler timers(8); // 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())) { return -1; } @@ -2728,7 +2728,7 @@ int header_reconstruction_test5(srsran::log_sink_message_spy& spy) srsran::timer_handler timers(8); // 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())) { return -1; } @@ -2807,7 +2807,7 @@ int header_reconstruction_test6(srsran::log_sink_message_spy& spy) srsran::timer_handler timers(8); // 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())) { return -1; } @@ -2906,7 +2906,7 @@ int header_reconstruction_test7(srsran::log_sink_message_spy& spy) srsran::timer_handler timers(8); // 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())) { return -1; } @@ -3008,7 +3008,7 @@ int header_reconstruction_test8(srsran::log_sink_message_spy& spy) srsran::timer_handler timers(8); // 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())) { return -1; } @@ -3039,7 +3039,7 @@ bool reset_test() srsran::timer_handler timers(8); 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())) { return -1; @@ -3081,7 +3081,7 @@ bool resume_test() srsran::timer_handler timers(8); 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())) { return -1; @@ -3122,7 +3122,7 @@ bool stop_test() rlc_am_tester tester; 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())) { return -1; @@ -3149,8 +3149,8 @@ bool status_pdu_test() srsran::timer_handler timers(8); int len = 0; - rlc_am_lte rlc1(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 rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 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())) { return -1; @@ -3258,8 +3258,8 @@ bool incorrect_status_pdu_test() srsran::timer_handler timers(8); int len = 0; - rlc_am_lte rlc1(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 rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 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())) { return -1; @@ -3323,8 +3323,8 @@ bool incorrect_status_pdu_test2() srsran::timer_handler timers(8); int len = 0; - rlc_am_lte rlc1(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 rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 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())) { return -1; @@ -3437,8 +3437,8 @@ bool reestablish_test() srsran::timer_handler timers(8); - rlc_am_lte rlc1(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 rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 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_2").set_hex_dump_max_size(100); @@ -3557,8 +3557,8 @@ bool discard_test() srsran::timer_handler timers(8); - rlc_am_lte rlc1(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 rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 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_2").set_hex_dump_max_size(100); diff --git a/lib/test/rlc/rlc_am_nr_test.cc b/lib/test/rlc/rlc_am_nr_test.cc index 16f3833a7..866b76202 100644 --- a/lib/test/rlc/rlc_am_nr_test.cc +++ b/lib/test/rlc/rlc_am_nr_test.cc @@ -35,7 +35,7 @@ using namespace srsue; 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 unique_byte_buffer_t sdu_bufs[NBUFS]; @@ -66,8 +66,8 @@ int basic_test() timer_handler timers(8); byte_buffer_t pdu_bufs[NBUFS]; - rlc_am_nr rlc1(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 rlc1(srsran_rat_t::nr, srslog::fetch_basic_logger("RLC_AM_1"), 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 TESTASSERT(0 == rlc1.get_buffer_state()); diff --git a/lib/test/rlc/rlc_um_nr_test.cc b/lib/test/rlc/rlc_um_nr_test.cc index 08f9ad721..80a4e5506 100644 --- a/lib/test/rlc/rlc_um_nr_test.cc +++ b/lib/test/rlc/rlc_um_nr_test.cc @@ -561,7 +561,7 @@ int rlc_um_nr_test8() 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() { rlc_um_nr_test_context1 ctxt; @@ -621,6 +621,8 @@ int rlc_um_nr_test9() TESTASSERT(*(ctxt.tester.sdus[i]->msg) == i); } + TESTASSERT(ctxt.timers.nof_running_timers() == 0); + return SRSRAN_SUCCESS; } @@ -676,13 +678,10 @@ int main(int argc, char** argv) return SRSRAN_ERROR; } -// temporarily disabling -#if 0 if (rlc_um_nr_test9()) { fprintf(stderr, "rlc_um_nr_test9() failed.\n"); return SRSRAN_ERROR; } -#endif #if PCAP pcap_handle->close(); diff --git a/srsenb/enb.conf.example b/srsenb/enb.conf.example index 61f1d95f0..ee7ec0fe8 100644 --- a/srsenb/enb.conf.example +++ b/srsenb/enb.conf.example @@ -361,6 +361,7 @@ enable = false # 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_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] @@ -397,3 +398,4 @@ enable = false #ts1_reloc_overall_timeout = 10000 #rlf_release_timer_ms = 4000 #rlf_min_ul_snr_estim = -2 +#s1_setup_max_retries = -1 diff --git a/srsenb/hdr/metrics_csv.h b/srsenb/hdr/metrics_csv.h index 3b5fa2ec1..84ecce117 100644 --- a/srsenb/hdr/metrics_csv.h +++ b/srsenb/hdr/metrics_csv.h @@ -41,11 +41,10 @@ namespace srsenb { class metrics_csv : public srsran::metrics_listener { public: - metrics_csv(std::string filename); + metrics_csv(std::string filename, enb_metrics_interface* enb_); ~metrics_csv(); void set_metrics(const enb_metrics_t& m, const uint32_t period_usec); - void set_handle(enb_metrics_interface* enb_); void stop(); private: diff --git a/srsenb/hdr/phy/phy_common.h b/srsenb/hdr/phy/phy_common.h index db03829d4..f590ff06d 100644 --- a/srsenb/hdr/phy/phy_common.h +++ b/srsenb/hdr/phy/phy_common.h @@ -100,8 +100,8 @@ public: if (cc_idx < cell_list_lte.size()) { ret = cell_list_lte[cc_idx].cell.nof_ports; - } else if (cc_idx == 1 && !cell_list_nr.empty()) { - // one RF port for basic NSA config + } else if ((cc_idx == 0 || cc_idx == 1) && !cell_list_nr.empty()) { + // one RF port for basic NSA/SA config ret = 1; } diff --git a/srsenb/hdr/phy/phy_metrics.h b/srsenb/hdr/phy/phy_metrics.h index 8307f55bb..cca2344ab 100644 --- a/srsenb/hdr/phy/phy_metrics.h +++ b/srsenb/hdr/phy/phy_metrics.h @@ -22,6 +22,8 @@ #ifndef SRSENB_PHY_METRICS_H #define SRSENB_PHY_METRICS_H +#include + namespace srsenb { // PHY metrics per user @@ -29,7 +31,15 @@ namespace srsenb { struct ul_metrics_t { float n; float pusch_sinr; - float pucch_sinr; + // Initialize this member with an invalid value as this field is optional. + float pusch_rssi = std::numeric_limits::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::quiet_NaN(); + // Initialize this member with an invalid value as this field is optional. + float pucch_ni = std::numeric_limits::quiet_NaN(); float rssi; float turbo_iters; float mcs; @@ -39,7 +49,9 @@ struct ul_metrics_t { struct dl_metrics_t { 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 { diff --git a/srsenb/hdr/stack/mac/common/mac_metrics.h b/srsenb/hdr/stack/mac/common/mac_metrics.h index 9c55ccc06..7300a1caf 100644 --- a/srsenb/hdr/stack/mac/common/mac_metrics.h +++ b/srsenb/hdr/stack/mac/common/mac_metrics.h @@ -30,6 +30,7 @@ namespace srsenb { /// MAC metrics per user struct mac_ue_metrics_t { uint16_t rnti; + uint32_t pci; uint32_t nof_tti; uint32_t cc_idx; int tx_pkts; @@ -44,16 +45,18 @@ struct mac_ue_metrics_t { float dl_ri; float dl_pmi; float phr; + float dl_cqi_offset; + float ul_snr_offset; // NR-only UL PHY metrics - float pusch_sinr; - float pucch_sinr; - float ul_rssi; - float fec_iters; - float dl_mcs; - int dl_mcs_samples; - float ul_mcs; - int ul_mcs_samples; + float pusch_sinr; + float pucch_sinr; + float ul_rssi; + float fec_iters; + float dl_mcs; + int dl_mcs_samples; + float ul_mcs; + int ul_mcs_samples; }; /// MAC misc information for each cc. struct mac_cc_info_t { diff --git a/srsenb/hdr/stack/mac/sched.h b/srsenb/hdr/stack/mac/sched.h index d7e84aa3d..0402b45c7 100644 --- a/srsenb/hdr/stack/mac/sched.h +++ b/srsenb/hdr/stack/mac/sched.h @@ -86,6 +86,7 @@ public: std::array get_enb_ue_cc_map(uint16_t rnti) final; std::array 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 metrics_read(uint16_t rnti, mac_ue_metrics_t& metrics); class carrier_sched; diff --git a/srsenb/hdr/stack/mac/sched_ue.h b/srsenb/hdr/stack/mac/sched_ue.h index 80ba401a1..b18bbd15b 100644 --- a/srsenb/hdr/stack/mac/sched_ue.h +++ b/srsenb/hdr/stack/mac/sched_ue.h @@ -27,6 +27,7 @@ #include "sched_ue_ctrl/sched_ue_cell.h" #include "sched_ue_ctrl/tpc.h" #include "srsenb/hdr/common/common_enb.h" +#include "srsenb/hdr/stack/mac/common/mac_metrics.h" #include "srsran/srslog/srslog.h" #include #include @@ -82,6 +83,7 @@ public: const ue_cfg_t& get_ue_cfg() const { return cfg; } 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 metrics_read(mac_ue_metrics_t& metrics); /******************************************************* * Functions used by scheduler metric objects diff --git a/srsenb/hdr/stack/mac/sched_ue_ctrl/sched_ue_cell.h b/srsenb/hdr/stack/mac/sched_ue_ctrl/sched_ue_cell.h index 839bf4880..325e433cc 100644 --- a/srsenb/hdr/stack/mac/sched_ue_ctrl/sched_ue_cell.h +++ b/srsenb/hdr/stack/mac/sched_ue_ctrl/sched_ue_cell.h @@ -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 sched_interface::ue_cfg_t* get_ue_cfg() const { return configured() ? ue_cfg : nullptr; } 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 rbgmask_t& rbgs) const; diff --git a/srsenb/hdr/stack/s1ap/s1ap.h b/srsenb/hdr/stack/s1ap/s1ap.h index 4ca256c1f..898ea13f4 100644 --- a/srsenb/hdr/stack/s1ap/s1ap.h +++ b/srsenb/hdr/stack/s1ap/s1ap.h @@ -131,6 +131,7 @@ private: rrc_interface_s1ap* rrc = nullptr; s1ap_args_t args; srslog::basic_logger& logger; + srslog::log_channel& alarms_channel; srsran::task_sched_handle task_sched; srsran::task_queue_handle mme_task_queue; srsran::socket_manager_itf* rx_socket_handler; @@ -338,8 +339,9 @@ private: srsran::proc_outcome_t init(); srsran::proc_outcome_t step() { return srsran::proc_outcome_t::yield; } 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"; } + uint16_t connect_count = 0; private: srsran::proc_outcome_t start_mme_connection(); diff --git a/srsenb/src/CMakeLists.txt b/srsenb/src/CMakeLists.txt index 7ff013171..d1c507d98 100644 --- a/srsenb/src/CMakeLists.txt +++ b/srsenb/src/CMakeLists.txt @@ -34,7 +34,7 @@ if (RPATH) endif (RPATH) 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) diff --git a/srsenb/src/enb_cfg_parser.cc b/srsenb/src/enb_cfg_parser.cc index 4c6f20eaf..a9a5b6e1d 100644 --- a/srsenb/src/enb_cfg_parser.cc +++ b/srsenb/src/enb_cfg_parser.cc @@ -21,6 +21,7 @@ #include "enb_cfg_parser.h" #include "srsenb/hdr/enb.h" +#include "srsgnb/hdr/stack/rrc/rrc_nr_config_utils.h" #include "srsran/asn1/rrc_utils.h" #include "srsran/common/band_helper.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) { for (uint32_t n = 0; n < (uint32_t)root.getLength(); ++n) { + auto& cellroot = root[n]; + 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"); 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; } + // 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 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"); @@ -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 - 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) { + if (rrc_nr_cfg_->is_standalone) { // 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.cell_id = rrc_nr_cfg_->cell_list[0].phy_cell.cell_id; args_->nr_stack.ngap.tac = rrc_nr_cfg_->cell_list[0].tac; } else { // NSA mode. - rrc_nr_cfg_->is_standalone = false; // 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.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 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; // 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"); 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) { - cfg.phy_cell.dl_freq_hz = band_helper.nr_arfcn_to_freq(cfg.dl_arfcn); - } - - 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); + // Derive cross-dependent cell params + if (set_derived_nr_cell_params(rrc_nr_cfg_->is_standalone, cfg) != SRSRAN_SUCCESS) { + ERROR("Failed to derive NR cell params."); + return SRSRAN_ERROR; } - // duplex mode - cfg.duplex_mode = band_helper.get_duplex_mode(cfg.band); + // phy_cell_cfg.root_seq_idx = cfg.root_seq_idx; // PRACH - cfg.phy_cell.prach.is_nr = true; - 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; + cfg.phy_cell.prach.hs_flag = phy_cfg_->prach_cnfg.prach_cfg_info.high_speed_flag; // PDSCH 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; - // 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); } diff --git a/srsenb/src/main.cc b/srsenb/src/main.cc index 6bc5e7256..d002b29d3 100644 --- a/srsenb/src/main.cc +++ b/srsenb/src/main.cc @@ -256,6 +256,7 @@ void parse_args(all_args_t* args, int argc, char* argv[]) ("expert.ts1_reloc_prep_timeout", bpo::value(&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(&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(&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(&args->stack.s1ap.max_s1_setup_retries)->default_value(-1), "Max S1 setup retries") // eMBMS section ("embms.enable", bpo::value(&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); 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) { metricshub.add_listener(&metrics_file); - metrics_file.set_handle(enb.get()); } srsenb::metrics_json json_metrics(json_channel, enb.get()); diff --git a/srsenb/src/metrics_csv.cc b/srsenb/src/metrics_csv.cc index 2ce0ede81..afca1b634 100644 --- a/srsenb/src/metrics_csv.cc +++ b/srsenb/src/metrics_csv.cc @@ -36,7 +36,8 @@ using namespace std; 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); } @@ -46,11 +47,6 @@ metrics_csv::~metrics_csv() stop(); } -void metrics_csv::set_handle(enb_metrics_interface* enb_) -{ - enb = enb_; -} - void metrics_csv::stop() { if (file.is_open()) { diff --git a/srsenb/src/metrics_json.cc b/srsenb/src/metrics_json.cc index 9945c29d1..23d5151da 100644 --- a/srsenb/src/metrics_json.cc +++ b/srsenb/src/metrics_json.cc @@ -54,6 +54,13 @@ DECLARE_METRIC("dl_bitrate", metric_dl_bitrate, float, ""); DECLARE_METRIC("dl_bler", metric_dl_bler, float, ""); DECLARE_METRIC("ul_snr", metric_ul_snr, 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_bler", metric_ul_bler, float, ""); DECLARE_METRIC("ul_phr", metric_ul_phr, float, ""); @@ -64,6 +71,13 @@ DECLARE_METRIC_SET("ue_container", metric_ue_rnti, metric_dl_cqi, 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_bler, metric_ul_snr, @@ -97,24 +111,40 @@ static void fill_ue_metrics(mset_ue_container& ue, const enb_metrics_t& m, unsig ue.write(m.stack.mac.ues[i].rnti); ue.write(std::max(0.1f, m.stack.mac.ues[i].dl_cqi)); if (!std::isnan(m.phy[i].dl.mcs)) { - ue.write(std::max(0.1f, m.phy[i].dl.mcs)); + ue.write(m.phy[i].dl.mcs); } if (m.stack.mac.ues[i].tx_brate > 0 && m.stack.mac.ues[i].nof_tti > 0) { ue.write( 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) { - ue.write(std::max(0.1f, (float)100 * m.stack.mac.ues[i].tx_errors / m.stack.mac.ues[i].tx_pkts)); + ue.write((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)) { - ue.write(std::max(0.1f, m.phy[i].ul.pusch_sinr)); + ue.write(m.phy[i].ul.pusch_sinr); + } + if (!std::isnan(m.phy[i].ul.pusch_rssi)) { + ue.write(m.phy[i].ul.pusch_rssi); + } + if (!std::isnan(m.phy[i].ul.pucch_rssi)) { + ue.write(m.phy[i].ul.pucch_rssi); + } + if (!std::isnan(m.phy[i].ul.pucch_ni)) { + ue.write(m.phy[i].ul.pucch_ni); + } + ue.write(m.phy[i].ul.pusch_tpc); + ue.write(m.phy[i].dl.pucch_tpc); + if (!std::isnan(m.stack.mac.ues[i].dl_cqi_offset)) { + ue.write(m.stack.mac.ues[i].dl_cqi_offset); + } + if (!std::isnan(m.stack.mac.ues[i].ul_snr_offset)) { + ue.write(m.stack.mac.ues[i].ul_snr_offset); } if (!std::isnan(m.phy[i].ul.mcs)) { - ue.write(std::max(0.1f, m.phy[i].ul.mcs)); + ue.write(m.phy[i].ul.mcs); } if (m.stack.mac.ues[i].rx_brate > 0 && m.stack.mac.ues[i].nof_tti > 0) { - ue.write( - std::max(0.1f, (float)m.stack.mac.ues[i].rx_brate / (m.stack.mac.ues[i].nof_tti * 0.001f))); + ue.write((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) { ue.write(std::max(0.1f, (float)100 * m.stack.mac.ues[i].rx_errors / m.stack.mac.ues[i].rx_pkts)); diff --git a/srsenb/src/metrics_stdout.cc b/srsenb/src/metrics_stdout.cc index 288707383..bdd96e1a8 100644 --- a/srsenb/src/metrics_stdout.cc +++ b/srsenb/src/metrics_stdout.cc @@ -98,6 +98,7 @@ void metrics_stdout::set_metrics_helper(uint32_t num_ue } fmt::print("{:>3.5}", (is_nr) ? "nr" : "lte"); + fmt::print(" {:>4}", mac.ues[i].pci); fmt::print("{:>5x}", mac.ues[i].rnti); if (not iszero(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) { n_reports = 0; fmt::print("\n"); - fmt::print(" -----------------DL----------------|-------------------------UL-------------------------\n"); - fmt::print("rat rnti cqi ri mcs brate ok nok (%) | pusch pucch phr mcs brate ok nok (%) bsr\n"); + fmt::print( + " -----------------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); diff --git a/srsenb/src/phy/nr/slot_worker.cc b/srsenb/src/phy/nr/slot_worker.cc index 09dc46091..474c533ec 100644 --- a/srsenb/src/phy/nr/slot_worker.cc +++ b/srsenb/src/phy/nr/slot_worker.cc @@ -23,6 +23,14 @@ #include "srsran/common/buffer_pool.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 nr { slot_worker::slot_worker(srsran::phy_common_interface& common_, @@ -95,6 +103,12 @@ bool slot_worker::init(const args_t& args) 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; } @@ -416,6 +430,16 @@ void slot_worker::work_imp() } 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, diff --git a/srsenb/src/stack/mac/mac.cc b/srsenb/src/stack/mac/mac.cc index f91dca224..1683545ee 100644 --- a/srsenb/src/stack/mac/mac.cc +++ b/srsenb/src/stack/mac/mac.cc @@ -250,7 +250,11 @@ void mac::get_metrics(mac_metrics_t& metrics) continue; } 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()); 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 scheduler.dl_rach_info(enb_cc_idx, rar_info); - logger.info( - "RACH: tti=%d, cc=%d, preamble=%d, offset=%d, temp_crnti=0x%x", tti, enb_cc_idx, preamble_idx, time_adv, rnti); - srsran::console("RACH: tti=%d, cc=%d, preamble=%d, offset=%d, temp_crnti=0x%x\n", + auto get_pci = [this, enb_cc_idx]() { + srsran::rwlock_read_guard lock(rwlock); + 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, enb_cc_idx, + pci, preamble_idx, time_adv, 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) ? (mch.mtch_sched[mtch_index].lcid_buffer_size) : ((mcs_data.tbs / 8) - 2); - 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].nbytes = bytes_received; + 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].nbytes = bytes_received; mch.mtch_sched[0].mtch_payload = mtch_payload_buffer; dl_sched_res->pdsch[0].dci.rnti = SRSRAN_MRNTI; if (bytes_received) { diff --git a/srsenb/src/stack/mac/sched.cc b/srsenb/src/stack/mac/sched.cc index b2823b7ae..d6c040362 100644 --- a/srsenb/src/stack/mac/sched.cc +++ b/srsenb/src/stack/mac/sched.cc @@ -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); } +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 template int sched::ue_db_access_locked(uint16_t rnti, Func&& f, const char* func_name, bool log_fail) diff --git a/srsenb/src/stack/mac/sched_grid.cc b/srsenb/src/stack/mac/sched_grid.cc index d59cf4307..b674ef323 100644 --- a/srsenb/src/stack/mac/sched_grid.cc +++ b/srsenb/src/stack/mac/sched_grid.cc @@ -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 pucch_mask.resize(cc_cfg->nof_prb()); - 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; + 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; uint32_t harq_pucch = 0; if (cc_cfg->sched_cfg->pucch_harq_max_rb > 0) { 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(); 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, - get_tti_tx_ul(), - cc_cfg->enb_cc_idx, - ul_alloc.alloc, - ul_alloc.needs_pdcch(), - cce_range, - ul_alloc.msg3_mcs, - uci_type); + get_tti_tx_ul(), + cc_cfg->enb_cc_idx, + ul_alloc.alloc, + ul_alloc.needs_pdcch(), + cce_range, + ul_alloc.msg3_mcs, + uci_type); 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); @@ -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(); if (logger.info.enabled()) { fmt::memory_buffer str_buffer; - fmt::format_to( - str_buffer, - "SCHED: {} {} rnti=0x{:x}, cc={}, pid={}, dci=({},{}), prb={}, n_rtx={}, cfi={}, tbs={}, bsr={} ({}-{})", - ul_alloc.is_msg3 ? "Msg3" : "UL", - ul_alloc.is_retx() ? "retx" : "tx", - user->get_rnti(), - cc_cfg->enb_cc_idx, - h->get_id(), - pusch.dci.location.L, - pusch.dci.location.ncce, - ul_alloc.alloc, - h->nof_retx(0), - tti_alloc.get_cfi(), - tbs, - new_pending_bytes, - total_data_before, - old_pending_bytes); + fmt::format_to(str_buffer, + "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_retx() ? "retx" : "tx", + user->get_rnti(), + cc_cfg->enb_cc_idx, + h->get_id(), + pusch.dci.location.L, + pusch.dci.location.ncce, + ul_alloc.alloc, + h->nof_retx(0), + tti_alloc.get_cfi(), + tbs, + new_pending_bytes, + total_data_before, + old_pending_bytes, + get_tti_tx_ul().to_uint()); logger.info("%s", srsran::to_c_str(str_buffer)); } diff --git a/srsenb/src/stack/mac/sched_ue.cc b/srsenb/src/stack/mac/sched_ue.cc index 673d3c1a9..c82fd2dfe 100644 --- a/srsenb/src/stack/mac/sched_ue.cc +++ b/srsenb/src/stack/mac/sched_ue.cc @@ -173,6 +173,13 @@ void sched_ue::unset_sr() 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) { return tti_point{static_cast(floor(static_cast((tti - offset).to_uint()) / period)) * period + diff --git a/srsenb/src/stack/rrc/rrc_bearer_cfg.cc b/srsenb/src/stack/rrc/rrc_bearer_cfg.cc index c212f638c..e8299b272 100644 --- a/srsenb/src/stack/rrc/rrc_bearer_cfg.cc +++ b/srsenb/src/stack/rrc/rrc_bearer_cfg.cc @@ -21,8 +21,8 @@ #include "srsenb/hdr/stack/rrc/rrc_bearer_cfg.h" #include "srsenb/hdr/common/common_enb.h" +#include "srsran/asn1/obj_id_cmp_utils.h" #include "srsran/asn1/rrc_utils.h" -#include "srsran/rrc/rrc_cfg_utils.h" namespace srsenb { diff --git a/srsenb/src/stack/rrc/rrc_mobility.cc b/srsenb/src/stack/rrc/rrc_mobility.cc index 995a54cac..d53b80431 100644 --- a/srsenb/src/stack/rrc/rrc_mobility.cc +++ b/srsenb/src/stack/rrc/rrc_mobility.cc @@ -24,6 +24,7 @@ #include "srsenb/hdr/stack/rrc/rrc_cell_cfg.h" #include "srsenb/hdr/stack/rrc/ue_meas_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/common/bcd_helpers.h" #include "srsran/common/common.h" @@ -34,7 +35,6 @@ #include "srsran/interfaces/enb_pdcp_interfaces.h" #include "srsran/interfaces/enb_rlc_interfaces.h" #include "srsran/interfaces/enb_s1ap_interfaces.h" -#include "srsran/rrc/rrc_cfg_utils.h" #include #include diff --git a/srsenb/src/stack/rrc/ue_meas_cfg.cc b/srsenb/src/stack/rrc/ue_meas_cfg.cc index 7817eb26d..45e1ab2e2 100644 --- a/srsenb/src/stack/rrc/ue_meas_cfg.cc +++ b/srsenb/src/stack/rrc/ue_meas_cfg.cc @@ -21,7 +21,8 @@ #include "srsenb/hdr/stack/rrc/ue_meas_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; diff --git a/srsenb/src/stack/rrc/ue_rr_cfg.cc b/srsenb/src/stack/rrc/ue_rr_cfg.cc index 93d8c1ee2..d2de26f03 100644 --- a/srsenb/src/stack/rrc/ue_rr_cfg.cc +++ b/srsenb/src/stack/rrc/ue_rr_cfg.cc @@ -23,8 +23,8 @@ #include "srsenb/hdr/stack/rrc/rrc_bearer_cfg.h" #include "srsenb/hdr/stack/rrc/rrc_cell_cfg.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/rrc/rrc_cfg_utils.h" #define SET_OPT_FIELD(fieldname, out, in) \ if (in.fieldname##_present) { \ diff --git a/srsenb/src/stack/s1ap/s1ap.cc b/srsenb/src/stack/s1ap/s1ap.cc index fd30d4f74..99d3e8d61 100644 --- a/srsenb/src/stack/s1ap/s1ap.cc +++ b/srsenb/src/stack/s1ap/s1ap.cc @@ -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() { procInfo("Starting new MME connection."); + connect_count++; 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; } -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()) { 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(); procInfo("S1AP socket closed."); 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 + } 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_, srslog::basic_logger& logger, 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(); } @@ -312,7 +323,7 @@ int s1ap::init(const s1ap_args_t& args_, rrc_interface_s1ap* rrc_) mme_connect_timer = task_sched.get_unique_timer(); auto mme_connect_run = [this](uint32_t tid) { 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(); }; @@ -330,7 +341,7 @@ int s1ap::init(const s1ap_args_t& args_, rrc_interface_s1ap* rrc_) running = true; // starting MME connection 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; @@ -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) { + 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; mme_connected = true; 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) { + 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); logger.error("S1 Setup Failure. Cause: %s", 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) { 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); return true; } @@ -1108,6 +1141,13 @@ bool s1ap::handle_handover_command(const asn1::s1ap::ho_cmd_s& msg) if (u == nullptr) { 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); return true; } diff --git a/srsenb/src/stack/upper/rlc.cc b/srsenb/src/stack/upper/rlc.cc index 758152506..194af80d9 100644 --- a/srsenb/src/stack/upper/rlc.cc +++ b/srsenb/src/stack/upper/rlc.cc @@ -84,14 +84,17 @@ void rlc::add_user(uint16_t rnti) void rlc::rem_user(uint16_t rnti) { - pthread_rwlock_wrlock(&rwlock); + pthread_rwlock_rdlock(&rwlock); if (users.count(rnti)) { users[rnti].rlc->stop(); - users.erase(rnti); } else { logger.error("Removing rnti=0x%x. Already removed", rnti); } pthread_rwlock_unlock(&rwlock); + + pthread_rwlock_wrlock(&rwlock); + users.erase(rnti); + pthread_rwlock_unlock(&rwlock); } void rlc::clear_buffer(uint16_t rnti) diff --git a/srsenb/test/enb_metrics_test.cc b/srsenb/test/enb_metrics_test.cc index 1a0e6bb52..ed1f52384 100644 --- a/srsenb/test/enb_metrics_test.cc +++ b/srsenb/test/enb_metrics_test.cc @@ -62,8 +62,8 @@ public: metrics[0].stack.mac.ues[0].dl_pmi = 1.0; metrics[0].stack.mac.ues[0].phr = 12.0; metrics[0].phy.resize(2); - metrics[0].phy[0].dl.mcs = 28.0; - metrics[0].phy[0].ul.mcs = 20.2; + metrics[0].phy[0].dl.mcs = 28.0; + metrics[0].phy[0].ul.mcs = 20.2; metrics[0].phy[0].ul.pucch_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].phr = 99.1; metrics[1].phy.resize(1); - metrics[1].phy[0].dl.mcs = 6.2; - metrics[1].phy[0].ul.mcs = 28.0; + metrics[1].phy[0].dl.mcs = 6.2; + metrics[1].phy[0].ul.mcs = 28.0; metrics[1].phy[0].ul.pucch_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].phr = 12.0; metrics[2].phy.resize(1); - metrics[2].phy[0].dl.mcs = 28.0; - metrics[2].phy[0].ul.mcs = 20.2; + metrics[2].phy[0].dl.mcs = 28.0; + metrics[2].phy[0].ul.mcs = 20.2; metrics[2].phy[0].ul.pusch_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); // the CSV file writer - metrics_csv metrics_file(csv_file_name); - metrics_file.set_handle(&enb); + metrics_csv metrics_file(csv_file_name, &enb); // create metrics hub and register metrics for stdout srsran::metrics_hub metricshub; diff --git a/srsenb/test/rrc/rrc_meascfg_test.cc b/srsenb/test/rrc/rrc_meascfg_test.cc index f141e7754..aa6bf3479 100644 --- a/srsenb/test/rrc/rrc_meascfg_test.cc +++ b/srsenb/test/rrc/rrc_meascfg_test.cc @@ -21,10 +21,10 @@ #include "srsenb/hdr/enb.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/common/test_common.h" #include "srsran/interfaces/enb_rrc_interface_types.h" -#include "srsran/rrc/rrc_cfg_utils.h" #include "test_helpers.h" using namespace asn1::rrc; diff --git a/srsgnb/hdr/stack/common/test/dummy_nr_classes.h b/srsgnb/hdr/stack/common/test/dummy_nr_classes.h index dcd65fbe5..b3b09772c 100644 --- a/srsgnb/hdr/stack/common/test/dummy_nr_classes.h +++ b/srsgnb/hdr/stack/common/test/dummy_nr_classes.h @@ -33,16 +33,16 @@ class ngap_dummy : public ngap_interface_rrc_nr void initial_ue(uint16_t rnti, uint32_t gnb_cc_idx, asn1::ngap_nr::rrcestablishment_cause_e cause, - srsran::unique_byte_buffer_t pdu) + srsran::const_byte_span pdu) {} void initial_ue(uint16_t rnti, uint32_t gnb_cc_idx, asn1::ngap_nr::rrcestablishment_cause_e cause, - srsran::unique_byte_buffer_t pdu, + srsran::const_byte_span pdu, 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; } 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; } diff --git a/srsgnb/hdr/stack/mac/sched_nr_interface.h b/srsgnb/hdr/stack/mac/sched_nr_interface.h index c6635c42c..77bd29c51 100644 --- a/srsgnb/hdr/stack/mac/sched_nr_interface.h +++ b/srsgnb/hdr/stack/mac/sched_nr_interface.h @@ -84,6 +84,7 @@ public: srsran_duplex_config_nr_t duplex = {}; srsran::phy_cfg_nr_t::ssb_cfg_t ssb = {}; srsran::bounded_vector bwps{1}; // idx0 for BWP-common + srsran_mib_nr_t mib; srsran::bounded_vector sibs; }; diff --git a/srsgnb/hdr/stack/mac/sched_nr_signalling.h b/srsgnb/hdr/stack/mac/sched_nr_signalling.h index dc8be12ae..df0d13aba 100644 --- a/srsgnb/hdr/stack/mac/sched_nr_signalling.h +++ b/srsgnb/hdr/stack/mac/sched_nr_signalling.h @@ -45,14 +45,18 @@ void sched_nzp_csi_rs(srsran::const_span nzp_csi_rs_set * * @param[in] sl_point Slot point carrying information about current slot. * @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: * 1) Subcarrier spacing: 15kHz * 2) Frequency below 3GHz * 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 bool fill_dci_sib(prb_interval interv, uint32_t sib_idx, const bwp_params_t& bwp_cfg, srsran_dci_dl_nr_t& dci); diff --git a/srsgnb/hdr/stack/ngap/ngap.h b/srsgnb/hdr/stack/ngap/ngap.h index ac64fcd38..edaaae4c7 100644 --- a/srsgnb/hdr/stack/ngap/ngap.h +++ b/srsgnb/hdr/stack/ngap/ngap.h @@ -59,14 +59,14 @@ public: void initial_ue(uint16_t rnti, uint32_t gnb_cc_idx, asn1::ngap_nr::rrcestablishment_cause_e cause, - srsran::unique_byte_buffer_t pdu); + srsran::const_byte_span pdu); void initial_ue(uint16_t rnti, uint32_t gnb_cc_idx, asn1::ngap_nr::rrcestablishment_cause_e cause, - srsran::unique_byte_buffer_t pdu, + srsran::const_byte_span pdu, 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; }; 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; }; diff --git a/srsgnb/hdr/stack/ngap/ngap_ue.h b/srsgnb/hdr/stack/ngap/ngap_ue.h index f4d11ed76..0c7511916 100644 --- a/srsgnb/hdr/stack/ngap/ngap_ue.h +++ b/srsgnb/hdr/stack/ngap/ngap_ue.h @@ -40,11 +40,11 @@ public: virtual ~ue(); // TS 38.413 - Section 9.2.5.1 - Initial UE Message 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, uint32_t s_tmsi = 0); // 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 bool send_initial_ctxt_setup_response(); // TS 38.413 - Section 9.2.2.3 - Initial Context Setup Failure @@ -86,4 +86,4 @@ private: }; } // namespace srsenb -#endif \ No newline at end of file +#endif diff --git a/srsgnb/hdr/stack/rrc/cell_asn1_config.h b/srsgnb/hdr/stack/rrc/cell_asn1_config.h index fbf0db3c6..c01ba08e2 100644 --- a/srsgnb/hdr/stack/rrc/cell_asn1_config.h +++ b/srsgnb/hdr/stack/rrc/cell_asn1_config.h @@ -22,15 +22,36 @@ #ifndef 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/common/common_nr.h" 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_mib_from_enb_cfg(const rrc_nr_cfg_t& cfg, asn1::rrc_nr::mib_s& mib); -int fill_sib1_from_enb_cfg(const rrc_nr_cfg_t& cfg, asn1::rrc_nr::sib1_s& sib1); +// SA helpers +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 diff --git a/srsgnb/hdr/stack/rrc/rrc_nr.h b/srsgnb/hdr/stack/rrc/rrc_nr.h index 6e8da1ff8..ce943add2 100644 --- a/srsgnb/hdr/stack/rrc/rrc_nr.h +++ b/srsgnb/hdr/stack/rrc/rrc_nr.h @@ -25,7 +25,7 @@ #include "srsenb/hdr/stack/enb_stack_base.h" #include "srsenb/hdr/stack/rrc/rrc_config_common.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/common/block_queue.h" #include "srsran/common/buffer_pool.h" @@ -147,11 +147,12 @@ private: // vars struct cell_ctxt_t { - asn1::rrc_nr::mib_s mib; - asn1::rrc_nr::sib1_s sib1; - asn1::rrc_nr::sys_info_ies_s::sib_type_and_info_l_ sibs; - srsran::unique_byte_buffer_t mib_buffer = nullptr; - std::vector sib_buffer; + asn1::rrc_nr::mib_s mib; + asn1::rrc_nr::sib1_s sib1; + asn1::rrc_nr::sys_info_ies_s::sib_type_and_info_l_ sibs; + srsran::unique_byte_buffer_t mib_buffer = nullptr; + std::vector sib_buffer; + std::unique_ptr master_cell_group; }; std::unique_ptr cell_ctxt; rnti_map_t > users; diff --git a/srsgnb/hdr/stack/rrc/rrc_config_nr.h b/srsgnb/hdr/stack/rrc/rrc_nr_config.h similarity index 93% rename from srsgnb/hdr/stack/rrc/rrc_config_nr.h rename to srsgnb/hdr/stack/rrc/rrc_nr_config.h index 07a75bfbc..135bf68f3 100644 --- a/srsgnb/hdr/stack/rrc/rrc_config_nr.h +++ b/srsgnb/hdr/stack/rrc/rrc_nr_config.h @@ -19,8 +19,8 @@ * */ -#ifndef SRSRAN_RRC_CONFIG_NR_H -#define SRSRAN_RRC_CONFIG_NR_H +#ifndef SRSRAN_RRC_NR_CONFIG_H +#define SRSRAN_RRC_NR_CONFIG_H #include "srsenb/hdr/phy/phy_interfaces.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 ssb_absolute_freq_point; // derived from DL ARFCN uint32_t band; + uint32_t coreset0_idx; // Table 13-{1,...15} row index srsran_duplex_mode_t duplex_mode; srsran_ssb_cfg_t ssb_cfg; }; @@ -70,4 +71,4 @@ struct rrc_nr_cfg_t { } // namespace srsenb -#endif // SRSRAN_RRC_CONFIG_NR_H +#endif // SRSRAN_RRC_NR_CONFIG_H diff --git a/srsgnb/hdr/stack/rrc/rrc_nr_config_utils.h b/srsgnb/hdr/stack/rrc/rrc_nr_config_utils.h new file mode 100644 index 000000000..6d63646f6 --- /dev/null +++ b/srsgnb/hdr/stack/rrc/rrc_nr_config_utils.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 diff --git a/srsgnb/hdr/stack/rrc/rrc_nr_ue.h b/srsgnb/hdr/stack/rrc/rrc_nr_ue.h index af03a23ea..4d20439ce 100644 --- a/srsgnb/hdr/stack/rrc/rrc_nr_ue.h +++ b/srsgnb/hdr/stack/rrc/rrc_nr_ue.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(); - 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); 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_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: - rrc_nr* parent = nullptr; - uint16_t rnti = SRSRAN_INVALID_RNTI; + void send_dl_ccch(const asn1::rrc_nr::dl_ccch_msg_s& dl_ccch_msg); + 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 */ void send_rrc_setup(); 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_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_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_ul_cfg(asn1::rrc_nr::cell_group_cfg_s& cell_group_cfg_pack); @@ -116,6 +134,8 @@ private: int add_drb(); + bool init_pucch(); + // logging helpers template void log_rrc_message(srsran::nr_srb srb, @@ -126,6 +146,11 @@ private: template 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 rrc_nr_state_t state = rrc_nr_state_t::RRC_IDLE; uint8_t transaction_id = 0; @@ -133,13 +158,19 @@ private: // RRC configs for UEs 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 sched_nr_interface::ue_cfg_t uecfg{}; 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 bool endc = false; uint16_t eutra_rnti = SRSRAN_INVALID_RNTI; diff --git a/srsgnb/src/stack/mac/mac_nr.cc b/srsgnb/src/stack/mac/mac_nr.cc index 79727c1da..a5badf98f 100644 --- a/srsgnb/src/stack/mac/mac_nr.cc +++ b/srsgnb/src/stack/mac/mac_nr.cc @@ -29,6 +29,8 @@ #include "srsran/common/time_prof.h" #include "srsran/mac/mac_rar_pdu_nr.h" +//#define WRITE_SIB_PCAP + namespace srsenb { 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) { uint32_t sib_idx = dl_res->sib_idxs[si_count++]; 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) { diff --git a/srsgnb/src/stack/mac/sched_nr_signalling.cc b/srsgnb/src/stack/mac/sched_nr_signalling.cc index 4002d617d..82d6fd912 100644 --- a/srsgnb/src/stack/mac/sched_nr_signalling.cc +++ b/srsgnb/src/stack/mac/sched_nr_signalling.cc @@ -55,7 +55,10 @@ void sched_nzp_csi_rs(srsran::const_span nzp_csi_rs_set } } -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) { if (ssb_list.full()) { srslog::fetch_basic_logger("MAC-NR").error("SCHED: Failed to allocate SSB"); @@ -75,17 +78,13 @@ void sched_ssb_basic(const slot_point& sl_point, uint32_t ssb_periodicity, ssb_l // code below is simplified, it assumes 15kHz subcarrier spacing and sub 3GHz carrier if (sl_point_mod == 0) { ssb_t ssb_msg = {}; - srsran_mib_nr_t mib_msg = {}; + srsran_mib_nr_t mib_msg = mib; mib_msg.sfn = sl_point.sfn(); mib_msg.hrf = (sl_point.slot_idx() % SRSRAN_NSLOTS_PER_FRAME_NR(srsran_subcarrier_spacing_15kHz) >= SRSRAN_NSLOTS_PER_FRAME_NR(srsran_subcarrier_spacing_15kHz) / 2); // This corresponds to "Position in Burst" = 1000 mib_msg.ssb_idx = 0; - // Setting the following 4 parameters is redundant, but it makes it explicit what values are passed to PHY - mib_msg.dmrs_typeA_pos = srsran_dmrs_sch_typeA_pos_2; - mib_msg.scs_common = srsran_subcarrier_spacing_15kHz; - mib_msg.coreset0_idx = 0; - mib_msg.ss0_idx = 0; + // Remaining MIB parameters remain constant // Pack mib message to be sent to PHY int packing_ret_code = srsran_pbch_msg_nr_mib_pack(&mib_msg, &ssb_msg.pbch_msg); @@ -104,7 +103,7 @@ void sched_dl_signalling(bwp_slot_allocator& bwp_alloc) cfg.idx = sl_pdcch.to_uint(); // Schedule SSB - sched_ssb_basic(sl_pdcch, bwp_params.cell_cfg.ssb.periodicity_ms, sl_grid.dl.phy.ssb); + sched_ssb_basic(sl_pdcch, bwp_params.cell_cfg.ssb.periodicity_ms, bwp_params.cell_cfg.mib, sl_grid.dl.phy.ssb); // Schedule NZP-CSI-RS sched_nzp_csi_rs(bwp_params.cfg.pdsch.nzp_csi_rs_sets, cfg, sl_grid.dl.phy.nzp_csi_rs); diff --git a/srsgnb/src/stack/mac/test/sched_nr_cfg_generators.h b/srsgnb/src/stack/mac/test/sched_nr_cfg_generators.h index ced17cdb2..d07538171 100644 --- a/srsgnb/src/stack/mac/test/sched_nr_cfg_generators.h +++ b/srsgnb/src/stack/mac/test/sched_nr_cfg_generators.h @@ -44,9 +44,11 @@ inline sched_nr_interface::cell_cfg_t get_default_cell_cfg( { sched_nr_interface::cell_cfg_t cell_cfg{}; - cell_cfg.carrier = phy_cfg.carrier; - cell_cfg.duplex = phy_cfg.duplex; - cell_cfg.ssb = phy_cfg.ssb; + cell_cfg.carrier = phy_cfg.carrier; + cell_cfg.duplex = phy_cfg.duplex; + cell_cfg.ssb = phy_cfg.ssb; + cell_cfg.mib.coreset0_idx = 6; + cell_cfg.mib.scs_common = srsran_subcarrier_spacing_15kHz; cell_cfg.bwps.resize(1); cell_cfg.bwps[0].pdcch = phy_cfg.pdcch; diff --git a/srsgnb/src/stack/ngap/ngap.cc b/srsgnb/src/stack/ngap/ngap.cc index 903a87919..7d396a320 100644 --- a/srsgnb/src/stack/ngap/ngap.cc +++ b/srsgnb/src/stack/ngap/ngap.cc @@ -223,7 +223,7 @@ int ngap::build_tai_cgi() void ngap::initial_ue(uint16_t rnti, uint32_t gnb_cc_idx, asn1::ngap_nr::rrcestablishment_cause_e cause, - srsran::unique_byte_buffer_t pdu) + srsran::const_byte_span pdu) { std::unique_ptr ue_ptr{new ue{this, rrc, gtpu, logger}}; ue_ptr->ctxt.rnti = rnti; @@ -233,13 +233,13 @@ void ngap::initial_ue(uint16_t rnti, logger.error("Failed to add rnti=0x%x", rnti); return; } - u->send_initial_ue_message(cause, std::move(pdu), false); + u->send_initial_ue_message(cause, pdu, false); } void ngap::initial_ue(uint16_t rnti, uint32_t gnb_cc_idx, asn1::ngap_nr::rrcestablishment_cause_e cause, - srsran::unique_byte_buffer_t pdu, + srsran::const_byte_span pdu, uint32_t s_tmsi) { std::unique_ptr ue_ptr{new ue{this, rrc, gtpu, logger}}; @@ -250,7 +250,7 @@ void ngap::initial_ue(uint16_t rnti, logger.error("Failed to add rnti=0x%x", rnti); return; } - u->send_initial_ue_message(cause, std::move(pdu), true, s_tmsi); + u->send_initial_ue_message(cause, pdu, true, s_tmsi); } void ngap::ue_notify_rrc_reconf_complete(uint16_t rnti, bool outcome) @@ -262,16 +262,16 @@ void ngap::ue_notify_rrc_reconf_complete(uint16_t rnti, bool outcome) u->notify_rrc_reconf_complete(outcome); } -void ngap::write_pdu(uint16_t rnti, srsran::unique_byte_buffer_t pdu) +void ngap::write_pdu(uint16_t rnti, srsran::const_byte_span pdu) { - logger.info(pdu->msg, pdu->N_bytes, "Received RRC SDU"); + logger.info(pdu.data(), pdu.size(), "Received RRC SDU"); ue* u = users.find_ue_rnti(rnti); if (u == nullptr) { logger.info("The rnti=0x%x does not exist", rnti); return; } - u->send_ul_nas_transport(std::move(pdu)); + u->send_ul_nas_transport(pdu); } /********************************************************* diff --git a/srsgnb/src/stack/ngap/ngap_ue.cc b/srsgnb/src/stack/ngap/ngap_ue.cc index 01ea8b2d1..52e964d2c 100644 --- a/srsgnb/src/stack/ngap/ngap_ue.cc +++ b/srsgnb/src/stack/ngap/ngap_ue.cc @@ -55,7 +55,7 @@ ngap::ue::~ue() {} ********************************************************************************/ bool ngap::ue::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, uint32_t s_tmsi) { @@ -80,8 +80,8 @@ bool ngap::ue::send_initial_ue_message(asn1::ngap_nr::rrcestablishment_cause_e c container.ran_ue_ngap_id.value = ctxt.ran_ue_ngap_id; // NAS_PDU - container.nas_pdu.value.resize(pdu->N_bytes); - memcpy(container.nas_pdu.value.data(), pdu->msg, pdu->N_bytes); + container.nas_pdu.value.resize(pdu.size()); + memcpy(container.nas_pdu.value.data(), pdu.data(), pdu.size()); // RRC Establishment Cause container.rrcestablishment_cause.value = cause; @@ -102,7 +102,7 @@ bool ngap::ue::send_initial_ue_message(asn1::ngap_nr::rrcestablishment_cause_e c return ngap_ptr->sctp_send_ngap_pdu(tx_pdu, ctxt.rnti, "InitialUEMessage"); } -bool ngap::ue::send_ul_nas_transport(srsran::unique_byte_buffer_t pdu) +bool ngap::ue::send_ul_nas_transport(srsran::const_byte_span pdu) { if (not ngap_ptr->amf_connected) { logger.warning("AMF not connected"); @@ -125,8 +125,8 @@ bool ngap::ue::send_ul_nas_transport(srsran::unique_byte_buffer_t pdu) container.ran_ue_ngap_id.value = ctxt.ran_ue_ngap_id; // NAS PDU - container.nas_pdu.value.resize(pdu->N_bytes); - memcpy(container.nas_pdu.value.data(), pdu->msg, pdu->N_bytes); + container.nas_pdu.value.resize(pdu.size()); + memcpy(container.nas_pdu.value.data(), pdu.data(), pdu.size()); // User Location Info // userLocationInformationNR @@ -285,4 +285,4 @@ bool ngap::ue::handle_pdu_session_res_setup_request(const asn1::ngap_nr::pdu_ses return true; } -} // namespace srsenb \ No newline at end of file +} // namespace srsenb diff --git a/srsgnb/src/stack/rrc/CMakeLists.txt b/srsgnb/src/stack/rrc/CMakeLists.txt index 4e6479b60..4b5bf5981 100644 --- a/srsgnb/src/stack/rrc/CMakeLists.txt +++ b/srsgnb/src/stack/rrc/CMakeLists.txt @@ -18,9 +18,13 @@ # and at http://www.gnu.org/licenses/. # +set(SOURCES rrc_nr_config_utils.cc) +add_library(srsgnb_rrc_config_utils STATIC ${SOURCES}) +target_link_libraries(srsgnb_rrc_config_utils srsran_phy) + set(SOURCES rrc_nr.cc rrc_nr_ue.cc cell_asn1_config.cc) add_library(srsgnb_rrc STATIC ${SOURCES}) -target_link_libraries(srsgnb_rrc srsran_rrc_nr) +target_link_libraries(srsgnb_rrc srsgnb_rrc_config_utils) include_directories(${PROJECT_SOURCE_DIR}) diff --git a/srsgnb/src/stack/rrc/cell_asn1_config.cc b/srsgnb/src/stack/rrc/cell_asn1_config.cc index b528f7a58..7c6f8717b 100644 --- a/srsgnb/src/stack/rrc/cell_asn1_config.cc +++ b/srsgnb/src/stack/rrc/cell_asn1_config.cc @@ -20,7 +20,9 @@ */ #include "srsgnb/hdr/stack/rrc/cell_asn1_config.h" -#include "srsran/rrc/nr/rrc_nr_cfg_utils.h" +#include "srsran/asn1/obj_id_cmp_utils.h" +#include "srsran/asn1/rrc_nr_utils.h" +#include "srsran/common/band_helper.h" #include using namespace asn1::rrc_nr; @@ -237,7 +239,8 @@ int fill_pdcch_cfg_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, pdcch_cfg_ { auto& cell_cfg = cfg.cell_list.at(cc); - for (uint32_t cs_idx = 0; cs_idx < SRSRAN_UE_DL_NR_MAX_NOF_CORESET; cs_idx++) { + // Note: Skip CORESET#0 + for (uint32_t cs_idx = 1; cs_idx < SRSRAN_UE_DL_NR_MAX_NOF_CORESET; cs_idx++) { if (cell_cfg.phy_cell.pdcch.coreset_present[cs_idx]) { auto& coreset_cfg = cell_cfg.phy_cell.pdcch.coreset[cs_idx]; @@ -272,7 +275,8 @@ int fill_pdcch_cfg_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, pdcch_cfg_ } } - for (uint32_t ss_idx = 0; ss_idx < SRSRAN_UE_DL_NR_MAX_NOF_SEARCH_SPACE; ss_idx++) { + // Note: Skip SearchSpace#0 + for (uint32_t ss_idx = 1; ss_idx < SRSRAN_UE_DL_NR_MAX_NOF_SEARCH_SPACE; ss_idx++) { if (cell_cfg.phy_cell.pdcch.search_space_present[ss_idx]) { // search spaces auto& search_space_cfg = cell_cfg.phy_cell.pdcch.search_space[ss_idx]; @@ -318,17 +322,204 @@ int fill_pdcch_cfg_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, pdcch_cfg_ return SRSRAN_SUCCESS; } +void fill_pdsch_cfg_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, pdsch_cfg_s& out) +{ + out.dmrs_dl_for_pdsch_map_type_a_present = true; + out.dmrs_dl_for_pdsch_map_type_a.set_setup(); + out.dmrs_dl_for_pdsch_map_type_a.setup().dmrs_add_position_present = true; + out.dmrs_dl_for_pdsch_map_type_a.setup().dmrs_add_position = dmrs_dl_cfg_s::dmrs_add_position_opts::pos1; + + out.tci_states_to_add_mod_list_present = true; + out.tci_states_to_add_mod_list.resize(1); + out.tci_states_to_add_mod_list[0].tci_state_id = 0; + out.tci_states_to_add_mod_list[0].qcl_type1.ref_sig.set_ssb(); + out.tci_states_to_add_mod_list[0].qcl_type1.ref_sig.ssb() = 0; + out.tci_states_to_add_mod_list[0].qcl_type1.qcl_type = asn1::rrc_nr::qcl_info_s::qcl_type_opts::type_d; + + out.res_alloc = pdsch_cfg_s::res_alloc_opts::res_alloc_type1; + out.rbg_size = pdsch_cfg_s::rbg_size_opts::cfg1; + out.prb_bundling_type.set_static_bundling(); + out.prb_bundling_type.static_bundling().bundle_size_present = true; + out.prb_bundling_type.static_bundling().bundle_size = + pdsch_cfg_s::prb_bundling_type_c_::static_bundling_s_::bundle_size_opts::wideband; + + // ZP-CSI + out.zp_csi_rs_res_to_add_mod_list_present = false; // TEMP + out.zp_csi_rs_res_to_add_mod_list.resize(1); + out.zp_csi_rs_res_to_add_mod_list[0].zp_csi_rs_res_id = 0; + out.zp_csi_rs_res_to_add_mod_list[0].res_map.freq_domain_alloc.set_row4(); + out.zp_csi_rs_res_to_add_mod_list[0].res_map.freq_domain_alloc.row4().from_number(0b100); + out.zp_csi_rs_res_to_add_mod_list[0].res_map.nrof_ports = asn1::rrc_nr::csi_rs_res_map_s::nrof_ports_opts::p4; + + out.zp_csi_rs_res_to_add_mod_list[0].res_map.first_ofdm_symbol_in_time_domain = 8; + out.zp_csi_rs_res_to_add_mod_list[0].res_map.cdm_type = asn1::rrc_nr::csi_rs_res_map_s::cdm_type_opts::fd_cdm2; + out.zp_csi_rs_res_to_add_mod_list[0].res_map.density.set_one(); + + out.zp_csi_rs_res_to_add_mod_list[0].res_map.freq_band.start_rb = 0; + out.zp_csi_rs_res_to_add_mod_list[0].res_map.freq_band.nrof_rbs = cfg.cell_list[cc].phy_cell.carrier.nof_prb; + out.zp_csi_rs_res_to_add_mod_list[0].periodicity_and_offset_present = true; + out.zp_csi_rs_res_to_add_mod_list[0].periodicity_and_offset.set_slots80() = 1; + + out.p_zp_csi_rs_res_set_present = false; // TEMP + out.p_zp_csi_rs_res_set.set_setup(); + out.p_zp_csi_rs_res_set.setup().zp_csi_rs_res_set_id = 0; + out.p_zp_csi_rs_res_set.setup().zp_csi_rs_res_id_list.resize(1); + out.p_zp_csi_rs_res_set.setup().zp_csi_rs_res_id_list[0] = 0; +} + /// Fill InitDlBwp with gNB config int fill_init_dl_bwp_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, bwp_dl_ded_s& init_dl_bwp) { init_dl_bwp.pdcch_cfg_present = true; HANDLE_ERROR(fill_pdcch_cfg_from_enb_cfg(cfg, cc, init_dl_bwp.pdcch_cfg.set_setup())); + init_dl_bwp.pdsch_cfg_present = true; + fill_pdsch_cfg_from_enb_cfg(cfg, cc, init_dl_bwp.pdsch_cfg.set_setup()); + // TODO: ADD missing fields return SRSRAN_SUCCESS; } +void fill_pucch_cfg_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, pucch_cfg_s& out) +{ + // Make 2 PUCCH resource sets + out.res_set_to_add_mod_list_present = true; + out.res_set_to_add_mod_list.resize(2); + + // Make PUCCH resource set for 1-2 bit + for (uint32_t set_id = 0; set_id < out.res_set_to_add_mod_list.size(); ++set_id) { + auto& res_set = out.res_set_to_add_mod_list[set_id]; + res_set.pucch_res_set_id = set_id; + res_set.res_list.resize(8); + for (uint32_t i = 0; i < res_set.res_list.size(); ++i) { + if (cfg.is_standalone) { + res_set.res_list[i] = i + set_id * 8; + } else { + res_set.res_list[i] = set_id; + } + } + } + + // Make 3 possible resources + out.res_to_add_mod_list_present = true; + out.res_to_add_mod_list.resize(18); + uint32_t j = 0, j2 = 0; + for (uint32_t i = 0; i < out.res_to_add_mod_list.size(); ++i) { + out.res_to_add_mod_list[i].pucch_res_id = i; + out.res_to_add_mod_list[i].intra_slot_freq_hop_present = true; + out.res_to_add_mod_list[i].second_hop_prb_present = true; + if (i < 8 or i == 16) { + out.res_to_add_mod_list[i].start_prb = 51; + out.res_to_add_mod_list[i].second_hop_prb = 0; + out.res_to_add_mod_list[i].format.set_format1().init_cyclic_shift = (4 * (j % 3)); + out.res_to_add_mod_list[i].format.format1().nrof_symbols = 14; + out.res_to_add_mod_list[i].format.format1().start_symbol_idx = 0; + out.res_to_add_mod_list[i].format.format1().time_domain_occ = j / 3; + j++; + } else if (i < 15) { + out.res_to_add_mod_list[i].start_prb = 1; + out.res_to_add_mod_list[i].second_hop_prb = 50; + out.res_to_add_mod_list[i].format.set_format2().nrof_prbs = 1; + out.res_to_add_mod_list[i].format.format2().nrof_symbols = 2; + out.res_to_add_mod_list[i].format.format2().start_symbol_idx = 2 * (j2 % 7); + j2++; + } else { + out.res_to_add_mod_list[i].start_prb = 50; + out.res_to_add_mod_list[i].second_hop_prb = 1; + out.res_to_add_mod_list[i].format.set_format2().nrof_prbs = 1; + out.res_to_add_mod_list[i].format.format2().nrof_symbols = 2; + out.res_to_add_mod_list[i].format.format2().start_symbol_idx = 2 * (j2 % 7); + j2++; + } + } + + out.format1_present = true; + out.format1.set_setup(); + + out.format2_present = true; + out.format2.set_setup(); + out.format2.setup().max_code_rate_present = true; + out.format2.setup().max_code_rate = pucch_max_code_rate_opts::zero_dot25; + + // SR resources + out.sched_request_res_to_add_mod_list_present = true; + out.sched_request_res_to_add_mod_list.resize(1); + auto& sr_res1 = out.sched_request_res_to_add_mod_list[0]; + sr_res1.sched_request_res_id = 1; + sr_res1.sched_request_id = 0; + sr_res1.periodicity_and_offset_present = true; + sr_res1.periodicity_and_offset.set_sl40() = 0; + sr_res1.res_present = true; + sr_res1.res = 16; + + // DL data + out.dl_data_to_ul_ack_present = true; + if (cfg.cell_list[cc].duplex_mode == SRSRAN_DUPLEX_MODE_FDD) { + out.dl_data_to_ul_ack.resize(1); + out.dl_data_to_ul_ack[0] = 4; + } else { + out.dl_data_to_ul_ack.resize(6); + out.dl_data_to_ul_ack[0] = 6; + out.dl_data_to_ul_ack[1] = 5; + out.dl_data_to_ul_ack[2] = 4; + out.dl_data_to_ul_ack[3] = 4; + out.dl_data_to_ul_ack[4] = 4; + out.dl_data_to_ul_ack[5] = 4; + } +} + +void fill_pusch_cfg_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, pusch_cfg_s& out) +{ + out.dmrs_ul_for_pusch_map_type_a_present = true; + out.dmrs_ul_for_pusch_map_type_a.set_setup(); + out.dmrs_ul_for_pusch_map_type_a.setup().dmrs_add_position_present = true; + out.dmrs_ul_for_pusch_map_type_a.setup().dmrs_add_position = dmrs_ul_cfg_s::dmrs_add_position_opts::pos1; + // PUSH power control skipped + out.res_alloc = pusch_cfg_s::res_alloc_opts::res_alloc_type1; + + // UCI + out.uci_on_pusch_present = true; + out.uci_on_pusch.set_setup(); + out.uci_on_pusch.setup().beta_offsets_present = true; + out.uci_on_pusch.setup().beta_offsets.set_semi_static(); + auto& beta_offset_semi_static = out.uci_on_pusch.setup().beta_offsets.semi_static(); + beta_offset_semi_static.beta_offset_ack_idx1_present = true; + beta_offset_semi_static.beta_offset_ack_idx1 = 9; + beta_offset_semi_static.beta_offset_ack_idx2_present = true; + beta_offset_semi_static.beta_offset_ack_idx2 = 9; + beta_offset_semi_static.beta_offset_ack_idx3_present = true; + beta_offset_semi_static.beta_offset_ack_idx3 = 9; + beta_offset_semi_static.beta_offset_csi_part1_idx1_present = true; + beta_offset_semi_static.beta_offset_csi_part1_idx1 = 6; + beta_offset_semi_static.beta_offset_csi_part1_idx2_present = true; + beta_offset_semi_static.beta_offset_csi_part1_idx2 = 6; + beta_offset_semi_static.beta_offset_csi_part2_idx1_present = true; + beta_offset_semi_static.beta_offset_csi_part2_idx1 = 6; + beta_offset_semi_static.beta_offset_csi_part2_idx2_present = true; + beta_offset_semi_static.beta_offset_csi_part2_idx2 = 6; + + out.uci_on_pusch.setup().scaling = uci_on_pusch_s::scaling_opts::f1; +} + +void fill_init_ul_bwp_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, bwp_ul_ded_s& out) +{ + if (cfg.is_standalone) { + out.pucch_cfg_present = true; + fill_pucch_cfg_from_enb_cfg(cfg, cc, out.pucch_cfg.set_setup()); + + out.pusch_cfg_present = true; + fill_pusch_cfg_from_enb_cfg(cfg, cc, out.pusch_cfg.set_setup()); + } +} + +/// Fill InitUlBwp with gNB config +void fill_ul_cfg_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, ul_cfg_s& out) +{ + out.init_ul_bwp_present = true; + fill_init_ul_bwp_from_enb_cfg(cfg, cc, out.init_ul_bwp); +} + /// Fill ServingCellConfig with gNB config int fill_serv_cell_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, serving_cell_cfg_s& serv_cell) { @@ -338,6 +529,16 @@ int fill_serv_cell_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, serving_ce serv_cell.init_dl_bwp_present = true; fill_init_dl_bwp_from_enb_cfg(cfg, cc, serv_cell.init_dl_bwp); + serv_cell.first_active_dl_bwp_id_present = true; + if (cfg.cell_list[0].duplex_mode == SRSRAN_DUPLEX_MODE_FDD) { + serv_cell.first_active_dl_bwp_id = 0; + } else { + serv_cell.first_active_dl_bwp_id = 1; + } + + serv_cell.ul_cfg_present = true; + fill_ul_cfg_from_enb_cfg(cfg, cc, serv_cell.ul_cfg); + // TODO: remaining fields return SRSRAN_SUCCESS; @@ -593,22 +794,434 @@ int fill_sp_cell_cfg_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, sp_cell_ return SRSRAN_SUCCESS; } -int fill_mib_from_enb_cfg(const rrc_nr_cfg_t& cfg, asn1::rrc_nr::mib_s& mib) +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/// Fill SRB with parameters derived from cfg +void fill_srb(const rrc_nr_cfg_t& cfg, srsran::nr_srb srb_id, asn1::rrc_nr::rlc_bearer_cfg_s& out) +{ + srsran_assert(srb_id > srsran::nr_srb::srb0 and srb_id < srsran::nr_srb::count, "Invalid srb_id argument"); + + out.lc_ch_id = srsran::srb_to_lcid(srb_id); + out.served_radio_bearer_present = true; + out.served_radio_bearer.set_srb_id() = (uint8_t)srb_id; + + out.rlc_cfg_present = true; + auto& ul_am = out.rlc_cfg.set_am().ul_am_rlc; + ul_am.sn_field_len_present = true; + ul_am.sn_field_len.value = asn1::rrc_nr::sn_field_len_am_opts::size12; + ul_am.t_poll_retx.value = asn1::rrc_nr::t_poll_retx_opts::ms45; + ul_am.poll_pdu.value = asn1::rrc_nr::poll_pdu_opts::infinity; + ul_am.poll_byte.value = asn1::rrc_nr::poll_byte_opts::infinity; + ul_am.max_retx_thres.value = asn1::rrc_nr::ul_am_rlc_s::max_retx_thres_opts::t8; + auto& dl_am = out.rlc_cfg.am().dl_am_rlc; + dl_am.sn_field_len_present = true; + dl_am.sn_field_len.value = asn1::rrc_nr::sn_field_len_am_opts::size12; + dl_am.t_reassembly.value = t_reassembly_opts::ms35; + dl_am.t_status_prohibit.value = asn1::rrc_nr::t_status_prohibit_opts::ms0; + + // mac-LogicalChannelConfig -- Cond LCH-Setup + out.mac_lc_ch_cfg_present = true; + out.mac_lc_ch_cfg.ul_specific_params_present = true; + out.mac_lc_ch_cfg.ul_specific_params.prio = srb_id == srsran::nr_srb::srb1 ? 1 : 3; + out.mac_lc_ch_cfg.ul_specific_params.prioritised_bit_rate.value = + lc_ch_cfg_s::ul_specific_params_s_::prioritised_bit_rate_opts::infinity; + out.mac_lc_ch_cfg.ul_specific_params.bucket_size_dur.value = + lc_ch_cfg_s::ul_specific_params_s_::bucket_size_dur_opts::ms5; + out.mac_lc_ch_cfg.ul_specific_params.lc_ch_group_present = true; + out.mac_lc_ch_cfg.ul_specific_params.lc_ch_group = 0; + out.mac_lc_ch_cfg.ul_specific_params.sched_request_id_present = true; + out.mac_lc_ch_cfg.ul_specific_params.sched_request_id = 0; + out.mac_lc_ch_cfg.ul_specific_params.lc_ch_sr_mask = false; + out.mac_lc_ch_cfg.ul_specific_params.lc_ch_sr_delay_timer_applied = false; +} + +/// Fill DRB with parameters derived from cfg +void fill_drb(const rrc_nr_cfg_t& cfg, uint32_t lcid, srsran::nr_drb drb_id, asn1::rrc_nr::rlc_bearer_cfg_s& out) +{ + out.lc_ch_id = lcid; + out.served_radio_bearer_present = true; + out.served_radio_bearer.set_drb_id() = (uint8_t)drb_id; + + out.rlc_cfg_present = true; + auto& ul_um = out.rlc_cfg.set_um_bi_dir().ul_um_rlc; + ul_um.sn_field_len_present = true; + ul_um.sn_field_len.value = sn_field_len_um_opts::size12; + auto& dl_um = out.rlc_cfg.um_bi_dir().dl_um_rlc; + dl_um.sn_field_len_present = true; + dl_um.sn_field_len.value = sn_field_len_um_opts::size12; + dl_um.t_reassembly.value = t_reassembly_opts::ms50; + + // MAC logical channel config + out.mac_lc_ch_cfg_present = true; + out.mac_lc_ch_cfg.ul_specific_params_present = true; + out.mac_lc_ch_cfg.ul_specific_params.prio = 11; // TODO + out.mac_lc_ch_cfg.ul_specific_params.prioritised_bit_rate = + lc_ch_cfg_s::ul_specific_params_s_::prioritised_bit_rate_opts::kbps0; + out.mac_lc_ch_cfg.ul_specific_params.bucket_size_dur = + asn1::rrc_nr::lc_ch_cfg_s::ul_specific_params_s_::bucket_size_dur_opts::ms100; + out.mac_lc_ch_cfg.ul_specific_params.lc_ch_group_present = true; + out.mac_lc_ch_cfg.ul_specific_params.lc_ch_group = 3; // TODO + out.mac_lc_ch_cfg.ul_specific_params.sched_request_id_present = true; + out.mac_lc_ch_cfg.ul_specific_params.sched_request_id = 0; // TODO + out.mac_lc_ch_cfg.ul_specific_params.lc_ch_sr_mask = false; + out.mac_lc_ch_cfg.ul_specific_params.lc_ch_sr_delay_timer_applied = false; + // TODO: add LC config to MAC +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/// Fill MasterCellConfig with gNB config +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) +{ + out.cell_group_id = 0; + out.rlc_bearer_to_add_mod_list_present = true; + out.rlc_bearer_to_add_mod_list.resize(1); + fill_srb(cfg, srsran::nr_srb::srb1, out.rlc_bearer_to_add_mod_list[0]); + + // mac-CellGroupConfig -- Need M + out.mac_cell_group_cfg_present = true; + out.mac_cell_group_cfg.sched_request_cfg_present = true; + out.mac_cell_group_cfg.sched_request_cfg.sched_request_to_add_mod_list_present = true; + out.mac_cell_group_cfg.sched_request_cfg.sched_request_to_add_mod_list.resize(1); + out.mac_cell_group_cfg.sched_request_cfg.sched_request_to_add_mod_list[0].sched_request_id = 0; + out.mac_cell_group_cfg.sched_request_cfg.sched_request_to_add_mod_list[0].sr_trans_max.value = + sched_request_to_add_mod_s::sr_trans_max_opts::n64; + out.mac_cell_group_cfg.bsr_cfg_present = true; + out.mac_cell_group_cfg.bsr_cfg.periodic_bsr_timer.value = bsr_cfg_s::periodic_bsr_timer_opts::sf20; + out.mac_cell_group_cfg.bsr_cfg.retx_bsr_timer.value = bsr_cfg_s::retx_bsr_timer_opts::sf320; + out.mac_cell_group_cfg.tag_cfg_present = true; + out.mac_cell_group_cfg.tag_cfg.tag_to_add_mod_list_present = true; + out.mac_cell_group_cfg.tag_cfg.tag_to_add_mod_list.resize(1); + out.mac_cell_group_cfg.tag_cfg.tag_to_add_mod_list[0].tag_id = 0; + out.mac_cell_group_cfg.tag_cfg.tag_to_add_mod_list[0].time_align_timer.value = time_align_timer_opts::infinity; + out.mac_cell_group_cfg.phr_cfg_present = true; + phr_cfg_s& phr = out.mac_cell_group_cfg.phr_cfg.set_setup(); + phr.phr_periodic_timer.value = asn1::rrc_nr::phr_cfg_s::phr_periodic_timer_opts::sf500; + phr.phr_prohibit_timer.value = asn1::rrc_nr::phr_cfg_s::phr_prohibit_timer_opts::sf200; + phr.phr_tx_pwr_factor_change.value = asn1::rrc_nr::phr_cfg_s::phr_tx_pwr_factor_change_opts::db3; + phr.multiple_phr = false; + phr.dummy = false; + phr.phr_type2_other_cell = false; + phr.phr_mode_other_cg.value = asn1::rrc_nr::phr_cfg_s::phr_mode_other_cg_opts::real; + out.mac_cell_group_cfg.skip_ul_tx_dynamic = false; + + // physicalCellGroupConfig -- Need M + out.phys_cell_group_cfg_present = true; + out.phys_cell_group_cfg.p_nr_fr1_present = true; + out.phys_cell_group_cfg.p_nr_fr1 = 10; + out.phys_cell_group_cfg.pdsch_harq_ack_codebook.value = + phys_cell_group_cfg_s::pdsch_harq_ack_codebook_opts::dynamic_value; + + // spCellConfig -- Need M + out.sp_cell_cfg_present = true; + fill_sp_cell_cfg_from_enb_cfg(cfg, cc, out.sp_cell_cfg); + out.sp_cell_cfg.recfg_with_sync_present = false; + + return SRSRAN_SUCCESS; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +int fill_mib_from_enb_cfg(const rrc_cell_cfg_nr_t& cell_cfg, asn1::rrc_nr::mib_s& mib) { - srsran::basic_cell_args_t args; - args.scs = cfg.cell_list[0].phy_cell.carrier.scs; - srsran::generate_default_mib(args, mib); + mib.sys_frame_num.from_number(0); + switch (cell_cfg.phy_cell.carrier.scs) { + case srsran_subcarrier_spacing_15kHz: + case srsran_subcarrier_spacing_60kHz: + mib.sub_carrier_spacing_common.value = asn1::rrc_nr::mib_s::sub_carrier_spacing_common_opts::scs15or60; + break; + case srsran_subcarrier_spacing_30kHz: + case srsran_subcarrier_spacing_120kHz: + mib.sub_carrier_spacing_common.value = asn1::rrc_nr::mib_s::sub_carrier_spacing_common_opts::scs30or120; + break; + default: + srsran_terminate("Invalid carrier SCS=%d Hz", SRSRAN_SUBC_SPACING_NR(cell_cfg.phy_cell.carrier.scs)); + } + mib.ssb_subcarrier_offset = 0; + mib.dmrs_type_a_position.value = mib_s::dmrs_type_a_position_opts::pos2; + mib.pdcch_cfg_sib1.search_space_zero = 0; + mib.pdcch_cfg_sib1.ctrl_res_set_zero = cell_cfg.coreset0_idx; + mib.cell_barred.value = mib_s::cell_barred_opts::not_barred; + mib.intra_freq_resel.value = mib_s::intra_freq_resel_opts::allowed; + mib.spare.from_number(0); return SRSRAN_SUCCESS; } -int fill_sib1_from_enb_cfg(const rrc_nr_cfg_t& cfg, asn1::rrc_nr::sib1_s& sib1) +void fill_pdcch_cfg_common(const rrc_cell_cfg_nr_t& cell_cfg, pdcch_cfg_common_s& cfg) +{ + cfg.ctrl_res_set_zero_present = true; // may be disabled later if called by sib1 generation + 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 fill_pdsch_cfg_common(const rrc_cell_cfg_nr_t& cell_cfg, 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 fill_init_dl_bwp(const rrc_cell_cfg_nr_t& cell_cfg, bwp_dl_common_s& cfg) +{ + cfg.generic_params.location_and_bw = 14025; + cfg.generic_params.subcarrier_spacing = (subcarrier_spacing_opts::options)cell_cfg.phy_cell.carrier.scs; + + cfg.pdcch_cfg_common_present = true; + fill_pdcch_cfg_common(cell_cfg, cfg.pdcch_cfg_common.set_setup()); + cfg.pdsch_cfg_common_present = true; + fill_pdsch_cfg_common(cell_cfg, cfg.pdsch_cfg_common.set_setup()); +} + +void fill_dl_cfg_common_sib(const rrc_cell_cfg_nr_t& cell_cfg, dl_cfg_common_sib_s& cfg) +{ + uint32_t scs_hz = SRSRAN_SUBC_SPACING_NR(cell_cfg.phy_cell.carrier.scs); + uint32_t prb_bw = scs_hz * SRSRAN_NRE; + + srsran::srsran_band_helper band_helper; + 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 = cell_cfg.band; + double ssb_freq_start = cell_cfg.ssb_cfg.ssb_freq_hz - SRSRAN_SSB_BW_SUBC * scs_hz / 2; + double offset_point_a_hz = ssb_freq_start - band_helper.nr_arfcn_to_freq(cell_cfg.dl_absolute_freq_point_a); + uint32_t offset_point_a_prbs = offset_point_a_hz / prb_bw; + cfg.freq_info_dl.offset_to_point_a = offset_point_a_prbs; + cfg.freq_info_dl.scs_specific_carrier_list.resize(1); + cfg.freq_info_dl.scs_specific_carrier_list[0].offset_to_carrier = 0; + cfg.freq_info_dl.scs_specific_carrier_list[0].subcarrier_spacing = + (subcarrier_spacing_opts::options)cell_cfg.phy_cell.carrier.scs; + cfg.freq_info_dl.scs_specific_carrier_list[0].carrier_bw = cell_cfg.phy_cell.carrier.nof_prb; + + fill_init_dl_bwp(cell_cfg, 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 fill_rach_cfg_common(const rrc_cell_cfg_nr_t& cell_cfg, 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 fill_ul_cfg_common_sib(const rrc_cell_cfg_nr_t& cell_cfg, ul_cfg_common_sib_s& cfg) { - srsran::basic_cell_args_t args; - args.is_standalone = cfg.is_standalone; - args.scs = subcarrier_spacing_e{(subcarrier_spacing_opts::options)cfg.cell_list[0].phy_cell.carrier.scs}.to_number(); - args.is_fdd = cfg.cell_list[0].duplex_mode == SRSRAN_DUPLEX_MODE_FDD; - srsran::generate_default_sib1(args, sib1); + srsran::srsran_band_helper band_helper; + + cfg.freq_info_ul.freq_band_list_present = true; + cfg.freq_info_ul.freq_band_list.resize(1); + cfg.freq_info_ul.freq_band_list[0].freq_band_ind_nr_present = true; + cfg.freq_info_ul.freq_band_list[0].freq_band_ind_nr = cell_cfg.band; + + cfg.freq_info_ul.absolute_freq_point_a_present = true; + cfg.freq_info_ul.absolute_freq_point_a = + band_helper.get_abs_freq_point_a_arfcn(cell_cfg.phy_cell.carrier.nof_prb, cell_cfg.ul_arfcn); + + cfg.freq_info_ul.scs_specific_carrier_list.resize(1); + cfg.freq_info_ul.scs_specific_carrier_list[0].offset_to_carrier = 0; + cfg.freq_info_ul.scs_specific_carrier_list[0].subcarrier_spacing = + (subcarrier_spacing_opts::options)cell_cfg.phy_cell.carrier.scs; + cfg.freq_info_ul.scs_specific_carrier_list[0].carrier_bw = cell_cfg.phy_cell.carrier.nof_prb; + + cfg.freq_info_ul.p_max_present = true; + cfg.freq_info_ul.p_max = 10; + + cfg.init_ul_bwp.generic_params.location_and_bw = 14025; + cfg.init_ul_bwp.generic_params.subcarrier_spacing.value = + (subcarrier_spacing_opts::options)cell_cfg.phy_cell.carrier.scs; + + cfg.init_ul_bwp.rach_cfg_common_present = true; + fill_rach_cfg_common(cell_cfg, 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 fill_serv_cell_cfg_common_sib(const rrc_cell_cfg_nr_t& cell_cfg, serving_cell_cfg_common_sib_s& cfg) +{ + fill_dl_cfg_common_sib(cell_cfg, cfg.dl_cfg_common); + + cfg.ul_cfg_common_present = true; + fill_ul_cfg_common_sib(cell_cfg, 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; +} + +int fill_sib1_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, asn1::rrc_nr::sib1_s& sib1) +{ + std::string plmn_str = "00101"; + uint32_t cell_id = 0x19B01; + const rrc_cell_cfg_nr_t& cell_cfg = cfg.cell_list[cc]; + + sib1.cell_sel_info_present = true; + sib1.cell_sel_info.q_rx_lev_min = -70; + sib1.cell_sel_info.q_qual_min_present = true; + sib1.cell_sel_info.q_qual_min = -20; + + sib1.cell_access_related_info.plmn_id_list.resize(1); + sib1.cell_access_related_info.plmn_id_list[0].plmn_id_list.resize(1); + srsran::plmn_id_t plmn; + plmn.from_string(plmn_str); + srsran::to_asn1(&sib1.cell_access_related_info.plmn_id_list[0].plmn_id_list[0], plmn); + sib1.cell_access_related_info.plmn_id_list[0].tac_present = true; + sib1.cell_access_related_info.plmn_id_list[0].tac.from_number(cell_cfg.tac); + sib1.cell_access_related_info.plmn_id_list[0].cell_id.from_number(cell_id); + sib1.cell_access_related_info.plmn_id_list[0].cell_reserved_for_oper.value = + plmn_id_info_s::cell_reserved_for_oper_opts::not_reserved; + + sib1.conn_est_fail_ctrl_present = true; + sib1.conn_est_fail_ctrl.conn_est_fail_count.value = conn_est_fail_ctrl_s::conn_est_fail_count_opts::n1; + sib1.conn_est_fail_ctrl.conn_est_fail_offset_validity.value = + conn_est_fail_ctrl_s::conn_est_fail_offset_validity_opts::s30; + sib1.conn_est_fail_ctrl.conn_est_fail_offset_present = true; + sib1.conn_est_fail_ctrl.conn_est_fail_offset = 1; + + // sib1.si_sched_info_present = true; + // sib1.si_sched_info.si_request_cfg.rach_occasions_si_present = true; + // sib1.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; + // sib1.si_sched_info.si_win_len.value = si_sched_info_s::si_win_len_opts::s20; + // sib1.si_sched_info.sched_info_list.resize(1); + // sib1.si_sched_info.sched_info_list[0].si_broadcast_status.value = + // sched_info_s::si_broadcast_status_opts::broadcasting; sib1.si_sched_info.sched_info_list[0].si_periodicity.value = + // sched_info_s::si_periodicity_opts::rf16; sib1.si_sched_info.sched_info_list[0].sib_map_info.resize(1); + // // scheduling of SI messages + // sib1.si_sched_info.sched_info_list[0].sib_map_info[0].type.value = sib_type_info_s::type_opts::sib_type2; + // sib1.si_sched_info.sched_info_list[0].sib_map_info[0].value_tag_present = true; + // sib1.si_sched_info.sched_info_list[0].sib_map_info[0].value_tag = 0; + + sib1.serving_cell_cfg_common_present = true; + fill_serv_cell_cfg_common_sib(cell_cfg, sib1.serving_cell_cfg_common); + + sib1.ue_timers_and_consts_present = true; + sib1.ue_timers_and_consts.t300.value = ue_timers_and_consts_s::t300_opts::ms1000; + sib1.ue_timers_and_consts.t301.value = ue_timers_and_consts_s::t301_opts::ms1000; + sib1.ue_timers_and_consts.t310.value = ue_timers_and_consts_s::t310_opts::ms1000; + sib1.ue_timers_and_consts.n310.value = ue_timers_and_consts_s::n310_opts::n1; + sib1.ue_timers_and_consts.t311.value = ue_timers_and_consts_s::t311_opts::ms30000; + sib1.ue_timers_and_consts.n311.value = ue_timers_and_consts_s::n311_opts::n1; + sib1.ue_timers_and_consts.t319.value = ue_timers_and_consts_s::t319_opts::ms1000; + return SRSRAN_SUCCESS; } +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +bool compute_diff_radio_bearer_cfg(const rrc_nr_cfg_t& cfg, + const radio_bearer_cfg_s& prev_bearers, + const radio_bearer_cfg_s& next_bearers, + radio_bearer_cfg_s& diff) +{ + // Compute SRB differences + std::vector srbs_to_rem; + srsran::compute_cfg_diff( + prev_bearers.srb_to_add_mod_list, next_bearers.srb_to_add_mod_list, diff.srb_to_add_mod_list, srbs_to_rem); + diff.srb_to_add_mod_list_present = diff.srb_to_add_mod_list.size() > 0; + + // Compute DRB differences + srsran::compute_cfg_diff(prev_bearers.drb_to_add_mod_list, + next_bearers.drb_to_add_mod_list, + diff.drb_to_add_mod_list, + diff.drb_to_release_list); + diff.drb_to_add_mod_list_present = diff.drb_to_add_mod_list.size() > 0; + diff.drb_to_release_list_present = diff.drb_to_release_list.size() > 0; + + return diff.srb_to_add_mod_list_present or diff.drb_to_release_list_present or diff.drb_to_add_mod_list_present; +} + +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) +{ + // Add SRBs + for (const srb_to_add_mod_s& srb : bearers.srb_to_add_mod_list) { + out.rlc_bearer_to_add_mod_list.push_back({}); + fill_srb(cfg, (srsran::nr_srb)srb.srb_id, out.rlc_bearer_to_add_mod_list.back()); + } + // Add DRBs + for (const drb_to_add_mod_s& drb : bearers.drb_to_add_mod_list) { + out.rlc_bearer_to_add_mod_list.push_back({}); + fill_srb(cfg, (srsran::nr_srb)drb.drb_id, out.rlc_bearer_to_add_mod_list.back()); + } + out.rlc_bearer_to_add_mod_list_present = out.rlc_bearer_to_add_mod_list.size() > 0; + + // Release DRBs + for (uint8_t drb_id : bearers.drb_to_release_list) { + out.rlc_bearer_to_release_list.push_back(drb_id); + } + out.rlc_bearer_to_release_list_present = out.rlc_bearer_to_release_list.size() > 0; +} + } // namespace srsenb diff --git a/srsgnb/src/stack/rrc/rrc_nr.cc b/srsgnb/src/stack/rrc/rrc_nr.cc index 5039b49f5..5c9498779 100644 --- a/srsgnb/src/stack/rrc/rrc_nr.cc +++ b/srsgnb/src/stack/rrc/rrc_nr.cc @@ -58,38 +58,15 @@ int rrc_nr::init(const rrc_nr_cfg_t& cfg_, rrc_eutra = rrc_eutra_; cfg = cfg_; - if (cfg.is_standalone) { - // Generate parameters of Coreset#0 and SS#0 - const uint32_t coreset0_idx = 7; - cfg.cell_list[0].phy_cell.pdcch.coreset_present[0] = true; - // Get pointA and SSB absolute frequencies - double pointA_abs_freq_Hz = cfg.cell_list[0].phy_cell.carrier.dl_center_frequency_hz - - cfg.cell_list[0].phy_cell.carrier.nof_prb * SRSRAN_NRE * - SRSRAN_SUBC_SPACING_NR(cfg.cell_list[0].phy_cell.carrier.scs) / 2; - double ssb_abs_freq_Hz = cfg.cell_list[0].phy_cell.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; - int ret = srsran_coreset_zero(cfg.cell_list[0].phy_cell.cell_id, - ssb_pointA_freq_offset_Hz, - cfg.cell_list[0].ssb_cfg.scs, - cfg.cell_list[0].phy_cell.carrier.scs, - coreset0_idx, - &cfg.cell_list[0].phy_cell.pdcch.coreset[0]); - srsran_assert(ret == SRSRAN_SUCCESS, "Failed to generate CORESET#0"); - cfg.cell_list[0].phy_cell.pdcch.search_space_present[0] = true; - cfg.cell_list[0].phy_cell.pdcch.search_space[0].id = 0; - cfg.cell_list[0].phy_cell.pdcch.search_space[0].coreset_id = 0; - cfg.cell_list[0].phy_cell.pdcch.search_space[0].type = srsran_search_space_type_common_0; - cfg.cell_list[0].phy_cell.pdcch.search_space[0].nof_candidates[0] = 1; - cfg.cell_list[0].phy_cell.pdcch.search_space[0].nof_candidates[1] = 1; - cfg.cell_list[0].phy_cell.pdcch.search_space[0].nof_candidates[2] = 1; - cfg.cell_list[0].phy_cell.pdcch.search_space[0].formats[0] = srsran_dci_format_nr_1_0; - cfg.cell_list[0].phy_cell.pdcch.search_space[0].nof_formats = 1; - cfg.cell_list[0].phy_cell.pdcch.search_space[0].duration = 1; - } + // Generate cell config structs cell_ctxt.reset(new cell_ctxt_t{}); + if (cfg.is_standalone) { + std::unique_ptr master_cell_group{new cell_group_cfg_s{}}; + int ret = fill_master_cell_cfg_from_enb_cfg(cfg, 0, *master_cell_group); + srsran_assert(ret == SRSRAN_SUCCESS, "Failed to configure MasterCellGroup"); + cell_ctxt->master_cell_group = std::move(master_cell_group); + } // derived slot_dur_ms = 1; @@ -154,6 +131,11 @@ template void rrc_nr::log_rrc_message(const char* sou srsran::const_byte_span pdu, const dl_ccch_msg_s& msg, const char* msg_type); +template void rrc_nr::log_rrc_message(const char* source, + const direction_t dir, + srsran::const_byte_span pdu, + const dl_dcch_msg_s& msg, + const char* msg_type); template void rrc_nr::log_rrc_message(const char* source, const direction_t dir, srsran::const_byte_span pdu, @@ -305,6 +287,8 @@ void rrc_nr::config_mac() srsran_assert(ret2, "Invalid NR cell configuration."); ret2 = srsran::make_duplex_cfg_from_serv_cell(base_sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common, &cell.duplex); srsran_assert(ret2, "Invalid NR cell configuration."); + ret2 = srsran::make_phy_mib(cell_ctxt->mib, &cell.mib); + srsran_assert(ret2, "Invalid NR cell MIB configuration."); // Set SIB1 and SI messages cell.sibs.resize(cell_ctxt->sib_buffer.size()); @@ -326,7 +310,7 @@ void rrc_nr::config_mac() int32_t rrc_nr::generate_sibs() { // MIB packing - fill_mib_from_enb_cfg(cfg, cell_ctxt->mib); + fill_mib_from_enb_cfg(cfg.cell_list[0], cell_ctxt->mib); bcch_bch_msg_s mib_msg; mib_msg.msg.set_mib() = cell_ctxt->mib; { @@ -350,7 +334,7 @@ int32_t rrc_nr::generate_sibs() } // SIB1 packing - fill_sib1_from_enb_cfg(cfg, cell_ctxt->sib1); + fill_sib1_from_enb_cfg(cfg, 0, cell_ctxt->sib1); si_sched_info_s::sched_info_list_l_& sched_info = cell_ctxt->sib1.si_sched_info.sched_info_list; // SI messages packing @@ -518,6 +502,12 @@ void rrc_nr::handle_ul_dcch(uint16_t rnti, uint32_t lcid, srsran::const_byte_spa case ul_dcch_msg_type_c::c1_c_::types_opts::rrc_setup_complete: u.handle_rrc_setup_complete(ul_dcch_msg.msg.c1().rrc_setup_complete()); break; + case ul_dcch_msg_type_c::c1_c_::types_opts::security_mode_complete: + u.handle_security_mode_complete(ul_dcch_msg.msg.c1().security_mode_complete()); + case ul_dcch_msg_type_c::c1_c_::types_opts::rrc_recfg_complete: + u.handle_rrc_reconfiguration_complete(ul_dcch_msg.msg.c1().rrc_recfg_complete()); + case ul_dcch_msg_type_c::c1_c_::types_opts::ul_info_transfer: + u.handle_ul_information_transfer(ul_dcch_msg.msg.c1().ul_info_transfer()); default: log_rx_pdu_fail(rnti, srb_to_lcid(lte_srb::srb0), pdu, "Unsupported UL-CCCH message type", false); // TODO Remove user @@ -577,6 +567,12 @@ int rrc_nr::start_security_mode_procedure(uint16_t rnti) } int rrc_nr::establish_rrc_bearer(uint16_t rnti, uint16_t pdu_session_id, srsran::const_byte_span nas_pdu, uint32_t lcid) { + if (not users.contains(rnti)) { + logger.error("Establishing RRC bearers for inexistent rnti=0x%x", rnti); + return SRSRAN_ERROR; + } + + users[rnti]->establish_eps_bearer(pdu_session_id, nas_pdu, lcid); return SRSRAN_SUCCESS; } @@ -590,7 +586,18 @@ int rrc_nr::allocate_lcid(uint16_t rnti) return SRSRAN_SUCCESS; } -void rrc_nr::write_dl_info(uint16_t rnti, srsran::unique_byte_buffer_t sdu) {} +void rrc_nr::write_dl_info(uint16_t rnti, srsran::unique_byte_buffer_t sdu) +{ + if (not users.contains(rnti)) { + logger.error("Received DL information transfer for inexistent rnti=0x%x", rnti); + return; + } + if (sdu == nullptr or sdu->size() == 0) { + logger.error("Received empty DL information transfer for rnti=0x%x", rnti); + return; + } + users[rnti]->send_dl_information_transfer(std::move(sdu)); +} /******************************************************************************* Interface for EUTRA RRC @@ -668,5 +675,6 @@ srsran::unique_byte_buffer_t rrc_nr::pack_into_pdu(const T& msg) return pdu; } template srsran::unique_byte_buffer_t rrc_nr::pack_into_pdu(const dl_ccch_msg_s& msg); +template srsran::unique_byte_buffer_t rrc_nr::pack_into_pdu(const dl_dcch_msg_s& msg); } // namespace srsenb diff --git a/srsgnb/src/stack/rrc/rrc_nr_config_utils.cc b/srsgnb/src/stack/rrc/rrc_nr_config_utils.cc new file mode 100644 index 000000000..625c2c54f --- /dev/null +++ b/srsgnb/src/stack/rrc/rrc_nr_config_utils.cc @@ -0,0 +1,292 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2021 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include "srsgnb/hdr/stack/rrc/rrc_nr_config_utils.h" +#include "srsran/common/band_helper.h" + +#define INVALID_PARAM(x, fmt, ...) \ + do { \ + if (not(x)) { \ + get_logger().error("ERROR: " fmt, ##__VA_ARGS__); \ + return SRSRAN_ERROR; \ + } \ + } while (0) + +namespace srsenb { + +static srslog::basic_logger& get_logger() +{ + static srslog::basic_logger& logger = srslog::fetch_basic_logger("ALL"); + return logger; +} + +/// Generate default phy cell configuration +void generate_default_nr_phy_cell(phy_cell_cfg_nr_t& phy_cell) +{ + phy_cell = {}; + + phy_cell.carrier.scs = srsran_subcarrier_spacing_15kHz; + phy_cell.carrier.nof_prb = 52; + phy_cell.carrier.max_mimo_layers = 1; + + phy_cell.dl_freq_hz = 0; // auto set + phy_cell.ul_freq_hz = 0; + phy_cell.num_ra_preambles = 52; + + // PRACH + phy_cell.prach.is_nr = true; + phy_cell.prach.config_idx = 8; + phy_cell.prach.root_seq_idx = 0; + phy_cell.prach.freq_offset = 1; + phy_cell.prach.num_ra_preambles = phy_cell.num_ra_preambles; + phy_cell.prach.hs_flag = false; + phy_cell.prach.tdd_config.configured = false; + + // PDCCH + // Configure CORESET ID 1 + phy_cell.pdcch.coreset_present[1] = true; + phy_cell.pdcch.coreset[1].id = 1; + phy_cell.pdcch.coreset[1].duration = 1; + phy_cell.pdcch.coreset[1].mapping_type = srsran_coreset_mapping_type_non_interleaved; + 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++) { + phy_cell.pdcch.coreset[1].freq_resources[i] = i < SRSRAN_FLOOR(phy_cell.carrier.nof_prb, 6); + } + + // Configure Search Space 1 as common + phy_cell.pdcch.search_space_present[1] = true; + phy_cell.pdcch.search_space[1].id = 1; + phy_cell.pdcch.search_space[1].coreset_id = 1; + phy_cell.pdcch.search_space[1].duration = 1; + phy_cell.pdcch.search_space[1].formats[0] = srsran_dci_format_nr_0_0; // DCI format for PUSCH + phy_cell.pdcch.search_space[1].formats[1] = srsran_dci_format_nr_1_0; // DCI format for PDSCH + phy_cell.pdcch.search_space[1].nof_formats = 2; + 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++) { + phy_cell.pdcch.search_space[1].nof_candidates[L] = + SRSRAN_MIN(2, srsran_pdcch_nr_max_candidates_coreset(&phy_cell.pdcch.coreset[1], L)); + } + + phy_cell.pdcch.ra_search_space_present = true; + phy_cell.pdcch.ra_search_space = phy_cell.pdcch.search_space[1]; + phy_cell.pdcch.ra_search_space.type = srsran_search_space_type_common_1; + + // PDSCH + phy_cell.pdsch.rs_power = 0; + phy_cell.pdsch.p_b = 0; +} + +/// Generate default rrc nr cell configuration +void generate_default_nr_cell(rrc_cell_cfg_nr_t& cell) +{ + cell = {}; + cell.coreset0_idx = 6; + cell.ssb_absolute_freq_point = 0; // auto derived + generate_default_nr_phy_cell(cell.phy_cell); +} + +/// Generate CORESET#0 and SSB absolute frequency (if not specified) +int derive_coreset0_params(rrc_cell_cfg_nr_t& cell) +{ + // Generate CORESET#0 + cell.phy_cell.pdcch.coreset_present[0] = true; + // Get pointA and SSB absolute frequencies + double pointA_abs_freq_Hz = + cell.phy_cell.carrier.dl_center_frequency_hz - + cell.phy_cell.carrier.nof_prb * SRSRAN_NRE * SRSRAN_SUBC_SPACING_NR(cell.phy_cell.carrier.scs) / 2; + double ssb_abs_freq_Hz = cell.phy_cell.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; + int ret = srsran_coreset_zero(cell.phy_cell.cell_id, + ssb_pointA_freq_offset_Hz, + cell.ssb_cfg.scs, + cell.phy_cell.carrier.scs, + cell.coreset0_idx, + &cell.phy_cell.pdcch.coreset[0]); + INVALID_PARAM(ret == SRSRAN_SUCCESS, "Failed to generate CORESET#0"); + return SRSRAN_SUCCESS; +} + +int derive_ssb_params(bool is_sa, + uint32_t dl_arfcn, + uint32_t band, + srsran_subcarrier_spacing_t pdcch_scs, + uint32_t coreset0_idx, + uint32_t nof_prb, + srsran_ssb_cfg_t& ssb) +{ + // Verify essential parameters are specified and valid + INVALID_PARAM(dl_arfcn > 0, "Invalid DL ARFCN=%d", dl_arfcn); + INVALID_PARAM(band > 0, "Band is a mandatory parameter"); + INVALID_PARAM(pdcch_scs < srsran_subcarrier_spacing_invalid, "Invalid carrier SCS"); + INVALID_PARAM(coreset0_idx < 15, "Invalid controlResourceSetZero"); + INVALID_PARAM(nof_prb > 0, "Invalid DL number of PRBS=%d", nof_prb); + + srsran::srsran_band_helper band_helper; + + double dl_freq_hz = band_helper.nr_arfcn_to_freq(dl_arfcn); + uint32_t dl_absolute_freq_point_a = band_helper.get_abs_freq_point_a_arfcn(nof_prb, dl_arfcn); + + ssb.center_freq_hz = dl_freq_hz; + ssb.duplex_mode = band_helper.get_duplex_mode(band); + + // derive SSB pattern and scs + ssb.pattern = band_helper.get_ssb_pattern(band, srsran_subcarrier_spacing_15kHz); + if (ssb.pattern == SRSRAN_SSB_PATTERN_A) { + // 15kHz SSB SCS + ssb.scs = srsran_subcarrier_spacing_15kHz; + } else { + // try to optain SSB pattern for same band with 30kHz SCS + ssb.pattern = band_helper.get_ssb_pattern(band, srsran_subcarrier_spacing_30kHz); + if (ssb.pattern == SRSRAN_SSB_PATTERN_B || ssb.pattern == SRSRAN_SSB_PATTERN_C) { + // SSB SCS is 30 kHz + ssb.scs = srsran_subcarrier_spacing_30kHz; + } else { + srsran_terminate("Can't derive SSB pattern from band %d", band); + } + } + + // derive SSB position + int coreset0_rb_offset = 0; + if (is_sa) { + // Get offset in RBs between CORESET#0 and SSB + coreset0_rb_offset = srsran_coreset0_ssb_offset(coreset0_idx, ssb.scs, pdcch_scs); + INVALID_PARAM(coreset0_rb_offset >= 0, "Failed to compute RB offset between CORESET#0 and SSB"); + } else { + // TODO: Verify if specified SSB frequency is valid + } + uint32_t ssb_abs_freq_point = + band_helper.get_abs_freq_ssb_arfcn(band, ssb.scs, dl_absolute_freq_point_a, coreset0_rb_offset); + INVALID_PARAM(ssb_abs_freq_point > 0, + "Can't derive SSB freq point for dl_arfcn=%d and band %d", + band_helper.freq_to_nr_arfcn(dl_freq_hz), + band); + + // Convert to frequency for PHY + ssb.ssb_freq_hz = band_helper.nr_arfcn_to_freq(ssb_abs_freq_point); + + ssb.periodicity_ms = 10; // TODO: make a param + ssb.beta_pss = 0.0; + ssb.beta_sss = 0.0; + ssb.beta_pbch = 0.0; + ssb.beta_pbch_dmrs = 0.0; + // set by PHY layer in worker_pool::set_common_cfg + ssb.srate_hz = 0.0; + ssb.scaling = 0.0; + + return SRSRAN_SUCCESS; +} + +int derive_phy_cell_freq_params(uint32_t dl_arfcn, uint32_t ul_arfcn, phy_cell_cfg_nr_t& phy_cell) +{ + // Verify essential parameters are specified and valid + INVALID_PARAM(dl_arfcn > 0, "DL ARFCN is a mandatory parameter"); + + // Use helper class to derive NR carrier parameters + srsran::srsran_band_helper band_helper; + + // derive DL freq from ARFCN + if (phy_cell.dl_freq_hz == 0) { + phy_cell.dl_freq_hz = band_helper.nr_arfcn_to_freq(dl_arfcn); + } + + // derive UL freq from ARFCN + if (phy_cell.ul_freq_hz == 0) { + // auto-detect UL frequency + if (ul_arfcn == 0) { + // derive UL ARFCN from given DL ARFCN + ul_arfcn = band_helper.get_ul_arfcn_from_dl_arfcn(dl_arfcn); + INVALID_PARAM(ul_arfcn > 0, "Can't derive UL ARFCN from DL ARFCN %d", dl_arfcn); + } + phy_cell.ul_freq_hz = band_helper.nr_arfcn_to_freq(ul_arfcn); + } + + // copy center frequencies + phy_cell.carrier.dl_center_frequency_hz = phy_cell.dl_freq_hz; + phy_cell.carrier.ul_center_frequency_hz = phy_cell.ul_freq_hz; + + return SRSRAN_SUCCESS; +} + +int set_derived_nr_cell_params(bool is_sa, rrc_cell_cfg_nr_t& cell) +{ + // Verify essential parameters are specified and valid + INVALID_PARAM(cell.dl_arfcn > 0, "DL ARFCN is a mandatory parameter"); + INVALID_PARAM(cell.band > 0, "Band is a mandatory parameter"); + INVALID_PARAM(cell.phy_cell.carrier.nof_prb > 0, "Number of PRBs is a mandatory parameter"); + + // Use helper class to derive NR carrier parameters + srsran::srsran_band_helper band_helper; + + if (cell.ul_arfcn == 0) { + // derive UL ARFCN from given DL ARFCN + cell.ul_arfcn = band_helper.get_ul_arfcn_from_dl_arfcn(cell.dl_arfcn); + INVALID_PARAM(cell.ul_arfcn > 0, "Can't derive UL ARFCN from DL ARFCN %d", cell.dl_arfcn); + } + + // duplex mode + cell.duplex_mode = band_helper.get_duplex_mode(cell.band); + + // PointA + cell.dl_absolute_freq_point_a = band_helper.get_abs_freq_point_a_arfcn(cell.phy_cell.carrier.nof_prb, cell.dl_arfcn); + cell.ul_absolute_freq_point_a = band_helper.get_abs_freq_point_a_arfcn(cell.phy_cell.carrier.nof_prb, cell.ul_arfcn); + + // Derive phy_cell parameters that depend on ARFCNs + derive_phy_cell_freq_params(cell.dl_arfcn, cell.ul_arfcn, cell.phy_cell); + + // Derive SSB params + derive_ssb_params(is_sa, + cell.dl_arfcn, + cell.band, + cell.phy_cell.carrier.scs, + cell.coreset0_idx, + cell.phy_cell.carrier.nof_prb, + cell.ssb_cfg); + cell.phy_cell.carrier.ssb_center_freq_hz = cell.ssb_cfg.ssb_freq_hz; + cell.ssb_absolute_freq_point = band_helper.freq_to_nr_arfcn(cell.ssb_cfg.ssb_freq_hz); + + // Derive remaining config params + if (is_sa) { + derive_coreset0_params(cell); + cell.phy_cell.pdcch.search_space_present[0] = true; + cell.phy_cell.pdcch.search_space[0].id = 0; + cell.phy_cell.pdcch.search_space[0].coreset_id = 0; + cell.phy_cell.pdcch.search_space[0].type = srsran_search_space_type_common_0; + cell.phy_cell.pdcch.search_space[0].nof_candidates[0] = 1; + cell.phy_cell.pdcch.search_space[0].nof_candidates[1] = 1; + cell.phy_cell.pdcch.search_space[0].nof_candidates[2] = 1; + cell.phy_cell.pdcch.search_space[0].formats[0] = srsran_dci_format_nr_1_0; + cell.phy_cell.pdcch.search_space[0].nof_formats = 1; + cell.phy_cell.pdcch.search_space[0].duration = 1; + } + + // Derive remaining PHY cell params + cell.phy_cell.prach.num_ra_preambles = cell.phy_cell.num_ra_preambles; + cell.phy_cell.prach.tdd_config.configured = (cell.duplex_mode == SRSRAN_DUPLEX_MODE_TDD); + + return check_nr_cell_cfg_valid(cell, is_sa); +} + +int check_nr_cell_cfg_valid(const rrc_cell_cfg_nr_t& cell, bool is_sa) +{ + // verify SSB params are consistent + INVALID_PARAM(cell.ssb_cfg.center_freq_hz == cell.phy_cell.dl_freq_hz, "Invalid SSB param generation"); + + return SRSRAN_SUCCESS; +} + +} // namespace srsenb \ No newline at end of file diff --git a/srsgnb/src/stack/rrc/rrc_nr_ue.cc b/srsgnb/src/stack/rrc/rrc_nr_ue.cc index d85d4f4b6..ef39c38e2 100644 --- a/srsgnb/src/stack/rrc/rrc_nr_ue.cc +++ b/srsgnb/src/stack/rrc/rrc_nr_ue.cc @@ -35,7 +35,7 @@ Every function in UE class is called from a mutex environment thus does not need extra protection. *******************************************************************************/ rrc_nr::ue::ue(rrc_nr* parent_, uint16_t rnti_, const sched_nr_ue_cfg_t& uecfg_, bool start_msg3_timer) : - parent(parent_), rnti(rnti_), uecfg(uecfg_) + parent(parent_), logger(parent_->logger), rnti(rnti_), uecfg(uecfg_) { // Derive UE cfg from rrc_cfg_nr_t uecfg.phy_cfg.pdcch = parent->cfg.cell_list[0].phy_cell.pdcch; @@ -65,12 +65,12 @@ void rrc_nr::ue::set_activity_timeout(activity_timeout_type_t type) deadline_ms = 10000; break; default: - parent->logger.error("Unknown timeout type %d", type); + logger.error("Unknown timeout type %d", type); return; } activity_timer.set(deadline_ms, [this, type](uint32_t tid) { activity_timer_expired(type); }); - parent->logger.debug("Setting timer for %s for rnti=0x%x to %dms", to_string(type).c_str(), rnti, deadline_ms); + logger.debug("Setting timer for %s for rnti=0x%x to %dms", to_string(type).c_str(), rnti, deadline_ms); set_activity(); } @@ -79,7 +79,7 @@ void rrc_nr::ue::set_activity(bool enabled) { if (not enabled) { if (activity_timer.is_running()) { - parent->logger.debug("Inactivity timer interrupted for rnti=0x%x", rnti); + logger.debug("Inactivity timer interrupted for rnti=0x%x", rnti); } activity_timer.stop(); return; @@ -87,12 +87,12 @@ void rrc_nr::ue::set_activity(bool enabled) // re-start activity timer with current timeout value activity_timer.run(); - parent->logger.debug("Activity registered for rnti=0x%x (timeout_value=%dms)", rnti, activity_timer.duration()); + logger.debug("Activity registered for rnti=0x%x (timeout_value=%dms)", rnti, activity_timer.duration()); } void rrc_nr::ue::activity_timer_expired(const activity_timeout_type_t type) { - parent->logger.info("Activity timer for rnti=0x%x expired after %d ms", rnti, activity_timer.time_elapsed()); + logger.info("Activity timer for rnti=0x%x expired after %d ms", rnti, activity_timer.time_elapsed()); switch (type) { case MSG5_RX_TIMEOUT: @@ -110,7 +110,7 @@ void rrc_nr::ue::activity_timer_expired(const activity_timeout_type_t type) default: // Unhandled activity timeout, just remove UE and log an error parent->rem_user(rnti); - parent->logger.error( + logger.error( "Unhandled reason for activity timer expiration. rnti=0x%x, cause %d", rnti, static_cast(type)); } } @@ -126,7 +126,7 @@ void rrc_nr::ue::send_dl_ccch(const dl_ccch_msg_s& dl_ccch_msg) // Allocate a new PDU buffer, pack the message and send to PDCP srsran::unique_byte_buffer_t pdu = parent->pack_into_pdu(dl_ccch_msg); if (pdu == nullptr) { - parent->logger.error("Failed to send DL-CCCH"); + logger.error("Failed to send DL-CCCH"); return; } fmt::memory_buffer fmtbuf; @@ -135,6 +135,20 @@ void rrc_nr::ue::send_dl_ccch(const dl_ccch_msg_s& dl_ccch_msg) parent->rlc->write_sdu(rnti, srsran::srb_to_lcid(srsran::nr_srb::srb0), std::move(pdu)); } +void rrc_nr::ue::send_dl_dcch(srsran::nr_srb srb, const asn1::rrc_nr::dl_dcch_msg_s& dl_dcch_msg) +{ + // Allocate a new PDU buffer, pack the message and send to PDCP + srsran::unique_byte_buffer_t pdu = parent->pack_into_pdu(dl_dcch_msg); + if (pdu == nullptr) { + logger.error("Failed to send DL-DCCH"); + return; + } + fmt::memory_buffer fmtbuf; + fmt::format_to(fmtbuf, "DL-DCCH.{}", dl_dcch_msg.msg.c1().type().to_string()); + log_rrc_message(srb, Tx, *pdu.get(), dl_dcch_msg, srsran::to_c_str(fmtbuf)); + parent->pdcp->write_sdu(rnti, srsran::srb_to_lcid(srb), std::move(pdu)); +} + int rrc_nr::ue::pack_secondary_cell_group_rlc_cfg(asn1::rrc_nr::cell_group_cfg_s& cell_group_cfg_pack) { // RLC for DRB1 (with fixed LCID) @@ -208,7 +222,6 @@ int rrc_nr::ue::pack_sp_cell_cfg_ded_init_dl_bwp(asn1::rrc_nr::cell_group_cfg_s& { cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.init_dl_bwp_present = true; - pack_sp_cell_cfg_ded_init_dl_bwp_pdsch_cfg(cell_group_cfg_pack); pack_sp_cell_cfg_ded_init_dl_bwp_radio_link_monitoring(cell_group_cfg_pack); return SRSRAN_SUCCESS; @@ -231,58 +244,6 @@ int rrc_nr::ue::pack_sp_cell_cfg_ded_init_dl_bwp_radio_link_monitoring( return SRSRAN_SUCCESS; } -int rrc_nr::ue::pack_sp_cell_cfg_ded_init_dl_bwp_pdsch_cfg(asn1::rrc_nr::cell_group_cfg_s& cell_group_cfg_pack) -{ - cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.init_dl_bwp.pdsch_cfg_present = true; - auto& pdsch_cfg_dedicated = cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.init_dl_bwp.pdsch_cfg; - - pdsch_cfg_dedicated.set_setup(); - pdsch_cfg_dedicated.setup().dmrs_dl_for_pdsch_map_type_a_present = true; - pdsch_cfg_dedicated.setup().dmrs_dl_for_pdsch_map_type_a.set_setup(); - pdsch_cfg_dedicated.setup().dmrs_dl_for_pdsch_map_type_a.setup().dmrs_add_position_present = true; - pdsch_cfg_dedicated.setup().dmrs_dl_for_pdsch_map_type_a.setup().dmrs_add_position = - asn1::rrc_nr::dmrs_dl_cfg_s::dmrs_add_position_opts::pos1; - pdsch_cfg_dedicated.setup().tci_states_to_add_mod_list_present = true; - pdsch_cfg_dedicated.setup().tci_states_to_add_mod_list.resize(1); - pdsch_cfg_dedicated.setup().tci_states_to_add_mod_list[0].tci_state_id = 0; - pdsch_cfg_dedicated.setup().tci_states_to_add_mod_list[0].qcl_type1.ref_sig.set_ssb(); - pdsch_cfg_dedicated.setup().tci_states_to_add_mod_list[0].qcl_type1.ref_sig.ssb() = 0; - pdsch_cfg_dedicated.setup().tci_states_to_add_mod_list[0].qcl_type1.qcl_type = - asn1::rrc_nr::qcl_info_s::qcl_type_opts::type_d; - pdsch_cfg_dedicated.setup().res_alloc = pdsch_cfg_s::res_alloc_opts::res_alloc_type1; - pdsch_cfg_dedicated.setup().rbg_size = asn1::rrc_nr::pdsch_cfg_s::rbg_size_opts::cfg1; - pdsch_cfg_dedicated.setup().prb_bundling_type.set_static_bundling(); - pdsch_cfg_dedicated.setup().prb_bundling_type.static_bundling().bundle_size_present = true; - pdsch_cfg_dedicated.setup().prb_bundling_type.static_bundling().bundle_size = - asn1::rrc_nr::pdsch_cfg_s::prb_bundling_type_c_::static_bundling_s_::bundle_size_opts::wideband; - - // ZP-CSI - pdsch_cfg_dedicated.setup().zp_csi_rs_res_to_add_mod_list_present = false; - pdsch_cfg_dedicated.setup().zp_csi_rs_res_to_add_mod_list.resize(1); - pdsch_cfg_dedicated.setup().zp_csi_rs_res_to_add_mod_list[0].zp_csi_rs_res_id = 0; - pdsch_cfg_dedicated.setup().zp_csi_rs_res_to_add_mod_list[0].res_map.freq_domain_alloc.set_row4(); - pdsch_cfg_dedicated.setup().zp_csi_rs_res_to_add_mod_list[0].res_map.freq_domain_alloc.row4().from_number(0b100); - pdsch_cfg_dedicated.setup().zp_csi_rs_res_to_add_mod_list[0].res_map.nrof_ports = - asn1::rrc_nr::csi_rs_res_map_s::nrof_ports_opts::p4; - - pdsch_cfg_dedicated.setup().zp_csi_rs_res_to_add_mod_list[0].res_map.first_ofdm_symbol_in_time_domain = 8; - pdsch_cfg_dedicated.setup().zp_csi_rs_res_to_add_mod_list[0].res_map.cdm_type = - asn1::rrc_nr::csi_rs_res_map_s::cdm_type_opts::fd_cdm2; - pdsch_cfg_dedicated.setup().zp_csi_rs_res_to_add_mod_list[0].res_map.density.set_one(); - - pdsch_cfg_dedicated.setup().zp_csi_rs_res_to_add_mod_list[0].res_map.freq_band.start_rb = 0; - pdsch_cfg_dedicated.setup().zp_csi_rs_res_to_add_mod_list[0].res_map.freq_band.nrof_rbs = 52; - pdsch_cfg_dedicated.setup().zp_csi_rs_res_to_add_mod_list[0].periodicity_and_offset_present = true; - pdsch_cfg_dedicated.setup().zp_csi_rs_res_to_add_mod_list[0].periodicity_and_offset.set_slots80(); - pdsch_cfg_dedicated.setup().zp_csi_rs_res_to_add_mod_list[0].periodicity_and_offset.slots80() = 1; - pdsch_cfg_dedicated.setup().p_zp_csi_rs_res_set_present = false; - pdsch_cfg_dedicated.setup().p_zp_csi_rs_res_set.set_setup(); - pdsch_cfg_dedicated.setup().p_zp_csi_rs_res_set.setup().zp_csi_rs_res_set_id = 0; - pdsch_cfg_dedicated.setup().p_zp_csi_rs_res_set.setup().zp_csi_rs_res_id_list.resize(1); - - return SRSRAN_SUCCESS; -} - int rrc_nr::ue::pack_sp_cell_cfg_ded_ul_cfg_init_ul_bwp_pucch_cfg(asn1::rrc_nr::cell_group_cfg_s& cell_group_cfg_pack) { // PUCCH @@ -352,13 +313,13 @@ int rrc_nr::ue::pack_sp_cell_cfg_ded_ul_cfg_init_ul_bwp_pucch_cfg(asn1::rrc_nr:: pucch_cfg.setup().res_to_add_mod_list_present = true; pucch_cfg.setup().res_to_add_mod_list.resize(3); if (not srsran::make_phy_res_config(resource_small, pucch_cfg.setup().res_to_add_mod_list[0], 0)) { - parent->logger.warning("Failed to create 1-2 bit NR PUCCH resource"); + logger.warning("Failed to create 1-2 bit NR PUCCH resource"); } if (not srsran::make_phy_res_config(resource_big, pucch_cfg.setup().res_to_add_mod_list[1], 1)) { - parent->logger.warning("Failed to create >2 bit NR PUCCH resource"); + logger.warning("Failed to create >2 bit NR PUCCH resource"); } if (not srsran::make_phy_res_config(resource_sr, pucch_cfg.setup().res_to_add_mod_list[2], 2)) { - parent->logger.warning("Failed to create SR NR PUCCH resource"); + logger.warning("Failed to create SR NR PUCCH resource"); } // Make 2 PUCCH resource sets @@ -462,14 +423,7 @@ int rrc_nr::ue::pack_sp_cell_cfg_ded_pdcch_serving_cell_cfg(asn1::rrc_nr::cell_g int rrc_nr::ue::pack_sp_cell_cfg_ded(asn1::rrc_nr::cell_group_cfg_s& cell_group_cfg_pack) { // SP Cell Dedicated config - cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded_present = true; - cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.first_active_dl_bwp_id_present = true; - - if (parent->cfg.cell_list[0].duplex_mode == SRSRAN_DUPLEX_MODE_FDD) { - cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.first_active_dl_bwp_id = 0; - } else { - cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.first_active_dl_bwp_id = 1; - } + cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded_present = true; pack_sp_cell_cfg_ded_ul_cfg(cell_group_cfg_pack); pack_sp_cell_cfg_ded_init_dl_bwp(cell_group_cfg_pack); @@ -479,7 +433,7 @@ int rrc_nr::ue::pack_sp_cell_cfg_ded(asn1::rrc_nr::cell_group_cfg_s& cell_group_ // spCellConfig if (fill_sp_cell_cfg_from_enb_cfg(parent->cfg, UE_PSCELL_CC_IDX, cell_group_cfg_pack.sp_cell_cfg) != SRSRAN_SUCCESS) { - parent->logger.error("Failed to pack spCellConfig for rnti=0x%x", rnti); + logger.error("Failed to pack spCellConfig for rnti=0x%x", rnti); } return SRSRAN_SUCCESS; @@ -659,7 +613,7 @@ int rrc_nr::ue::pack_secondary_cell_group_cfg(asn1::dyn_octstring& packed_second packed_secondary_cell_config.resize(256); asn1::bit_ref bref_pack(packed_secondary_cell_config.data(), packed_secondary_cell_config.size()); if (cell_group_cfg_pack.pack(bref_pack) != asn1::SRSASN_SUCCESS) { - parent->logger.error("Failed to pack NR secondary cell config"); + logger.error("Failed to pack NR secondary cell config"); return SRSRAN_ERROR; } packed_secondary_cell_config.resize(bref_pack.distance_bytes()); @@ -680,7 +634,7 @@ int rrc_nr::ue::pack_rrc_reconfiguration(asn1::dyn_octstring& packed_rrc_reconfi recfg_ies.secondary_cell_group_present = true; if (pack_secondary_cell_group_cfg(recfg_ies.secondary_cell_group) == SRSRAN_ERROR) { - parent->logger.error("Failed to pack secondary cell group"); + logger.error("Failed to pack secondary cell group"); return SRSRAN_ERROR; } @@ -688,7 +642,7 @@ int rrc_nr::ue::pack_rrc_reconfiguration(asn1::dyn_octstring& packed_rrc_reconfi packed_rrc_reconfig.resize(512); asn1::bit_ref bref_pack(packed_rrc_reconfig.data(), packed_rrc_reconfig.size()); if (reconfig.pack(bref_pack) != asn1::SRSASN_SUCCESS) { - parent->logger.error("Failed to pack RRC Reconfiguration"); + logger.error("Failed to pack RRC Reconfiguration"); return SRSRAN_ERROR; } packed_rrc_reconfig.resize(bref_pack.distance_bytes()); @@ -714,7 +668,7 @@ int rrc_nr::ue::pack_nr_radio_bearer_config(asn1::dyn_octstring& packed_nr_beare packed_nr_bearer_config.resize(128); asn1::bit_ref bref_pack(packed_nr_bearer_config.data(), packed_nr_bearer_config.size()); if (radio_bearer_cfg_pack.pack(bref_pack) != asn1::SRSASN_SUCCESS) { - parent->logger.error("Failed to pack NR radio bearer config"); + logger.error("Failed to pack NR radio bearer config"); return SRSRAN_ERROR; } @@ -878,25 +832,36 @@ int rrc_nr::ue::add_drb() void rrc_nr::ue::handle_rrc_setup_request(const asn1::rrc_nr::rrc_setup_request_s& msg) { + const uint8_t max_wait_time_secs = 16; if (not parent->ngap->is_amf_connected()) { - parent->logger.error("MME isn't connected. Sending Connection Reject"); - const uint8_t max_wait_time_secs = 16; - send_rrc_reject(max_wait_time_secs); // See TS 38.331, RejectWaitTime + logger.error("MME isn't connected. Sending Connection Reject"); + send_rrc_reject(max_wait_time_secs); + return; + } + + // Allocate PUCCH resources and reject if not available + if (not init_pucch()) { + logger.warning("Could not allocate PUCCH resources for rnti=0x%x. Sending Connection Reject", rnti); + send_rrc_reject(max_wait_time_secs); return; } - // TODO: Allocate PUCCH resources and reject if not available + const rrc_setup_request_ies_s& ies = msg.rrc_setup_request; - switch (msg.rrc_setup_request.ue_id.type().value) { - case asn1::rrc_nr::init_ue_id_c::types_opts::ng_minus5_g_s_tmsi_part1: - // TODO: communicate with NGAP + switch (ies.ue_id.type().value) { + case init_ue_id_c::types_opts::ng_minus5_g_s_tmsi_part1: + ctxt.setup_ue_id = ies.ue_id.ng_minus5_g_s_tmsi_part1().to_number(); break; case asn1::rrc_nr::init_ue_id_c::types_opts::random_value: + ctxt.setup_ue_id = ies.ue_id.random_value().to_number(); // TODO: communicate with NGAP break; default: - parent->logger.error("Unsupported RRCSetupRequest"); + logger.error("Unsupported RRCSetupRequest"); + send_rrc_reject(max_wait_time_secs); + return; } + ctxt.connection_cause.value = ies.establishment_cause.value; send_rrc_setup(); set_activity_timeout(UE_INACTIVITY_TIMEOUT); @@ -907,27 +872,62 @@ void rrc_nr::ue::send_rrc_reject(uint8_t reject_wait_time_secs) { dl_ccch_msg_s msg; rrc_reject_ies_s& reject = msg.msg.set_c1().set_rrc_reject().crit_exts.set_rrc_reject(); + + // See TS 38.331, RejectWaitTime if (reject_wait_time_secs > 0) { reject.wait_time_present = true; reject.wait_time = reject_wait_time_secs; } send_dl_ccch(msg); + + // TODO: remove user } /// TS 38.331, RRCSetup void rrc_nr::ue::send_rrc_setup() { + const uint8_t max_wait_time_secs = 16; + + // Add SRB1 to UE context + // Note: See 5.3.5.6.3 - SRB addition/modification + next_radio_bearer_cfg.srb_to_add_mod_list_present = true; + next_radio_bearer_cfg.srb_to_add_mod_list.resize(1); + srb_to_add_mod_s& srb1 = next_radio_bearer_cfg.srb_to_add_mod_list[0]; + srb1.srb_id = 1; + + // Generate RRC setup message + dl_ccch_msg_s msg; rrc_setup_s& setup = msg.msg.set_c1().set_rrc_setup(); setup.rrc_transaction_id = (uint8_t)((transaction_id++) % 4); rrc_setup_ies_s& setup_ies = setup.crit_exts.set_rrc_setup(); // Fill RRC Setup - // Note: See 5.3.5.6.3 - SRB addition/modification - setup_ies.radio_bearer_cfg.srb_to_add_mod_list_present = true; - setup_ies.radio_bearer_cfg.srb_to_add_mod_list.resize(1); - srb_to_add_mod_s& srb1 = setup_ies.radio_bearer_cfg.srb_to_add_mod_list[0]; - srb1.srb_id = 1; + // - Setup SRB1 + compute_diff_radio_bearer_cfg(parent->cfg, radio_bearer_cfg, next_radio_bearer_cfg, setup_ies.radio_bearer_cfg); + + // - Setup masterCellGroup + asn1::rrc_nr::cell_group_cfg_s master_cell_group = *parent->cell_ctxt->master_cell_group; + // - Derive master cell group config bearers + fill_cellgroup_with_radio_bearer_cfg(parent->cfg, setup_ies.radio_bearer_cfg, master_cell_group); + { + srsran::unique_byte_buffer_t pdu = srsran::make_byte_buffer(); + asn1::bit_ref bref{pdu->data(), pdu->get_tailroom()}; + if (master_cell_group.pack(bref) != SRSRAN_SUCCESS) { + logger.error("Failed to pack master cell group"); + send_rrc_reject(max_wait_time_secs); + return; + } + pdu->N_bytes = bref.distance_bytes(); + + setup_ies.master_cell_group.resize(pdu->N_bytes); + memcpy(setup_ies.master_cell_group.data(), pdu->data(), pdu->N_bytes); + } + if (logger.debug.enabled()) { + asn1::json_writer js; + parent->cell_ctxt->master_cell_group->to_json(js); + logger.debug("Containerized MasterCellGroup: %s", js.to_string().c_str()); + } send_dl_ccch(msg); } @@ -935,7 +935,122 @@ void rrc_nr::ue::send_rrc_setup() /// TS 38.331, RRCSetupComplete void rrc_nr::ue::handle_rrc_setup_complete(const asn1::rrc_nr::rrc_setup_complete_s& msg) { - // TODO: handle RRCSetupComplete + // Update current radio bearer cfg + radio_bearer_cfg = next_radio_bearer_cfg; + + // Create UE context in NGAP + using ngap_cause_t = asn1::ngap_nr::rrcestablishment_cause_opts::options; + auto ngap_cause = (ngap_cause_t)ctxt.connection_cause.value; // NGAP and RRC causes seem to have a 1-1 mapping + parent->ngap->initial_ue( + rnti, uecfg.carriers[0].cc, ngap_cause, msg.crit_exts.rrc_setup_complete().ded_nas_msg, ctxt.setup_ue_id); +} + +/// TS 38.331, SecurityModeCommand +void rrc_nr::ue::send_security_mode_command() +{ + asn1::rrc_nr::dl_dcch_msg_s dl_dcch_msg; + dl_dcch_msg.msg.set_c1().set_security_mode_cmd().rrc_transaction_id = (uint8_t)((transaction_id++) % 4); + security_mode_cmd_ies_s& ies = dl_dcch_msg.msg.c1().security_mode_cmd().crit_exts.set_security_mode_cmd(); + + ies.security_cfg_smc.security_algorithm_cfg.integrity_prot_algorithm_present = true; + ies.security_cfg_smc.security_algorithm_cfg.integrity_prot_algorithm.value = integrity_prot_algorithm_opts::nia0; + ies.security_cfg_smc.security_algorithm_cfg.ciphering_algorithm.value = ciphering_algorithm_opts::nea0; + + send_dl_dcch(srsran::nr_srb::srb1, dl_dcch_msg); +} + +/// TS 38.331, SecurityModeComplete +void rrc_nr::ue::handle_security_mode_complete(const asn1::rrc_nr::security_mode_complete_s& msg) +{ + // TODO: handle SecurityModeComplete + + // Note: Skip UE capabilities + + send_rrc_reconfiguration(); +} + +void rrc_nr::ue::send_rrc_reconfiguration() +{ + asn1::rrc_nr::dl_dcch_msg_s dl_dcch_msg; + dl_dcch_msg.msg.set_c1().set_rrc_recfg().rrc_transaction_id = (uint8_t)((transaction_id++) % 4); + rrc_recfg_ies_s& ies = dl_dcch_msg.msg.c1().rrc_recfg().crit_exts.set_rrc_recfg(); + + // Add new SRBs/DRBs + ies.radio_bearer_cfg_present = + compute_diff_radio_bearer_cfg(parent->cfg, radio_bearer_cfg, next_radio_bearer_cfg, ies.radio_bearer_cfg); + + ies.non_crit_ext_present = true; + ies.non_crit_ext.master_cell_group_present = false; // TODO + + // Update lower layers + + send_dl_dcch(srsran::nr_srb::srb1, dl_dcch_msg); +} + +void rrc_nr::ue::handle_rrc_reconfiguration_complete(const asn1::rrc_nr::rrc_recfg_complete_s& msg) +{ + radio_bearer_cfg = next_radio_bearer_cfg; +} + +void rrc_nr::ue::send_dl_information_transfer(srsran::unique_byte_buffer_t sdu) +{ + dl_dcch_msg_s dl_dcch_msg; + dl_dcch_msg.msg.set_c1().set_dl_info_transfer().rrc_transaction_id = (uint8_t)((transaction_id++) % 4); + dl_info_transfer_ies_s& ies = dl_dcch_msg.msg.c1().dl_info_transfer().crit_exts.set_dl_info_transfer(); + + ies.ded_nas_msg_present = true; + ies.ded_nas_msg.resize(sdu->N_bytes); + memcpy(ies.ded_nas_msg.data(), sdu->data(), ies.ded_nas_msg.size()); + + send_dl_dcch(srsran::nr_srb::srb1, dl_dcch_msg); +} + +void rrc_nr::ue::handle_ul_information_transfer(const asn1::rrc_nr::ul_info_transfer_s& msg) +{ + // Forward dedicatedNAS-Message to NGAP + parent->ngap->write_pdu(rnti, msg.crit_exts.ul_info_transfer().ded_nas_msg); +} + +void rrc_nr::ue::establish_eps_bearer(uint32_t pdu_session_id, srsran::const_byte_span nas_pdu, uint32_t lcid) +{ + // Add SRB2, if not yet added + if (radio_bearer_cfg.srb_to_add_mod_list.size() <= 1) { + next_radio_bearer_cfg.srb_to_add_mod_list_present = true; + next_radio_bearer_cfg.srb_to_add_mod_list.resize(1); + next_radio_bearer_cfg.srb_to_add_mod_list[0].srb_id = 2; + } + + drb_to_add_mod_s drb; + drb.cn_assoc_present = true; + drb.cn_assoc.set_sdap_cfg().pdu_session = 1; + drb.cn_assoc.sdap_cfg().sdap_hdr_dl.value = asn1::rrc_nr::sdap_cfg_s::sdap_hdr_dl_opts::absent; + drb.cn_assoc.sdap_cfg().sdap_hdr_ul.value = asn1::rrc_nr::sdap_cfg_s::sdap_hdr_ul_opts::absent; + drb.cn_assoc.sdap_cfg().default_drb = true; + drb.cn_assoc.sdap_cfg().mapped_qos_flows_to_add_present = true; + drb.cn_assoc.sdap_cfg().mapped_qos_flows_to_add.resize(1); + drb.cn_assoc.sdap_cfg().mapped_qos_flows_to_add[0] = 1; + + drb.drb_id = 1; + drb.pdcp_cfg_present = true; + drb.pdcp_cfg.drb.discard_timer_present = true; + drb.pdcp_cfg.drb.discard_timer.value = pdcp_cfg_s::drb_s_::discard_timer_opts::ms100; + drb.pdcp_cfg.drb.pdcp_sn_size_ul_present = true; + drb.pdcp_cfg.drb.pdcp_sn_size_ul.value = asn1::rrc_nr::pdcp_cfg_s::drb_s_::pdcp_sn_size_ul_opts::len18bits; + drb.pdcp_cfg.drb.pdcp_sn_size_dl_present = true; + drb.pdcp_cfg.drb.pdcp_sn_size_dl.value = asn1::rrc_nr::pdcp_cfg_s::drb_s_::pdcp_sn_size_dl_opts::len18bits; + drb.pdcp_cfg.drb.hdr_compress.set_not_used(); + drb.pdcp_cfg.t_reordering_present = true; + drb.pdcp_cfg.t_reordering.value = asn1::rrc_nr::pdcp_cfg_s::t_reordering_opts::ms0; + + next_radio_bearer_cfg.drb_to_add_mod_list_present = true; + next_radio_bearer_cfg.drb_to_add_mod_list.push_back(drb); +} + +bool rrc_nr::ue::init_pucch() +{ + // TODO: Allocate PUCCH resources + + return true; } /** @@ -977,4 +1092,4 @@ void rrc_nr::ue::log_rrc_container(const direction_t dir, parent->log_rrc_message(srsran::to_c_str(strbuf), Tx, pdu, msg, msg_type); } -} // namespace srsenb \ No newline at end of file +} // namespace srsenb diff --git a/srsgnb/src/stack/rrc/test/CMakeLists.txt b/srsgnb/src/stack/rrc/test/CMakeLists.txt index 6d72ed657..1ce79545b 100644 --- a/srsgnb/src/stack/rrc/test/CMakeLists.txt +++ b/srsgnb/src/stack/rrc/test/CMakeLists.txt @@ -21,5 +21,5 @@ add_library(rrc_nr_test_helpers rrc_nr_test_helpers.cc) add_executable(rrc_nr_test rrc_nr_test.cc) -target_link_libraries(rrc_nr_test srsgnb_rrc test_helpers rrc_nr_test_helpers) +target_link_libraries(rrc_nr_test srsgnb_rrc srsgnb_rrc_config_utils test_helpers rrc_nr_test_helpers ${ATOMIC_LIBS}) add_test(rrc_nr_test rrc_nr_test -i ${CMAKE_CURRENT_SOURCE_DIR}/../..) \ No newline at end of file diff --git a/srsgnb/src/stack/rrc/test/rrc_nr_test.cc b/srsgnb/src/stack/rrc/test/rrc_nr_test.cc index ca1fb5f35..998a66b4a 100644 --- a/srsgnb/src/stack/rrc/test/rrc_nr_test.cc +++ b/srsgnb/src/stack/rrc/test/rrc_nr_test.cc @@ -25,6 +25,7 @@ #include "srsenb/test/rrc/test_helpers.h" #include "srsgnb/hdr/stack/common/test/dummy_nr_classes.h" #include "srsgnb/hdr/stack/rrc/rrc_nr.h" +#include "srsgnb/hdr/stack/rrc/rrc_nr_config_utils.h" #include "srsgnb/src/stack/mac/test/sched_nr_cfg_generators.h" #include "srsran/common/test_common.h" #include "srsran/interfaces/gnb_rrc_nr_interfaces.h" @@ -64,9 +65,11 @@ void test_sib_generation() phy_cfg_t phy_cfg{}; rrc_nr_cfg_t rrc_cfg_nr = {}; rrc_cfg_nr.cell_list.emplace_back(); + generate_default_nr_cell(rrc_cfg_nr.cell_list[0]); rrc_cfg_nr.cell_list[0].phy_cell.carrier.pci = 500; - rrc_cfg_nr.cell_list[0].dl_arfcn = 634240; - rrc_cfg_nr.cell_list[0].band = 78; + rrc_cfg_nr.cell_list[0].dl_arfcn = 368500; + rrc_cfg_nr.cell_list[0].band = 3; + rrc_cfg_nr.cell_list[0].duplex_mode = SRSRAN_DUPLEX_MODE_FDD; rrc_cfg_nr.is_standalone = true; args.enb.n_prb = 50; enb_conf_sections::set_derived_args_nr(&args, &rrc_cfg_nr, &phy_cfg); @@ -116,6 +119,7 @@ int test_rrc_setup() phy_cfg_t phy_cfg{}; rrc_nr_cfg_t rrc_cfg_nr = rrc_nr_cfg_t{}; rrc_cfg_nr.cell_list.emplace_back(); + generate_default_nr_cell(rrc_cfg_nr.cell_list[0]); rrc_cfg_nr.cell_list[0].phy_cell.carrier.pci = 500; rrc_cfg_nr.cell_list[0].dl_arfcn = 634240; rrc_cfg_nr.cell_list[0].band = 78; @@ -154,9 +158,11 @@ void test_rrc_sa_connection() phy_cfg_t phy_cfg{}; rrc_nr_cfg_t rrc_cfg_nr = rrc_nr_cfg_t{}; rrc_cfg_nr.cell_list.emplace_back(); + generate_default_nr_cell(rrc_cfg_nr.cell_list[0]); rrc_cfg_nr.cell_list[0].phy_cell.carrier.pci = 500; - rrc_cfg_nr.cell_list[0].dl_arfcn = 634240; - rrc_cfg_nr.cell_list[0].band = 78; + rrc_cfg_nr.cell_list[0].dl_arfcn = 368500; + rrc_cfg_nr.cell_list[0].band = 3; + rrc_cfg_nr.cell_list[0].duplex_mode = SRSRAN_DUPLEX_MODE_FDD; rrc_cfg_nr.is_standalone = true; args.enb.n_prb = 50; enb_conf_sections::set_derived_args_nr(&args, &rrc_cfg_nr, &phy_cfg); @@ -177,7 +183,7 @@ int main(int argc, char** argv) auto& logger = srslog::fetch_basic_logger("ASN1"); logger.set_level(srslog::basic_levels::info); auto& rrc_logger = srslog::fetch_basic_logger("RRC-NR"); - rrc_logger.set_level(srslog::basic_levels::info); + rrc_logger.set_level(srslog::basic_levels::debug); srslog::init(); diff --git a/srsgnb/src/stack/rrc/test/rrc_nr_test_helpers.cc b/srsgnb/src/stack/rrc/test/rrc_nr_test_helpers.cc index 8641577b5..b883a598a 100644 --- a/srsgnb/src/stack/rrc/test/rrc_nr_test_helpers.cc +++ b/srsgnb/src/stack/rrc/test/rrc_nr_test_helpers.cc @@ -72,6 +72,14 @@ void test_rrc_nr_connection_establishment(srsran::task_scheduler& task_sched, rrc_setup_complete_s& complete = ul_dcch_msg.msg.set_c1().set_rrc_setup_complete(); complete.rrc_transaction_id = dl_ccch_msg.msg.c1().rrc_setup().rrc_transaction_id; rrc_setup_complete_ies_s& complete_ies = complete.crit_exts.set_rrc_setup_complete(); + complete_ies.sel_plmn_id = 1; // First PLMN in list + complete_ies.registered_amf_present = true; + complete_ies.registered_amf.amf_id.from_number(0x800101); + complete_ies.guami_type_present = true; + complete_ies.guami_type.value = rrc_setup_complete_ies_s::guami_type_opts::native; + complete_ies.ded_nas_msg.from_string("7E01280E534C337E004109000BF200F110800101347B80802E02F07071002D7E004109000BF200F" + "110800101347B80801001002E02F0702F0201015200F11000006418010174000090530101"); + { pdu = srsran::make_byte_buffer(); asn1::bit_ref bref{pdu->data(), pdu->get_tailroom()}; diff --git a/srsue/src/phy/nr/cc_worker.cc b/srsue/src/phy/nr/cc_worker.cc index c04ce63e0..784cfc772 100644 --- a/srsue/src/phy/nr/cc_worker.cc +++ b/srsue/src/phy/nr/cc_worker.cc @@ -165,6 +165,14 @@ void cc_worker::decode_pdcch_dl() logger.info("PDCCH: cc=%d, %s", cc_idx, str.data()); } + if (logger.debug.enabled()) { + // log coreset info + srsran_coreset_t* coreset = &ue_dl.cfg.coreset[dci_rx[i].ctx.coreset_id]; + std::array coreset_str; + srsran_coreset_to_str(coreset, coreset_str.data(), coreset_str.size()); + logger.info("PDCCH: coreset=%d, %s", cc_idx, coreset_str.data()); + } + // Enqueue UL grants phy.set_dl_pending_grant(cfg, dl_slot_cfg, dci_rx[i]); } diff --git a/srsue/src/stack/rrc/rrc_meas.cc b/srsue/src/stack/rrc/rrc_meas.cc index 9d6f3ae34..de065c725 100644 --- a/srsue/src/stack/rrc/rrc_meas.cc +++ b/srsue/src/stack/rrc/rrc_meas.cc @@ -20,9 +20,9 @@ */ #include "srsue/hdr/stack/rrc/rrc_meas.h" +#include "srsran/asn1/obj_id_cmp_utils.h" #include "srsran/asn1/rrc/dl_dcch_msg.h" #include "srsran/interfaces/ue_phy_interfaces.h" -#include "srsran/rrc/rrc_cfg_utils.h" #include "srsue/hdr/stack/rrc/rrc.h" /************************************************************************ @@ -412,7 +412,7 @@ void rrc::rrc_meas::var_meas_report_list::generate_report(const uint32_t measId) meas_results_s* report = &ul_dcch_msg.msg.c1().meas_report().crit_exts.c1().meas_report_r8().meas_results; - report->meas_id = (uint8_t)measId; + report->meas_id = (uint8_t)measId; report->meas_result_pcell.rsrp_result = rrc_value_to_range(quant_rsrp, serv_cell->get_rsrp()); report->meas_result_pcell.rsrq_result = rrc_value_to_range(quant_rsrq, serv_cell->get_rsrq());