diff --git a/lib/include/srsran/common/test_common.h b/lib/include/srsran/common/test_common.h index d74f952ba..972ac5b8a 100644 --- a/lib/include/srsran/common/test_common.h +++ b/lib/include/srsran/common/test_common.h @@ -154,6 +154,10 @@ inline void test_init(int argc, char** argv) inline void copy_msg_to_buffer(unique_byte_buffer_t& pdu, const_byte_span msg) { pdu = srsran::make_byte_buffer(); + if (pdu == nullptr) { + srslog::fetch_basic_logger("ALL").error("Couldn't allocate PDU in %s().", __FUNCTION__); + return; + } memcpy(pdu->msg, msg.data(), msg.size()); pdu->N_bytes = msg.size(); } diff --git a/lib/include/srsran/common/test_pcap.h b/lib/include/srsran/common/test_pcap.h new file mode 100644 index 000000000..567fc9ac6 --- /dev/null +++ b/lib/include/srsran/common/test_pcap.h @@ -0,0 +1,68 @@ +/** + * + * \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_TEST_PCAP_H +#define SRSRAN_TEST_PCAP_H + +#if HAVE_PCAP +#include "srsran/common/mac_pcap.h" +#include "srsran/mac/mac_sch_pdu_nr.h" +static std::unique_ptr pcap_handle = nullptr; +#define PCAP_CRNTI (0x1001) +#define PCAP_TTI (666) +#endif + +namespace srsran { + +int write_mac_sdu_nr(const uint32_t lcid, const uint8_t* payload, const uint32_t len); + +int write_rlc_am_sdu_nr(const uint32_t lcid, const uint8_t* payload, const uint32_t len) +{ +#if HAVE_PCAP + if (pcap_handle) { + byte_buffer_t mac_sdu; + // Add dummy RLC AM PDU header + mac_sdu.msg[0] = 0x80; + mac_sdu.msg[1] = 0x00; + + // Add dummy PDCP header + mac_sdu.msg[2] = 0x00; + mac_sdu.msg[3] = 0x00; + + mac_sdu.N_bytes = 4; + memcpy(mac_sdu.msg + 4, payload, len); + mac_sdu.N_bytes += len; + return write_mac_sdu_nr(lcid, mac_sdu.msg, mac_sdu.N_bytes); + } +#endif // HAVE_PCAP + return SRSRAN_ERROR; +} + +int write_mac_sdu_nr(const uint32_t lcid, const uint8_t* payload, const uint32_t len) +{ +#if HAVE_PCAP + if (pcap_handle) { + byte_buffer_t tx_buffer; + srsran::mac_sch_pdu_nr tx_pdu; + tx_pdu.init_tx(&tx_buffer, len + 10); + tx_pdu.add_sdu(lcid, payload, len); + tx_pdu.pack(); + pcap_handle->write_dl_crnti_nr(tx_buffer.msg, tx_buffer.N_bytes, PCAP_CRNTI, 0, PCAP_TTI); + return SRSRAN_SUCCESS; + } +#endif // HAVE_PCAP + return SRSRAN_ERROR; +} + +} // namespace srsran + +#endif // SRSRAN_TEST_COMMON_H diff --git a/lib/include/srsran/interfaces/enb_mac_interfaces.h b/lib/include/srsran/interfaces/enb_mac_interfaces.h index 2da352d51..9c94b8d8a 100644 --- a/lib/include/srsran/interfaces/enb_mac_interfaces.h +++ b/lib/include/srsran/interfaces/enb_mac_interfaces.h @@ -133,6 +133,18 @@ public: */ virtual int cqi_info(uint32_t tti, uint16_t rnti, uint32_t cc_idx, uint32_t cqi_value) = 0; + /** + * PHY callback for giving MAC the Channel Quality information of a given RNTI, TTI, eNb cell/carrier for a specific + * subband + * @param tti the given TTI + * @param rnti the UE identifier in the eNb + * @param cc_idx The eNb Cell/Carrier where the measurement corresponds + * @param sb_idx Index of the Sub-band + * @param cqi_value the corresponding Channel Quality Information + * @return SRSRAN_SUCCESS if no error occurs, SRSRAN_ERROR* if an error occurs + */ + virtual int sb_cqi_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, uint32_t sb_idx, uint32_t cqi_value) = 0; + typedef enum { PUSCH = 0, PUCCH, SRS } ul_channel_t; /** diff --git a/lib/include/srsran/interfaces/enb_metrics_interface.h b/lib/include/srsran/interfaces/enb_metrics_interface.h index fc73e9bfb..943fe8648 100644 --- a/lib/include/srsran/interfaces/enb_metrics_interface.h +++ b/lib/include/srsran/interfaces/enb_metrics_interface.h @@ -26,7 +26,7 @@ #include "srsenb/hdr/common/common_enb.h" #include "srsenb/hdr/phy/phy_metrics.h" -#include "srsenb/hdr/stack/mac/mac_metrics.h" +#include "srsenb/hdr/stack/mac/common/mac_metrics.h" #include "srsenb/hdr/stack/rrc/rrc_metrics.h" #include "srsenb/hdr/stack/s1ap/s1ap_metrics.h" #include "srsran/common/metrics_hub.h" diff --git a/lib/include/srsran/interfaces/enb_rrc_interfaces.h b/lib/include/srsran/interfaces/enb_rrc_interfaces.h index b3d185489..f7648d4db 100644 --- a/lib/include/srsran/interfaces/enb_rrc_interfaces.h +++ b/lib/include/srsran/interfaces/enb_rrc_interfaces.h @@ -136,21 +136,40 @@ class rrc_nr_interface_rrc { public: /// Request addition of NR carrier for UE (TODO: add configuration check, QCI, security, etc.) - virtual int sgnb_addition_request(uint16_t rnti) = 0; + virtual int sgnb_addition_request(uint16_t eutra_rnti) = 0; /// Provide information whether the requested configuration was applied successfully by the UE - virtual int sgnb_reconfiguration_complete(uint16_t rnti, asn1::dyn_octstring reconfig_response) = 0; + virtual int sgnb_reconfiguration_complete(uint16_t eutra_rnti, asn1::dyn_octstring reconfig_response) = 0; }; /// X2AP inspired interface for response from NR RRC to EUTRA RRC class rrc_eutra_interface_rrc_nr { public: - /// Signal successful addition of UE - virtual void sgnb_addition_ack(uint16_t rnti, + /** + * @brief Signal successful addition of UE + * + * @param eutra_rnti The RNTI that the EUTRA RRC used to request the SgNB addition + * @param nr_secondary_cell_group_cfg_r15 Encoded part of the RRC Reconfiguration + * @param nr_radio_bearer_cfg1_r15 Encoded part of the RRC Reconfiguration + */ + virtual void sgnb_addition_ack(uint16_t eutra_rnti, const asn1::dyn_octstring& nr_secondary_cell_group_cfg_r15, const asn1::dyn_octstring& nr_radio_bearer_cfg1_r15) = 0; - virtual void sgnb_addition_reject(uint16_t rnti) = 0; + + /** + * @brief Signal unsuccessful SgNB addition + * + * @param eutra_rnti The RNTI that the EUTRA RRC used to request the SgNB addition + */ + virtual void sgnb_addition_reject(uint16_t eutra_rnti) = 0; + + /** + * @brief Signal completion of SgNB addition after UE (with new NR identity) has attached + * + * @param nr_rnti The RNTI that the EUTRA RRC used to request the SgNB addition + */ + virtual void sgnb_addition_complete(uint16_t eutra_rnti) = 0; }; } // namespace srsenb diff --git a/lib/include/srsran/interfaces/gnb_interfaces.h b/lib/include/srsran/interfaces/gnb_interfaces.h index 1031b318b..836f8a353 100644 --- a/lib/include/srsran/interfaces/gnb_interfaces.h +++ b/lib/include/srsran/interfaces/gnb_interfaces.h @@ -41,6 +41,9 @@ class mac_interface_rrc_nr public: // Provides cell configuration including SIB periodicity, etc. virtual int cell_cfg(srsenb::sched_interface::cell_cfg_t* cell_cfg) = 0; + + /// Allocates a new user/RNTI at MAC. Returns RNTI on success or SRSRAN_INVALID_RNTI otherwise. + virtual uint16_t reserve_rnti() = 0; }; class mac_interface_rlc_nr @@ -154,6 +157,9 @@ public: // Provides MIB packed message virtual int read_pdu_bcch_bch(const uint32_t tti, srsran::unique_byte_buffer_t& buffer) = 0; virtual int read_pdu_bcch_dlsch(uint32_t sib_index, srsran::unique_byte_buffer_t& buffer) = 0; + + /// User management + virtual int add_user(uint16_t rnti) = 0; }; class rrc_interface_rlc_nr { @@ -192,6 +198,7 @@ public: // TBD }; +// Combined interface for stack (MAC and RRC) to access PHY class phy_interface_stack_nr : public phy_interface_rrc_nr, public phy_interface_mac_nr { public: @@ -208,9 +215,11 @@ public: class mac_interface_phy_nr { public: - const static int MAX_SSB = 4; - const static int MAX_GRANTS = 64; - const static int MAX_NZP_CSI_RS = 4; + const static int MAX_SSB = 4; + const static int MAX_GRANTS = 64; + const static int MAX_PUCCH_MSG = 64; + const static int MAX_PUCCH_CANDIDATES = 2; + const static int MAX_NZP_CSI_RS = 4; struct pdcch_dl_t { srsran_dci_cfg_nr_t dci_cfg = {}; @@ -245,10 +254,20 @@ public: std::array data = {}; ///< Data pointer }; + /** + * @brief Describes a possible PUCCH candidate transmission + * @note The physical layer shall try decoding all the possible PUCCH candidates and report back to the stack the + * strongest of the candidates. This is thought to be used in the case of SR opportunities in which the UE could + * transmit HARQ-ACK in two possible resources. + */ + struct pucch_candidate_t { + srsran_uci_cfg_nr_t uci_cfg; ///< UCI configuration for the opportunity + srsran_pucch_nr_resource_t resource; ///< PUCCH resource to use + }; + struct pucch_t { - srsran_uci_cfg_nr_t uci_cfg; ///< UCI configuration - srsran_pucch_nr_common_cfg_t pucch_cfg; ///< UE dedicated PUCCH configuration - srsran_pucch_nr_resource_t resource; ///< PUCCH resource + srsran_pucch_nr_common_cfg_t pucch_cfg; ///< UE dedicated PUCCH configuration + srsran::bounded_vector candidates; ///< PUCCH candidates to decode }; struct ul_sched_t { @@ -257,8 +276,8 @@ public: }; struct pucch_info_t { - srsran_uci_data_nr_t uci_data; ///< RNTI is available under cfg->pucch->rnti - // ... add signal measurements here + srsran_uci_data_nr_t uci_data; ///< RNTI is available under cfg->pucch->rnti + srsran_csi_trs_measurements_t csi; ///< DMRS based signal Channel State Information (CSI) }; struct pusch_info_t { diff --git a/lib/include/srsran/interfaces/sched_interface.h b/lib/include/srsran/interfaces/sched_interface.h index 6f31c8750..13c2c5e2b 100644 --- a/lib/include/srsran/interfaces/sched_interface.h +++ b/lib/include/srsran/interfaces/sched_interface.h @@ -297,11 +297,12 @@ public: virtual int dl_mac_buffer_state(uint16_t rnti, uint32_t ce_code, uint32_t nof_cmds) = 0; /* DL information */ - virtual int dl_ack_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, uint32_t tb_idx, bool ack) = 0; - virtual int dl_rach_info(uint32_t enb_cc_idx, dl_sched_rar_info_t rar_info) = 0; - virtual int dl_ri_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, uint32_t ri_value) = 0; - virtual int dl_pmi_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, uint32_t pmi_value) = 0; - virtual int dl_cqi_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, uint32_t cqi_value) = 0; + virtual int dl_ack_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, uint32_t tb_idx, bool ack) = 0; + virtual int dl_rach_info(uint32_t enb_cc_idx, dl_sched_rar_info_t rar_info) = 0; + virtual int dl_ri_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, uint32_t ri_value) = 0; + virtual int dl_pmi_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, uint32_t pmi_value) = 0; + virtual int dl_cqi_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, uint32_t cqi_value) = 0; + virtual int dl_sb_cqi_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, uint32_t sb_idx, uint32_t cqi) = 0; /* UL information */ virtual int ul_crc_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, bool crc) = 0; diff --git a/lib/include/srsran/phy/gnb/gnb_ul.h b/lib/include/srsran/phy/gnb/gnb_ul.h index 2219d15ac..0fb188060 100644 --- a/lib/include/srsran/phy/gnb/gnb_ul.h +++ b/lib/include/srsran/phy/gnb/gnb_ul.h @@ -66,7 +66,8 @@ SRSRAN_API int srsran_gnb_ul_get_pucch(srsran_gnb_ul_t* q, const srsran_pucch_nr_common_cfg_t* cfg, const srsran_pucch_nr_resource_t* resource, const srsran_uci_cfg_nr_t* uci_cfg, - srsran_uci_value_nr_t* uci_value); + srsran_uci_value_nr_t* uci_value, + srsran_csi_trs_measurements_t* meas); SRSRAN_API uint32_t srsran_gnb_ul_pucch_info(srsran_gnb_ul_t* q, const srsran_pucch_nr_resource_t* resource, diff --git a/lib/include/srsran/phy/phch/cqi.h b/lib/include/srsran/phy/phch/cqi.h index 4b00070a6..25889128c 100644 --- a/lib/include/srsran/phy/phch/cqi.h +++ b/lib/include/srsran/phy/phch/cqi.h @@ -60,7 +60,6 @@ typedef struct { bool ri_idx_present; bool format_is_subband; uint8_t subband_wideband_ratio; ///< K value in TS 36.331. 0 for wideband reporting, (1..4) otherwise - uint32_t subband_size; srsran_cqi_report_mode_t periodic_mode; srsran_cqi_report_mode_t aperiodic_mode; } srsran_cqi_report_cfg_t; @@ -88,7 +87,7 @@ typedef struct SRSRAN_API { uint8_t wideband_cqi; // 4-bit width uint8_t subband_diff_cqi; // 2-bit width uint32_t position_subband; // L-bit width -} srsran_cqi_ue_subband_t; +} srsran_cqi_ue_diff_subband_t; /* Table 5.2.3.3.1-1: Fields for channel quality information feedback for wideband CQI reports (transmission mode 1, transmission mode 2, transmission mode 3, transmission mode 7 and @@ -110,12 +109,12 @@ typedef struct SRSRAN_API { typedef struct SRSRAN_API { uint8_t subband_cqi; // 4-bit width uint8_t subband_label; // 1- or 2-bit width -} srsran_cqi_format2_subband_t; +} srsran_cqi_ue_subband_t; typedef enum { SRSRAN_CQI_TYPE_WIDEBAND = 0, - SRSRAN_CQI_TYPE_SUBBAND, SRSRAN_CQI_TYPE_SUBBAND_UE, + SRSRAN_CQI_TYPE_SUBBAND_UE_DIFF, SRSRAN_CQI_TYPE_SUBBAND_HL } srsran_cqi_type_t; @@ -135,8 +134,8 @@ typedef struct SRSRAN_API { typedef struct { union { srsran_cqi_format2_wideband_t wideband; - srsran_cqi_format2_subband_t subband; srsran_cqi_ue_subband_t subband_ue; + srsran_cqi_ue_diff_subband_t subband_ue_diff; srsran_cqi_hl_subband_t subband_hl; }; bool data_crc; @@ -156,11 +155,18 @@ srsran_cqi_value_tostring(srsran_cqi_cfg_t* cfg, srsran_cqi_value_t* value, char SRSRAN_API bool srsran_cqi_periodic_send(const srsran_cqi_report_cfg_t* periodic_cfg, uint32_t tti, srsran_frame_type_t frame_type); +SRSRAN_API bool srsran_cqi_periodic_is_subband(const srsran_cqi_report_cfg_t* cfg, + uint32_t tti, + uint32_t nof_prb, + srsran_frame_type_t frame_type); + SRSRAN_API bool srsran_cqi_periodic_ri_send(const srsran_cqi_report_cfg_t* periodic_cfg, uint32_t tti, srsran_frame_type_t frame_type); SRSRAN_API int srsran_cqi_hl_get_no_subbands(int nof_prb); +SRSRAN_API int srsran_cqi_hl_get_L(int nof_prb); + SRSRAN_API uint8_t srsran_cqi_from_snr(float snr); SRSRAN_API float srsran_cqi_to_coderate(uint32_t cqi, bool use_alt_table); diff --git a/lib/include/srsran/phy/phch/prach.h b/lib/include/srsran/phy/phch/prach.h index 3498cb4a4..298180b69 100644 --- a/lib/include/srsran/phy/phch/prach.h +++ b/lib/include/srsran/phy/phch/prach.h @@ -179,6 +179,8 @@ SRSRAN_API bool srsran_prach_tti_opportunity(srsran_prach_t* p, uint32_t current SRSRAN_API bool srsran_prach_tti_opportunity_config_fdd(uint32_t config_idx, uint32_t current_tti, int allowed_subframe); +SRSRAN_API bool srsran_prach_in_window_config_fdd(uint32_t config_idx, uint32_t current_tti, int allowed_subframe); + SRSRAN_API bool srsran_prach_tti_opportunity_config_tdd(uint32_t config_idx, uint32_t tdd_ul_dl_config, uint32_t current_tti, diff --git a/lib/src/asn1/rrc_nr.cc b/lib/src/asn1/rrc_nr.cc index f266a97b6..8aafe61a3 100644 --- a/lib/src/asn1/rrc_nr.cc +++ b/lib/src/asn1/rrc_nr.cc @@ -3048,7 +3048,7 @@ SRSASN_CODE pdcch_cfg_common_s::pack(bit_ref& bref) const if (ext) { ext_groups_packer_guard group_flags; group_flags[0] |= first_pdcch_monitoring_occasion_of_po.is_present(); - group_flags.pack(bref); + HANDLE_CODE(group_flags.pack(bref)); if (group_flags[0]) { varlength_field_pack_guard varlen_scope(bref, false); @@ -3100,7 +3100,7 @@ SRSASN_CODE pdcch_cfg_common_s::unpack(cbit_ref& bref) if (ext) { ext_groups_unpacker_guard group_flags(1); - group_flags.unpack(bref); + HANDLE_CODE(group_flags.unpack(bref)); if (group_flags[0]) { varlength_field_unpack_guard varlen_scope(bref, false); diff --git a/lib/src/asn1/rrc_utils.cc b/lib/src/asn1/rrc_utils.cc index af79bcac9..b08a54e1e 100644 --- a/lib/src/asn1/rrc_utils.cc +++ b/lib/src/asn1/rrc_utils.cc @@ -568,7 +568,8 @@ void set_phy_cfg_t_dedicated_cfg(phy_cfg_t* cfg, const asn1::rrc::phys_cfg_ded_s cqi_report_periodic.cqi_format_ind_periodic_r10.type().value == asn1::rrc::cqi_report_periodic_r10_c::setup_s_::cqi_format_ind_periodic_r10_c_::types::subband_cqi_r10; if (cfg->dl_cfg.cqi_report.format_is_subband) { - cfg->dl_cfg.cqi_report.subband_size = cqi_report_periodic.cqi_format_ind_periodic_r10.subband_cqi_r10().k; + cfg->dl_cfg.cqi_report.subband_wideband_ratio = + cqi_report_periodic.cqi_format_ind_periodic_r10.subband_cqi_r10().k; } if (cqi_report_periodic.ri_cfg_idx_present) { cfg->dl_cfg.cqi_report.ri_idx = cqi_report_periodic.ri_cfg_idx; @@ -595,7 +596,7 @@ void set_phy_cfg_t_dedicated_cfg(phy_cfg_t* cfg, const asn1::rrc::phys_cfg_ded_s asn1_type.cqi_report_cfg.cqi_report_periodic.setup().cqi_format_ind_periodic.type().value == asn1::rrc::cqi_report_periodic_c::setup_s_::cqi_format_ind_periodic_c_::types::subband_cqi; if (cfg->dl_cfg.cqi_report.format_is_subband) { - cfg->dl_cfg.cqi_report.subband_size = + cfg->dl_cfg.cqi_report.subband_wideband_ratio = asn1_type.cqi_report_cfg.cqi_report_periodic.setup().cqi_format_ind_periodic.subband_cqi().k; } if (asn1_type.cqi_report_cfg.cqi_report_periodic.setup().ri_cfg_idx_present) { @@ -871,7 +872,7 @@ void set_phy_cfg_t_scell_config(phy_cfg_t* cfg, const asn1::rrc::scell_to_add_mo cqi_cfg.cqi_format_ind_periodic_r10.type().value == cqi_cfg_t::cqi_format_ind_periodic_r10_c_::types::subband_cqi_r10; if (cfg->dl_cfg.cqi_report.format_is_subband) { - cfg->dl_cfg.cqi_report.subband_size = cqi_cfg.cqi_format_ind_periodic_r10.subband_cqi_r10().k; + cfg->dl_cfg.cqi_report.subband_wideband_ratio = cqi_cfg.cqi_format_ind_periodic_r10.subband_cqi_r10().k; } if (cqi_cfg.ri_cfg_idx_present) { cfg->dl_cfg.cqi_report.ri_idx = cqi_cfg.ri_cfg_idx; diff --git a/lib/src/common/phy_cfg_nr.cc b/lib/src/common/phy_cfg_nr.cc index 9fd7d7675..1827480f7 100644 --- a/lib/src/common/phy_cfg_nr.cc +++ b/lib/src/common/phy_cfg_nr.cc @@ -299,7 +299,18 @@ bool phy_cfg_nr_t::get_uci_cfg(const srsran_slot_cfg_t& slot_cfg, } // Generate configuration for SR - // ... + uint32_t sr_resource_id[SRSRAN_PUCCH_MAX_NOF_SR_RESOURCES] = {}; + int n = srsran_ue_ul_nr_sr_send_slot(pucch.sr_resources, slot_cfg.idx, sr_resource_id); + if (n < SRSRAN_SUCCESS) { + ERROR("Calculating SR opportunities"); + return false; + } + + if (n > 0) { + uci_cfg.pucch.sr_resource_id = sr_resource_id[0]; + uci_cfg.o_sr = srsran_ra_ul_nr_nof_sr_bits((uint32_t)n); + uci_cfg.sr_positive_present = true; + } // Generate configuration for CSI reports // ... @@ -333,4 +344,4 @@ bool phy_cfg_nr_t::get_pusch_uci_cfg(const srsran_slot_cfg_t& slot_cfg, return true; } -} // namespace srsran \ No newline at end of file +} // namespace srsran diff --git a/lib/src/phy/ch_estimation/dmrs_pucch.c b/lib/src/phy/ch_estimation/dmrs_pucch.c index 6beacc42a..3e646af05 100644 --- a/lib/src/phy/ch_estimation/dmrs_pucch.c +++ b/lib/src/phy/ch_estimation/dmrs_pucch.c @@ -247,7 +247,7 @@ int srsran_dmrs_pucch_format1_estimate(const srsran_pucch_nr_t* q, res->rsrp_dBfs = srsran_convert_power_to_dB(rsrp); res->epre = epre; res->epre_dBfs = srsran_convert_power_to_dB(epre); - res->noise_estimate = epre - rsrp; + res->noise_estimate = SRSRAN_MAX(epre - rsrp, 1e-6f); res->noise_estimate_dbm = srsran_convert_power_to_dB(res->noise_estimate); res->snr = rsrp / res->noise_estimate; res->snr_db = srsran_convert_power_to_dB(res->snr); @@ -407,7 +407,7 @@ int srsran_dmrs_pucch_format2_estimate(const srsran_pucch_nr_t* q, res->rsrp_dBfs = srsran_convert_power_to_dB(rsrp); res->epre = epre; res->epre_dBfs = srsran_convert_power_to_dB(epre); - res->noise_estimate = epre - rsrp; + res->noise_estimate = SRSRAN_MAX(epre - rsrp, 1e-6f); res->noise_estimate_dbm = srsran_convert_power_to_dB(res->noise_estimate); res->snr = rsrp / res->noise_estimate; res->snr_db = srsran_convert_power_to_dB(res->snr); diff --git a/lib/src/phy/enb/enb_dl.c b/lib/src/phy/enb/enb_dl.c index f546dfa67..3b62f0146 100644 --- a/lib/src/phy/enb/enb_dl.c +++ b/lib/src/phy/enb/enb_dl.c @@ -450,7 +450,15 @@ bool srsran_enb_dl_gen_cqi_periodic(const srsran_cell_t* cell, cqi_cfg->ri_len = srsran_ri_nof_bits(cell); cqi_enabled = true; } else if (srsran_cqi_periodic_send(&dl_cfg->cqi_report, tti, cell->frame_type)) { - cqi_cfg->type = SRSRAN_CQI_TYPE_WIDEBAND; + if (dl_cfg->cqi_report.format_is_subband && + srsran_cqi_periodic_is_subband(&dl_cfg->cqi_report, tti, cell->nof_prb, cell->frame_type)) { + // 36.213 table 7.2.2-1, periodic CQI supports UE-selected only + cqi_cfg->type = SRSRAN_CQI_TYPE_SUBBAND_UE; + cqi_cfg->L = srsran_cqi_hl_get_L(cell->nof_prb); + cqi_cfg->subband_label_2_bits = cqi_cfg->L > 1; + } else { + cqi_cfg->type = SRSRAN_CQI_TYPE_WIDEBAND; + } if (dl_cfg->tm == SRSRAN_TM4) { cqi_cfg->pmi_present = true; cqi_cfg->rank_is_not_one = last_ri > 0; diff --git a/lib/src/phy/gnb/gnb_ul.c b/lib/src/phy/gnb/gnb_ul.c index d7e78ac16..725e82f0d 100644 --- a/lib/src/phy/gnb/gnb_ul.c +++ b/lib/src/phy/gnb/gnb_ul.c @@ -219,6 +219,11 @@ static int gnb_ul_decode_pucch_format1(srsran_gnb_ul_t* q, return SRSRAN_ERROR; } + // As format 1 with positive SR is not encoded with any payload, set SR to 1 + if (uci_cfg->sr_positive_present) { + uci_value->sr = 1; + } + // Take valid decision uci_value->valid = (norm_corr > 0.5f); @@ -257,7 +262,8 @@ int srsran_gnb_ul_get_pucch(srsran_gnb_ul_t* q, const srsran_pucch_nr_common_cfg_t* cfg, const srsran_pucch_nr_resource_t* resource, const srsran_uci_cfg_nr_t* uci_cfg, - srsran_uci_value_nr_t* uci_value) + srsran_uci_value_nr_t* uci_value, + srsran_csi_trs_measurements_t* meas) { if (q == NULL || slot_cfg == NULL || cfg == NULL || resource == NULL || uci_cfg == NULL || uci_value == NULL) { return SRSRAN_ERROR_INVALID_INPUTS; @@ -266,17 +272,39 @@ int srsran_gnb_ul_get_pucch(srsran_gnb_ul_t* q, // Estimate channel switch (resource->format) { case SRSRAN_PUCCH_NR_FORMAT_1: - return gnb_ul_decode_pucch_format1(q, slot_cfg, cfg, resource, uci_cfg, uci_value); + if (gnb_ul_decode_pucch_format1(q, slot_cfg, cfg, resource, uci_cfg, uci_value) < SRSRAN_SUCCESS) { + return SRSRAN_ERROR; + } + break; case SRSRAN_PUCCH_NR_FORMAT_2: - return gnb_ul_decode_pucch_format2(q, slot_cfg, cfg, resource, uci_cfg, uci_value); + if (gnb_ul_decode_pucch_format2(q, slot_cfg, cfg, resource, uci_cfg, uci_value) < SRSRAN_SUCCESS) { + return SRSRAN_ERROR; + } + break; case SRSRAN_PUCCH_NR_FORMAT_0: case SRSRAN_PUCCH_NR_FORMAT_3: case SRSRAN_PUCCH_NR_FORMAT_4: case SRSRAN_PUCCH_NR_FORMAT_ERROR: ERROR("Invalid or not implemented PUCCH-NR format %d", (int)resource->format); + return SRSRAN_ERROR; } - return SRSRAN_ERROR; + // Copy DMRS measurements + if (meas != NULL) { + meas->rsrp = q->chest_pucch.rsrp; + meas->rsrp_dB = q->chest_pucch.rsrp_dBfs; + meas->epre = q->chest_pucch.epre; + meas->epre_dB = q->chest_pucch.epre_dBfs; + meas->n0 = q->chest_pucch.noise_estimate; + meas->n0_dB = q->chest_pucch.noise_estimate_dbm; + meas->snr_dB = q->chest_pucch.snr_db; + meas->cfo_hz = q->chest_pucch.cfo_hz; + meas->cfo_hz_max = NAN; // Unavailable + meas->delay_us = q->chest_pucch.ta_us; + meas->nof_re = 0; // Unavailable + } + + return SRSRAN_SUCCESS; } uint32_t srsran_gnb_ul_pucch_info(srsran_gnb_ul_t* q, diff --git a/lib/src/phy/phch/cqi.c b/lib/src/phy/phch/cqi.c index 49ed32071..bd6b05206 100644 --- a/lib/src/phy/phch/cqi.c +++ b/lib/src/phy/phch/cqi.c @@ -74,7 +74,7 @@ static int cqi_hl_subband_pack(srsran_cqi_cfg_t* cfg, srsran_cqi_hl_subband_t* m return bit_count; } -static int cqi_ue_subband_pack(srsran_cqi_cfg_t* cfg, srsran_cqi_ue_subband_t* msg, uint8_t* buff) +static int cqi_ue_subband_pack(srsran_cqi_cfg_t* cfg, srsran_cqi_ue_diff_subband_t* msg, uint8_t* buff) { uint8_t* body_ptr = buff; srsran_bit_unpack(msg->wideband_cqi, &body_ptr, 4); @@ -110,7 +110,7 @@ static int cqi_format2_wideband_pack(srsran_cqi_cfg_t* cfg, srsran_cqi_format2_w return (int)(body_ptr - buff); } -static int cqi_format2_subband_pack(srsran_cqi_cfg_t* cfg, srsran_cqi_format2_subband_t* msg, uint8_t* buff) +static int cqi_format2_subband_pack(srsran_cqi_cfg_t* cfg, srsran_cqi_ue_subband_t* msg, uint8_t* buff) { uint8_t* body_ptr = buff; srsran_bit_unpack(msg->subband_cqi, &body_ptr, 4); @@ -123,10 +123,10 @@ int srsran_cqi_value_pack(srsran_cqi_cfg_t* cfg, srsran_cqi_value_t* value, uint switch (cfg->type) { case SRSRAN_CQI_TYPE_WIDEBAND: return cqi_format2_wideband_pack(cfg, &value->wideband, buff); - case SRSRAN_CQI_TYPE_SUBBAND: - return cqi_format2_subband_pack(cfg, &value->subband, buff); case SRSRAN_CQI_TYPE_SUBBAND_UE: - return cqi_ue_subband_pack(cfg, &value->subband_ue, buff); + return cqi_format2_subband_pack(cfg, &value->subband_ue, buff); + case SRSRAN_CQI_TYPE_SUBBAND_UE_DIFF: + return cqi_ue_subband_pack(cfg, &value->subband_ue_diff, buff); case SRSRAN_CQI_TYPE_SUBBAND_HL: return cqi_hl_subband_pack(cfg, &value->subband_hl, buff); } @@ -172,7 +172,7 @@ int cqi_hl_subband_unpack(srsran_cqi_cfg_t* cfg, uint8_t* buff, srsran_cqi_hl_su return bit_count; } -int cqi_ue_subband_unpack(srsran_cqi_cfg_t* cfg, uint8_t* buff, srsran_cqi_ue_subband_t* msg) +int cqi_ue_subband_unpack(srsran_cqi_cfg_t* cfg, uint8_t* buff, srsran_cqi_ue_diff_subband_t* msg) { uint8_t* body_ptr = buff; msg->wideband_cqi = srsran_bit_pack(&body_ptr, 4); @@ -206,7 +206,7 @@ static int cqi_format2_wideband_unpack(srsran_cqi_cfg_t* cfg, uint8_t* buff, srs return 4; } -static int cqi_format2_subband_unpack(srsran_cqi_cfg_t* cfg, uint8_t* buff, srsran_cqi_format2_subband_t* msg) +static int cqi_format2_subband_unpack(srsran_cqi_cfg_t* cfg, uint8_t* buff, srsran_cqi_ue_subband_t* msg) { uint8_t* body_ptr = buff; msg->subband_cqi = srsran_bit_pack(&body_ptr, 4); @@ -219,10 +219,10 @@ int srsran_cqi_value_unpack(srsran_cqi_cfg_t* cfg, uint8_t buff[SRSRAN_CQI_MAX_B switch (cfg->type) { case SRSRAN_CQI_TYPE_WIDEBAND: return cqi_format2_wideband_unpack(cfg, buff, &value->wideband); - case SRSRAN_CQI_TYPE_SUBBAND: - return cqi_format2_subband_unpack(cfg, buff, &value->subband); case SRSRAN_CQI_TYPE_SUBBAND_UE: - return cqi_ue_subband_unpack(cfg, buff, &value->subband_ue); + return cqi_format2_subband_unpack(cfg, buff, &value->subband_ue); + case SRSRAN_CQI_TYPE_SUBBAND_UE_DIFF: + return cqi_ue_subband_unpack(cfg, buff, &value->subband_ue_diff); case SRSRAN_CQI_TYPE_SUBBAND_HL: return cqi_hl_subband_unpack(cfg, buff, &value->subband_hl); } @@ -251,7 +251,7 @@ cqi_format2_wideband_tostring(srsran_cqi_cfg_t* cfg, srsran_cqi_format2_wideband } static int -cqi_format2_subband_tostring(srsran_cqi_cfg_t* cfg, srsran_cqi_format2_subband_t* msg, char* buff, uint32_t buff_len) +cqi_format2_subband_tostring(srsran_cqi_cfg_t* cfg, srsran_cqi_ue_subband_t* msg, char* buff, uint32_t buff_len) { int n = 0; @@ -261,7 +261,8 @@ cqi_format2_subband_tostring(srsran_cqi_cfg_t* cfg, srsran_cqi_format2_subband_t return n; } -static int cqi_ue_subband_tostring(srsran_cqi_cfg_t* cfg, srsran_cqi_ue_subband_t* msg, char* buff, uint32_t buff_len) +static int +cqi_ue_subband_tostring(srsran_cqi_cfg_t* cfg, srsran_cqi_ue_diff_subband_t* msg, char* buff, uint32_t buff_len) { int n = 0; @@ -301,11 +302,11 @@ int srsran_cqi_value_tostring(srsran_cqi_cfg_t* cfg, srsran_cqi_value_t* value, case SRSRAN_CQI_TYPE_WIDEBAND: ret = cqi_format2_wideband_tostring(cfg, &value->wideband, buff, buff_len); break; - case SRSRAN_CQI_TYPE_SUBBAND: - ret = cqi_format2_subband_tostring(cfg, &value->subband, buff, buff_len); - break; case SRSRAN_CQI_TYPE_SUBBAND_UE: - ret = cqi_ue_subband_tostring(cfg, &value->subband_ue, buff, buff_len); + ret = cqi_format2_subband_tostring(cfg, &value->subband_ue, buff, buff_len); + break; + case SRSRAN_CQI_TYPE_SUBBAND_UE_DIFF: + ret = cqi_ue_subband_tostring(cfg, &value->subband_ue_diff, buff, buff_len); break; case SRSRAN_CQI_TYPE_SUBBAND_HL: ret = cqi_hl_subband_tostring(cfg, &value->subband_hl, buff, buff_len); @@ -348,10 +349,10 @@ int srsran_cqi_size(srsran_cqi_cfg_t* cfg) } } break; - case SRSRAN_CQI_TYPE_SUBBAND: + case SRSRAN_CQI_TYPE_SUBBAND_UE: size = 4 + ((cfg->subband_label_2_bits) ? 2 : 1); break; - case SRSRAN_CQI_TYPE_SUBBAND_UE: + case SRSRAN_CQI_TYPE_SUBBAND_UE_DIFF: size = 4 + 2 + cfg->L; break; case SRSRAN_CQI_TYPE_SUBBAND_HL: @@ -453,7 +454,7 @@ static bool cqi_get_N_tdd(uint32_t I_cqi_pmi, uint32_t* N_p, uint32_t* N_offset) return true; } -static bool cqi_send(uint32_t I_cqi_pmi, uint32_t tti, bool is_fdd) +static bool cqi_send(uint32_t I_cqi_pmi, uint32_t tti, bool is_fdd, uint32_t H) { uint32_t N_p = 0; @@ -470,7 +471,7 @@ static bool cqi_send(uint32_t I_cqi_pmi, uint32_t tti, bool is_fdd) } if (N_p) { - if ((tti - N_offset) % N_p == 0) { + if ((tti - N_offset) % (H * N_p) == 0) { return true; } } @@ -526,6 +527,51 @@ static bool ri_send(uint32_t I_cqi_pmi, uint32_t I_ri, uint32_t tti, bool is_fdd return false; } +/* Returns the subband size for higher layer-configured subband feedback, + * i.e., the number of RBs per subband as a function of the cell bandwidth + * (Table 7.2.1-3 in TS 36.213) + */ +static int cqi_hl_get_subband_size(int nof_prb) +{ + if (nof_prb < 7) { + return 0; + } else if (nof_prb <= 26) { + return 4; + } else if (nof_prb <= 63) { + return 6; + } else if (nof_prb <= 110) { + return 8; + } else { + return -1; + } +} + +/* Returns the bandwidth parts (J) + * (Table 7.2.2-2 in TS 36.213) + */ +static int cqi_hl_get_bwp_J(int nof_prb) +{ + if (nof_prb < 7) { + return 0; + } else if (nof_prb <= 26) { + return 4; + } else if (nof_prb <= 63) { + return 6; + } else if (nof_prb <= 110) { + return 8; + } else { + return -1; + } +} + +/* Returns the number of bits to index a bandwidth part (L) + * L = ceil(log2(nof_prb/k/J)) + */ +int srsran_cqi_hl_get_L(int nof_prb) +{ + return (int)ceil((float)nof_prb / cqi_hl_get_subband_size(nof_prb) / cqi_hl_get_bwp_J(nof_prb)); +} + bool srsran_cqi_periodic_ri_send(const srsran_cqi_report_cfg_t* cfg, uint32_t tti, srsran_frame_type_t frame_type) { return cfg->periodic_configured && cfg->ri_idx_present && @@ -534,7 +580,20 @@ bool srsran_cqi_periodic_ri_send(const srsran_cqi_report_cfg_t* cfg, uint32_t tt bool srsran_cqi_periodic_send(const srsran_cqi_report_cfg_t* cfg, uint32_t tti, srsran_frame_type_t frame_type) { - return cfg->periodic_configured && cqi_send(cfg->pmi_idx, tti, frame_type == SRSRAN_FDD); + return cfg->periodic_configured && cqi_send(cfg->pmi_idx, tti, frame_type == SRSRAN_FDD, 1); +} + +bool srsran_cqi_periodic_is_subband(const srsran_cqi_report_cfg_t* cfg, + uint32_t tti, + uint32_t nof_prb, + srsran_frame_type_t frame_type) +{ + uint32_t K = cfg->subband_wideband_ratio; + uint32_t J = cqi_hl_get_bwp_J(nof_prb); + uint32_t H = J * K + 1; + + // A periodic report is subband if it's a CQI opportunity and is not wideband + return srsran_cqi_periodic_send(cfg, tti, frame_type) && !cqi_send(cfg->pmi_idx, tti, frame_type == SRSRAN_FDD, H); } // CQI-to-Spectral Efficiency: 36.213 Table 7.2.3-1 @@ -601,25 +660,6 @@ uint8_t srsran_cqi_from_snr(float snr) return 0; } -/* Returns the subband size for higher layer-configured subband feedback, - * i.e., the number of RBs per subband as a function of the cell bandwidth - * (Table 7.2.1-3 in TS 36.213) - */ -static int cqi_hl_get_subband_size(int nof_prb) -{ - if (nof_prb < 7) { - return 0; - } else if (nof_prb <= 26) { - return 4; - } else if (nof_prb <= 63) { - return 6; - } else if (nof_prb <= 110) { - return 8; - } else { - return -1; - } -} - /* Returns the number of subbands to be reported in CQI measurements as * defined in clause 7.2 in TS 36.213, i.e., the N parameter */ diff --git a/lib/src/phy/phch/prach.c b/lib/src/phy/phch/prach.c index d46aee861..85144d694 100644 --- a/lib/src/phy/phch/prach.c +++ b/lib/src/phy/phch/prach.c @@ -163,6 +163,23 @@ bool srsran_prach_tti_opportunity_config_fdd(uint32_t config_idx, uint32_t curre return false; } +bool srsran_prach_in_window_config_fdd(uint32_t config_idx, uint32_t current_tti, int allowed_subframe) +{ + if (srsran_prach_tti_opportunity_config_fdd(config_idx, current_tti, allowed_subframe)) { + return true; + } + + uint32_t preamble_format = srsran_prach_get_preamble_format(config_idx); + float T_tot = (prach_Tseq[preamble_format] + prach_Tcp[preamble_format]) * SRSRAN_LTE_TS; + uint32_t tti_dur = (uint32_t)ceilf(T_tot * 1000); + for (uint32_t i = 1; i < tti_dur; ++i) { + if (srsran_prach_tti_opportunity_config_fdd(config_idx, current_tti - i, allowed_subframe)) { + return true; + } + } + return false; +} + uint32_t srsran_prach_nof_f_idx_tdd(uint32_t config_idx, uint32_t tdd_ul_dl_config) { if (config_idx < 64 && tdd_ul_dl_config < 7) { diff --git a/lib/src/phy/phch/pucch_nr.c b/lib/src/phy/phch/pucch_nr.c index 0e6933527..faabd1067 100644 --- a/lib/src/phy/phch/pucch_nr.c +++ b/lib/src/phy/phch/pucch_nr.c @@ -569,7 +569,7 @@ static int pucch_nr_format2_encode(srsran_pucch_nr_t* q, return SRSRAN_ERROR; } - // Calculate number of encoded symbols + // Calculate number of encoded bits int e = srsran_uci_nr_pucch_format_2_3_4_E(resource); if (e < SRSRAN_SUCCESS) { ERROR("Error selecting E"); @@ -614,8 +614,13 @@ static int pucch_nr_format2_decode(srsran_pucch_nr_t* q, return SRSRAN_ERROR; } - // Calculate number of encoded symbols - uint32_t E = srsran_uci_nr_pucch_format_2_3_4_E(resource); + // Calculate number of encoded bits + int e = srsran_uci_nr_pucch_format_2_3_4_E(resource); + if (e < SRSRAN_SUCCESS) { + ERROR("Error selecting E"); + return SRSRAN_ERROR; + } + uint32_t E = (uint32_t)e; // Undo mapping to physical resources uint32_t l_start = resource->start_symbol_idx; @@ -643,13 +648,13 @@ static int pucch_nr_format2_decode(srsran_pucch_nr_t* q, } // Equalise - if (srsran_predecoding_single(q->d, q->ce, q->d, NULL, E, 1.0f, chest_res->noise_estimate) < SRSRAN_SUCCESS) { + if (srsran_predecoding_single(q->d, q->ce, q->d, NULL, E / 2, 1.0f, chest_res->noise_estimate) < SRSRAN_SUCCESS) { ERROR("Error Pre-decoding"); return SRSRAN_ERROR; } // Soft-demodulate - if (srsran_demod_soft_demodulate_b(SRSRAN_MOD_QPSK, q->d, llr, E) < SRSRAN_SUCCESS) { + if (srsran_demod_soft_demodulate_b(SRSRAN_MOD_QPSK, q->d, llr, E / 2) < SRSRAN_SUCCESS) { ERROR("Error soft-demodulate"); return SRSRAN_ERROR; } diff --git a/lib/src/phy/phch/ra_ul_nr.c b/lib/src/phy/phch/ra_ul_nr.c index 28250b171..f5c404730 100644 --- a/lib/src/phy/phch/ra_ul_nr.c +++ b/lib/src/phy/phch/ra_ul_nr.c @@ -487,17 +487,21 @@ static int ra_ul_nr_pucch_resource_default(uint32_t r_pucch, srsran_pucch_nr_res } static int ra_ul_nr_pucch_resource_hl(const srsran_pucch_nr_hl_cfg_t* cfg, - uint32_t O_uci, + const srsran_uci_cfg_nr_t* uci_cfg, uint32_t pucch_resource_id, srsran_pucch_nr_resource_t* resource) { - uint32_t N2 = cfg->sets[1].max_payload_size > 0 ? cfg->sets[1].max_payload_size : SRSRAN_UCI_NR_MAX_NOF_BITS; - uint32_t N3 = cfg->sets[2].max_payload_size > 0 ? cfg->sets[2].max_payload_size : SRSRAN_UCI_NR_MAX_NOF_BITS; + uint32_t O_uci = srsran_uci_nr_total_bits(uci_cfg); + uint32_t N2 = cfg->sets[1].max_payload_size > 0 ? cfg->sets[1].max_payload_size : SRSRAN_UCI_NR_MAX_NOF_BITS; + uint32_t N3 = cfg->sets[2].max_payload_size > 0 ? cfg->sets[2].max_payload_size : SRSRAN_UCI_NR_MAX_NOF_BITS; // If the UE transmits O UCI UCI information bits, that include HARQ-ACK information bits, the UE determines a PUCCH // resource set to be... uint32_t resource_set_id = 3; - if (O_uci <= 2 && cfg->sets[0].nof_resources > 0) { + if (uci_cfg->nof_csi == 0 && uci_cfg->ack.count <= 2) { + // a first set of PUCCH resources with pucch-ResourceSetId = 0 if O_UCI ≤ 2 including 1 or 2 HARQ-ACK + // information bits and a positive or negative SR on one SR transmission occasion if transmission of HARQ-ACK + // information and SR occurs simultaneously, or resource_set_id = 0; } else if (O_uci <= N2 && cfg->sets[1].nof_resources > 0) { resource_set_id = 1; @@ -533,14 +537,11 @@ int srsran_ra_ul_nr_pucch_resource(const srsran_pucch_nr_hl_cfg_t* pucch_cfg, return SRSRAN_ERROR_INVALID_INPUTS; } - uint32_t O_uci = srsran_uci_nr_total_bits(uci_cfg); - // Use SR PUCCH resource // - At least one positive SR - // - up to 2 HARQ-ACK + // - No HARQ-ACK // - No CSI report - if (uci_cfg->sr_positive_present > 0 && uci_cfg->ack.count <= SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS && - uci_cfg->nof_csi == 0) { + if (uci_cfg->sr_positive_present > 0 && uci_cfg->ack.count == 0 && uci_cfg->nof_csi == 0) { uint32_t sr_resource_id = uci_cfg->pucch.sr_resource_id; if (sr_resource_id >= SRSRAN_PUCCH_MAX_NOF_SR_RESOURCES) { ERROR("SR resource ID (%d) exceeds the maximum ID (%d)", sr_resource_id, SRSRAN_PUCCH_MAX_NOF_SR_RESOURCES); @@ -559,12 +560,63 @@ int srsran_ra_ul_nr_pucch_resource(const srsran_pucch_nr_hl_cfg_t* pucch_cfg, return SRSRAN_SUCCESS; } + // Use SR PUCCH resource + // - At least one positive SR + // - up to 2 HARQ-ACK + // - No CSI report + if (uci_cfg->sr_positive_present && uci_cfg->ack.count <= SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS && + uci_cfg->nof_csi == 0) { + uint32_t sr_resource_id = uci_cfg->pucch.sr_resource_id; + if (sr_resource_id >= SRSRAN_PUCCH_MAX_NOF_SR_RESOURCES) { + ERROR("SR resource ID (%d) exceeds the maximum ID (%d)", sr_resource_id, SRSRAN_PUCCH_MAX_NOF_SR_RESOURCES); + return SRSRAN_ERROR; + } + + if (!pucch_cfg->sr_resources[sr_resource_id].configured) { + ERROR("SR resource ID (%d) is not configured", sr_resource_id); + return SRSRAN_ERROR; + } + + // Select PUCCH resource for SR + srsran_pucch_nr_resource_t resource_sr = pucch_cfg->sr_resources[sr_resource_id].resource; + + // Select PUCCH resource for HARQ-ACK + srsran_pucch_nr_resource_t resource_harq = {}; + if (ra_ul_nr_pucch_resource_hl(pucch_cfg, uci_cfg, uci_cfg->pucch.resource_id, &resource_harq) < SRSRAN_SUCCESS) { + ERROR("Error selecting HARQ-ACK resource"); + return SRSRAN_ERROR; + } + + // If a UE would transmit positive or negative SR in a resource using PUCCH format 0 and HARQ-ACK information bits + // in a resource using PUCCH format 1 in a slot, the UE transmits only a PUCCH with the HARQ-ACK information bits + // in the resource using PUCCH format 1. + if (resource_sr.format == SRSRAN_PUCCH_NR_FORMAT_0 && resource_harq.format == SRSRAN_PUCCH_NR_FORMAT_1) { + *resource = resource_harq; + return SRSRAN_SUCCESS; + } + + // If the UE would transmit positive SR in a first resource using PUCCH format 1 and at most two HARQ-ACK + // information bits in a second resource using PUCCH format 1 in a slot, the UE transmits a PUCCH with HARQ-ACK + // information bits in the first resource using PUCCH format 1 as described in Clause 9.2.3. If a UE would transmit + // negative SR in a resource using PUCCH format 1 and at most two HARQ-ACK information bits in a resource using + // PUCCH format 1 in a slot, the UE transmits a PUCCH in the resource using PUCCH format 1 for HARQ-ACK + // information as described in Clause 9.2.3. + if (resource_sr.format == SRSRAN_PUCCH_NR_FORMAT_1 && resource_harq.format == SRSRAN_PUCCH_NR_FORMAT_1) { + *resource = resource_sr; + return SRSRAN_SUCCESS; + } + + // The impossible happened... + ERROR("The impossible happened..."); + return SRSRAN_ERROR; + } + // Use format 2, 3 or 4 resource from higher layers // - Irrelevant SR opportunities // - More than 2 HARQ-ACK // - No CSI report if (uci_cfg->o_sr > 0 && uci_cfg->ack.count > SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS && uci_cfg->nof_csi == 0) { - return ra_ul_nr_pucch_resource_hl(pucch_cfg, O_uci, uci_cfg->pucch.resource_id, resource); + return ra_ul_nr_pucch_resource_hl(pucch_cfg, uci_cfg, uci_cfg->pucch.resource_id, resource); } // Use format 2, 3 or 4 CSI report resource from higher layers @@ -583,7 +635,7 @@ int srsran_ra_ul_nr_pucch_resource(const srsran_pucch_nr_hl_cfg_t* pucch_cfg, uint32_t r_pucch = (2 * uci_cfg->pucch.n_cce_0) + 2 * uci_cfg->pucch.resource_id; return ra_ul_nr_pucch_resource_default(r_pucch, resource); } - return ra_ul_nr_pucch_resource_hl(pucch_cfg, O_uci, uci_cfg->pucch.resource_id, resource); + return ra_ul_nr_pucch_resource_hl(pucch_cfg, uci_cfg, uci_cfg->pucch.resource_id, resource); } uint32_t srsran_ra_ul_nr_nof_sr_bits(uint32_t K) diff --git a/lib/src/phy/rf/rf_soapy_imp.c b/lib/src/phy/rf/rf_soapy_imp.c index 62dc9738b..99abce9ae 100644 --- a/lib/src/phy/rf/rf_soapy_imp.c +++ b/lib/src/phy/rf/rf_soapy_imp.c @@ -265,11 +265,15 @@ int rf_soapy_stop_tx_stream(void* h) void rf_soapy_flush_buffer(void* h) { int n; - cf_t tmp1[1024]; - cf_t tmp2[1024]; - void* data[2] = {tmp1, tmp2}; + cf_t dummy[1024]; + void* data[SRSRAN_MAX_CHANNELS] = {}; + + for (int i = 0; i < SRSRAN_MAX_CHANNELS; i++) { + data[i] = dummy; + } + do { - n = rf_soapy_recv_with_time_multi(h, data, 1024, 0, NULL, NULL); + n = rf_soapy_recv_with_time_multi(h, data, sizeof(dummy), 0, NULL, NULL); } while (n > 0); } @@ -857,7 +861,9 @@ int rf_soapy_recv_with_time_multi(void* h, int rf_soapy_recv_with_time(void* h, void* data, uint32_t nsamples, bool blocking, time_t* secs, double* frac_secs) { - return rf_soapy_recv_with_time_multi(h, &data, nsamples, blocking, secs, frac_secs); + void* data_multi[SRSRAN_MAX_PORTS] = {NULL}; + data_multi[0] = data; + return rf_soapy_recv_with_time_multi(h, data_multi, nsamples, blocking, secs, frac_secs); } int rf_soapy_send_timed(void* h, diff --git a/lib/src/phy/rf/rf_soapy_imp.h b/lib/src/phy/rf/rf_soapy_imp.h index 153088923..bbaa38135 100644 --- a/lib/src/phy/rf/rf_soapy_imp.h +++ b/lib/src/phy/rf/rf_soapy_imp.h @@ -23,6 +23,7 @@ #define SRSRAN_RF_SOAPY_IMP_H_ #include "srsran/config.h" +#include "srsran/phy/common/phy_common.h" #include "srsran/phy/rf/rf.h" #include #include @@ -75,8 +76,12 @@ SRSRAN_API double rf_soapy_set_rx_freq(void* h, uint32_t ch, double freq); SRSRAN_API int rf_soapy_recv_with_time(void* h, void* data, uint32_t nsamples, bool blocking, time_t* secs, double* frac_secs); -SRSRAN_API int -rf_soapy_recv_with_time_multi(void* h, void** data, uint32_t nsamples, bool blocking, time_t* secs, double* frac_secs); +SRSRAN_API int rf_soapy_recv_with_time_multi(void* h, + void* data[SRSRAN_MAX_PORTS], + uint32_t nsamples, + bool blocking, + time_t* secs, + double* frac_secs); SRSRAN_API double rf_soapy_set_tx_srate(void* h, double freq); diff --git a/lib/src/phy/ue/ue_dl.c b/lib/src/phy/ue/ue_dl.c index d2fb6efce..65ad2209e 100644 --- a/lib/src/phy/ue/ue_dl.c +++ b/lib/src/phy/ue/ue_dl.c @@ -864,9 +864,11 @@ void srsran_ue_dl_gen_cqi_periodic(srsran_ue_dl_t* q, } else if (srsran_cqi_periodic_send(&cfg->cfg.cqi_report, tti, q->cell.frame_type)) { if (cfg->cfg.cqi_report.format_is_subband) { // TODO: Implement subband periodic reports - uci_data->cfg.cqi.type = SRSRAN_CQI_TYPE_SUBBAND; - uci_data->value.cqi.subband.subband_cqi = wideband_value; - uci_data->value.cqi.subband.subband_label = 0; + uci_data->cfg.cqi.type = SRSRAN_CQI_TYPE_SUBBAND_UE; + uci_data->value.cqi.subband_ue.subband_cqi = wideband_value; + uci_data->value.cqi.subband_ue.subband_label = tti / 100 % 2; + uci_data->cfg.cqi.L = srsran_cqi_hl_get_L(q->cell.nof_prb); + uci_data->cfg.cqi.subband_label_2_bits = uci_data->cfg.cqi.L > 1; } else { uci_data->cfg.cqi.type = SRSRAN_CQI_TYPE_WIDEBAND; uci_data->value.cqi.wideband.wideband_cqi = wideband_value; diff --git a/lib/test/asn1/CMakeLists.txt b/lib/test/asn1/CMakeLists.txt index 3bb349a42..4253218c6 100644 --- a/lib/test/asn1/CMakeLists.txt +++ b/lib/test/asn1/CMakeLists.txt @@ -55,7 +55,7 @@ target_link_libraries(rrc_asn1_test rrc_asn1 asn1_utils srsran_common) add_test(rrc_asn1_test rrc_asn1_test) add_executable(srsran_asn1_rrc_nr_test srsran_asn1_rrc_nr_test.cc) -target_link_libraries(srsran_asn1_rrc_nr_test rrc_nr_asn1 asn1_utils srsran_common) +target_link_libraries(srsran_asn1_rrc_nr_test rrc_nr_asn1 asn1_utils srsran_common srsran_mac) add_test(srsran_asn1_rrc_nr_test srsran_asn1_rrc_nr_test) add_executable(ngap_asn1_test ngap_test.cc) diff --git a/lib/test/asn1/srsran_asn1_rrc_nr_test.cc b/lib/test/asn1/srsran_asn1_rrc_nr_test.cc index 800120f54..24497e75c 100644 --- a/lib/test/asn1/srsran_asn1_rrc_nr_test.cc +++ b/lib/test/asn1/srsran_asn1_rrc_nr_test.cc @@ -25,6 +25,9 @@ #define JSON_OUTPUT 0 +#define HAVE_PCAP 0 +#include "srsran/common/test_pcap.h" + using namespace asn1; using namespace asn1::rrc_nr; @@ -374,19 +377,109 @@ int test_cell_group_config() cell_group_cfg_s cell_group_cfg_pack; cell_group_cfg_pack.sp_cell_cfg_present = true; cell_group_cfg_pack.sp_cell_cfg.serv_cell_idx_present = true; + + // 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.init_dl_bwp_present = true; + + // PDCCH config + cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.init_dl_bwp.pdcch_cfg_present = true; + auto& pdcch_cfg_dedicated = cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.init_dl_bwp.pdcch_cfg; + pdcch_cfg_dedicated.set_setup(); + pdcch_cfg_dedicated.setup().ctrl_res_set_to_add_mod_list_present = true; + pdcch_cfg_dedicated.setup().ctrl_res_set_to_add_mod_list.resize(1); + pdcch_cfg_dedicated.setup().ctrl_res_set_to_add_mod_list[0].ctrl_res_set_id = 2; + pdcch_cfg_dedicated.setup().ctrl_res_set_to_add_mod_list[0].freq_domain_res.from_number( + 0b111111110000000000000000000000000000000000000); + pdcch_cfg_dedicated.setup().ctrl_res_set_to_add_mod_list[0].dur = 1; + pdcch_cfg_dedicated.setup().ctrl_res_set_to_add_mod_list[0].cce_reg_map_type.set_non_interleaved(); + pdcch_cfg_dedicated.setup().ctrl_res_set_to_add_mod_list[0].precoder_granularity = + asn1::rrc_nr::ctrl_res_set_s::precoder_granularity_opts::same_as_reg_bundle; + + // search spaces + pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list_present = true; + pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list.resize(1); + pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list[0].search_space_id = 2; + pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list[0].ctrl_res_set_id_present = true; + pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list[0].ctrl_res_set_id = 2; + pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list[0].monitoring_slot_periodicity_and_offset_present = true; + pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list[0].monitoring_slot_periodicity_and_offset.set_sl1(); + pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list[0].monitoring_symbols_within_slot_present = true; + pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list[0].monitoring_symbols_within_slot.from_number( + 0b10000000000000); + pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list[0].nrof_candidates_present = true; + pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list[0].nrof_candidates.aggregation_level1 = + asn1::rrc_nr::search_space_s::nrof_candidates_s_::aggregation_level1_opts::n0; + pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list[0].nrof_candidates.aggregation_level2 = + asn1::rrc_nr::search_space_s::nrof_candidates_s_::aggregation_level2_opts::n2; + pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list[0].nrof_candidates.aggregation_level4 = + asn1::rrc_nr::search_space_s::nrof_candidates_s_::aggregation_level4_opts::n1; + pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list[0].nrof_candidates.aggregation_level8 = + asn1::rrc_nr::search_space_s::nrof_candidates_s_::aggregation_level8_opts::n0; + pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list[0].nrof_candidates.aggregation_level16 = + asn1::rrc_nr::search_space_s::nrof_candidates_s_::aggregation_level16_opts::n0; + pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list[0].search_space_type_present = true; + pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list[0].search_space_type.set_ue_specific(); + pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list[0].search_space_type.ue_specific().dci_formats = asn1:: + rrc_nr::search_space_s::search_space_type_c_::ue_specific_s_::dci_formats_opts::formats0_minus0_and_minus1_minus0; + + 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 = true; + 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(0x100); + 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 = true; + 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); + cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.first_active_dl_bwp_id_present = true; + 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.ul_cfg_present = true; - // TODO: add setup + // Serving cell config (only to setup) cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.pdcch_serving_cell_cfg_present = true; - auto& pdcch_cfg = cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.pdcch_serving_cell_cfg.set_setup(); - // TODO: add PDCCH config + cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.pdcch_serving_cell_cfg.set_setup(); cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.pdsch_serving_cell_cfg_present = true; - auto& pdsch_cfg = cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.pdsch_serving_cell_cfg.set_setup(); - // TODO: add PDSCH config + cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.pdsch_serving_cell_cfg.set_setup(); cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg_present = true; cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg.set_setup(); @@ -433,15 +526,60 @@ int test_cell_group_config() .subcarrier_spacing = subcarrier_spacing_opts::khz15; cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.dl_cfg_common.init_dl_bwp .pdcch_cfg_common_present = true; - cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.dl_cfg_common.init_dl_bwp.pdcch_cfg_common - .set_setup(); - // TODO: add PDCCH config - + auto& pdcch_cfg_common = + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.dl_cfg_common.init_dl_bwp.pdcch_cfg_common; + pdcch_cfg_common.set_setup(); + pdcch_cfg_common.setup().ext = false; + pdcch_cfg_common.setup().common_ctrl_res_set_present = true; + pdcch_cfg_common.setup().common_ctrl_res_set.ctrl_res_set_id = 1; + pdcch_cfg_common.setup().common_ctrl_res_set.freq_domain_res.from_number( + 0b111111110000000000000000000000000000000000000); + pdcch_cfg_common.setup().common_ctrl_res_set.dur = 1; + pdcch_cfg_common.setup().common_ctrl_res_set.cce_reg_map_type.set_non_interleaved(); + pdcch_cfg_common.setup().common_ctrl_res_set.precoder_granularity = + asn1::rrc_nr::ctrl_res_set_s::precoder_granularity_opts::same_as_reg_bundle; + + // common search space list + pdcch_cfg_common.setup().common_search_space_list_present = true; + pdcch_cfg_common.setup().common_search_space_list.resize(1); + pdcch_cfg_common.setup().common_search_space_list[0].search_space_id = 1; + pdcch_cfg_common.setup().common_search_space_list[0].ctrl_res_set_id_present = true; + pdcch_cfg_common.setup().common_search_space_list[0].ctrl_res_set_id = 1; + pdcch_cfg_common.setup().common_search_space_list[0].search_space_type_present = true; + pdcch_cfg_common.setup().common_search_space_list[0].search_space_type.set_common(); + pdcch_cfg_common.setup() + .common_search_space_list[0] + .search_space_type.common() + .dci_format0_minus0_and_format1_minus0_present = true; + pdcch_cfg_common.setup().common_search_space_list[0].nrof_candidates_present = true; + pdcch_cfg_common.setup().common_search_space_list[0].nrof_candidates.aggregation_level1 = + asn1::rrc_nr::search_space_s::nrof_candidates_s_::aggregation_level1_opts::n1; + pdcch_cfg_common.setup().common_search_space_list[0].nrof_candidates.aggregation_level2 = + asn1::rrc_nr::search_space_s::nrof_candidates_s_::aggregation_level2_opts::n1; + pdcch_cfg_common.setup().common_search_space_list[0].nrof_candidates.aggregation_level4 = + asn1::rrc_nr::search_space_s::nrof_candidates_s_::aggregation_level4_opts::n1; + pdcch_cfg_common.setup().common_search_space_list[0].nrof_candidates.aggregation_level8 = + asn1::rrc_nr::search_space_s::nrof_candidates_s_::aggregation_level8_opts::n0; + pdcch_cfg_common.setup().common_search_space_list[0].nrof_candidates.aggregation_level16 = + asn1::rrc_nr::search_space_s::nrof_candidates_s_::aggregation_level16_opts::n0; + pdcch_cfg_common.setup().common_search_space_list[0].monitoring_slot_periodicity_and_offset_present = true; + pdcch_cfg_common.setup().common_search_space_list[0].monitoring_slot_periodicity_and_offset.set_sl1(); + pdcch_cfg_common.setup().common_search_space_list[0].monitoring_symbols_within_slot_present = true; + pdcch_cfg_common.setup().common_search_space_list[0].monitoring_symbols_within_slot.from_number(0b10000000000000); + pdcch_cfg_common.setup().ra_search_space_present = true; + pdcch_cfg_common.setup().ra_search_space = 1; + + // PDSCH config common cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.dl_cfg_common.init_dl_bwp .pdsch_cfg_common_present = true; cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.dl_cfg_common.init_dl_bwp.pdsch_cfg_common .set_setup(); - // TODO: add PDSCH config + auto& pdsch_cfg_common = cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.dl_cfg_common.init_dl_bwp + .pdsch_cfg_common.setup(); + pdsch_cfg_common.pdsch_time_domain_alloc_list_present = true; + pdsch_cfg_common.pdsch_time_domain_alloc_list.resize(1); + pdsch_cfg_common.pdsch_time_domain_alloc_list[0].map_type = pdsch_time_domain_res_alloc_s::map_type_opts::type_a; + pdsch_cfg_common.pdsch_time_domain_alloc_list[0].start_symbol_and_len = 40; // UL config cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common_present = true; @@ -461,24 +599,122 @@ int test_cell_group_config() cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.init_ul_bwp.generic_params .subcarrier_spacing = subcarrier_spacing_opts::khz15; - // TODO: add config field for RACH -#if 0 + // RACH config cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.init_ul_bwp.rach_cfg_common_present=true; - cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.init_ul_bwp.rach_cfg_common.set_setup(); - cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.init_ul_bwp.rach_cfg_common.setup().prach_root_seq_idx = 10; -#endif - - uint8_t buffer[1024]; - asn1::bit_ref bref_pack(buffer, sizeof(buffer)); + auto& rach_cfg_common_pack = + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.init_ul_bwp.rach_cfg_common; + + rach_cfg_common_pack.set_setup(); + rach_cfg_common_pack.setup().rach_cfg_generic.prach_cfg_idx = 0; + rach_cfg_common_pack.setup().rach_cfg_generic.msg1_fdm = rach_cfg_generic_s::msg1_fdm_opts::one; + rach_cfg_common_pack.setup().rach_cfg_generic.msg1_freq_start = 1; + rach_cfg_common_pack.setup().rach_cfg_generic.zero_correlation_zone_cfg = 0; + rach_cfg_common_pack.setup().rach_cfg_generic.preamb_rx_target_pwr = -110; + rach_cfg_common_pack.setup().rach_cfg_generic.preamb_trans_max = + asn1::rrc_nr::rach_cfg_generic_s::preamb_trans_max_opts::n7; + rach_cfg_common_pack.setup().rach_cfg_generic.pwr_ramp_step = + asn1::rrc_nr::rach_cfg_generic_s::pwr_ramp_step_opts::db4; + rach_cfg_common_pack.setup().rach_cfg_generic.ra_resp_win = asn1::rrc_nr::rach_cfg_generic_s::ra_resp_win_opts::sl10; + rach_cfg_common_pack.setup().ra_contention_resolution_timer = + asn1::rrc_nr::rach_cfg_common_s::ra_contention_resolution_timer_opts::sf64; + rach_cfg_common_pack.setup().prach_root_seq_idx.set( + asn1::rrc_nr::rach_cfg_common_s::prach_root_seq_idx_c_::types_opts::l839); + rach_cfg_common_pack.setup().prach_root_seq_idx.set_l839() = 1; + rach_cfg_common_pack.setup().restricted_set_cfg = + asn1::rrc_nr::rach_cfg_common_s::restricted_set_cfg_opts::unrestricted_set; + + // PUSCH config common + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.init_ul_bwp + .pusch_cfg_common_present = true; + auto& pusch_cfg_common_pack = + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.init_ul_bwp.pusch_cfg_common; + pusch_cfg_common_pack.set_setup(); + pusch_cfg_common_pack.setup().pusch_time_domain_alloc_list_present = true; + pusch_cfg_common_pack.setup().pusch_time_domain_alloc_list.resize(2); + pusch_cfg_common_pack.setup().pusch_time_domain_alloc_list[0].k2_present = true; + pusch_cfg_common_pack.setup().pusch_time_domain_alloc_list[0].k2 = 4; + pusch_cfg_common_pack.setup().pusch_time_domain_alloc_list[0].map_type = + asn1::rrc_nr::pusch_time_domain_res_alloc_s::map_type_opts::type_a; + pusch_cfg_common_pack.setup().pusch_time_domain_alloc_list[0].start_symbol_and_len = 27; + pusch_cfg_common_pack.setup().pusch_time_domain_alloc_list[1].k2_present = true; + pusch_cfg_common_pack.setup().pusch_time_domain_alloc_list[1].k2 = 3; + pusch_cfg_common_pack.setup().pusch_time_domain_alloc_list[1].map_type = + asn1::rrc_nr::pusch_time_domain_res_alloc_s::map_type_opts::type_a; + pusch_cfg_common_pack.setup().pusch_time_domain_alloc_list[1].start_symbol_and_len = 27; + pusch_cfg_common_pack.setup().p0_nominal_with_grant = -90; + + // PUCCH config common + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.init_ul_bwp + .pucch_cfg_common_present = true; + auto& pucch_cfg_common_pack = + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.init_ul_bwp.pucch_cfg_common; + pucch_cfg_common_pack.set_setup(); + pucch_cfg_common_pack.setup().pucch_group_hop = asn1::rrc_nr::pucch_cfg_common_s::pucch_group_hop_opts::neither; + pucch_cfg_common_pack.setup().p0_nominal_present = true; + pucch_cfg_common_pack.setup().p0_nominal = -90; + + // SSB config (optional) + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ssb_positions_in_burst_present = true; + auto& ssb_pos_in_burst = cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ssb_positions_in_burst; + ssb_pos_in_burst.set_medium_bitmap().from_number(0b10000000); + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ssb_periodicity_serving_cell_present = true; + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ssb_periodicity_serving_cell = + serving_cell_cfg_common_s::ssb_periodicity_serving_cell_opts::ms20; + + // TDD UL-DL config + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.tdd_ul_dl_cfg_common_present = true; + auto& tdd_config = cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.tdd_ul_dl_cfg_common; + tdd_config.ref_subcarrier_spacing = subcarrier_spacing_e::khz15; + tdd_config.pattern1.dl_ul_tx_periodicity = asn1::rrc_nr::tdd_ul_dl_pattern_s::dl_ul_tx_periodicity_opts::ms10; + tdd_config.pattern1.nrof_dl_slots = 6; + tdd_config.pattern1.nrof_dl_symbols = 0; + tdd_config.pattern1.nrof_ul_slots = 3; + tdd_config.pattern1.nrof_ul_symbols = 0; + + // pack only cell group info + asn1::dyn_octstring packed_cell_group; + packed_cell_group.resize(256); + asn1::bit_ref bref_pack(packed_cell_group.data(), packed_cell_group.size()); TESTASSERT(cell_group_cfg_pack.pack(bref_pack) == asn1::SRSASN_SUCCESS); TESTASSERT(test_pack_unpack_consistency(cell_group_cfg_pack) == SRSASN_SUCCESS); + packed_cell_group.resize(bref_pack.distance_bytes()); #if JSON_OUTPUT - int packed_len = bref_pack.distance_bytes(); asn1::json_writer json_writer2; cell_group_cfg_pack.to_json(json_writer2); - srslog::fetch_basic_logger("RRC").info( - buffer, packed_len, "Cell group config repacked (%d B): \n %s", packed_len, json_writer2.to_string().c_str()); + srslog::fetch_basic_logger("RRC").info(packed_cell_group.data(), + packed_cell_group.size(), + "Cell group config repacked (%d B): \n %s", + packed_cell_group.size(), + json_writer2.to_string().c_str()); +#endif + +#if HAVE_PCAP + // pack full DL-DCCH with RRC reconfig for PCAP output + dl_dcch_msg_s dcch; + dcch.msg.set_c1().set_rrc_recfg(); + rrc_recfg_s& reconfig = dcch.msg.c1().rrc_recfg(); + reconfig.rrc_transaction_id = 0; + reconfig.crit_exts.set_rrc_recfg(); + rrc_recfg_ies_s& recfg_ies = reconfig.crit_exts.rrc_recfg(); + recfg_ies.secondary_cell_group_present = true; + recfg_ies.secondary_cell_group = packed_cell_group; + + asn1::dyn_octstring packed_dcch; + packed_dcch.resize(1024); + asn1::bit_ref bref_dcch_pack(packed_dcch.data(), packed_dcch.size()); + TESTASSERT(dcch.pack(bref_dcch_pack) == asn1::SRSASN_SUCCESS); + packed_dcch.resize(bref_dcch_pack.distance_bytes() + 10); + + asn1::json_writer json_writer3; + dcch.to_json(json_writer3); + srslog::fetch_basic_logger("RRC").info(packed_dcch.data(), + packed_dcch.size(), + "Full DCCH repacked (%d B): \n %s", + packed_dcch.size(), + json_writer3.to_string().c_str()); + + srsran::write_rlc_am_sdu_nr(1, packed_dcch.data(), packed_dcch.size()); #endif return SRSRAN_SUCCESS; @@ -496,6 +732,11 @@ int main() // Start the log backend. srslog::init(); +#if HAVE_PCAP + pcap_handle = std::unique_ptr(new srsran::mac_pcap()); + pcap_handle->open("srsran_asn1_rrc_nr_test.pcap"); +#endif + TESTASSERT(test_eutra_nr_capabilities() == SRSRAN_SUCCESS); TESTASSERT(test_ue_mrdc_capabilities() == SRSRAN_SUCCESS); TESTASSERT(test_ue_rrc_reconfiguration() == SRSRAN_SUCCESS); @@ -505,5 +746,12 @@ int main() srslog::flush(); printf("Success\n"); - return 0; + +#if HAVE_PCAP + if (pcap_handle) { + pcap_handle->close(); + } +#endif + + return SRSRAN_SUCCESS; } diff --git a/lib/test/asn1/srsran_asn1_rrc_ul_dcch_test.cc b/lib/test/asn1/srsran_asn1_rrc_ul_dcch_test.cc index 2e7ed852f..31b80aa2a 100644 --- a/lib/test/asn1/srsran_asn1_rrc_ul_dcch_test.cc +++ b/lib/test/asn1/srsran_asn1_rrc_ul_dcch_test.cc @@ -61,7 +61,7 @@ int rrc_ue_cap_info_test(srsran::mac_pcap* pcap) rrc_logger.set_level(srslog::basic_levels::debug); rrc_logger.set_hex_dump_max_size(128); - rrc_args_t args = {}; + srsue::rrc_args_t args = {}; args.feature_group = 0xe6041c00; args.nof_supported_bands = 1; args.supported_bands[0] = 8; @@ -128,7 +128,7 @@ int rrc_ue_cap_info_test(srsran::mac_pcap* pcap) int pack_fail_test() { - rrc_args_t args = {}; + srsue::rrc_args_t args = {}; args.feature_group = 0xe6041c00; args.nof_supported_bands = 1; args.supported_bands[0] = 8; diff --git a/srsenb/enb.conf.example b/srsenb/enb.conf.example index d3c36dc18..eeb99daf9 100644 --- a/srsenb/enb.conf.example +++ b/srsenb/enb.conf.example @@ -323,6 +323,10 @@ enable = false # metrics_period_secs: Sets the period at which metrics are requested from the eNB. # metrics_csv_enable: Write eNB metrics to CSV file. # metrics_csv_filename: File path to use for CSV metrics. +# report_json_enable: Write eNB report to JSON file (default disabled) +# report_json_filename: Report JSON filename (default /tmp/enb_report.json) +# alarms_log_enable: Enable Alarms logging (default diabled) +# alarms_filename: Alarms logging filename (default /tmp/alarms.log) # tracing_enable: Write source code tracing information to a file. # tracing_filename: File path to use for tracing information. # tracing_buffcapacity: Maximum capacity in bytes the tracing framework can store. @@ -330,14 +334,16 @@ enable = false # pregenerate_signals: Pregenerate uplink signals after attach. Improves CPU performance. # tx_amplitude: Transmit amplitude factor (set 0-1 to reduce PAPR) # rrc_inactivity_timer Inactivity timeout used to remove UE context from RRC (in milliseconds). +# max_mac_dl_kos: Maximum number of consecutive KOs in DL before triggering the UE's release (default 100) +# max_mac_ul_kos: Maximum number of consecutive KOs in UL before triggering the UE's release (default 100) # max_prach_offset_us: Maximum allowed RACH offset (in us) # nof_prealloc_ues: Number of UE memory resources to preallocate during eNB initialization for faster UE creation (Default 8) # rlf_release_timer_ms: Time taken by eNB to release UE context after it detects an RLF # eea_pref_list: Ordered preference list for the selection of encryption algorithm (EEA) (default: EEA0, EEA2, EEA1). # eia_pref_list: Ordered preference list for the selection of integrity algorithm (EIA) (default: EIA2, EIA1, EIA0). # gtpu_tunnel_timeout: Time that GTPU takes to release indirect forwarding tunnel since the last received GTPU PDU (0 for no timer). -#ts1_reloc_prep_timeout: S1AP TS 36.413 TS1RelocPrep Expiry Timeout value in milliseconds -#ts1_reloc_overall_timeout: S1AP TS 36.413 TS1RelocOverall Expiry Timeout value in milliseconds +# ts1_reloc_prep_timeout: S1AP TS 36.413 TS1RelocPrep Expiry Timeout value in milliseconds +# ts1_reloc_overall_timeout: S1AP TS 36.413 TS1RelocOverall Expiry Timeout value in milliseconds # rlf_release_timer_ms: Time taken by eNB to release UE context after it detects an RLF # rlf_min_ul_snr_estim: SNR threshold in dB below which the enb is notified with rlf ko # @@ -360,7 +366,8 @@ enable = false #pregenerate_signals = false #tx_amplitude = 0.6 #rrc_inactivity_timer = 30000 -#max_nof_kos = 100 +#max_mac_dl_kos = 100 +#max_mac_ul_kos = 100 #max_prach_offset_us = 30 #nof_prealloc_ues = 8 #rlf_release_timer_ms = 4000 diff --git a/srsenb/hdr/phy/nr/worker_pool.h b/srsenb/hdr/phy/nr/worker_pool.h index f40776efc..d3fb0edf8 100644 --- a/srsenb/hdr/phy/nr/worker_pool.h +++ b/srsenb/hdr/phy/nr/worker_pool.h @@ -58,6 +58,10 @@ private: int ri_info(uint32_t tti, uint16_t rnti, uint32_t cc_idx, uint32_t ri_value) override { return 0; } int pmi_info(uint32_t tti, uint16_t rnti, uint32_t cc_idx, uint32_t pmi_value) override { return 0; } int cqi_info(uint32_t tti, uint16_t rnti, uint32_t cc_idx, uint32_t cqi_value) override { return 0; } + int sb_cqi_info(uint32_t tti, uint16_t rnti, uint32_t cc_idx, uint32_t sb_idx, uint32_t cqi_value) override + { + return 0; + } int snr_info(uint32_t tti, uint16_t rnti, uint32_t cc_idx, float snr_db, ul_channel_t ch) override { return 0; } int ta_info(uint32_t tti, uint16_t rnti, float ta_us) override { return 0; } int ack_info(uint32_t tti, uint16_t rnti, uint32_t cc_idx, uint32_t tb_idx, bool ack) override { return 0; } diff --git a/srsenb/hdr/stack/enb_stack_base.h b/srsenb/hdr/stack/enb_stack_base.h index 302738def..6d44b420d 100644 --- a/srsenb/hdr/stack/enb_stack_base.h +++ b/srsenb/hdr/stack/enb_stack_base.h @@ -68,14 +68,6 @@ typedef struct { int stack_hex_limit; } stack_log_args_t; -// Expert arguments to create GW without core NW -typedef struct { - std::string ip_addr; - srsue::gw_args_t gw_args; - uint8_t drb_lcid; - uint16_t rnti; -} core_less_args_t; - typedef struct { std::string type; uint32_t sync_queue_size; // Max allowed difference between PHY and Stack clocks (in TTI) @@ -87,7 +79,6 @@ typedef struct { pcap_args_t s1ap_pcap; stack_log_args_t log; embms_args_t embms; - core_less_args_t coreless; } stack_args_t; struct stack_metrics_t; diff --git a/srsenb/hdr/stack/enb_stack_lte.h b/srsenb/hdr/stack/enb_stack_lte.h index 8e1694b45..058787576 100644 --- a/srsenb/hdr/stack/enb_stack_lte.h +++ b/srsenb/hdr/stack/enb_stack_lte.h @@ -75,6 +75,10 @@ public: { return mac.cqi_info(tti, rnti, cc_idx, cqi_value); } + int sb_cqi_info(uint32_t tti, uint16_t rnti, uint32_t cc_idx, uint32_t sb_idx, uint32_t cqi_value) final + { + return mac.sb_cqi_info(tti, rnti, cc_idx, sb_idx, cqi_value); + } int snr_info(uint32_t tti_rx, uint16_t rnti, uint32_t cc_idx, float snr_db, ul_channel_t ch) final { return mac.snr_info(tti_rx, rnti, cc_idx, snr_db, ch); diff --git a/srsenb/hdr/stack/gnb_stack_nr.h b/srsenb/hdr/stack/gnb_stack_nr.h index 8fd97d47c..139570a08 100644 --- a/srsenb/hdr/stack/gnb_stack_nr.h +++ b/srsenb/hdr/stack/gnb_stack_nr.h @@ -81,11 +81,11 @@ public: void toggle_padding() override { srsran::console("padding not available for NR\n"); } - int slot_indication(const srsran_slot_cfg_t& slot_cfg) override; - int get_dl_sched(const srsran_slot_cfg_t& slot_cfg, dl_sched_t& dl_sched) override; - int get_ul_sched(const srsran_slot_cfg_t& slot_cfg, ul_sched_t& ul_sched) override; - int pucch_info(const srsran_slot_cfg_t& slot_cfg, const pucch_info_t& pucch_info) override; - int pusch_info(const srsran_slot_cfg_t& slot_cfg, const pusch_info_t& pusch_info) override; + int slot_indication(const srsran_slot_cfg_t& slot_cfg) override; + int get_dl_sched(const srsran_slot_cfg_t& slot_cfg, dl_sched_t& dl_sched) override; + int get_ul_sched(const srsran_slot_cfg_t& slot_cfg, ul_sched_t& ul_sched) override; + int pucch_info(const srsran_slot_cfg_t& slot_cfg, const pucch_info_t& pucch_info) override; + int pusch_info(const srsran_slot_cfg_t& slot_cfg, const pusch_info_t& pusch_info) override; void rach_detected(const rach_info_t& rach_info) override; private: diff --git a/srsenb/hdr/stack/mac/mac_metrics.h b/srsenb/hdr/stack/mac/common/mac_metrics.h similarity index 100% rename from srsenb/hdr/stack/mac/mac_metrics.h rename to srsenb/hdr/stack/mac/common/mac_metrics.h diff --git a/srsenb/hdr/stack/mac/mac.h b/srsenb/hdr/stack/mac/mac.h index 736429889..7a5d6171f 100644 --- a/srsenb/hdr/stack/mac/mac.h +++ b/srsenb/hdr/stack/mac/mac.h @@ -65,6 +65,7 @@ public: int ri_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, uint32_t ri_value) override; int pmi_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, uint32_t pmi_value) override; int cqi_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, uint32_t cqi_value) override; + int sb_cqi_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, uint32_t sb_idx, uint32_t cqi_value) override; int snr_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, float snr, ul_channel_t ch) override; int ta_info(uint32_t tti, uint16_t rnti, float ta_us) override; int ack_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, uint32_t tb_idx, bool ack) override; diff --git a/srsenb/hdr/stack/mac/mac_nr.h b/srsenb/hdr/stack/mac/mac_nr.h index 14fcc7fb5..bc8ecac28 100644 --- a/srsenb/hdr/stack/mac/mac_nr.h +++ b/srsenb/hdr/stack/mac/mac_nr.h @@ -24,27 +24,19 @@ #include "srsran/common/block_queue.h" #include "srsran/common/mac_pcap.h" -#include "srsran/mac/mac_sch_pdu_nr.h" +#include "srsenb/hdr/common/rnti_pool.h" #include "srsenb/hdr/stack/enb_stack_base.h" +#include "srsenb/hdr/stack/mac/nr/ue_nr.h" #include "srsran/common/task_scheduler.h" #include "srsran/interfaces/enb_metrics_interface.h" +#include "srsran/interfaces/enb_rlc_interfaces.h" #include "srsran/interfaces/gnb_interfaces.h" namespace srsenb { struct mac_nr_args_t { srsenb::pcap_args_t pcap; - - // params for the dummy user - srsenb::sched_interface::sched_args_t sched; - uint16_t rnti; - uint32_t drb_lcid; - - // Add args - std::string log_level; - uint32_t log_hex_limit; - uint32_t tb_size = 64; }; class mac_nr final : public mac_interface_phy_nr, public mac_interface_rrc_nr, public mac_interface_rlc_nr @@ -56,7 +48,7 @@ public: int init(const mac_nr_args_t& args_, phy_interface_stack_nr* phy, stack_interface_mac* stack_, - rlc_interface_mac_nr* rlc_, + rlc_interface_mac* rlc_, rrc_interface_mac_nr* rrc_); void stop(); @@ -64,6 +56,7 @@ public: // MAC interface for RRC int cell_cfg(srsenb::sched_interface::cell_cfg_t* cell_cfg) override; + uint16_t reserve_rnti() override; int read_pdu_bcch_bch(uint8_t* payload); // MAC interface for RLC @@ -75,6 +68,7 @@ public: int rx_data_indication(stack_interface_phy_nr::rx_data_ind_t& grant); void process_pdus(); + void rach_detected(const srsran_slot_cfg_t& slot_cfg, uint32_t enb_cc_idx, uint32_t preamble_idx, uint32_t time_adv); int slot_indication(const srsran_slot_cfg_t& slot_cfg) override; int get_dl_sched(const srsran_slot_cfg_t& slot_cfg, dl_sched_t& dl_sched) override; int get_ul_sched(const srsran_slot_cfg_t& slot_cfg, ul_sched_t& ul_sched) override; @@ -83,26 +77,41 @@ public: void rach_detected(const rach_info_t& rach_info) override; private: + uint16_t add_ue(uint32_t enb_cc_idx); + int remove_ue(uint16_t rnti); + + // internal misc helpers + bool is_rnti_valid_unsafe(uint16_t rnti); + bool is_rnti_active_unsafe(uint16_t rnti); + // PDU processing int handle_pdu(srsran::unique_byte_buffer_t pdu); // Interaction with other components - phy_interface_stack_nr* phy_h = nullptr; - stack_interface_mac* stack_h = nullptr; - rlc_interface_mac_nr* rlc_h = nullptr; - rrc_interface_mac_nr* rrc_h = nullptr; + phy_interface_stack_nr* phy = nullptr; + stack_interface_mac* stack = nullptr; + rlc_interface_mac* rlc = nullptr; + rrc_interface_mac_nr* rrc = nullptr; // args srsran::task_sched_handle task_sched; + srsran::task_multiqueue::queue_handle stack_task_queue; std::unique_ptr pcap = nullptr; mac_nr_args_t args = {}; srslog::basic_logger& logger; - bool started = false; + std::atomic started = {false}; srsenb::sched_interface::cell_cfg_t cfg = {}; + // Map of active UEs + pthread_rwlock_t rwlock = {}; + static const uint16_t FIRST_RNTI = 0x4601; + srsran::static_circular_map, SRSENB_MAX_UES> ue_db; + + std::atomic ue_counter; + // BCH buffers struct sib_info_t { uint32_t index; @@ -112,15 +121,8 @@ private: std::vector bcch_dlsch_payload; srsran::unique_byte_buffer_t bcch_bch_payload = nullptr; - // UE-specific buffer - srsran::mac_sch_pdu_nr ue_tx_pdu; - std::vector ue_tx_buffer; - srsran::block_queue - ue_rx_pdu_queue; ///< currently only DCH PDUs supported (add BCH, PCH, etc) - - srsran::unique_byte_buffer_t ue_rlc_buffer; - - srsran::mac_sch_pdu_nr ue_rx_pdu; + // Number of rach preambles detected for a cc. + std::vector detected_rachs; }; } // namespace srsenb diff --git a/srsenb/hdr/stack/mac/nr/sched_nr.h b/srsenb/hdr/stack/mac/nr/sched_nr.h index d4519e472..25b766680 100644 --- a/srsenb/hdr/stack/mac/nr/sched_nr.h +++ b/srsenb/hdr/stack/mac/nr/sched_nr.h @@ -36,7 +36,7 @@ namespace srsenb { namespace sched_nr_impl { class sched_worker_manager; -class serv_cell_ctxt; +class serv_cell_manager; } // namespace sched_nr_impl class ue_event_manager; @@ -51,10 +51,11 @@ public: void ue_cfg(uint16_t rnti, const ue_cfg_t& cfg) override; void dl_ack_info(uint16_t rnti, uint32_t cc, uint32_t pid, uint32_t tb_idx, bool ack) override; + void ul_crc_info(uint16_t rnti, uint32_t cc, uint32_t pid, bool crc) override; void ul_sr_info(tti_point tti_rx, uint16_t rnti) override; int get_dl_sched(tti_point pdsch_tti, uint32_t cc, dl_sched_t& result) override; - int get_ul_sched(tti_point pdcch_tti, uint32_t cc, ul_sched_t& result) override; + int get_ul_sched(tti_point pusch_tti, uint32_t cc, ul_sched_t& result) override; private: int generate_slot_result(tti_point pdcch_tti, uint32_t cc); @@ -71,14 +72,11 @@ private: std::mutex ue_db_mutex; ue_map_t ue_db; - // management of UE feedback - std::unique_ptr pending_events; - // management of Sched Result buffering std::unique_ptr pending_results; // management of cell resources - std::vector > cells; + std::vector > cells; }; } // namespace srsenb diff --git a/srsenb/hdr/stack/mac/nr/sched_nr_bwp.h b/srsenb/hdr/stack/mac/nr/sched_nr_cell.h similarity index 73% rename from srsenb/hdr/stack/mac/nr/sched_nr_bwp.h rename to srsenb/hdr/stack/mac/nr/sched_nr_cell.h index 8200da252..eb95ba789 100644 --- a/srsenb/hdr/stack/mac/nr/sched_nr_bwp.h +++ b/srsenb/hdr/stack/mac/nr/sched_nr_cell.h @@ -19,8 +19,8 @@ * */ -#ifndef SRSRAN_SCHED_NR_BWP_H -#define SRSRAN_SCHED_NR_BWP_H +#ifndef SRSRAN_SCHED_NR_CELL_H +#define SRSRAN_SCHED_NR_CELL_H #include "sched_nr_cfg.h" #include "sched_nr_rb_grid.h" @@ -44,12 +44,14 @@ public: explicit ra_sched(const bwp_params& bwp_cfg_); int dl_rach_info(const dl_sched_rar_info_t& rar_info); - void run_slot(bwp_slot_allocator& slot_grid); + void run_slot(bwp_slot_allocator& slot_grid, slot_ue_map_t& slot_ues); size_t empty() const { return pending_rars.empty(); } private: - alloc_result - allocate_pending_rar(bwp_slot_allocator& slot_grid, const pending_rar_t& rar, uint32_t& nof_grants_alloc); + alloc_result allocate_pending_rar(bwp_slot_allocator& slot_grid, + const pending_rar_t& rar, + slot_ue_map_t& slot_ues, + uint32_t& nof_grants_alloc); const bwp_params* bwp_cfg = nullptr; srslog::basic_logger& logger; @@ -71,17 +73,21 @@ public: bwp_res_grid grid; }; -class serv_cell_ctxt +class serv_cell_manager { public: - srsran::bounded_vector bwps; + using feedback_callback_t = srsran::move_callback; + + explicit serv_cell_manager(const sched_cell_params& cell_cfg_); - explicit serv_cell_ctxt(const sched_cell_params& cell_cfg_); + srsran::bounded_vector bwps; + const sched_cell_params& cfg; - const sched_cell_params* cfg; +private: + srslog::basic_logger& logger; }; } // namespace sched_nr_impl } // namespace srsenb -#endif // SRSRAN_SCHED_NR_BWP_H +#endif // SRSRAN_SCHED_NR_CELL_H diff --git a/srsenb/hdr/stack/mac/nr/sched_nr_cfg.h b/srsenb/hdr/stack/mac/nr/sched_nr_cfg.h index 23ee5446f..864892894 100644 --- a/srsenb/hdr/stack/mac/nr/sched_nr_cfg.h +++ b/srsenb/hdr/stack/mac/nr/sched_nr_cfg.h @@ -56,6 +56,14 @@ struct bwp_params { uint32_t P; uint32_t N_rbg; + struct pusch_ra_time_cfg { + uint32_t msg3_delay; ///< Includes K2 and delta. See TS 36.214 6.1.2.1.1-2/4/5 + uint32_t K; + uint32_t S; + uint32_t L; + }; + std::vector pusch_ra_list; + bwp_params(const cell_cfg_t& cell, const sched_cfg_t& sched_cfg_, uint32_t cc, uint32_t bwp_id); }; diff --git a/srsenb/hdr/stack/mac/nr/sched_nr_harq.h b/srsenb/hdr/stack/mac/nr/sched_nr_harq.h index 27051e16d..aeb7eccc8 100644 --- a/srsenb/hdr/stack/mac/nr/sched_nr_harq.h +++ b/srsenb/hdr/stack/mac/nr/sched_nr_harq.h @@ -89,6 +89,12 @@ public: tx_harq_softbuffer& get_softbuffer() { return *softbuffer; } + bool set_tbs(uint32_t tbs) + { + softbuffer->reset(); + return harq_proc::set_tbs(tbs); + } + private: srsran::unique_pool_ptr softbuffer; }; @@ -119,22 +125,23 @@ public: void new_tti(tti_point tti_rx_); void dl_ack_info(uint32_t pid, uint32_t tb_idx, bool ack) { dl_harqs[pid].ack_info(tb_idx, ack); } + void ul_crc_info(uint32_t pid, bool ack) { ul_harqs[pid].ack_info(0, ack); } dl_harq_proc* find_pending_dl_retx() { return find_dl([this](const dl_harq_proc& h) { return h.has_pending_retx(tti_rx); }); } - harq_proc* find_pending_ul_retx() + ul_harq_proc* find_pending_ul_retx() { - return find_ul([this](const harq_proc& h) { return h.has_pending_retx(tti_rx); }); + return find_ul([this](const ul_harq_proc& h) { return h.has_pending_retx(tti_rx); }); } dl_harq_proc* find_empty_dl_harq() { - return find_dl([](const harq_proc& h) { return h.empty(); }); + return find_dl([](const dl_harq_proc& h) { return h.empty(); }); } - harq_proc* find_empty_ul_harq() + ul_harq_proc* find_empty_ul_harq() { - return find_ul([](const harq_proc& h) { return h.empty(); }); + return find_ul([](const ul_harq_proc& h) { return h.empty(); }); } private: @@ -145,7 +152,7 @@ private: return (it == dl_harqs.end()) ? nullptr : &(*it); } template - harq_proc* find_ul(Predicate p) + ul_harq_proc* find_ul(Predicate p) { auto it = std::find_if(ul_harqs.begin(), ul_harqs.end(), p); return (it == ul_harqs.end()) ? nullptr : &(*it); diff --git a/srsenb/hdr/stack/mac/nr/sched_nr_interface.h b/srsenb/hdr/stack/mac/nr/sched_nr_interface.h index 5e83ebc69..1a4f6f864 100644 --- a/srsenb/hdr/stack/mac/nr/sched_nr_interface.h +++ b/srsenb/hdr/stack/mac/nr/sched_nr_interface.h @@ -72,9 +72,7 @@ public: srsran::bounded_vector bwps{1}; // idx0 for BWP-common }; - struct sched_cfg_t { - uint32_t nof_concurrent_subframes = 1; - }; + struct sched_cfg_t {}; struct ue_cc_cfg_t { bool active = false; @@ -82,7 +80,9 @@ public: }; struct ue_cfg_t { - uint32_t maxharq_tx = 4; + uint32_t maxharq_tx = 4; + int fixed_dl_mcs = -1; + int fixed_ul_mcs = -1; srsran::bounded_vector carriers; srsran::phy_cfg_nr_t phy_cfg = {}; }; @@ -109,6 +109,7 @@ public: virtual int get_ul_sched(tti_point tti_rx, uint32_t cc, ul_sched_t& result) = 0; virtual void dl_ack_info(uint16_t rnti, uint32_t cc, uint32_t pid, uint32_t tb_idx, bool ack) = 0; + virtual void ul_crc_info(uint16_t rnti, uint32_t cc, uint32_t pid, bool crc) = 0; virtual void ul_sr_info(tti_point, uint16_t rnti) = 0; }; diff --git a/srsenb/hdr/stack/mac/nr/sched_nr_rb_grid.h b/srsenb/hdr/stack/mac/nr/sched_nr_rb_grid.h index 3c3077b95..f75a6a036 100644 --- a/srsenb/hdr/stack/mac/nr/sched_nr_rb_grid.h +++ b/srsenb/hdr/stack/mac/nr/sched_nr_rb_grid.h @@ -81,6 +81,10 @@ private: srsran::bounded_vector slots; }; +/** + * Class responsible for jointly filling the DL/UL sched result fields and allocate RB/PDCCH resources in the RB grid + * to avoid potential RB/PDCCH collisions + */ class bwp_slot_allocator { public: @@ -88,7 +92,11 @@ public: void new_slot(tti_point pdcch_tti_) { pdcch_tti = pdcch_tti_; } - alloc_result alloc_rar(uint32_t aggr_idx, const pending_rar_t& rar, prb_interval interv, uint32_t max_nof_grants); + alloc_result alloc_rar_and_msg3(uint32_t aggr_idx, + const pending_rar_t& rar, + prb_interval interv, + slot_ue_map_t& ues, + uint32_t max_nof_grants); alloc_result alloc_pdsch(slot_ue& ue, const prb_grant& dl_grant); alloc_result alloc_pusch(slot_ue& ue, const rbgmask_t& dl_mask); @@ -98,6 +106,8 @@ public: const bwp_params& cfg; private: + alloc_result verify_pusch_space(bwp_slot_grid& pusch_grid, bwp_slot_grid* pdcch_grid = nullptr) const; + srslog::basic_logger& logger; bwp_res_grid& bwp_grid; diff --git a/srsenb/hdr/stack/mac/nr/sched_nr_ue.h b/srsenb/hdr/stack/mac/nr/sched_nr_ue.h index 3a12a0f49..fcf8c93a4 100644 --- a/srsenb/hdr/stack/mac/nr/sched_nr_ue.h +++ b/srsenb/hdr/stack/mac/nr/sched_nr_ue.h @@ -39,41 +39,37 @@ class slot_ue { public: slot_ue() = default; - explicit slot_ue(resource_guard::token ue_token, uint16_t rnti_, tti_point tti_rx_, uint32_t cc); + explicit slot_ue(uint16_t rnti_, tti_point tti_rx_, uint32_t cc); slot_ue(slot_ue&&) noexcept = default; slot_ue& operator=(slot_ue&&) noexcept = default; - bool empty() const { return ue_token.empty(); } - void release() { ue_token.release(); } + bool empty() const { return rnti == SCHED_NR_INVALID_RNTI; } + void release() { rnti = SCHED_NR_INVALID_RNTI; } uint16_t rnti = SCHED_NR_INVALID_RNTI; tti_point tti_rx; uint32_t cc = SCHED_NR_MAX_CARRIERS; // UE parameters common to all sectors - const bwp_ue_cfg* cfg = nullptr; - bool pending_sr; + bool pending_sr; // UE parameters that are sector specific - const ue_cc_cfg_t* cc_cfg = nullptr; - tti_point pdcch_tti; - tti_point pdsch_tti; - tti_point pusch_tti; - tti_point uci_tti; - uint32_t dl_cqi; - uint32_t ul_cqi; - dl_harq_proc* h_dl = nullptr; - harq_proc* h_ul = nullptr; - -private: - resource_guard::token ue_token; + const bwp_ue_cfg* cfg = nullptr; + tti_point pdcch_tti; + tti_point pdsch_tti; + tti_point pusch_tti; + tti_point uci_tti; + uint32_t dl_cqi; + uint32_t ul_cqi; + dl_harq_proc* h_dl = nullptr; + ul_harq_proc* h_ul = nullptr; }; class ue_carrier { public: ue_carrier(uint16_t rnti, const ue_cfg_t& cfg, const sched_cell_params& cell_params_); - slot_ue try_reserve(tti_point pdcch_tti, const ue_cfg_t& cfg); - void push_feedback(srsran::move_callback callback); + void new_tti(tti_point pdcch_tti, const ue_cfg_t& uecfg_); + slot_ue try_reserve(tti_point pdcch_tti); const uint16_t rnti; const uint32_t cc; @@ -87,11 +83,6 @@ public: private: bwp_ue_cfg bwp_cfg; const sched_cell_params& cell_params; - - resource_guard busy; - tti_point last_tti_rx; - - srsran::deque > pending_feedback; }; class ue @@ -99,12 +90,16 @@ class ue public: ue(uint16_t rnti, const ue_cfg_t& cfg, const sched_params& sched_cfg_); - slot_ue try_reserve(tti_point tti_rx, uint32_t cc); + slot_ue try_reserve(tti_point pdcch_tti, uint32_t cc); - void set_cfg(const ue_cfg_t& cfg); + void set_cfg(const ue_cfg_t& cfg); + const ue_cfg_t& cfg() const { return ue_cfg; } void ul_sr_info(tti_point tti_rx) { pending_sr = true; } + bool has_ca() const { return ue_cfg.carriers.size() > 1; } + uint32_t pcell_cc() const { return ue_cfg.carriers[0].cc; } + std::array, SCHED_NR_MAX_CARRIERS> carriers; private: @@ -113,11 +108,11 @@ private: bool pending_sr = false; - int current_idx = 0; - std::array ue_cfgs; + ue_cfg_t ue_cfg; }; -using ue_map_t = srsran::static_circular_map, SCHED_NR_MAX_USERS>; +using ue_map_t = srsran::static_circular_map, SCHED_NR_MAX_USERS>; +using slot_ue_map_t = srsran::static_circular_map; } // namespace sched_nr_impl diff --git a/srsenb/hdr/stack/mac/nr/sched_nr_worker.h b/srsenb/hdr/stack/mac/nr/sched_nr_worker.h index 40a3f7e35..ddf533ab7 100644 --- a/srsenb/hdr/stack/mac/nr/sched_nr_worker.h +++ b/srsenb/hdr/stack/mac/nr/sched_nr_worker.h @@ -22,7 +22,7 @@ #ifndef SRSRAN_SCHED_NR_WORKER_H #define SRSRAN_SCHED_NR_WORKER_H -#include "sched_nr_bwp.h" +#include "sched_nr_cell.h" #include "sched_nr_cfg.h" #include "sched_nr_rb_grid.h" #include "sched_nr_ue.h" @@ -42,25 +42,41 @@ using ul_sched_t = sched_nr_interface::ul_sched_t; class slot_cc_worker { public: - explicit slot_cc_worker(serv_cell_ctxt& sched); + using feedback_callback_t = srsran::move_callback; - void start(tti_point tti_rx_, ue_map_t& ue_db_); + explicit slot_cc_worker(serv_cell_manager& sched); + + void start(tti_point pdcch_tti, ue_map_t& ue_db_); void run(); - void end_tti(); + void finish(); bool running() const { return tti_rx.is_valid(); } + /// Enqueue feedback directed at a given UE in a given cell + void enqueue_cc_feedback(uint16_t rnti, feedback_callback_t fdbk); + private: + /// Run all pending feedback. This should be called at the beginning of a TTI + void run_feedback(ue_map_t& ue_db); + void alloc_dl_ues(); void alloc_ul_ues(); void log_result() const; const sched_cell_params& cfg; - serv_cell_ctxt& cell; + serv_cell_manager& cell; srslog::basic_logger& logger; tti_point tti_rx; bwp_slot_allocator bwp_alloc; + // Process of UE cell-specific feedback + struct feedback_t { + uint16_t rnti; + feedback_callback_t fdbk; + }; + std::mutex feedback_mutex; + srsran::deque pending_feedback, tmp_feedback_to_run; + srsran::static_circular_map slot_ues; }; @@ -76,28 +92,50 @@ class sched_worker_manager }; public: - explicit sched_worker_manager(ue_map_t& ue_db_, const sched_params& cfg_); + explicit sched_worker_manager(ue_map_t& ue_db_, + const sched_params& cfg_, + srsran::span > cells_); sched_worker_manager(const sched_worker_manager&) = delete; sched_worker_manager(sched_worker_manager&&) = delete; ~sched_worker_manager(); - void start_slot(tti_point tti_rx, srsran::move_callback process_feedback); - bool run_slot(tti_point tti_rx, uint32_t cc); - void release_slot(tti_point tti_rx); - bool save_sched_result(tti_point pdcch_tti, uint32_t cc, dl_sched_t& dl_res, ul_sched_t& ul_res); + void run_slot(tti_point tti_tx, uint32_t cc, dl_sched_t& dl_res, ul_sched_t& ul_res); + + void enqueue_event(uint16_t rnti, srsran::move_callback ev); + void enqueue_cc_feedback(uint16_t rnti, uint32_t cc, slot_cc_worker::feedback_callback_t fdbk) + { + cc_worker_list[cc]->worker.enqueue_cc_feedback(rnti, std::move(fdbk)); + } private: - const sched_params& cfg; - ue_map_t& ue_db; - srslog::basic_logger& logger; + bool save_sched_result(tti_point pdcch_tti, uint32_t cc, dl_sched_t& dl_res, ul_sched_t& ul_res); - std::mutex ue_db_mutex; + const sched_params& cfg; + ue_map_t& ue_db; + srsran::span > cells; + srslog::basic_logger& logger; + + struct ue_event_t { + uint16_t rnti; + srsran::move_callback callback; + }; + std::mutex event_mutex; + srsran::deque next_slot_events, slot_events; std::vector > slot_worker_ctxts; + struct cc_context { + std::condition_variable cvar; + bool waiting = false; + slot_cc_worker worker; - srsran::bounded_vector cell_grid_list; + cc_context(serv_cell_manager& sched) : worker(sched) {} + }; - slot_worker_ctxt& get_sf(tti_point tti_rx); + std::mutex slot_mutex; + std::condition_variable cvar; + tti_point current_tti; + std::atomic worker_count{0}; // variable shared across slot_cc_workers + std::vector > cc_worker_list; }; } // namespace sched_nr_impl diff --git a/srsenb/hdr/stack/mac/nr/ue_nr.h b/srsenb/hdr/stack/mac/nr/ue_nr.h new file mode 100644 index 000000000..355d9a6ed --- /dev/null +++ b/srsenb/hdr/stack/mac/nr/ue_nr.h @@ -0,0 +1,104 @@ +/** + * + * \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 SRSENB_UE_NR_H +#define SRSENB_UE_NR_H + +#include "srsenb/hdr/stack/mac/common/mac_metrics.h" +#include "srsran/common/block_queue.h" +#include "srsran/common/interfaces_common.h" +#include "srsran/interfaces/enb_rlc_interfaces.h" +#include "srsran/interfaces/sched_interface.h" +#include "srsran/mac/mac_sch_pdu_nr.h" +#include +#include + +namespace srsenb { + +class rrc_interface_mac_nr; +class rlc_interface_mac_nr; +class phy_interface_stack_nr; + +class ue_nr : public srsran::read_pdu_interface +{ +public: + ue_nr(uint16_t rnti, + uint32_t enb_cc_idx, + sched_interface* sched_, + rrc_interface_mac_nr* rrc_, + rlc_interface_mac* rlc, + phy_interface_stack_nr* phy_, + srslog::basic_logger& logger); + + virtual ~ue_nr(); + void reset(); + void ue_cfg(const sched_interface::ue_cfg_t& ue_cfg); + + void set_tti(uint32_t tti); + uint16_t get_rnti() const { return rnti; } + void set_active(bool active) { active_state.store(active, std::memory_order_relaxed); } + bool is_active() const { return active_state.load(std::memory_order_relaxed); } + + uint8_t* generate_pdu(uint32_t enb_cc_idx, + uint32_t harq_pid, + uint32_t tb_idx, + const sched_interface::dl_sched_pdu_t pdu[sched_interface::MAX_RLC_PDU_LIST], + uint32_t nof_pdu_elems, + uint32_t grant_size); + int process_pdu(srsran::unique_byte_buffer_t pdu); + + std::mutex metrics_mutex = {}; + void metrics_read(mac_ue_metrics_t* metrics_); + void metrics_rx(bool crc, uint32_t tbs); + void metrics_tx(bool crc, uint32_t tbs); + void metrics_phr(float phr); + void metrics_dl_ri(uint32_t dl_cqi); + void metrics_dl_pmi(uint32_t dl_cqi); + void metrics_dl_cqi(uint32_t dl_cqi); + void metrics_cnt(); + + uint32_t read_pdu(uint32_t lcid, uint8_t* payload, uint32_t requested_bytes) final; + +private: + rlc_interface_mac* rlc = nullptr; + rrc_interface_mac_nr* rrc = nullptr; + phy_interface_stack_nr* phy = nullptr; + srslog::basic_logger& logger; + sched_interface* sched = nullptr; + + uint64_t conres_id = 0; + uint16_t rnti = 0; + uint32_t last_tti = 0; + uint32_t nof_failures = 0; + + std::atomic active_state{true}; + + uint32_t phr_counter = 0; + uint32_t dl_cqi_counter = 0; + uint32_t dl_ri_counter = 0; + uint32_t dl_pmi_counter = 0; + mac_ue_metrics_t ue_metrics = {}; + + // UE-specific buffer for MAC PDU packing, unpacking and handling + srsran::mac_sch_pdu_nr mac_pdu_dl, mac_pdu_ul; + std::vector ue_tx_buffer; + srsran::block_queue + ue_rx_pdu_queue; ///< currently only DCH PDUs supported (add BCH, PCH, etc) + srsran::unique_byte_buffer_t ue_rlc_buffer; + + // Mutexes + std::mutex mutex; +}; + +} // namespace srsenb + +#endif // SRSENB_UE_NR_H diff --git a/srsenb/hdr/stack/mac/sched.h b/srsenb/hdr/stack/mac/sched.h index 00821c3b8..80911c7cf 100644 --- a/srsenb/hdr/stack/mac/sched.h +++ b/srsenb/hdr/stack/mac/sched.h @@ -70,6 +70,7 @@ public: int dl_ri_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, uint32_t ri_value) final; int dl_pmi_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, uint32_t pmi_value) final; int dl_cqi_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, uint32_t cqi_value) final; + int dl_sb_cqi_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, uint32_t sb_idx, uint32_t cqi_value) final; int ul_crc_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, bool crc) final; int ul_sr_info(uint32_t tti, uint16_t rnti) override; int ul_bsr(uint16_t rnti, uint32_t lcg_id, uint32_t bsr) final; diff --git a/srsenb/hdr/stack/mac/sched_ue.h b/srsenb/hdr/stack/mac/sched_ue.h index 0a64dd9b3..9eb4abb1c 100644 --- a/srsenb/hdr/stack/mac/sched_ue.h +++ b/srsenb/hdr/stack/mac/sched_ue.h @@ -69,6 +69,7 @@ public: void set_dl_ri(tti_point tti_rx, uint32_t enb_cc_idx, uint32_t ri); void set_dl_pmi(tti_point tti_rx, uint32_t enb_cc_idx, uint32_t ri); void set_dl_cqi(tti_point tti_rx, uint32_t enb_cc_idx, uint32_t cqi); + void set_dl_sb_cqi(tti_point tti_rx, uint32_t enb_cc_idx, uint32_t sb_idx, uint32_t cqi); int set_ack_info(tti_point tti_rx, uint32_t enb_cc_idx, uint32_t tb_idx, bool ack); void set_ul_crc(tti_point tti_rx, uint32_t enb_cc_idx, bool crc_res); 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 768765d3b..b38e32576 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 @@ -43,6 +43,7 @@ struct sched_ue_cell { void finish_tti(tti_point tti_rx); int set_dl_wb_cqi(tti_point tti_rx, uint32_t dl_cqi_); + int set_dl_sb_cqi(tti_point tti_rx, uint32_t sb_idx, uint32_t dl_cqi_); bool configured() const { return ue_cc_idx >= 0; } int get_ue_cc_idx() const { return ue_cc_idx; } @@ -89,6 +90,8 @@ struct sched_ue_cell { int fixed_mcs_ul = 0, fixed_mcs_dl = 0; private: + void check_cc_activation(uint32_t dl_cqi); + // args srslog::basic_logger& logger; const sched_interface::ue_cfg_t* ue_cfg = nullptr; diff --git a/srsenb/hdr/stack/mac/ue.h b/srsenb/hdr/stack/mac/ue.h index e5b206d81..674366933 100644 --- a/srsenb/hdr/stack/mac/ue.h +++ b/srsenb/hdr/stack/mac/ue.h @@ -22,7 +22,7 @@ #ifndef SRSENB_UE_H #define SRSENB_UE_H -#include "mac_metrics.h" +#include "common/mac_metrics.h" #include "srsran/adt/circular_array.h" #include "srsran/adt/circular_map.h" #include "srsran/adt/pool/pool_interface.h" diff --git a/srsenb/hdr/stack/ngap/ngap.h b/srsenb/hdr/stack/ngap/ngap.h index 428a14cbb..d015dc9d1 100644 --- a/srsenb/hdr/stack/ngap/ngap.h +++ b/srsenb/hdr/stack/ngap/ngap.h @@ -21,6 +21,7 @@ #ifndef SRSENB_NGAP_H #define SRSENB_NGAP_H +#include "ngap_metrics.h" #include "srsenb/hdr/common/common_enb.h" #include "srsran/adt/circular_map.h" #include "srsran/adt/optional.h" @@ -75,6 +76,8 @@ public: // Stack interface bool handle_amf_rx_msg(srsran::unique_byte_buffer_t pdu, const sockaddr_in& from, const sctp_sndrcvinfo& sri, int flags); + void get_metrics(ngap_metrics_t& m); + void get_args(ngap_args_t& args_); private: static const int AMF_PORT = 38412; diff --git a/srsenb/hdr/stack/ngap/ngap_metrics.h b/srsenb/hdr/stack/ngap/ngap_metrics.h new file mode 100644 index 000000000..fb3dc843a --- /dev/null +++ b/srsenb/hdr/stack/ngap/ngap_metrics.h @@ -0,0 +1,30 @@ +/** + * + * \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 SRSENB_NGAP_METRICS_H +#define SRSENB_NGAP_METRICS_H + +namespace srsenb { + +typedef enum { + ngap_attaching = 0, // Attempting to create NG connection + ngap_connected, // NG connected + ngap_error // Failure +} ngap_status_t; + +struct ngap_metrics_t { + ngap_status_t status; +}; + +} // namespace srsenb + +#endif // SRSENB_NGAP_METRICS_H diff --git a/srsenb/hdr/stack/rrc/rrc.h b/srsenb/hdr/stack/rrc/rrc.h index e5a14b593..63181f67a 100644 --- a/srsenb/hdr/stack/rrc/rrc.h +++ b/srsenb/hdr/stack/rrc/rrc.h @@ -135,10 +135,11 @@ public: int notify_ue_erab_updates(uint16_t rnti, srsran::const_byte_span nas_pdu) override; // rrc_eutra_interface_rrc_nr - void sgnb_addition_ack(uint16_t rnti, + void sgnb_addition_ack(uint16_t eutra_rnti, const asn1::dyn_octstring& nr_secondary_cell_group_cfg_r15, const asn1::dyn_octstring& nr_radio_bearer_cfg1_r15) override; - void sgnb_addition_reject(uint16_t rnti) override; + void sgnb_addition_reject(uint16_t eutra_rnti) override; + void sgnb_addition_complete(uint16_t eutra_rnti) override; // rrc_interface_pdcp void write_pdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t pdu) override; diff --git a/srsenb/hdr/stack/rrc/rrc_config_nr.h b/srsenb/hdr/stack/rrc/rrc_config_nr.h new file mode 100644 index 000000000..469d7bfee --- /dev/null +++ b/srsenb/hdr/stack/rrc/rrc_config_nr.h @@ -0,0 +1,45 @@ +/** + * + * \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_CONFIG_NR_H +#define SRSRAN_RRC_CONFIG_NR_H + +#include "srsran/asn1/rrc_nr.h" +#include "srsue/hdr/phy/phy_common.h" + +namespace srsenb { + +// TODO: Make this common to NR and LTE +struct rrc_nr_cfg_sr_t { + uint32_t period; + // asn1::rrc::sched_request_cfg_c::setup_s_::dsr_trans_max_e_ dsr_max; + uint32_t nof_prb; + uint32_t sf_mapping[80]; + uint32_t nof_subframes; +}; + +struct rrc_nr_cfg_t { + asn1::rrc_nr::mib_s mib; + asn1::rrc_nr::sib1_s sib1; + asn1::rrc_nr::sys_info_ies_s::sib_type_and_info_item_c_ sibs[ASN1_RRC_NR_MAX_SIB]; + uint32_t nof_sibs; + rrc_nr_cfg_sr_t sr_cfg; + rrc_cfg_cqi_t cqi_cfg; + srsran_cell_t cell; + + std::string log_level; + uint32_t log_hex_limit; +}; + +} // namespace srsenb + +#endif // SRSRAN_RRC_CONFIG_NR_H diff --git a/srsenb/hdr/stack/rrc/rrc_endc.h b/srsenb/hdr/stack/rrc/rrc_endc.h index 91334858f..a30390505 100644 --- a/srsenb/hdr/stack/rrc/rrc_endc.h +++ b/srsenb/hdr/stack/rrc/rrc_endc.h @@ -57,6 +57,7 @@ public: void handle_sgnb_addition_ack(const asn1::dyn_octstring& nr_secondary_cell_group_cfg_r15, const asn1::dyn_octstring& nr_radio_bearer_cfg1_r15); void handle_sgnb_addition_reject(); + void handle_sgnb_addition_complete(); private: // Send SgNB addition request to gNB @@ -72,10 +73,15 @@ private: bool endc_supported = false; asn1::rrc::rrc_conn_recfg_complete_s pending_recfg_complete; + // temporary storage for NR reconfiguration + asn1::dyn_octstring nr_secondary_cell_group_cfg_r15; + asn1::dyn_octstring nr_radio_bearer_cfg1_r15; + // events struct sgnb_add_req_sent_ev {}; struct sgnb_add_req_ack_ev {}; struct sgnb_add_req_reject_ev {}; + struct rrc_recfg_sent_ev {}; struct prach_nr_received_ev {}; using recfg_complete_ev = asn1::rrc::rrc_conn_recfg_complete_s; @@ -84,6 +90,7 @@ private: // states struct idle_st {}; struct wait_sgnb_add_req_resp {}; + struct prepare_recfg {}; struct wait_recfg_comp {}; struct wait_prach_nr {}; @@ -95,11 +102,8 @@ private: protected: // states - state_list states{this, - idle_st{}, - wait_sgnb_add_req_resp{}, - wait_recfg_comp{}, - wait_prach_nr{}}; + state_list + states{this, idle_st{}, wait_sgnb_add_req_resp{}, prepare_recfg{}, wait_recfg_comp{}, wait_prach_nr{}}; // transitions using fsm = rrc_endc; @@ -109,8 +113,9 @@ protected: // +-----------------------+-----------------------+------------------------+----------------------------+-------------------------+ row< idle_st, wait_sgnb_add_req_resp, sgnb_add_req_sent_ev, nullptr >, // +-----------------------+-----------------------+------------------------+----------------------------+-------------------------+ - row< wait_sgnb_add_req_resp, wait_recfg_comp, sgnb_add_req_ack_ev >, + row< wait_sgnb_add_req_resp, prepare_recfg, sgnb_add_req_ack_ev >, row< wait_sgnb_add_req_resp, idle_st, sgnb_add_req_reject_ev >, + row< prepare_recfg, wait_recfg_comp, rrc_recfg_sent_ev >, row< wait_recfg_comp, idle_st, recfg_complete_ev, &fsm::handle_recfg_complete > // +-----------------------+-----------------------+------------------------+----------------------------+-------------------------+ >; diff --git a/srsenb/hdr/stack/rrc/rrc_nr.h b/srsenb/hdr/stack/rrc/rrc_nr.h index 21e8c74a3..ac55a56e8 100644 --- a/srsenb/hdr/stack/rrc/rrc_nr.h +++ b/srsenb/hdr/stack/rrc/rrc_nr.h @@ -23,6 +23,7 @@ #define SRSENB_RRC_NR_H #include "rrc_config_common.h" +#include "rrc_config_nr.h" #include "rrc_metrics.h" #include "srsenb/hdr/stack/enb_stack_base.h" #include "srsran/asn1/rrc_nr.h" @@ -32,6 +33,8 @@ #include "srsran/common/task_scheduler.h" #include "srsran/common/threads.h" #include "srsran/common/timeout.h" +#include "srsran/interfaces/enb_pdcp_interfaces.h" +#include "srsran/interfaces/enb_rlc_interfaces.h" #include "srsran/interfaces/enb_rrc_interfaces.h" #include "srsran/interfaces/gnb_interfaces.h" #include "srsran/interfaces/gnb_ngap_interfaces.h" @@ -43,30 +46,6 @@ namespace srsenb { enum class rrc_nr_state_t { RRC_IDLE, RRC_INACTIVE, RRC_CONNECTED }; -// TODO: Make this common to NR and LTE -struct rrc_nr_cfg_sr_t { - uint32_t period; - // asn1::rrc::sched_request_cfg_c::setup_s_::dsr_trans_max_e_ dsr_max; - uint32_t nof_prb; - uint32_t sf_mapping[80]; - uint32_t nof_subframes; -}; - -struct rrc_nr_cfg_t { - asn1::rrc_nr::mib_s mib; - asn1::rrc_nr::sib1_s sib1; - asn1::rrc_nr::sys_info_ies_s::sib_type_and_info_item_c_ sibs[ASN1_RRC_NR_MAX_SIB]; - uint32_t nof_sibs; - rrc_nr_cfg_sr_t sr_cfg; - rrc_cfg_cqi_t cqi_cfg; - srsran_cell_t cell; - - std::string log_level; - uint32_t log_hex_limit; - - srsenb::core_less_args_t coreless; -}; - class rrc_nr final : public rrc_interface_pdcp_nr, public rrc_interface_mac_nr, public rrc_interface_rlc_nr, @@ -79,8 +58,8 @@ public: int32_t init(const rrc_nr_cfg_t& cfg, phy_interface_stack_nr* phy, mac_interface_rrc_nr* mac, - rlc_interface_rrc_nr* rlc, - pdcp_interface_rrc_nr* pdcp, + rlc_interface_rrc* rlc, + pdcp_interface_rrc* pdcp, ngap_interface_rrc_nr* ngap_, gtpu_interface_rrc_nr* gtpu, rrc_eutra_interface_rrc_nr* rrc_eutra_); @@ -90,7 +69,8 @@ public: void get_metrics(srsenb::rrc_metrics_t& m); rrc_nr_cfg_t update_default_cfg(const rrc_nr_cfg_t& rrc_cfg); - void add_user(uint16_t rnti); + int add_user(uint16_t rnti); + int update_user(uint16_t new_rnti, uint16_t old_rnti); void config_mac(); int32_t generate_sibs(); int read_pdu_bcch_bch(const uint32_t tti, srsran::unique_byte_buffer_t& buffer) final; @@ -119,7 +99,7 @@ public: void send_connection_setup(); void send_dl_ccch(asn1::rrc_nr::dl_ccch_msg_s* dl_dcch_msg); - int handle_sgnb_addition_request(); + int handle_sgnb_addition_request(uint16_t eutra_rnti); // getters bool is_connected() { return state == rrc_nr_state_t::RRC_CONNECTED; } @@ -128,14 +108,19 @@ public: // setters + int pack_rrc_reconfiguraiton(); + private: - rrc_nr* parent; - uint16_t rnti; + rrc_nr* parent = nullptr; + uint16_t rnti = SRSRAN_INVALID_RNTI; + + int pack_rrc_reconfiguraiton(asn1::dyn_octstring& packed_rrc_reconfig); + int pack_secondary_cell_group_config(asn1::dyn_octstring& packed_secondary_cell_config); + int pack_nr_radio_bearer_config(asn1::dyn_octstring& packed_nr_bearer_config); // state rrc_nr_state_t state = rrc_nr_state_t::RRC_IDLE; uint8_t transaction_id = 0; - srsran::timer_handler::unique_timer rrc_setup_periodic_timer; }; private: @@ -144,8 +129,8 @@ private: // interfaces phy_interface_stack_nr* phy = nullptr; mac_interface_rrc_nr* mac = nullptr; - rlc_interface_rrc_nr* rlc = nullptr; - pdcp_interface_rrc_nr* pdcp = nullptr; + rlc_interface_rrc* rlc = nullptr; + pdcp_interface_rrc* pdcp = nullptr; gtpu_interface_rrc_nr* gtpu = nullptr; ngap_interface_rrc_nr* ngap = nullptr; rrc_eutra_interface_rrc_nr* rrc_eutra = nullptr; diff --git a/srsenb/hdr/stack/rrc/rrc_ue.h b/srsenb/hdr/stack/rrc/rrc_ue.h index 5f50e3948..7aab2cf3b 100644 --- a/srsenb/hdr/stack/rrc/rrc_ue.h +++ b/srsenb/hdr/stack/rrc/rrc_ue.h @@ -118,11 +118,6 @@ public: bool handle_ue_ctxt_mod_req(const asn1::s1ap::ue_context_mod_request_s& msg); void handle_ue_info_resp(const asn1::rrc::ue_info_resp_r9_s& msg, srsran::unique_byte_buffer_t pdu); - // SgNB handler - void handle_sgnb_addition_ack(const asn1::dyn_octstring& nr_secondary_cell_group_cfg_r15, - const asn1::dyn_octstring& nr_radio_bearer_cfg1_r15); - void handle_sgnb_addition_reject(); - void set_bitrates(const asn1::s1ap::ue_aggregate_maximum_bitrate_s& rates); /// Helper to check UE ERABs diff --git a/srsenb/src/main.cc b/srsenb/src/main.cc index 097490d14..689557992 100644 --- a/srsenb/src/main.cc +++ b/srsenb/src/main.cc @@ -229,10 +229,10 @@ void parse_args(all_args_t* args, int argc, char* argv[]) ("expert.equalizer_mode", bpo::value(&args->phy.equalizer_mode)->default_value("mmse"), "Equalizer mode") ("expert.estimator_fil_w", bpo::value(&args->phy.estimator_fil_w)->default_value(0.1), "Chooses the coefficients for the 3-tap channel estimator centered filter.") ("expert.lte_sample_rates", bpo::value(&use_standard_lte_rates)->default_value(false), "Whether to use default LTE sample rates instead of shorter variants.") - ("expert.report_json_enable", bpo::value(&args->general.report_json_enable)->default_value(false), "Write eNB report to JSON file") - ("expert.report_json_filename", bpo::value(&args->general.report_json_filename)->default_value("/tmp/enb_report.json"), "Report JSON filename") - ("expert.alarms_log_enable", bpo::value(&args->general.alarms_log_enable)->default_value(false), "Log alarms") - ("expert.alarms_filename", bpo::value(&args->general.alarms_filename)->default_value("/tmp/enb_alarms.log"), "Alarms filename") + ("expert.report_json_enable", bpo::value(&args->general.report_json_enable)->default_value(false), "Write eNB report to JSON file (default disabled)") + ("expert.report_json_filename", bpo::value(&args->general.report_json_filename)->default_value("/tmp/enb_report.json"), "Report JSON filename (default /tmp/enb_report.json)") + ("expert.alarms_log_enable", bpo::value(&args->general.alarms_log_enable)->default_value(false), "Enable Alarms logging (default diabled)") + ("expert.alarms_filename", bpo::value(&args->general.alarms_filename)->default_value("/tmp/enb_alarms.log"), "Alarms logging filename (default /tmp/alarms.log)") ("expert.tracing_enable", bpo::value(&args->general.tracing_enable)->default_value(false), "Events tracing") ("expert.tracing_filename", bpo::value(&args->general.tracing_filename)->default_value("/tmp/enb_tracing.log"), "Tracing events filename") ("expert.tracing_buffcapacity", bpo::value(&args->general.tracing_buffcapacity)->default_value(1000000), "Tracing buffer capcity") @@ -243,8 +243,8 @@ void parse_args(all_args_t* args, int argc, char* argv[]) ("expert.eia_pref_list", bpo::value(&args->general.eia_pref_list)->default_value("EIA2, EIA1, EIA0"), "Ordered preference list for the selection of integrity algorithm (EIA) (default: EIA2, EIA1, EIA0).") ("expert.nof_prealloc_ues", bpo::value(&args->stack.mac.nof_prealloc_ues)->default_value(8), "Number of UE resources to preallocate during eNB initialization") ("expert.lcid_padding", bpo::value(&args->stack.mac.lcid_padding)->default_value(3), "LCID on which to put MAC padding") - ("expert.max_mac_dl_kos", bpo::value(&args->general.max_mac_dl_kos)->default_value(100), "Maximum number of consecutive KOs in DL before triggering the UE's release") - ("expert.max_mac_ul_kos", bpo::value(&args->general.max_mac_ul_kos)->default_value(100), "Maximum number of consecutive KOs in UL before triggering the UE's release") + ("expert.max_mac_dl_kos", bpo::value(&args->general.max_mac_dl_kos)->default_value(100), "Maximum number of consecutive KOs in DL before triggering the UE's release (default 100)") + ("expert.max_mac_ul_kos", bpo::value(&args->general.max_mac_ul_kos)->default_value(100), "Maximum number of consecutive KOs in UL before triggering the UE's release (default 100)") ("expert.gtpu_tunnel_timeout", bpo::value(&args->stack.gtpu_indirect_tunnel_timeout_msec)->default_value(0), "Maximum time that GTPU takes to release indirect forwarding tunnel since the last received GTPU PDU. (0 for infinity)") ("expert.rlf_release_timer_ms", bpo::value(&args->general.rlf_release_timer_ms)->default_value(4000), "Time taken by eNB to release UE context after it detects an RLF") ("expert.extended_cp", bpo::value(&args->phy.extended_cp)->default_value(false), "Use extended cyclic prefix") @@ -252,7 +252,6 @@ void parse_args(all_args_t* args, int argc, char* argv[]) ("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.") - // eMBMS section ("embms.enable", bpo::value(&args->stack.embms.enable)->default_value(false), "Enables MBMS in the eNB") ("embms.m1u_multiaddr", bpo::value(&args->stack.embms.m1u_multiaddr)->default_value("239.255.0.1"), "M1-U Multicast address the eNB joins.") @@ -268,14 +267,7 @@ void parse_args(all_args_t* args, int argc, char* argv[]) ("vnf.port", bpo::value(&args->phy.vnf_args.bind_port)->default_value(3333), "Bind port") ("log.vnf_level", bpo::value(&args->phy.vnf_args.log_level), "VNF log level") ("log.vnf_hex_limit", bpo::value(&args->phy.vnf_args.log_hex_limit), "VNF log hex dump limit") - - // Arguments for coreless operation - ("coreless.ip_devname", bpo::value(&args->stack.coreless.gw_args.tun_dev_name)->default_value("tun1"), "Name of the TUN device") - ("coreless.ip_address", bpo::value(&args->stack.coreless.ip_addr)->default_value("192.168.1.1"), "IP address of the TUN device") - ("coreless.ip_netmask", bpo::value(&args->stack.coreless.gw_args.tun_dev_netmask)->default_value("255.255.255.0"), "Netmask of the TUN device") - ("coreless.drb_lcid", bpo::value(&args->stack.coreless.drb_lcid)->default_value(4), "LCID of the dummy DRB") - ("coreless.rnti", bpo::value(&args->stack.coreless.rnti)->default_value(1234), "RNTI of the dummy user") - ; + ; // Positional options - config file location bpo::options_description position("Positional options"); diff --git a/srsenb/src/phy/nr/slot_worker.cc b/srsenb/src/phy/nr/slot_worker.cc index 026cd00a7..4acc710eb 100644 --- a/srsenb/src/phy/nr/slot_worker.cc +++ b/srsenb/src/phy/nr/slot_worker.cc @@ -76,7 +76,6 @@ bool slot_worker::init(const args_t& args) return false; } - // Prepare UL arguments srsran_gnb_ul_args_t ul_args = {}; ul_args.pusch.measure_time = true; @@ -158,22 +157,37 @@ bool slot_worker::work_ul() // For each PUCCH... for (stack_interface_phy_nr::pucch_t& pucch : ul_sched.pucch) { - stack_interface_phy_nr::pucch_info_t pucch_info = {}; - pucch_info.uci_data.cfg = pucch.uci_cfg; - - // Decode PUCCH - if (srsran_gnb_ul_get_pucch(&gnb_ul, - &ul_slot_cfg, - &pucch.pucch_cfg, - &pucch.resource, - &pucch_info.uci_data.cfg, - &pucch_info.uci_data.value) < SRSRAN_SUCCESS) { - logger.error("Error getting PUCCH"); - return false; + srsran::bounded_vector + pucch_info(pucch.candidates.size()); + + // For each candidate decode PUCCH + for (uint32_t i = 0; i < (uint32_t)pucch.candidates.size(); i++) { + pucch_info[i].uci_data.cfg = pucch.candidates[i].uci_cfg; + + // Decode PUCCH + if (srsran_gnb_ul_get_pucch(&gnb_ul, + &ul_slot_cfg, + &pucch.pucch_cfg, + &pucch.candidates[i].resource, + &pucch_info[i].uci_data.cfg, + &pucch_info[i].uci_data.value, + &pucch_info[i].csi) < SRSRAN_SUCCESS) { + logger.error("Error getting PUCCH"); + return false; + } + } + + // Find most suitable PUCCH candidate + uint32_t best_candidate = 0; + for (uint32_t i = 1; i < (uint32_t)pucch_info.size(); i++) { + // Select candidate if exceeds the previous best candidate SNR + if (pucch_info[i].csi.snr_dB > pucch_info[best_candidate].csi.snr_dB) { + best_candidate = i; + } } // Inform stack - if (stack.pucch_info(ul_slot_cfg, pucch_info) < SRSRAN_SUCCESS) { + if (stack.pucch_info(ul_slot_cfg, pucch_info[best_candidate]) < SRSRAN_SUCCESS) { logger.error("Error pushing PUCCH information to stack"); return false; } @@ -181,7 +195,11 @@ bool slot_worker::work_ul() // Log PUCCH decoding if (logger.info.enabled()) { std::array str; - srsran_gnb_ul_pucch_info(&gnb_ul, &pucch.resource, &pucch_info.uci_data, str.data(), (uint32_t)str.size()); + srsran_gnb_ul_pucch_info(&gnb_ul, + &pucch.candidates[0].resource, + &pucch_info[best_candidate].uci_data, + str.data(), + (uint32_t)str.size()); logger.info("PUCCH: %s", str.data()); } diff --git a/srsenb/src/phy/phy_ue_db.cc b/srsenb/src/phy/phy_ue_db.cc index 38cdace8f..1e3d79292 100644 --- a/srsenb/src/phy/phy_ue_db.cc +++ b/srsenb/src/phy/phy_ue_db.cc @@ -677,14 +677,14 @@ int phy_ue_db::send_uci_data(uint32_t tti, case SRSRAN_CQI_TYPE_WIDEBAND: cqi_value = uci_value.cqi.wideband.wideband_cqi; break; - case SRSRAN_CQI_TYPE_SUBBAND: - cqi_value = uci_value.cqi.subband.subband_cqi; + case SRSRAN_CQI_TYPE_SUBBAND_UE: + cqi_value = uci_value.cqi.subband_ue.subband_cqi; break; case SRSRAN_CQI_TYPE_SUBBAND_HL: cqi_value = uci_value.cqi.subband_hl.wideband_cqi_cw0; break; - case SRSRAN_CQI_TYPE_SUBBAND_UE: - cqi_value = uci_value.cqi.subband_ue.wideband_cqi; + case SRSRAN_CQI_TYPE_SUBBAND_UE_DIFF: + cqi_value = uci_value.cqi.subband_ue_diff.wideband_cqi; break; } stack->cqi_info(tti, rnti, cqi_cc_idx, cqi_value); diff --git a/srsenb/src/stack/enb_stack_lte.cc b/srsenb/src/stack/enb_stack_lte.cc index c30c26f73..b56394f71 100644 --- a/srsenb/src/stack/enb_stack_lte.cc +++ b/srsenb/src/stack/enb_stack_lte.cc @@ -22,6 +22,7 @@ #include "srsenb/hdr/stack/enb_stack_lte.h" #include "srsenb/hdr/common/rnti_pool.h" #include "srsenb/hdr/enb.h" +#include "srsenb/hdr/stack/rrc/rrc_config_nr.h" #include "srsran/interfaces/enb_metrics_interface.h" #include "srsran/rlc/bearer_mem_pool.h" #include "srsran/srslog/event_trace.h" @@ -140,7 +141,7 @@ int enb_stack_lte::init(const stack_args_t& args_, const rrc_cfg_t& rrc_cfg_) // add sync queue sync_task_queue = task_sched.make_task_queue(args.sync_queue_size); - // Init all layers + // Init all LTE layers if (!mac.init(args.mac, rrc_cfg.cell_list, phy, &rlc, &rrc)) { stack_logger.error("Couldn't initialize MAC"); return SRSRAN_ERROR; @@ -156,6 +157,21 @@ int enb_stack_lte::init(const stack_args_t& args_, const rrc_cfg_t& rrc_cfg_) return SRSRAN_ERROR; } + // NR layers + mac_nr_args_t mac_args = {}; + mac_args.pcap = args.mac_pcap; + if (mac_nr.init(mac_args, nullptr, nullptr, &rlc_nr, &rrc_nr) != SRSRAN_SUCCESS) { + stack_logger.error("Couldn't initialize MAC-NR"); + return SRSRAN_ERROR; + } + + rrc_nr_cfg_t rrc_cfg_nr = {}; + if (rrc_nr.init(rrc_cfg_nr, nullptr, &mac_nr, &rlc_nr, &pdcp_nr, nullptr, nullptr, &rrc) != SRSRAN_SUCCESS) { + stack_logger.error("Couldn't initialize RRC-NR"); + return SRSRAN_ERROR; + } + // FIXME: Add RLC and PDCP + gtpu_args_t gtpu_args; gtpu_args.embms_enable = args.embms.enable; gtpu_args.embms_m1u_multiaddr = args.embms.m1u_multiaddr; diff --git a/srsenb/src/stack/gnb_stack_nr.cc b/srsenb/src/stack/gnb_stack_nr.cc index b348bbc42..aebd91d07 100644 --- a/srsenb/src/stack/gnb_stack_nr.cc +++ b/srsenb/src/stack/gnb_stack_nr.cc @@ -32,7 +32,7 @@ gnb_stack_nr::gnb_stack_nr() : task_sched{512, 128}, thread("gNB"), rlc_logger(s m_pdcp.reset(new pdcp_nr(&task_sched, "PDCP-NR")); m_rrc.reset(new rrc_nr(&task_sched)); m_sdap.reset(new sdap()); - m_gw.reset(new srsue::gw()); + m_gw.reset(new srsue::gw(srslog::fetch_basic_logger("GW"))); // m_gtpu.reset(new srsenb::gtpu()); ue_task_queue = task_sched.make_task_queue(); @@ -71,13 +71,8 @@ int gnb_stack_nr::init(const srsenb::stack_args_t& args_, const rrc_nr_cfg_t& rr // Init all layers mac_nr_args_t mac_args = {}; - mac_args.log_level = args.log.mac_level; - mac_args.log_hex_limit = args.log.mac_hex_limit; mac_args.pcap = args.mac_pcap; - mac_args.sched = args.mac.sched; - mac_args.tb_size = args.mac.nr_tb_size; - mac_args.rnti = args.coreless.rnti; - m_mac->init(mac_args, phy, this, m_rlc.get(), m_rrc.get()); + m_mac->init(mac_args, phy, this, nullptr, m_rrc.get()); rlc_logger.set_level(srslog::str_to_basic_level(args.log.rlc_level)); rlc_logger.set_hex_dump_max_size(args.log.rlc_hex_limit); @@ -88,19 +83,12 @@ int gnb_stack_nr::init(const srsenb::stack_args_t& args_, const rrc_nr_cfg_t& rr pdcp_args.log_hex_limit = args.log.pdcp_hex_limit; m_pdcp->init(pdcp_args, m_rlc.get(), m_rrc.get(), m_sdap.get()); - m_rrc->init(rrc_cfg_, phy, m_mac.get(), m_rlc.get(), m_pdcp.get(), nullptr, nullptr, nullptr); + m_rrc->init(rrc_cfg_, phy, m_mac.get(), nullptr, nullptr, nullptr, nullptr, nullptr); m_sdap->init(m_pdcp.get(), nullptr, m_gw.get()); - m_gw->init(args.coreless.gw_args, this); - char* err_str = nullptr; - if (m_gw->setup_if_addr(5, - LIBLTE_MME_PDN_TYPE_IPV4, - htonl(inet_addr(args.coreless.ip_addr.c_str())), - nullptr, - err_str)) { - printf("Error configuring TUN interface\n"); - } + srsue::gw_args_t gw_args = {}; + m_gw->init(gw_args, this); // TODO: add NGAP // m_gtpu->init(args.s1ap.gtp_bind_addr, args.s1ap.mme_addr, @@ -155,7 +143,6 @@ void gnb_stack_nr::run_tti_impl(uint32_t tti) void gnb_stack_nr::process_pdus() { - mac_task_queue.push([this]() { m_mac->process_pdus(); }); } /******************************************************** @@ -179,12 +166,12 @@ int gnb_stack_nr::rx_data_indication(rx_data_ind_t& grant) // Temporary GW interface void gnb_stack_nr::write_sdu(uint32_t lcid, srsran::unique_byte_buffer_t sdu) { - m_pdcp->write_sdu(args.coreless.rnti, lcid, std::move(sdu)); + // not implemented } bool gnb_stack_nr::has_active_radio_bearer(uint32_t eps_bearer_id) { - return (eps_bearer_id == args.coreless.drb_lcid); + return false; } int gnb_stack_nr::slot_indication(const srsran_slot_cfg_t& slot_cfg) { diff --git a/srsenb/src/stack/mac/mac.cc b/srsenb/src/stack/mac/mac.cc index 00974df04..8bdc264c2 100644 --- a/srsenb/src/stack/mac/mac.cc +++ b/srsenb/src/stack/mac/mac.cc @@ -401,6 +401,19 @@ int mac::cqi_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, uint32_t cqi return SRSRAN_SUCCESS; } +int mac::sb_cqi_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, uint32_t sb_idx, uint32_t cqi_value) +{ + logger.set_context(tti); + srsran::rwlock_read_guard lock(rwlock); + + if (not check_ue_active(rnti)) { + return SRSRAN_ERROR; + } + + scheduler.dl_sb_cqi_info(tti, rnti, enb_cc_idx, sb_idx, cqi_value); + return SRSRAN_SUCCESS; +} + int mac::snr_info(uint32_t tti_rx, uint16_t rnti, uint32_t enb_cc_idx, float snr, ul_channel_t ch) { logger.set_context(tti_rx); @@ -824,9 +837,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) { @@ -978,7 +991,7 @@ void mac::write_mcch(const srsran::sib2_mbms_t* sib2_, sib2 = *sib2_; sib13 = *sib13_; memcpy(mcch_payload_buffer, mcch_payload, mcch_payload_length * sizeof(uint8_t)); - current_mcch_length = mcch_payload_length; + current_mcch_length = mcch_payload_length; std::unique_ptr ptr = std::unique_ptr{ new ue(SRSRAN_MRNTI, args.nof_prb, &scheduler, rrc_h, rlc_h, phy_h, logger, cells.size(), softbuffer_pool.get())}; auto ret = ue_db.insert(SRSRAN_MRNTI, std::move(ptr)); diff --git a/srsenb/src/stack/mac/nr/CMakeLists.txt b/srsenb/src/stack/mac/nr/CMakeLists.txt index 310691697..ce097c76f 100644 --- a/srsenb/src/stack/mac/nr/CMakeLists.txt +++ b/srsenb/src/stack/mac/nr/CMakeLists.txt @@ -18,7 +18,18 @@ # and at http://www.gnu.org/licenses/. # -set(SOURCES mac_nr.cc sched_nr.cc sched_nr_ue.cc sched_nr_worker.cc sched_nr_rb_grid.cc sched_nr_harq.cc - sched_nr_pdcch.cc sched_nr_cfg.cc sched_nr_helpers.cc sched_nr_bwp.cc sched_nr_rb.cc harq_softbuffer.cc) +set(SOURCES mac_nr.cc + ue_nr.cc + sched_nr.cc + sched_nr_ue.cc + sched_nr_worker.cc + sched_nr_rb_grid.cc + sched_nr_harq.cc + sched_nr_pdcch.cc + sched_nr_cfg.cc + sched_nr_helpers.cc + sched_nr_cell.cc + sched_nr_rb.cc + harq_softbuffer.cc) add_library(srsgnb_mac STATIC ${SOURCES}) diff --git a/srsenb/src/stack/mac/nr/mac_nr.cc b/srsenb/src/stack/mac/nr/mac_nr.cc index 9fe88fafc..17932b51f 100644 --- a/srsenb/src/stack/mac/nr/mac_nr.cc +++ b/srsenb/src/stack/mac/nr/mac_nr.cc @@ -22,6 +22,9 @@ #include "srsenb/hdr/stack/mac/mac_nr.h" #include "srsran/common/buffer_pool.h" #include "srsran/common/log_helper.h" +#include "srsran/common/rwlock_guard.h" +#include "srsran/common/standard_streams.h" +#include "srsran/common/time_prof.h" #include #include #include @@ -31,7 +34,9 @@ namespace srsenb { mac_nr::mac_nr(srsran::task_sched_handle task_sched_) : logger(srslog::fetch_basic_logger("MAC-NR")), task_sched(task_sched_) -{} +{ + stack_task_queue = task_sched.make_task_queue(); +} mac_nr::~mac_nr() { @@ -41,18 +46,15 @@ mac_nr::~mac_nr() int mac_nr::init(const mac_nr_args_t& args_, phy_interface_stack_nr* phy_, stack_interface_mac* stack_, - rlc_interface_mac_nr* rlc_, + rlc_interface_mac* rlc_, rrc_interface_mac_nr* rrc_) { args = args_; - phy_h = phy_; - stack_h = stack_; - rlc_h = rlc_; - rrc_h = rrc_; - - logger.set_level(srslog::str_to_basic_level(args.log_level)); - logger.set_hex_dump_max_size(args.log_hex_limit); + phy = phy_; + stack = stack_; + rlc = rlc_; + rrc = rrc_; if (args.pcap.enable) { pcap = std::unique_ptr(new srsran::mac_pcap()); @@ -64,20 +66,6 @@ int mac_nr::init(const mac_nr_args_t& args_, return SRSRAN_ERROR; } - // allocate 8 tx buffers for UE (TODO: as we don't handle softbuffers why do we need so many buffers) - for (int i = 0; i < SRSRAN_FDD_NOF_HARQ; i++) { - srsran::unique_byte_buffer_t buffer = srsran::make_byte_buffer(); - if (buffer == nullptr) { - return SRSRAN_ERROR; - } - ue_tx_buffer.emplace_back(std::move(buffer)); - } - - ue_rlc_buffer = srsran::make_byte_buffer(); - if (ue_rlc_buffer == nullptr) { - return SRSRAN_ERROR; - } - logger.info("Started"); started = true; @@ -98,77 +86,171 @@ void mac_nr::stop() void mac_nr::get_metrics(srsenb::mac_metrics_t& metrics) {} -int mac_nr::rx_data_indication(stack_interface_phy_nr::rx_data_ind_t& rx_data) +int mac_nr::cell_cfg(srsenb::sched_interface::cell_cfg_t* cell_cfg) { - // push received PDU on queue - if (rx_data.tb != nullptr) { - if (pcap) { - pcap->write_ul_crnti_nr(rx_data.tb->msg, rx_data.tb->N_bytes, rx_data.rnti, true, rx_data.tti); + cfg = *cell_cfg; + + // read SIBs from RRC (SIB1 for now only) + for (int i = 0; i < 1 /* srsenb::sched_interface::MAX_SIBS */; i++) { + if (cell_cfg->sibs->len > 0) { + sib_info_t sib = {}; + sib.index = i; + sib.periodicity = cell_cfg->sibs->period_rf; + sib.payload = srsran::make_byte_buffer(); + if (sib.payload == nullptr) { + logger.error("Couldn't allocate PDU in %s().", __FUNCTION__); + return SRSRAN_ERROR; + } + if (rrc->read_pdu_bcch_dlsch(sib.index, sib.payload) != SRSRAN_SUCCESS) { + logger.error("Couldn't read SIB %d from RRC", sib.index); + } + + logger.info("Including SIB %d into SI scheduling", sib.index); + bcch_dlsch_payload.push_back(std::move(sib)); } - ue_rx_pdu_queue.push(std::move(rx_data.tb)); } - // inform stack that new PDUs may have been received - stack_h->process_pdus(); - return SRSRAN_SUCCESS; } -/** - * Called from the main stack thread to process received PDUs - */ -void mac_nr::process_pdus() +void mac_nr::rach_detected(const srsran_slot_cfg_t& slot_cfg, + uint32_t enb_cc_idx, + uint32_t preamble_idx, + uint32_t time_adv) { - while (started and not ue_rx_pdu_queue.empty()) { - srsran::unique_byte_buffer_t pdu = ue_rx_pdu_queue.wait_pop(); - /// TODO; delegate to demux class - handle_pdu(std::move(pdu)); - } + static srsran::mutexed_tprof rach_tprof("rach_tprof", "MAC-NR", 1); + logger.set_context(slot_cfg.idx); + auto rach_tprof_meas = rach_tprof.start(); + + stack_task_queue.push([this, slot_cfg, enb_cc_idx, preamble_idx, time_adv, rach_tprof_meas]() mutable { + uint16_t rnti = add_ue(enb_cc_idx); + if (rnti == SRSRAN_INVALID_RNTI) { + return; + } + + rach_tprof_meas.defer_stop(); + + // TODO: Generate RAR data + // .. + + // Log this event. + ++detected_rachs[enb_cc_idx]; + + // Add new user to the scheduler so that it can RX/TX SRB0 + // .. + + // Register new user in RRC + if (rrc->add_user(rnti) == SRSRAN_ERROR) { + // ue_rem(rnti); + return; + } + + // Trigger scheduler RACH + // scheduler.dl_rach_info(enb_cc_idx, rar_info); + + logger.info("RACH: cc=%d, preamble=%d, offset=%d, temp_crnti=0x%x", + slot_cfg.idx, + enb_cc_idx, + preamble_idx, + time_adv, + rnti); + srsran::console("RACH: cc=%d, preamble=%d, offset=%d, temp_crnti=0x%x\n", + slot_cfg.idx, + enb_cc_idx, + preamble_idx, + time_adv, + rnti); + }); } -int mac_nr::handle_pdu(srsran::unique_byte_buffer_t pdu) +uint16_t mac_nr::add_ue(uint32_t enb_cc_idx) { - logger.info(pdu->msg, pdu->N_bytes, "Handling MAC PDU (%d B)", pdu->N_bytes); + ue_nr* inserted_ue = nullptr; + uint16_t rnti = SRSRAN_INVALID_RNTI; + + do { + // Assign new RNTI + rnti = FIRST_RNTI + (ue_counter.fetch_add(1, std::memory_order_relaxed) % 60000); + + // Pre-check if rnti is valid + { + srsran::rwlock_read_guard read_lock(rwlock); + if (not is_rnti_valid_unsafe(rnti)) { + continue; + } + } - ue_rx_pdu.init_rx(true); - if (ue_rx_pdu.unpack(pdu->msg, pdu->N_bytes) != SRSRAN_SUCCESS) { - return SRSRAN_ERROR; - } + // Allocate and initialize UE object + // TODO: add sched interface + std::unique_ptr ue_ptr = std::unique_ptr(new ue_nr(rnti, enb_cc_idx, nullptr, rrc, rlc, phy, logger)); + + // Add UE to rnti map + srsran::rwlock_write_guard rw_lock(rwlock); + if (not is_rnti_valid_unsafe(rnti)) { + continue; + } + auto ret = ue_db.insert(rnti, std::move(ue_ptr)); + if (ret.has_value()) { + inserted_ue = ret.value()->second.get(); + } else { + logger.info("Failed to allocate rnti=0x%x. Attempting a different rnti.", rnti); + } + } while (inserted_ue == nullptr); - for (uint32_t i = 0; i < ue_rx_pdu.get_num_subpdus(); ++i) { - srsran::mac_sch_subpdu_nr subpdu = ue_rx_pdu.get_subpdu(i); - logger.info("Handling subPDU %d/%d: lcid=%d, sdu_len=%d", - i, - ue_rx_pdu.get_num_subpdus(), - subpdu.get_lcid(), - subpdu.get_sdu_length()); + // Set PCAP if available + // .. - // rlc_h->write_pdu(args.rnti, subpdu.get_lcid(), subpdu.get_sdu(), subpdu.get_sdu_length()); + return rnti; +} + +// Remove UE from the perspective of L2/L3 +int mac_nr::remove_ue(uint16_t rnti) +{ + srsran::rwlock_write_guard lock(rwlock); + if (is_rnti_active_unsafe(rnti)) { + ue_db.erase(rnti); + } else { + logger.error("User rnti=0x%x not found", rnti); + return SRSRAN_ERROR; } + return SRSRAN_SUCCESS; } -int mac_nr::cell_cfg(srsenb::sched_interface::cell_cfg_t* cell_cfg) +uint16_t mac_nr::reserve_rnti() { - cfg = *cell_cfg; + uint16_t rnti = add_ue(0); + if (rnti == SRSRAN_INVALID_RNTI) { + return rnti; + } - // read SIBs from RRC (SIB1 for now only) - for (int i = 0; i < srsenb::sched_interface::MAX_SIBS; i++) { - if (cell_cfg->sibs->len > 0) { - sib_info_t sib = {}; - sib.index = i; - sib.periodicity = cell_cfg->sibs->period_rf; - sib.payload = srsran::make_byte_buffer(); - if (rrc_h->read_pdu_bcch_dlsch(sib.index, sib.payload) != SRSRAN_SUCCESS) { - logger.error("Couldn't read SIB %d from RRC", sib.index); - } + return rnti; +} - logger.info("Including SIB %d into SI scheduling", sib.index); - bcch_dlsch_payload.push_back(std::move(sib)); - } +bool mac_nr::is_rnti_valid_unsafe(uint16_t rnti) +{ + if (not started) { + logger.info("RACH ignored as eNB is being shutdown"); + return false; + } + if (ue_db.full()) { + logger.warning("Maximum number of connected UEs %zd connected to the eNB. Ignoring PRACH", SRSENB_MAX_UES); + return false; + } + if (not ue_db.has_space(rnti)) { + logger.info("Failed to allocate rnti=0x%x. Attempting a different rnti.", rnti); + return false; } + return true; +} - return SRSRAN_SUCCESS; +bool mac_nr::is_rnti_active_unsafe(uint16_t rnti) +{ + if (not ue_db.contains(rnti)) { + logger.error("User rnti=0x%x not found", rnti); + return false; + } + return ue_db[rnti]->is_active(); } int mac_nr::slot_indication(const srsran_slot_cfg_t& slot_cfg) @@ -190,8 +272,22 @@ int mac_nr::pucch_info(const srsran_slot_cfg_t& slot_cfg, const mac_interface_ph } int mac_nr::pusch_info(const srsran_slot_cfg_t& slot_cfg, const mac_interface_phy_nr::pusch_info_t& pusch_info) { - return 0; + // FIXME: does the PUSCH info call include received PDUs? + uint16_t rnti = pusch_info.rnti; + srsran::unique_byte_buffer_t rx_pdu; + auto process_pdu_task = [this, rnti](srsran::unique_byte_buffer_t& pdu) { + srsran::rwlock_read_guard lock(rwlock); + if (is_rnti_active_unsafe(rnti)) { + ue_db[rnti]->process_pdu(std::move(pdu)); + } else { + logger.debug("Discarding PDU rnti=0x%x", rnti); + } + }; + stack_task_queue.try_push(std::bind(process_pdu_task, std::move(rx_pdu))); + + return SRSRAN_SUCCESS; } + void mac_nr::rach_detected(const mac_interface_phy_nr::rach_info_t& rach_info) {} } // namespace srsenb diff --git a/srsenb/src/stack/mac/nr/sched_nr.cc b/srsenb/src/stack/mac/nr/sched_nr.cc index 1a61f00a7..e50607b27 100644 --- a/srsenb/src/stack/mac/nr/sched_nr.cc +++ b/srsenb/src/stack/mac/nr/sched_nr.cc @@ -21,7 +21,7 @@ #include "srsenb/hdr/stack/mac/nr/sched_nr.h" #include "srsenb/hdr/stack/mac/nr/harq_softbuffer.h" -#include "srsenb/hdr/stack/mac/nr/sched_nr_bwp.h" +#include "srsenb/hdr/stack/mac/nr/sched_nr_cell.h" #include "srsenb/hdr/stack/mac/nr/sched_nr_worker.h" #include "srsran/common/thread_pool.h" @@ -31,62 +31,6 @@ using namespace sched_nr_impl; static int assert_ue_cfg_valid(uint16_t rnti, const sched_nr_interface::ue_cfg_t& uecfg); -class ue_event_manager -{ - using callback_t = srsran::move_callback; - using callback_list = srsran::deque; - -public: - explicit ue_event_manager(ue_map_t& ue_db_) : ue_db(ue_db_) {} - - void push_event(srsran::move_callback event) - { - std::lock_guard lock(common_mutex); - common_events.push_back(std::move(event)); - } - void push_cc_feedback(uint16_t rnti, uint32_t cc, srsran::move_callback event) - { - std::lock_guard lock(common_mutex); - feedback_list.emplace_back(); - feedback_list.back().rnti = rnti; - feedback_list.back().cc = cc; - feedback_list.back().callback = std::move(event); - } - void new_slot() - { - { - std::lock_guard lock(common_mutex); - common_events.swap(common_events_tmp); // reuse memory - feedback_list.swap(feedback_list_tmp); - } - while (not common_events_tmp.empty()) { - common_events_tmp.front()(); - common_events_tmp.pop_front(); - } - while (not feedback_list_tmp.empty()) { - auto& e = feedback_list_tmp.front(); - if (ue_db.contains(e.rnti) and ue_db[e.rnti]->carriers[e.cc] != nullptr) { - ue_db[e.rnti]->carriers[e.cc]->push_feedback(std::move(e.callback)); - } - feedback_list_tmp.pop_front(); - } - } - -private: - ue_map_t& ue_db; - - std::mutex common_mutex; - callback_list common_events; - struct ue_feedback { - uint16_t rnti = SCHED_NR_INVALID_RNTI; - uint32_t cc = SCHED_NR_MAX_CARRIERS; - srsran::move_callback callback; - }; - srsran::deque feedback_list; - callback_list common_events_tmp; - srsran::deque feedback_list_tmp; -}; - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class sched_result_manager @@ -151,21 +95,26 @@ private: /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -sched_nr::sched_nr(const sched_cfg_t& sched_cfg) : - cfg(sched_cfg), pending_events(new ue_event_manager(ue_db)), logger(srslog::fetch_basic_logger("MAC")) -{} +sched_nr::sched_nr(const sched_cfg_t& sched_cfg) : cfg(sched_cfg), logger(srslog::fetch_basic_logger("MAC")) {} sched_nr::~sched_nr() {} int sched_nr::cell_cfg(srsran::const_span cell_list) { + // Initiate Common Sched Configuration cfg.cells.reserve(cell_list.size()); for (uint32_t cc = 0; cc < cell_list.size(); ++cc) { cfg.cells.emplace_back(cc, cell_list[cc], cfg.sched_cfg); } + // Initiate cell-specific schedulers + cells.reserve(cell_list.size()); + for (uint32_t cc = 0; cc < cell_list.size(); ++cc) { + cells.emplace_back(new serv_cell_manager{cfg.cells[cc]}); + } + pending_results.reset(new sched_result_manager(cell_list.size())); - sched_workers.reset(new sched_nr_impl::sched_worker_manager(ue_db, cfg)); + sched_workers.reset(new sched_nr_impl::sched_worker_manager(ue_db, cfg, cells)); return SRSRAN_SUCCESS; } @@ -173,7 +122,7 @@ int sched_nr::cell_cfg(srsran::const_span cell_list) void sched_nr::ue_cfg(uint16_t rnti, const ue_cfg_t& uecfg) { srsran_assert(assert_ue_cfg_valid(rnti, uecfg) == SRSRAN_SUCCESS, "Invalid UE configuration"); - pending_events->push_event([this, rnti, uecfg]() { ue_cfg_impl(rnti, uecfg); }); + sched_workers->enqueue_event(rnti, [this, rnti, uecfg]() { ue_cfg_impl(rnti, uecfg); }); } void sched_nr::ue_cfg_impl(uint16_t rnti, const ue_cfg_t& uecfg) @@ -188,27 +137,12 @@ void sched_nr::ue_cfg_impl(uint16_t rnti, const ue_cfg_t& uecfg) /// Generate {tti,cc} scheduling decision int sched_nr::generate_slot_result(tti_point pdcch_tti, uint32_t cc) { - tti_point tti_rx = pdcch_tti - TX_ENB_DELAY; - - // Lock carrier workers for provided tti_rx - sched_workers->start_slot(tti_rx, [this]() { - // In case it is first worker for the given slot - // synchronize {tti,cc} state. e.g. reserve UE resources for {tti,cc} decision, process feedback - pending_events->new_slot(); - }); - - // unlocked, parallel region - bool all_workers_finished = sched_workers->run_slot(tti_rx, cc); - - if (all_workers_finished) { - // once all workers of the same subframe finished, synchronize sched outcome with ue_db - sched_workers->release_slot(tti_rx); - } - // Copy results to intermediate buffer dl_sched_t& dl_res = pending_results->add_dl_result(pdcch_tti, cc); ul_sched_t& ul_res = pending_results->add_ul_result(pdcch_tti, cc); - sched_workers->save_sched_result(pdcch_tti, cc, dl_res, ul_res); + + // Generate {slot_idx,cc} result + sched_workers->run_slot(pdcch_tti, cc, dl_res, ul_res); return SRSRAN_SUCCESS; } @@ -222,29 +156,31 @@ int sched_nr::get_dl_sched(tti_point tti_tx, uint32_t cc, dl_sched_t& result) result = pending_results->pop_dl_result(tti_tx, cc); return SRSRAN_SUCCESS; } -int sched_nr::get_ul_sched(tti_point tti_rx, uint32_t cc, ul_sched_t& result) +int sched_nr::get_ul_sched(tti_point pusch_tti, uint32_t cc, ul_sched_t& result) { - if (not pending_results->has_ul_result(tti_rx, cc)) { - return SRSRAN_ERROR; + if (not pending_results->has_ul_result(pusch_tti, cc)) { + // sched result hasn't been generated + return SRSRAN_SUCCESS; } - result = pending_results->pop_ul_result(tti_rx, cc); + result = pending_results->pop_ul_result(pusch_tti, cc); return SRSRAN_SUCCESS; } void sched_nr::dl_ack_info(uint16_t rnti, uint32_t cc, uint32_t pid, uint32_t tb_idx, bool ack) { - pending_events->push_cc_feedback( + sched_workers->enqueue_cc_feedback( rnti, cc, [pid, tb_idx, ack](ue_carrier& ue_cc) { ue_cc.harq_ent.dl_ack_info(pid, tb_idx, ack); }); } +void sched_nr::ul_crc_info(uint16_t rnti, uint32_t cc, uint32_t pid, bool crc) +{ + sched_workers->enqueue_cc_feedback(rnti, cc, [pid, crc](ue_carrier& ue_cc) { ue_cc.harq_ent.ul_crc_info(pid, crc); }); +} + void sched_nr::ul_sr_info(tti_point tti_rx, uint16_t rnti) { - pending_events->push_event([this, rnti, tti_rx]() { - if (ue_db.contains(rnti)) { - ue_db[rnti]->ul_sr_info(tti_rx); - } - }); + sched_workers->enqueue_event(rnti, [this, rnti, tti_rx]() { ue_db[rnti]->ul_sr_info(tti_rx); }); } #define VERIFY_INPUT(cond, msg, ...) \ diff --git a/srsenb/src/stack/mac/nr/sched_nr_bwp.cc b/srsenb/src/stack/mac/nr/sched_nr_cell.cc similarity index 83% rename from srsenb/src/stack/mac/nr/sched_nr_bwp.cc rename to srsenb/src/stack/mac/nr/sched_nr_cell.cc index c6e1ae864..abc70ca7e 100644 --- a/srsenb/src/stack/mac/nr/sched_nr_bwp.cc +++ b/srsenb/src/stack/mac/nr/sched_nr_cell.cc @@ -19,7 +19,7 @@ * */ -#include "srsenb/hdr/stack/mac/nr/sched_nr_bwp.h" +#include "srsenb/hdr/stack/mac/nr/sched_nr_cell.h" #include "srsran/common/standard_streams.h" #include "srsran/common/string_helpers.h" @@ -28,8 +28,10 @@ namespace sched_nr_impl { ra_sched::ra_sched(const bwp_params& bwp_cfg_) : bwp_cfg(&bwp_cfg_), logger(srslog::fetch_basic_logger("MAC")) {} -alloc_result -ra_sched::allocate_pending_rar(bwp_slot_allocator& slot_grid, const pending_rar_t& rar, uint32_t& nof_grants_alloc) +alloc_result ra_sched::allocate_pending_rar(bwp_slot_allocator& slot_grid, + const pending_rar_t& rar, + slot_ue_map_t& slot_ues, + uint32_t& nof_grants_alloc) { const uint32_t rar_aggr_level = 2; const prb_bitmap& prbs = slot_grid.res_grid()[slot_grid.get_pdcch_tti()].dl_prbs.prbs(); @@ -38,11 +40,11 @@ ra_sched::allocate_pending_rar(bwp_slot_allocator& slot_grid, const pending_rar_ for (nof_grants_alloc = rar.msg3_grant.size(); nof_grants_alloc > 0; nof_grants_alloc--) { ret = alloc_result::invalid_coderate; uint32_t start_prb_idx = 0; - for (uint32_t nprb = 1; nprb < bwp_cfg->cfg.rb_width and ret == alloc_result::invalid_coderate; ++nprb) { + for (uint32_t nprb = 4; nprb < bwp_cfg->cfg.rb_width and ret == alloc_result::invalid_coderate; ++nprb) { prb_interval interv = find_empty_interval_of_length(prbs, nprb, start_prb_idx); start_prb_idx = interv.stop(); if (interv.length() == nprb) { - ret = slot_grid.alloc_rar(rar_aggr_level, rar, interv, nof_grants_alloc); + ret = slot_grid.alloc_rar_and_msg3(rar_aggr_level, rar, interv, slot_ues, nof_grants_alloc); } else { ret = alloc_result::no_sch_space; } @@ -59,10 +61,14 @@ ra_sched::allocate_pending_rar(bwp_slot_allocator& slot_grid, const pending_rar_ return ret; } -void ra_sched::run_slot(bwp_slot_allocator& slot_grid) +void ra_sched::run_slot(bwp_slot_allocator& slot_grid, slot_ue_map_t& slot_ues) { static const uint32_t PRACH_RAR_OFFSET = 3; tti_point pdcch_tti = slot_grid.get_pdcch_tti(); + tti_point msg3_tti = pdcch_tti + bwp_cfg->pusch_ra_list[0].msg3_delay; + if (not slot_grid.res_grid()[msg3_tti].is_ul) { + return; + } for (auto it = pending_rars.begin(); it != pending_rars.end();) { pending_rar_t& rar = *it; @@ -88,9 +94,9 @@ void ra_sched::run_slot(bwp_slot_allocator& slot_grid) return; } - // Try to schedule DCI + RBGs for RAR Grant + // Try to schedule DCIs + RBGs for RAR Grants uint32_t nof_rar_allocs = 0; - alloc_result ret = allocate_pending_rar(slot_grid, rar, nof_rar_allocs); + alloc_result ret = allocate_pending_rar(slot_grid, rar, slot_ues, nof_rar_allocs); if (ret == alloc_result::success) { // If RAR allocation was successful: @@ -156,14 +162,15 @@ bwp_ctxt::bwp_ctxt(const bwp_params& bwp_cfg) : cfg(&bwp_cfg), ra(bwp_cfg), grid ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -serv_cell_ctxt::serv_cell_ctxt(const sched_cell_params& cell_cfg_) : cfg(&cell_cfg_) +serv_cell_manager::serv_cell_manager(const sched_cell_params& cell_cfg_) : + cfg(cell_cfg_), logger(srslog::fetch_basic_logger("MAC")) { - for (uint32_t bwp_id = 0; bwp_id < cfg->cell_cfg.bwps.size(); ++bwp_id) { + for (uint32_t bwp_id = 0; bwp_id < cfg.cell_cfg.bwps.size(); ++bwp_id) { bwps.emplace_back(cell_cfg_.bwps[bwp_id]); } // Pre-allocate HARQs in common pool of softbuffers - harq_softbuffer_pool::get_instance().init_pool(cfg->nof_prb()); + harq_softbuffer_pool::get_instance().init_pool(cfg.nof_prb()); } } // namespace sched_nr_impl diff --git a/srsenb/src/stack/mac/nr/sched_nr_cfg.cc b/srsenb/src/stack/mac/nr/sched_nr_cfg.cc index 98e87828a..0d51a8b95 100644 --- a/srsenb/src/stack/mac/nr/sched_nr_cfg.cc +++ b/srsenb/src/stack/mac/nr/sched_nr_cfg.cc @@ -21,6 +21,9 @@ #include "srsenb/hdr/stack/mac/nr/sched_nr_cfg.h" #include "srsenb/hdr/stack/mac/nr/sched_nr_helpers.h" +extern "C" { +#include "srsran/phy/phch/ra_ul_nr.h" +} namespace srsenb { namespace sched_nr_impl { @@ -28,18 +31,34 @@ namespace sched_nr_impl { bwp_params::bwp_params(const cell_cfg_t& cell, const sched_cfg_t& sched_cfg_, uint32_t cc_, uint32_t bwp_id_) : cell_cfg(cell), sched_cfg(sched_cfg_), cc(cc_), bwp_id(bwp_id_), cfg(cell.bwps[bwp_id_]) { + srsran_assert(bwp_id != 0 or cfg.pdcch.coreset_present[0], "CORESET#0 has to be active for initial BWP"); + P = get_P(cfg.rb_width, cfg.pdsch.rbg_size_cfg_1); N_rbg = get_nof_rbgs(cfg.rb_width, cfg.start_rb, cfg.pdsch.rbg_size_cfg_1); - srsran_assert(bwp_id != 0 or cfg.pdcch.coreset_present[0], "CORESET#0 has to be active for initial BWP"); + pusch_ra_list.resize(cfg.pusch.nof_common_time_ra); + const uint32_t coreset_id = 0; + srsran_sch_grant_nr_t grant; + for (uint32_t m = 0; m < cfg.pusch.nof_common_time_ra; ++m) { + int ret = + srsran_ra_ul_nr_time(&cfg.pusch, srsran_rnti_type_ra, srsran_search_space_type_rar, coreset_id, m, &grant); + srsran_assert(ret == SRSRAN_SUCCESS, "Failed to obtain RA config"); + pusch_ra_list[m].msg3_delay = grant.k; + ret = srsran_ra_ul_nr_time(&cfg.pusch, srsran_rnti_type_c, srsran_search_space_type_ue, coreset_id, m, &grant); + pusch_ra_list[m].K = grant.k; + pusch_ra_list[m].S = grant.S; + pusch_ra_list[m].L = grant.L; + srsran_assert(ret == SRSRAN_SUCCESS, "Failed to obtain RA config"); + } + srsran_assert(not pusch_ra_list.empty(), "Time-Domain Resource Allocation not valid"); } sched_cell_params::sched_cell_params(uint32_t cc_, const cell_cfg_t& cell, const sched_cfg_t& sched_cfg_) : cc(cc_), cell_cfg(cell), sched_cfg(sched_cfg_) { bwps.reserve(cell.bwps.size()); - for (uint32_t i = 0; i < cell.bwps.size(); ++i) { - bwps.emplace_back(cell, sched_cfg_, cc, i); + for (uint32_t i = 0; i < cell_cfg.bwps.size(); ++i) { + bwps.emplace_back(cell_cfg, sched_cfg_, cc, i); } srsran_assert(not bwps.empty(), "No BWPs were configured"); } diff --git a/srsenb/src/stack/mac/nr/sched_nr_helpers.cc b/srsenb/src/stack/mac/nr/sched_nr_helpers.cc index 73083f1f1..146403fff 100644 --- a/srsenb/src/stack/mac/nr/sched_nr_helpers.cc +++ b/srsenb/src/stack/mac/nr/sched_nr_helpers.cc @@ -30,7 +30,10 @@ namespace sched_nr_impl { bool fill_dci_rar(prb_interval interv, const bwp_params& cell, srsran_dci_dl_nr_t& dci) { - dci.mcs = 5; + dci.mcs = 5; + dci.ctx.format = srsran_dci_format_nr_1_0; + // TODO: Fill + return true; } @@ -43,11 +46,12 @@ void fill_dci_common(const slot_ue& ue, const bwp_params& bwp_cfg, DciDlOrUl& dc dci.cc_id = ue.cc; dci.tpc = 1; // harq - harq_proc* h = std::is_same::value ? ue.h_dl : ue.h_ul; - dci.pid = h->pid; - dci.ndi = h->ndi(); - dci.mcs = h->mcs(); - dci.rv = rv_idx[h->nof_retx() % 4]; + harq_proc* h = std::is_same::value ? static_cast(ue.h_dl) + : static_cast(ue.h_ul); + dci.pid = h->pid; + dci.ndi = h->ndi(); + dci.mcs = h->mcs(); + dci.rv = rv_idx[h->nof_retx() % 4]; // PRB assignment const prb_grant& grant = h->prbs(); if (grant.is_alloc_type0()) { @@ -84,7 +88,7 @@ void fill_ul_dci_ue_fields(const slot_ue& ue, srsran_dci_location_t dci_pos, srsran_dci_ul_nr_t& dci) { - bool ret = ue.cfg->phy().get_dci_ctx_pdsch_rnti_c(ss_id, dci_pos, ue.rnti, dci.ctx); + bool ret = ue.cfg->phy().get_dci_ctx_pusch_rnti_c(ss_id, dci_pos, ue.rnti, dci.ctx); srsran_assert(ret, "Invalid DL DCI format"); fill_dci_common(ue, bwp_cfg, dci); diff --git a/srsenb/src/stack/mac/nr/sched_nr_rb_grid.cc b/srsenb/src/stack/mac/nr/sched_nr_rb_grid.cc index c20afcb8e..33ff84d8f 100644 --- a/srsenb/src/stack/mac/nr/sched_nr_rb_grid.cc +++ b/srsenb/src/stack/mac/nr/sched_nr_rb_grid.cc @@ -20,6 +20,7 @@ */ #include "srsenb/hdr/stack/mac/nr/sched_nr_rb_grid.h" +#include "srsenb/hdr/stack/mac/nr/sched_nr_cell.h" #include "srsenb/hdr/stack/mac/nr/sched_nr_helpers.h" namespace srsenb { @@ -54,6 +55,8 @@ void bwp_slot_grid::reset() ul_prbs.reset(); dl_pdcchs.clear(); ul_pdcchs.clear(); + pdschs.clear(); + puschs.clear(); pending_acks.clear(); } @@ -70,15 +73,21 @@ bwp_slot_allocator::bwp_slot_allocator(bwp_res_grid& bwp_grid_) : logger(srslog::fetch_basic_logger("MAC")), cfg(*bwp_grid_.cfg), bwp_grid(bwp_grid_) {} -alloc_result bwp_slot_allocator::alloc_rar(uint32_t aggr_idx, - const srsenb::sched_nr_impl::pending_rar_t& rar, - prb_interval interv, - uint32_t nof_grants) +alloc_result bwp_slot_allocator::alloc_rar_and_msg3(uint32_t aggr_idx, + const srsenb::sched_nr_impl::pending_rar_t& rar, + prb_interval interv, + slot_ue_map_t& ues, + uint32_t max_nof_grants) { - static const uint32_t msg3_nof_prbs = 3; + static const uint32_t msg3_nof_prbs = 3, m = 0; bwp_slot_grid& bwp_pdcch_slot = bwp_grid[pdcch_tti]; - bwp_slot_grid& bwp_msg3_slot = bwp_grid[pdcch_tti + 4]; + tti_point msg3_tti = pdcch_tti + cfg.pusch_ra_list[m].msg3_delay; + bwp_slot_grid& bwp_msg3_slot = bwp_grid[msg3_tti]; + alloc_result ret = verify_pusch_space(bwp_msg3_slot, nullptr); + if (ret != alloc_result::success) { + return ret; + } if (bwp_pdcch_slot.dl_pdcchs.full()) { logger.warning("SCHED: Maximum number of DL allocations reached"); @@ -95,10 +104,10 @@ alloc_result bwp_slot_allocator::alloc_rar(uint32_t } // Check Msg3 RB collision - uint32_t total_ul_nof_prbs = msg3_nof_prbs * nof_grants; + uint32_t total_ul_nof_prbs = msg3_nof_prbs * max_nof_grants; uint32_t total_ul_nof_rbgs = srsran::ceil_div(total_ul_nof_prbs, get_P(bwp_grid.nof_prbs(), false)); - prb_interval msg3_rbgs = find_empty_interval_of_length(bwp_msg3_slot.ul_prbs.prbs(), total_ul_nof_rbgs); - if (msg3_rbgs.length() < total_ul_nof_rbgs) { + prb_interval msg3_rbs = find_empty_interval_of_length(bwp_msg3_slot.ul_prbs.prbs(), total_ul_nof_rbgs); + if (msg3_rbs.length() < total_ul_nof_rbgs) { logger.debug("SCHED: No space in PUSCH for Msg3."); return alloc_result::sch_collision; } @@ -112,6 +121,8 @@ alloc_result bwp_slot_allocator::alloc_rar(uint32_t return alloc_result::no_cch_space; } + // RAR allocation successful. + // Generate DCI for RAR pdcch_dl_t& pdcch = bwp_pdcch_slot.dl_pdcchs.back(); if (not fill_dci_rar(interv, *bwp_grid.cfg, pdcch.dci)) { @@ -119,10 +130,39 @@ alloc_result bwp_slot_allocator::alloc_rar(uint32_t bwp_pdcch_slot.coresets[coreset_id]->rem_last_dci(); return alloc_result::invalid_coderate; } - - // RAR allocation successful. + // Generate RAR PDSCH bwp_pdcch_slot.dl_prbs.add(interv); + // Generate Msg3 grants in PUSCH + uint32_t last_msg3 = msg3_rbs.start(); + const int mcs = 0, max_harq_msg3_retx = 4; + int dai = 0; + srsran_slot_cfg_t slot_cfg; + slot_cfg.idx = msg3_tti.sf_idx(); + for (const auto& grant : rar.msg3_grant) { + slot_ue& ue = ues[grant.temp_crnti]; + bool success = ue.h_ul->new_tx( + msg3_tti, msg3_tti, prb_interval{last_msg3, last_msg3 + msg3_nof_prbs}, mcs, 100, max_harq_msg3_retx); + srsran_assert(success, "Failed to allocate Msg3"); + last_msg3 += msg3_nof_prbs; + srsran_dci_ul_nr_t msg3_dci; // Create dummy Msg3 DCI + msg3_dci.ctx.coreset_id = 1; + msg3_dci.ctx.rnti_type = srsran_rnti_type_ra; + msg3_dci.ctx.ss_type = srsran_search_space_type_rar; + msg3_dci.ctx.format = srsran_dci_format_nr_0_0; + msg3_dci.cc_id = cfg.cc; + msg3_dci.bwp_id = cfg.bwp_id; + msg3_dci.rv = 0; + msg3_dci.mcs = 0; + msg3_dci.time_domain_assigment = dai++; + bwp_msg3_slot.puschs.emplace_back(); + pusch_t& pusch = bwp_msg3_slot.puschs.back(); + success = ue.cfg->phy().get_pusch_cfg(slot_cfg, msg3_dci, pusch.sch); + srsran_assert(success, "Error converting DCI to PUSCH grant"); + pusch.sch.grant.tb[0].softbuffer.rx = ue.h_ul->get_softbuffer().get(); + } + bwp_msg3_slot.ul_prbs.add(msg3_rbs); + return alloc_result::success; } @@ -166,7 +206,8 @@ alloc_result bwp_slot_allocator::alloc_pdsch(slot_ue& ue, const prb_grant& dl_gr // Allocate HARQ if (ue.h_dl->empty()) { - int mcs = 20; + srsran_assert(ue.cfg->ue_cfg()->fixed_dl_mcs >= 0, "Dynamic MCS not yet supported"); + int mcs = ue.cfg->ue_cfg()->fixed_dl_mcs; int tbs = 100; bool ret = ue.h_dl->new_tx(ue.pdsch_tti, ue.uci_tti, dl_grant, mcs, tbs, 4); srsran_assert(ret, "Failed to allocate DL HARQ"); @@ -185,6 +226,7 @@ alloc_result bwp_slot_allocator::alloc_pdsch(slot_ue& ue, const prb_grant& dl_gr bwp_uci_slot.pending_acks.end(), [&ue](const harq_ack_t& p) { return p.res.rnti == ue.rnti; }); pdcch.dci.dai %= 4; + pdcch.dci_cfg = ue.cfg->phy().get_dci_cfg(); // Generate PUCCH bwp_uci_slot.pending_acks.emplace_back(); @@ -200,33 +242,30 @@ alloc_result bwp_slot_allocator::alloc_pdsch(slot_ue& ue, const prb_grant& dl_gr slot_cfg.idx = ue.pdsch_tti.sf_idx(); bool ret = ue.cfg->phy().get_pdsch_cfg(slot_cfg, pdcch.dci, pdsch.sch); srsran_assert(ret, "Error converting DCI to grant"); + pdsch.sch.grant.tb[0].softbuffer.tx = ue.h_dl->get_softbuffer().get(); if (ue.h_dl->nof_retx() == 0) { ue.h_dl->set_tbs(pdsch.sch.grant.tb[0].tbs); // update HARQ with correct TBS } else { srsran_assert(pdsch.sch.grant.tb[0].tbs == (int)ue.h_dl->tbs(), "The TBS did not remain constant in retx"); } - pdsch.sch.grant.tb[0].softbuffer.tx = ue.h_dl->get_softbuffer().get(); return alloc_result::success; } alloc_result bwp_slot_allocator::alloc_pusch(slot_ue& ue, const rbg_bitmap& ul_mask) { + auto& bwp_pdcch_slot = bwp_grid[ue.pdcch_tti]; + auto& bwp_pusch_slot = bwp_grid[ue.pusch_tti]; + alloc_result ret = verify_pusch_space(bwp_pusch_slot, &bwp_pdcch_slot); + if (ret != alloc_result::success) { + return ret; + } + if (ue.h_ul == nullptr) { logger.warning("SCHED: Trying to allocate PUSCH for rnti=0x%x with no available HARQs", ue.rnti); return alloc_result::no_rnti_opportunity; } - auto& bwp_pdcch_slot = bwp_grid[ue.pdcch_tti]; - auto& bwp_pusch_slot = bwp_grid[ue.pusch_tti]; - if (not bwp_pusch_slot.is_ul) { - logger.warning("SCHED: Trying to allocate PUSCH in TDD non-UL slot index=%d", bwp_pusch_slot.slot_idx); - return alloc_result::no_sch_space; - } - pdcch_ul_list_t& pdcchs = bwp_pdcch_slot.ul_pdcchs; - if (pdcchs.full()) { - logger.warning("SCHED: Maximum number of UL allocations reached"); - return alloc_result::no_grant_space; - } + pdcch_ul_list_t& pdcchs = bwp_pdcch_slot.ul_pdcchs; const rbg_bitmap& pusch_mask = bwp_pusch_slot.ul_prbs.rbgs(); if ((pusch_mask & ul_mask).any()) { return alloc_result::sch_collision; @@ -239,10 +278,11 @@ alloc_result bwp_slot_allocator::alloc_pusch(slot_ue& ue, const rbg_bitmap& ul_m } if (ue.h_ul->empty()) { - int mcs = 20; - int tbs = 100; - bool ret = ue.h_ul->new_tx(ue.pusch_tti, ue.pusch_tti, ul_mask, mcs, tbs, ue.cfg->ue_cfg()->maxharq_tx); - srsran_assert(ret, "Failed to allocate UL HARQ"); + srsran_assert(ue.cfg->ue_cfg()->fixed_ul_mcs >= 0, "Dynamic MCS not yet supported"); + int mcs = ue.cfg->ue_cfg()->fixed_ul_mcs; + int tbs = 100; + bool success = ue.h_ul->new_tx(ue.pusch_tti, ue.pusch_tti, ul_mask, mcs, tbs, ue.cfg->ue_cfg()->maxharq_tx); + srsran_assert(success, "Failed to allocate UL HARQ"); } else { srsran_assert(ue.h_ul->new_retx(ue.pusch_tti, ue.pusch_tti, ul_mask), "Failed to allocate UL HARQ retx"); } @@ -251,11 +291,43 @@ alloc_result bwp_slot_allocator::alloc_pusch(slot_ue& ue, const rbg_bitmap& ul_m // Generate PDCCH pdcch_ul_t& pdcch = pdcchs.back(); fill_ul_dci_ue_fields(ue, *bwp_grid.cfg, ss_id, pdcch.dci.ctx.location, pdcch.dci); + pdcch.dci_cfg = ue.cfg->phy().get_dci_cfg(); // Generate PUSCH - bwp_pusch_slot.ul_prbs.add(ul_mask); + bwp_pusch_slot.ul_prbs |= ul_mask; + bwp_pusch_slot.puschs.emplace_back(); + pusch_t& pusch = bwp_pusch_slot.puschs.back(); + srsran_slot_cfg_t slot_cfg; + slot_cfg.idx = ue.pusch_tti.sf_idx(); + bool success = ue.cfg->phy().get_pusch_cfg(slot_cfg, pdcch.dci, pusch.sch); + srsran_assert(success, "Error converting DCI to PUSCH grant"); + pusch.sch.grant.tb[0].softbuffer.rx = ue.h_ul->get_softbuffer().get(); return alloc_result::success; } +alloc_result bwp_slot_allocator::verify_pusch_space(bwp_slot_grid& pusch_grid, bwp_slot_grid* pdcch_grid) const +{ + if (not pusch_grid.is_ul) { + logger.warning("SCHED: Trying to allocate PUSCH in TDD non-UL slot index=%d", pusch_grid.slot_idx); + return alloc_result::no_sch_space; + } + if (pdcch_grid != nullptr) { + // DCI needed + if (not pdcch_grid->is_dl) { + logger.warning("SCHED: Trying to allocate PDCCH in TDD non-DL slot index=%d", pdcch_grid->slot_idx); + return alloc_result::no_sch_space; + } + if (pdcch_grid->ul_pdcchs.full()) { + logger.warning("SCHED: Maximum number of PUSCH allocations reached"); + return alloc_result::no_grant_space; + } + } + if (pusch_grid.puschs.full()) { + logger.warning("SCHED: Maximum number of PUSCH allocations reached"); + return alloc_result::no_grant_space; + } + return alloc_result::success; +} + } // namespace sched_nr_impl } // namespace srsenb \ No newline at end of file diff --git a/srsenb/src/stack/mac/nr/sched_nr_ue.cc b/srsenb/src/stack/mac/nr/sched_nr_ue.cc index dac82de04..2a3660afc 100644 --- a/srsenb/src/stack/mac/nr/sched_nr_ue.cc +++ b/srsenb/src/stack/mac/nr/sched_nr_ue.cc @@ -25,9 +25,7 @@ namespace srsenb { namespace sched_nr_impl { -slot_ue::slot_ue(resource_guard::token ue_token_, uint16_t rnti_, tti_point tti_rx_, uint32_t cc_) : - ue_token(std::move(ue_token_)), rnti(rnti_), tti_rx(tti_rx_), cc(cc_) -{} +slot_ue::slot_ue(uint16_t rnti_, tti_point tti_rx_, uint32_t cc_) : rnti(rnti_), tti_rx(tti_rx_), cc(cc_) {} /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -39,46 +37,28 @@ ue_carrier::ue_carrier(uint16_t rnti_, const ue_cfg_t& uecfg_, const sched_cell_ harq_ent(cell_params_.nof_prb()) {} -void ue_carrier::push_feedback(srsran::move_callback callback) -{ - pending_feedback.push_back(std::move(callback)); -} - -slot_ue ue_carrier::try_reserve(tti_point tti_rx, const ue_cfg_t& uecfg_) +void ue_carrier::new_tti(tti_point pdcch_tti, const ue_cfg_t& uecfg_) { - slot_ue sfu(busy, rnti, tti_rx, cc); - if (sfu.empty()) { - return sfu; - } - // successfully acquired. Process any CC-specific pending feedback if (bwp_cfg.ue_cfg() != &uecfg_) { bwp_cfg = bwp_ue_cfg(rnti, cell_params.bwps[0], uecfg_); } - while (not pending_feedback.empty()) { - pending_feedback.front()(*this); - pending_feedback.pop_front(); - } - if (not last_tti_rx.is_valid()) { - last_tti_rx = tti_rx; - harq_ent.new_tti(tti_rx); - } else { - while (last_tti_rx++ < tti_rx) { - harq_ent.new_tti(tti_rx); - } - } + harq_ent.new_tti(pdcch_tti - TX_ENB_DELAY); +} - // set UE parameters common to all carriers - sfu.cfg = &bwp_cfg; +slot_ue ue_carrier::try_reserve(tti_point pdcch_tti) +{ + tti_point tti_rx = pdcch_tti - TX_ENB_DELAY; // copy cc-specific parameters and find available HARQs - sfu.cc_cfg = &uecfg_.carriers[cc]; - sfu.pdcch_tti = tti_rx + TX_ENB_DELAY; + slot_ue sfu(rnti, tti_rx, cc); + sfu.cfg = &bwp_cfg; + sfu.pdcch_tti = pdcch_tti; const uint32_t k0 = 0; sfu.pdsch_tti = sfu.pdcch_tti + k0; uint32_t k1 = sfu.cfg->phy().harq_ack.dl_data_to_ul_ack[sfu.pdsch_tti.sf_idx() % sfu.cfg->phy().harq_ack.nof_dl_data_to_ul_ack]; sfu.uci_tti = sfu.pdsch_tti + k1; - uint32_t k2 = k1; + uint32_t k2 = bwp_cfg.active_bwp().pusch_ra_list[0].K; sfu.pusch_tti = sfu.pdcch_tti + k2; sfu.dl_cqi = dl_cqi; sfu.ul_cqi = ul_cqi; @@ -109,9 +89,9 @@ slot_ue ue_carrier::try_reserve(tti_point tti_rx, const ue_cfg_t& uecfg_) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -ue::ue(uint16_t rnti_, const ue_cfg_t& cfg, const sched_params& sched_cfg_) : rnti(rnti_), sched_cfg(sched_cfg_) +ue::ue(uint16_t rnti_, const ue_cfg_t& cfg, const sched_params& sched_cfg_) : + rnti(rnti_), sched_cfg(sched_cfg_), ue_cfg(cfg) { - ue_cfgs[0] = cfg; for (uint32_t cc = 0; cc < cfg.carriers.size(); ++cc) { if (cfg.carriers[cc].active) { carriers[cc].reset(new ue_carrier(rnti, cfg, sched_cfg.cells[cc])); @@ -121,19 +101,19 @@ ue::ue(uint16_t rnti_, const ue_cfg_t& cfg, const sched_params& sched_cfg_) : rn void ue::set_cfg(const ue_cfg_t& cfg) { - current_idx = (current_idx + 1U) % ue_cfgs.size(); - ue_cfgs[current_idx] = ue_cfg_extended(rnti, cfg); + ue_cfg = cfg; } -slot_ue ue::try_reserve(tti_point tti_rx, uint32_t cc) +slot_ue ue::try_reserve(tti_point pdcch_tti, uint32_t cc) { if (carriers[cc] == nullptr) { return slot_ue(); } - slot_ue sfu = carriers[cc]->try_reserve(tti_rx, ue_cfgs[current_idx]); + slot_ue sfu = carriers[cc]->try_reserve(pdcch_tti); if (sfu.empty()) { return slot_ue(); } + // set UE-common parameters sfu.pending_sr = pending_sr; diff --git a/srsenb/src/stack/mac/nr/sched_nr_worker.cc b/srsenb/src/stack/mac/nr/sched_nr_worker.cc index 8c2445268..26d5fd13f 100644 --- a/srsenb/src/stack/mac/nr/sched_nr_worker.cc +++ b/srsenb/src/stack/mac/nr/sched_nr_worker.cc @@ -25,24 +25,57 @@ namespace srsenb { namespace sched_nr_impl { -slot_cc_worker::slot_cc_worker(serv_cell_ctxt& cc_sched) : - cell(cc_sched), cfg(*cc_sched.cfg), bwp_alloc(cc_sched.bwps[0].grid), logger(srslog::fetch_basic_logger("MAC")) +slot_cc_worker::slot_cc_worker(serv_cell_manager& cc_sched) : + cell(cc_sched), cfg(cc_sched.cfg), bwp_alloc(cc_sched.bwps[0].grid), logger(srslog::fetch_basic_logger("MAC")) {} +void slot_cc_worker::enqueue_cc_feedback(uint16_t rnti, feedback_callback_t fdbk) +{ + std::lock_guard lock(feedback_mutex); + pending_feedback.emplace_back(); + pending_feedback.back().rnti = rnti; + pending_feedback.back().fdbk = std::move(fdbk); +} + +void slot_cc_worker::run_feedback(ue_map_t& ue_db) +{ + { + std::lock_guard lock(feedback_mutex); + tmp_feedback_to_run.swap(pending_feedback); + } + + for (feedback_t& f : tmp_feedback_to_run) { + if (ue_db.contains(f.rnti) and ue_db[f.rnti]->carriers[cfg.cc] != nullptr) { + f.fdbk(*ue_db[f.rnti]->carriers[cfg.cc]); + } else { + logger.warning("SCHED: feedback received for invalid rnti=0x%x, cc=%d", f.rnti, cfg.cc); + } + } + tmp_feedback_to_run.clear(); +} + /// Called at the beginning of TTI in a locked context, to reserve available UE resources -void slot_cc_worker::start(tti_point tti_rx_, ue_map_t& ue_db) +void slot_cc_worker::start(tti_point pdcch_tti, ue_map_t& ue_db) { srsran_assert(not running(), "scheduler worker::start() called for active worker"); - tti_rx = tti_rx_; + tti_rx = pdcch_tti - TX_ENB_DELAY; - // Try reserve UE cells for this worker + // Run pending cell feedback + run_feedback(ue_db); + + // Reserve UEs for this worker slot for (auto& ue_pair : ue_db) { uint16_t rnti = ue_pair.first; ue& u = *ue_pair.second; + if (u.carriers[cfg.cc] == nullptr) { + continue; + } + + u.carriers[cfg.cc]->new_tti(pdcch_tti, u.cfg()); - slot_ues.insert(rnti, u.try_reserve(tti_rx, cfg.cc)); + slot_ues.insert(rnti, u.try_reserve(pdcch_tti, cfg.cc)); if (slot_ues[rnti].empty()) { - // Failed to synchronize because UE is being used by another worker + // Failed to generate slot UE because UE has no conditions for DL/UL tx slot_ues.erase(rnti); continue; } @@ -57,7 +90,7 @@ void slot_cc_worker::run() bwp_alloc.new_slot(tti_rx + TX_ENB_DELAY); // Allocate pending RARs - cell.bwps[0].ra.run_slot(bwp_alloc); + cell.bwps[0].ra.run_slot(bwp_alloc, slot_ues); // TODO: Prioritize PDCCH scheduling for DL and UL data in a Round-Robin fashion alloc_dl_ues(); @@ -65,18 +98,17 @@ void slot_cc_worker::run() // Log CC scheduler result log_result(); -} - -void slot_cc_worker::end_tti() -{ - srsran_assert(running(), "scheduler worker::end() called for non-active worker"); // releases UE resources slot_ues.clear(); - tti_rx = {}; } +void slot_cc_worker::finish() +{ + // synchronize results +} + void slot_cc_worker::alloc_dl_ues() { if (slot_ues.empty()) { @@ -115,126 +147,157 @@ void slot_cc_worker::log_result() const if (pdcch.dci.ctx.rnti_type == srsran_rnti_type_c) { const slot_ue& ue = slot_ues[pdcch.dci.ctx.rnti]; fmt::format_to(fmtbuf, - "SCHED: DL {}, cc={}, rnti=0x{:x}, pid={}, nrtx={}, dai={}, tti_pdsch={}, tti_ack={}", + "SCHED: DL {}, cc={}, rnti=0x{:x}, pid={}, nrtx={}, f={}, dai={}, tti_pdsch={}, tti_ack={}", ue.h_dl->nof_retx() == 0 ? "tx" : "retx", - cell.cfg->cc, + cell.cfg.cc, ue.rnti, - ue.h_dl->pid, + pdcch.dci.pid, ue.h_dl->nof_retx(), + srsran_dci_format_nr_string(pdcch.dci.ctx.format), pdcch.dci.dai, ue.pdsch_tti, ue.uci_tti); } else if (pdcch.dci.ctx.rnti_type == srsran_rnti_type_ra) { - fmt::format_to(fmtbuf, "SCHED: DL RAR, cc={}", cell.cfg->cc); + fmt::format_to(fmtbuf, "SCHED: DL RAR, cc={}", cell.cfg.cc); } else { fmt::format_to(fmtbuf, "SCHED: unknown format"); } + logger.info("%s", srsran::to_c_str(fmtbuf)); + } + for (const pdcch_ul_t& pdcch : bwp_slot.ul_pdcchs) { + fmt::memory_buffer fmtbuf; + if (pdcch.dci.ctx.rnti_type == srsran_rnti_type_c) { + const slot_ue& ue = slot_ues[pdcch.dci.ctx.rnti]; + fmt::format_to(fmtbuf, + "SCHED: UL {}, cc={}, rnti=0x{:x}, pid={}, nrtx={}, f={}, tti_pusch={}", + ue.h_dl->nof_retx() == 0 ? "tx" : "retx", + cell.cfg.cc, + ue.rnti, + pdcch.dci.pid, + ue.h_dl->nof_retx(), + srsran_dci_format_nr_string(pdcch.dci.ctx.format), + ue.pusch_tti); + } else { + fmt::format_to(fmtbuf, "SCHED: unknown rnti format"); + } + logger.info("%s", srsran::to_c_str(fmtbuf)); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -sched_worker_manager::sched_worker_manager(ue_map_t& ue_db_, const sched_params& cfg_) : - cfg(cfg_), ue_db(ue_db_), logger(srslog::fetch_basic_logger("MAC")) +sched_worker_manager::sched_worker_manager(ue_map_t& ue_db_, + const sched_params& cfg_, + srsran::span > cells_) : + cfg(cfg_), ue_db(ue_db_), logger(srslog::fetch_basic_logger("MAC")), cells(cells_) { + cc_worker_list.reserve(cfg.cells.size()); for (uint32_t cc = 0; cc < cfg.cells.size(); ++cc) { - cell_grid_list.emplace_back(cfg.cells[cc]); - } - - // Note: For now, we only allow parallelism at the sector level - slot_worker_ctxts.resize(cfg.sched_cfg.nof_concurrent_subframes); - for (size_t i = 0; i < cfg.sched_cfg.nof_concurrent_subframes; ++i) { - slot_worker_ctxts[i].reset(new slot_worker_ctxt()); - slot_worker_ctxts[i]->workers.reserve(cfg.cells.size()); - for (uint32_t cc = 0; cc < cfg.cells.size(); ++cc) { - slot_worker_ctxts[i]->workers.emplace_back(cell_grid_list[cc]); - } + cc_worker_list.emplace_back(new cc_context{*cells[cc]}); } } sched_worker_manager::~sched_worker_manager() = default; -sched_worker_manager::slot_worker_ctxt& sched_worker_manager::get_sf(tti_point tti_rx) +void sched_worker_manager::enqueue_event(uint16_t rnti, srsran::move_callback ev) { - return *slot_worker_ctxts[tti_rx.to_uint() % slot_worker_ctxts.size()]; + std::lock_guard lock(event_mutex); + next_slot_events.push_back(ue_event_t{rnti, std::move(ev)}); } -void sched_worker_manager::start_slot(tti_point tti_rx, srsran::move_callback process_feedback) +void sched_worker_manager::run_slot(tti_point tti_tx, uint32_t cc, dl_sched_t& dl_res, ul_sched_t& ul_res) { - auto& sf_worker_ctxt = get_sf(tti_rx); - - std::unique_lock lock(sf_worker_ctxt.slot_mutex); - while ((sf_worker_ctxt.tti_rx.is_valid() and sf_worker_ctxt.tti_rx != tti_rx)) { - // wait for previous slot to finish - sf_worker_ctxt.nof_workers_waiting++; - sf_worker_ctxt.cvar.wait(lock); - sf_worker_ctxt.nof_workers_waiting--; - } - if (sf_worker_ctxt.tti_rx == tti_rx) { - // another worker with the same slot idx already started - return; - } - + srsran::bounded_vector waiting_cvars; { - std::lock_guard db_lock(ue_db_mutex); - - process_feedback(); + std::unique_lock lock(slot_mutex); + while (current_tti.is_valid() and current_tti != tti_tx) { + // Wait for previous slot to finish + cc_worker_list[cc]->waiting = true; + cc_worker_list[cc]->cvar.wait(lock); + cc_worker_list[cc]->waiting = false; + } + if (not current_tti.is_valid()) { + /* First Worker to start slot */ + + // process non-cc specific feedback if pending (e.g. SRs, buffer updates, UE config) for UEs with CA + // NOTE: there is no parallelism in these operations + slot_events.clear(); + { + std::lock_guard ev_lock(event_mutex); + next_slot_events.swap(slot_events); + } + for (ue_event_t& ev : slot_events) { + if (not ue_db.contains(ev.rnti) or ue_db[ev.rnti]->has_ca()) { + ev.callback(); + } + } - for (uint32_t cc = 0; cc < sf_worker_ctxt.workers.size(); ++cc) { - sf_worker_ctxt.workers[cc].start(tti_rx, ue_db); + // mark the start of slot. awake remaining workers if locking on the mutex + current_tti = tti_tx; + worker_count.store(static_cast(cc_worker_list.size()), std::memory_order_relaxed); + for (auto& w : cc_worker_list) { + if (w->waiting) { + waiting_cvars.push_back(&w->cvar); + } + } + lock.unlock(); + for (auto& w : waiting_cvars) { + w->notify_one(); + } + waiting_cvars.clear(); } } - sf_worker_ctxt.tti_rx = tti_rx; - sf_worker_ctxt.worker_count.store(static_cast(sf_worker_ctxt.workers.size()), std::memory_order_relaxed); - if (sf_worker_ctxt.nof_workers_waiting > 0) { - sf_worker_ctxt.cvar.notify_all(); + /* Parallel Region */ + + // process non-cc specific feedback if pending (e.g. SRs, buffer updates, UE config) for UEs without CA + for (ue_event_t& ev : slot_events) { + if (ue_db.contains(ev.rnti) and not ue_db[ev.rnti]->has_ca() and ue_db[ev.rnti]->pcell_cc() == cc) { + ev.callback(); + } } -} -bool sched_worker_manager::run_slot(tti_point tti_rx_, uint32_t cc) -{ - auto& sf_worker_ctxt = get_sf(tti_rx_); - srsran_assert(sf_worker_ctxt.tti_rx == tti_rx_, "invalid run_tti(tti, cc) arguments"); + // process pending feedback and pre-cache UE state for slot decision + cc_worker_list[cc]->worker.start(tti_tx, ue_db); // Get {tti, cc} scheduling decision - sf_worker_ctxt.workers[cc].run(); + cc_worker_list[cc]->worker.run(); // decrement the number of active workers - int rem_workers = sf_worker_ctxt.worker_count.fetch_sub(1, std::memory_order_release) - 1; + int rem_workers = worker_count.fetch_sub(1, std::memory_order_release) - 1; srsran_assert(rem_workers >= 0, "invalid number of calls to run_tti(tti, cc)"); + if (rem_workers == 0) { + /* Last Worker to finish slot */ - return rem_workers == 0; -} - -void sched_worker_manager::release_slot(tti_point tti_rx_) -{ - auto& sf_worker_ctxt = get_sf(tti_rx_); - srsran_assert(sf_worker_ctxt.tti_rx == tti_rx_, "invalid run_tti(tti, cc) arguments"); - srsran_assert(sf_worker_ctxt.worker_count == 0, "invalid number of calls to run_tti(tti, cc)"); - - { - std::lock_guard lock(ue_db_mutex); + // Signal the release of slot if it is the last worker that finished its own generation + std::unique_lock lock(slot_mutex); + current_tti = {}; // All the workers of the same slot have finished. Synchronize scheduling decisions with UEs state - for (slot_cc_worker& worker : sf_worker_ctxt.workers) { - worker.end_tti(); + for (auto& c : cc_worker_list) { + c->worker.finish(); + if (c->waiting) { + waiting_cvars.push_back(&c->cvar); + } } - } - std::unique_lock lock(sf_worker_ctxt.slot_mutex); - sf_worker_ctxt.tti_rx = {}; - if (sf_worker_ctxt.nof_workers_waiting > 0) { + // Awake waiting workers lock.unlock(); - sf_worker_ctxt.cvar.notify_one(); + for (auto& c : waiting_cvars) { + c->notify_one(); + } } + + // Copy results to intermediate buffer + save_sched_result(tti_tx, cc, dl_res, ul_res); } bool sched_worker_manager::save_sched_result(tti_point pdcch_tti, uint32_t cc, dl_sched_t& dl_res, ul_sched_t& ul_res) { - auto& bwp_slot = cell_grid_list[cc].bwps[0].grid[pdcch_tti]; + // NOTE: Unlocked region + auto& bwp_slot = cells[cc]->bwps[0].grid[pdcch_tti]; dl_res.pdcch_dl = bwp_slot.dl_pdcchs; dl_res.pdcch_ul = bwp_slot.ul_pdcchs; @@ -262,15 +325,34 @@ bool sched_worker_manager::save_sched_result(tti_point pdcch_tti, uint32_t cc, d if (uci_cfg.ack.count > 0 || uci_cfg.nof_csi > 0 || uci_cfg.o_sr > 0) { if (not ul_res.pusch.empty()) { // Put UCI configuration in PUSCH config - srsran_assert(phy_cfg->get_pusch_uci_cfg(slot_cfg, uci_cfg, ul_res.pusch[0].sch), - "Error setting UCI configuration in PUSCH"); + bool ret = phy_cfg->get_pusch_uci_cfg(slot_cfg, uci_cfg, ul_res.pusch[0].sch); + srsran_assert(ret, "Error setting UCI configuration in PUSCH"); } else { // Put UCI configuration in PUCCH config ul_res.pucch.emplace_back(); pucch_t& pucch = ul_res.pucch.back(); - pucch.uci_cfg = uci_cfg; - srsran_assert(phy_cfg->get_pucch_uci_cfg(slot_cfg, pucch.uci_cfg, pucch.pucch_cfg, pucch.resource), + pucch.candidates.emplace_back(); + pucch.candidates.back().uci_cfg = uci_cfg; + srsran_assert(phy_cfg->get_pucch_uci_cfg( + slot_cfg, pucch.candidates.back().uci_cfg, pucch.pucch_cfg, pucch.candidates.back().resource), "Error getting PUCCH UCI cfg"); + + // If this slot has a SR opportunity and the selected PUCCH format is 1, consider positive SR. + if (uci_cfg.sr_positive_present and uci_cfg.ack.count > 0 and + pucch.candidates.back().resource.format == SRSRAN_PUCCH_NR_FORMAT_1) { + // Set SR negative + if (uci_cfg.o_sr > 0) { + uci_cfg.sr_positive_present = false; + } + + // Append new resource + pucch.candidates.emplace_back(); + pucch.candidates.back().uci_cfg = uci_cfg; + srsran_assert( + phy_cfg->get_pucch_uci_cfg( + slot_cfg, pucch.candidates.back().uci_cfg, pucch.pucch_cfg, pucch.candidates.back().resource), + "Error getting PUCCH UCI cfg"); + } } } } @@ -282,4 +364,4 @@ bool sched_worker_manager::save_sched_result(tti_point pdcch_tti, uint32_t cc, d } } // namespace sched_nr_impl -} // namespace srsenb \ No newline at end of file +} // namespace srsenb diff --git a/srsenb/src/stack/mac/nr/ue_nr.cc b/srsenb/src/stack/mac/nr/ue_nr.cc new file mode 100644 index 000000000..42ff4710e --- /dev/null +++ b/srsenb/src/stack/mac/nr/ue_nr.cc @@ -0,0 +1,186 @@ +/** + * + * \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 +#include +#include +#include + +#include "srsenb/hdr/stack/mac/nr/ue_nr.h" +#include "srsran/common/string_helpers.h" +#include "srsran/interfaces/gnb_interfaces.h" + +namespace srsenb { + +ue_nr::ue_nr(uint16_t rnti_, + uint32_t enb_cc_idx, + sched_interface* sched_, + rrc_interface_mac_nr* rrc_, + rlc_interface_mac* rlc_, + phy_interface_stack_nr* phy_, + srslog::basic_logger& logger_) : + rnti(rnti_), sched(sched_), rrc(rrc_), rlc(rlc_), phy(phy_), logger(logger_) +{} + +ue_nr::~ue_nr() {} + +void ue_nr::reset() +{ + ue_metrics = {}; + nof_failures = 0; +} + +void ue_nr::ue_cfg(const sched_interface::ue_cfg_t& ue_cfg) +{ + // nop +} + +void ue_nr::set_tti(uint32_t tti) +{ + last_tti = tti; +} + +int ue_nr::process_pdu(srsran::unique_byte_buffer_t pdu) +{ + logger.info(pdu->msg, pdu->N_bytes, "Handling MAC PDU (%d B)", pdu->N_bytes); + + mac_pdu_ul.init_rx(true); + if (mac_pdu_ul.unpack(pdu->msg, pdu->N_bytes) != SRSRAN_SUCCESS) { + return SRSRAN_ERROR; + } + + if (logger.info.enabled()) { + fmt::memory_buffer str_buffer; + // mac_pdu_ul.to_string(str_buffer); + logger.info("0x%x %s", rnti, srsran::to_c_str(str_buffer)); + } + + for (uint32_t i = 0; i < mac_pdu_ul.get_num_subpdus(); ++i) { + srsran::mac_sch_subpdu_nr subpdu = mac_pdu_ul.get_subpdu(i); + logger.info("Handling subPDU %d/%d: lcid=%d, sdu_len=%d", + i, + mac_pdu_ul.get_num_subpdus(), + subpdu.get_lcid(), + subpdu.get_sdu_length()); + + rlc->write_pdu(rnti, subpdu.get_lcid(), subpdu.get_sdu(), subpdu.get_sdu_length()); + } + return SRSRAN_SUCCESS; +} + +uint32_t ue_nr::read_pdu(uint32_t lcid, uint8_t* payload, uint32_t requested_bytes) +{ + return rlc->read_pdu(rnti, lcid, payload, requested_bytes); +} + +uint8_t* ue_nr::generate_pdu(uint32_t enb_cc_idx, + uint32_t harq_pid, + uint32_t tb_idx, + const sched_interface::dl_sched_pdu_t pdu[sched_interface::MAX_RLC_PDU_LIST], + uint32_t nof_pdu_elems, + uint32_t grant_size) +{ + std::lock_guard lock(mutex); + uint8_t* ret = nullptr; + if (enb_cc_idx < SRSRAN_MAX_CARRIERS && harq_pid < SRSRAN_FDD_NOF_HARQ && tb_idx < SRSRAN_MAX_TB) { + srsran::byte_buffer_t* buffer = nullptr; // TODO: read from scheduler output + buffer->clear(); + + mac_pdu_dl.init_tx(buffer, grant_size); + + // read RLC PDU + ue_rlc_buffer->clear(); + int lcid = 4; + int pdu_len = rlc->read_pdu(rnti, lcid, ue_rlc_buffer->msg, grant_size - 2); + + // Only create PDU if RLC has something to tx + if (pdu_len > 0) { + logger.info("Adding MAC PDU for RNTI=%d", rnti); + ue_rlc_buffer->N_bytes = pdu_len; + logger.info(ue_rlc_buffer->msg, ue_rlc_buffer->N_bytes, "Read %d B from RLC", ue_rlc_buffer->N_bytes); + + // add to MAC PDU and pack + mac_pdu_dl.add_sdu(4, ue_rlc_buffer->msg, ue_rlc_buffer->N_bytes); + mac_pdu_dl.pack(); + } + + if (logger.info.enabled()) { + fmt::memory_buffer str_buffer; + // mac_pdu_dl.to_string(str_buffer); + logger.info("0x%x %s", rnti, srsran::to_c_str(str_buffer)); + } + } else { + logger.error( + "Invalid parameters calling generate_pdu: cc_idx=%d, harq_pid=%d, tb_idx=%d", enb_cc_idx, harq_pid, tb_idx); + } + return ret; +} + +/******* METRICS interface ***************/ +void ue_nr::metrics_read(mac_ue_metrics_t* metrics_) +{ + uint32_t ul_buffer = sched->get_ul_buffer(rnti); + uint32_t dl_buffer = sched->get_dl_buffer(rnti); + + std::lock_guard lock(metrics_mutex); + ue_metrics.rnti = rnti; + ue_metrics.ul_buffer = ul_buffer; + ue_metrics.dl_buffer = dl_buffer; + + // set PCell sector id + std::array cc_list = sched->get_enb_ue_cc_map(rnti); + auto it = std::find(cc_list.begin(), cc_list.end(), 0); + ue_metrics.cc_idx = std::distance(cc_list.begin(), it); + + *metrics_ = ue_metrics; + + phr_counter = 0; + dl_cqi_counter = 0; + ue_metrics = {}; +} + +void ue_nr::metrics_dl_cqi(uint32_t dl_cqi) +{ + std::lock_guard lock(metrics_mutex); + ue_metrics.dl_cqi = SRSRAN_VEC_CMA((float)dl_cqi, ue_metrics.dl_cqi, dl_cqi_counter); + dl_cqi_counter++; +} + +void ue_nr::metrics_rx(bool crc, uint32_t tbs) +{ + std::lock_guard lock(metrics_mutex); + if (crc) { + ue_metrics.rx_brate += tbs * 8; + } else { + ue_metrics.rx_errors++; + } + ue_metrics.rx_pkts++; +} + +void ue_nr::metrics_tx(bool crc, uint32_t tbs) +{ + std::lock_guard lock(metrics_mutex); + if (crc) { + ue_metrics.tx_brate += tbs * 8; + } else { + ue_metrics.tx_errors++; + } + ue_metrics.tx_pkts++; +} + +void ue_nr::metrics_cnt() +{ + std::lock_guard lock(metrics_mutex); + ue_metrics.nof_tti++; +} + +} // namespace srsenb diff --git a/srsenb/src/stack/mac/sched.cc b/srsenb/src/stack/mac/sched.cc index 6a4d4c8d0..b952f7336 100644 --- a/srsenb/src/stack/mac/sched.cc +++ b/srsenb/src/stack/mac/sched.cc @@ -218,6 +218,13 @@ int sched::dl_cqi_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, uint32_ rnti, [tti, enb_cc_idx, cqi_value](sched_ue& ue) { ue.set_dl_cqi(tti_point{tti}, enb_cc_idx, cqi_value); }); } +int sched::dl_sb_cqi_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, uint32_t sb_idx, uint32_t cqi_value) +{ + return ue_db_access_locked(rnti, [tti, enb_cc_idx, cqi_value, sb_idx](sched_ue& ue) { + ue.set_dl_sb_cqi(tti_point{tti}, enb_cc_idx, sb_idx, cqi_value); + }); +} + int sched::dl_rach_info(uint32_t enb_cc_idx, dl_sched_rar_info_t rar_info) { std::lock_guard lock(sched_mutex); diff --git a/srsenb/src/stack/mac/sched_carrier.cc b/srsenb/src/stack/mac/sched_carrier.cc index 5d9ea4044..246edc6cb 100644 --- a/srsenb/src/stack/mac/sched_carrier.cc +++ b/srsenb/src/stack/mac/sched_carrier.cc @@ -448,7 +448,7 @@ void sched::carrier_sched::alloc_dl_users(sf_sched* tti_result) // NOTE: In case of 6 PRBs, do not transmit if there is going to be a PRACH in the UL to avoid collisions if (cc_cfg->nof_prb() == 6) { tti_point tti_rx_ack = to_tx_dl_ack(tti_result->get_tti_rx()); - if (srsran_prach_tti_opportunity_config_fdd(cc_cfg->cfg.prach_config, tti_rx_ack.to_uint(), -1)) { + if (srsran_prach_in_window_config_fdd(cc_cfg->cfg.prach_config, tti_rx_ack.to_uint(), -1)) { tti_result->reserve_dl_rbgs(0, cc_cfg->nof_rbgs); } } diff --git a/srsenb/src/stack/mac/sched_grid.cc b/srsenb/src/stack/mac/sched_grid.cc index dc86f7527..397aa1cfb 100644 --- a/srsenb/src/stack/mac/sched_grid.cc +++ b/srsenb/src/stack/mac/sched_grid.cc @@ -108,7 +108,7 @@ void sf_grid_t::new_tti(tti_point tti_rx_) ul_mask |= pucch_mask; // Reserve PRBs for PRACH - if (srsran_prach_tti_opportunity_config_fdd(cc_cfg->cfg.prach_config, to_tx_ul(tti_rx).to_uint(), -1)) { + if (srsran_prach_in_window_config_fdd(cc_cfg->cfg.prach_config, to_tx_ul(tti_rx).to_uint(), -1)) { prbmask_t prach_mask{cc_cfg->nof_prb()}; prach_mask.fill(cc_cfg->cfg.prach_freq_offset, cc_cfg->cfg.prach_freq_offset + 6); reserve_ul_prbs(prach_mask, false); // TODO: set to true once test sib.conf files are updated @@ -328,7 +328,7 @@ void sf_sched::new_tti(tti_point tti_rx_, sf_sched_result* cc_results_) // setup first prb to be used for msg3 alloc. Account for potential PRACH alloc last_msg3_prb = tti_alloc.get_pucch_width(); tti_point tti_msg3_alloc = to_tx_ul(tti_rx) + MSG3_DELAY_MS; - if (srsran_prach_tti_opportunity_config_fdd(cc_cfg->cfg.prach_config, tti_msg3_alloc.to_uint(), -1)) { + if (srsran_prach_in_window_config_fdd(cc_cfg->cfg.prach_config, tti_msg3_alloc.to_uint(), -1)) { last_msg3_prb = std::max(last_msg3_prb, cc_cfg->cfg.prach_freq_offset + 6); } } diff --git a/srsenb/src/stack/mac/sched_ue.cc b/srsenb/src/stack/mac/sched_ue.cc index fb75d6e00..4a5203fc7 100644 --- a/srsenb/src/stack/mac/sched_ue.cc +++ b/srsenb/src/stack/mac/sched_ue.cc @@ -284,11 +284,12 @@ void sched_ue::set_dl_pmi(tti_point tti_rx, uint32_t enb_cc_idx, uint32_t pmi) void sched_ue::set_dl_cqi(tti_point tti_rx, uint32_t enb_cc_idx, uint32_t cqi) { - if (cells[enb_cc_idx].cc_state() != cc_st::idle) { - cells[enb_cc_idx].set_dl_wb_cqi(tti_rx, cqi); - } else { - logger.warning("Received DL CQI for invalid enb cell index %d", enb_cc_idx); - } + cells[enb_cc_idx].set_dl_wb_cqi(tti_rx, cqi); +} + +void sched_ue::set_dl_sb_cqi(tti_point tti_rx, uint32_t enb_cc_idx, uint32_t sb_idx, uint32_t cqi) +{ + cells[enb_cc_idx].set_dl_sb_cqi(tti_rx, sb_idx, cqi); } void sched_ue::set_ul_snr(tti_point tti_rx, uint32_t enb_cc_idx, float snr, uint32_t ul_ch_code) diff --git a/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc b/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc index 5c259e4b6..c3c985678 100644 --- a/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc +++ b/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc @@ -174,15 +174,28 @@ void sched_ue_cell::finish_tti(tti_point tti_rx) harq_ent.finish_tti(tti_rx); } -int sched_ue_cell::set_dl_wb_cqi(tti_point tti_rx, uint32_t dl_cqi_) +void sched_ue_cell::check_cc_activation(uint32_t dl_cqi) { - CHECK_VALID_CC("DL CQI"); - dl_cqi_ctxt.cqi_wb_info(tti_rx, dl_cqi_); - if (ue_cc_idx > 0 and cc_state_ == cc_st::activating and dl_cqi_ > 0) { + if (ue_cc_idx > 0 and cc_state_ == cc_st::activating and dl_cqi > 0) { // Wait for SCell to receive a positive CQI before activating it cc_state_ = cc_st::active; logger.info("SCHED: SCell index=%d is now active", ue_cc_idx); } +} + +int sched_ue_cell::set_dl_wb_cqi(tti_point tti_rx, uint32_t dl_cqi_) +{ + CHECK_VALID_CC("DL CQI"); + dl_cqi_ctxt.cqi_wb_info(tti_rx, dl_cqi_); + check_cc_activation(dl_cqi_); + return SRSRAN_SUCCESS; +} + +int sched_ue_cell::set_dl_sb_cqi(tti_point tti_rx, uint32_t sb_idx, uint32_t dl_cqi_) +{ + CHECK_VALID_CC("DL CQI"); + dl_cqi_ctxt.cqi_sb_info(tti_rx, sb_idx, dl_cqi_); + check_cc_activation(dl_cqi_); return SRSRAN_SUCCESS; } diff --git a/srsenb/src/stack/ngap/ngap.cc b/srsenb/src/stack/ngap/ngap.cc index 6ed213af7..338c5c742 100644 --- a/srsenb/src/stack/ngap/ngap.cc +++ b/srsenb/src/stack/ngap/ngap.cc @@ -152,6 +152,24 @@ void ngap::stop() amf_socket.close(); } +void ngap::get_metrics(ngap_metrics_t& m) +{ + if (!running) { + m.status = ngap_error; + return; + } + if (amf_connected) { + m.status = ngap_connected; + } else { + m.status = ngap_attaching; + } +} + +void ngap::get_args(ngap_args_t& args_) +{ + args_ = args; +} + bool ngap::is_amf_connected() { return amf_connected; diff --git a/srsenb/src/stack/rrc/rrc.cc b/srsenb/src/stack/rrc/rrc.cc index b14c0280e..479ad804a 100644 --- a/srsenb/src/stack/rrc/rrc.cc +++ b/srsenb/src/stack/rrc/rrc.cc @@ -563,16 +563,25 @@ void rrc::set_erab_status(uint16_t rnti, const asn1::s1ap::bearers_subject_to_st EN-DC/NSA helper functions *******************************************************************************/ -void rrc::sgnb_addition_ack(uint16_t rnti, +void rrc::sgnb_addition_ack(uint16_t eutra_rnti, const asn1::dyn_octstring& nr_secondary_cell_group_cfg_r15, const asn1::dyn_octstring& nr_radio_bearer_cfg1_r15) { - users.at(rnti)->endc_handler->handle_sgnb_addition_ack(nr_secondary_cell_group_cfg_r15, nr_radio_bearer_cfg1_r15); + users.at(eutra_rnti) + ->endc_handler->handle_sgnb_addition_ack(nr_secondary_cell_group_cfg_r15, nr_radio_bearer_cfg1_r15); + + // trigger RRC Reconfiguration to send NR config to UE + users.at(eutra_rnti)->send_connection_reconf(); +} + +void rrc::sgnb_addition_reject(uint16_t eutra_rnti) +{ + users.at(eutra_rnti)->endc_handler->handle_sgnb_addition_reject(); } -void rrc::sgnb_addition_reject(uint16_t rnti) +void rrc::sgnb_addition_complete(uint16_t eutra_rnti) { - users.at(rnti)->endc_handler->handle_sgnb_addition_reject(); + users.at(eutra_rnti)->endc_handler->handle_sgnb_addition_complete(); } /******************************************************************************* diff --git a/srsenb/src/stack/rrc/rrc_endc.cc b/srsenb/src/stack/rrc/rrc_endc.cc index 985ea28ce..46d0ffeed 100644 --- a/srsenb/src/stack/rrc/rrc_endc.cc +++ b/srsenb/src/stack/rrc/rrc_endc.cc @@ -133,7 +133,7 @@ bool rrc::ue::rrc_endc::fill_conn_recfg(asn1::rrc::rrc_conn_recfg_r8_ies_s* conn meas_cfg.meas_gap_cfg_present = true; meas_cfg.meas_gap_cfg.set_setup(); meas_cfg.meas_gap_cfg.setup().gap_offset.set_gp0() = 16; - } else { + } else if (is_in_state()) { // only add reconfigure EN-DC extension/release 15.10 field if ENDC activation is active conn_recfg->non_crit_ext_present = true; conn_recfg->non_crit_ext.non_crit_ext_present = true; @@ -148,8 +148,21 @@ bool rrc::ue::rrc_endc::fill_conn_recfg(asn1::rrc::rrc_conn_recfg_r8_ies_s* conn rrc_conn_recfg_v1510_ies_s& reconf_v1510 = conn_recfg->non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext .non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext; reconf_v1510.nr_cfg_r15_present = true; + reconf_v1510.nr_cfg_r15.set_setup(); + + reconf_v1510.nr_cfg_r15.setup().endc_release_and_add_r15 = false; + reconf_v1510.nr_cfg_r15.setup().nr_secondary_cell_group_cfg_r15_present = true; + reconf_v1510.nr_cfg_r15.setup().nr_secondary_cell_group_cfg_r15 = nr_secondary_cell_group_cfg_r15; + reconf_v1510.sk_counter_r15_present = true; reconf_v1510.sk_counter_r15 = 0; + + reconf_v1510.nr_radio_bearer_cfg1_r15_present = true; + reconf_v1510.nr_radio_bearer_cfg1_r15 = nr_radio_bearer_cfg1_r15; + + // inform FSM + rrc_recfg_sent_ev recfg_sent{}; + trigger(recfg_sent); } return true; @@ -235,18 +248,22 @@ void rrc::ue::rrc_endc::handle_ue_meas_report(const meas_report_s& msg) trigger(sgnb_add_req); } -void rrc::ue::rrc_endc::handle_sgnb_addition_ack(const asn1::dyn_octstring& nr_secondary_cell_group_cfg_r15, - const asn1::dyn_octstring& nr_radio_bearer_cfg1_r15) +void rrc::ue::rrc_endc::handle_sgnb_addition_ack(const asn1::dyn_octstring& nr_secondary_cell_group_cfg_r15_, + const asn1::dyn_octstring& nr_radio_bearer_cfg1_r15_) { logger.info("Received SgNB addition acknowledgement for rnti=%d", rrc_ue->rnti); - // prepare reconfiguration message with NR fields - srsran::unique_byte_buffer_t pdu = srsran::make_byte_buffer(); - if (pdu == nullptr) { - logger.error("Couldn't allocate PDU in %s().", __FUNCTION__); - return; - } - // rrc_enb->send_connection_reconf(std::move(pdu)); + // store received configurations + nr_secondary_cell_group_cfg_r15 = nr_secondary_cell_group_cfg_r15_; + nr_radio_bearer_cfg1_r15 = nr_radio_bearer_cfg1_r15_; + + logger.debug(nr_secondary_cell_group_cfg_r15.data(), + nr_secondary_cell_group_cfg_r15.size(), + "nr-SecondaryCellGroupConfig-r15:"); + logger.debug(nr_radio_bearer_cfg1_r15.data(), nr_radio_bearer_cfg1_r15.size(), "nr-RadioBearerConfig1-r15:"); + + sgnb_add_req_ack_ev sgnb_add_ack{}; + trigger(sgnb_add_ack); } void rrc::ue::rrc_endc::handle_sgnb_addition_reject() @@ -259,4 +276,9 @@ void rrc::ue::rrc_endc::handle_recfg_complete(wait_recfg_comp& s, const recfg_co logger.info("User rnti=0x%x successfully enabled EN-DC", rrc_ue->rnti); } +void rrc::ue::rrc_endc::handle_sgnb_addition_complete() +{ + logger.info("Received SgNB addition complete for rnti=%d", rrc_ue->rnti); +} + } // namespace srsenb diff --git a/srsenb/src/stack/rrc/rrc_mobility.cc b/srsenb/src/stack/rrc/rrc_mobility.cc index 2c4e93453..b4cd0008d 100644 --- a/srsenb/src/stack/rrc/rrc_mobility.cc +++ b/srsenb/src/stack/rrc/rrc_mobility.cc @@ -237,7 +237,7 @@ void rrc::ue::rrc_mobility::handle_ue_meas_report(const meas_report_s& msg, srsr } if (meas_res.meas_result_neigh_cells.type().value != meas_results_s::meas_result_neigh_cells_c_::types::meas_result_list_eutra) { - Error("MeasReports regarding non-EUTRA are not supported!"); + Info("Skipping MeasReport for non-EUTRA neighbor."); return; } const meas_id_list& measid_list = rrc_ue->current_ue_cfg.meas_cfg.meas_id_to_add_mod_list; diff --git a/srsenb/src/stack/rrc/rrc_nr.cc b/srsenb/src/stack/rrc/rrc_nr.cc index 732484ed8..2c90ddcb8 100644 --- a/srsenb/src/stack/rrc/rrc_nr.cc +++ b/srsenb/src/stack/rrc/rrc_nr.cc @@ -35,8 +35,8 @@ rrc_nr::rrc_nr(srsran::task_sched_handle task_sched_) : int rrc_nr::init(const rrc_nr_cfg_t& cfg_, phy_interface_stack_nr* phy_, mac_interface_rrc_nr* mac_, - rlc_interface_rrc_nr* rlc_, - pdcp_interface_rrc_nr* pdcp_, + rlc_interface_rrc* rlc_, + pdcp_interface_rrc* pdcp_, ngap_interface_rrc_nr* ngap_, gtpu_interface_rrc_nr* gtpu_, rrc_eutra_interface_rrc_nr* rrc_eutra_) @@ -45,8 +45,9 @@ int rrc_nr::init(const rrc_nr_cfg_t& cfg_, mac = mac_; rlc = rlc_; pdcp = pdcp_; - gtpu = gtpu_; ngap = ngap_; + gtpu = gtpu_; + rrc_eutra = rrc_eutra_; // TODO: overwriting because we are not passing config right now cfg = update_default_cfg(cfg_); @@ -65,22 +66,6 @@ int rrc_nr::init(const rrc_nr_cfg_t& cfg_, config_mac(); - // add dummy user - logger.info("Creating dummy DRB for RNTI=%d on LCID=%d", cfg.coreless.rnti, cfg.coreless.drb_lcid); - add_user(cfg.coreless.rnti); - srsran::rlc_config_t rlc_cnfg = srsran::rlc_config_t::default_rlc_um_nr_config(6); - rlc->add_bearer(cfg.coreless.rnti, cfg.coreless.drb_lcid, rlc_cnfg); - srsran::pdcp_config_t pdcp_cnfg{cfg.coreless.drb_lcid, - srsran::PDCP_RB_IS_DRB, - srsran::SECURITY_DIRECTION_DOWNLINK, - srsran::SECURITY_DIRECTION_UPLINK, - srsran::PDCP_SN_LEN_18, - srsran::pdcp_t_reordering_t::ms500, - srsran::pdcp_discard_timer_t::infinity, - false, - srsran::srsran_rat_t::nr}; - pdcp->add_bearer(cfg.coreless.rnti, cfg.coreless.drb_lcid, pdcp_cnfg); - logger.info("Started"); running = true; @@ -180,16 +165,46 @@ rrc_nr_cfg_t rrc_nr::update_default_cfg(const rrc_nr_cfg_t& current) } // This function is called from PRACH worker (can wait) -void rrc_nr::add_user(uint16_t rnti) +int rrc_nr::add_user(uint16_t rnti) { if (users.count(rnti) == 0) { users.insert(std::make_pair(rnti, std::unique_ptr(new ue(this, rnti)))); rlc->add_user(rnti); pdcp->add_user(rnti); logger.info("Added new user rnti=0x%x", rnti); + return SRSRAN_SUCCESS; } else { logger.error("Adding user rnti=0x%x (already exists)", rnti); + return SRSRAN_ERROR; + } +} + +/* Function called by MAC after the reception of a C-RNTI CE indicating that the UE still has a + * valid RNTI. + */ +int rrc_nr::update_user(uint16_t new_rnti, uint16_t old_rnti) +{ + // Remove new_rnti + auto new_ue_it = users.find(new_rnti); + if (new_ue_it != users.end()) { + // TODO: cleanup new user? + return SRSRAN_ERROR; + } + + // Send Reconfiguration to old_rnti if is RRC_CONNECT or RRC Release if already released here + auto old_it = users.find(old_rnti); + if (old_it == users.end()) { + logger.info("rnti=0x%x received MAC CRNTI CE: 0x%x, but old context is unavailable", new_rnti, old_rnti); + return SRSRAN_ERROR; + } + ue* ue_ptr = old_it->second.get(); + + // Assume that SgNB addition is running + logger.info("Resuming rnti=0x%x RRC connection due to received C-RNTI CE from rnti=0x%x.", old_rnti, new_rnti); + if (ue_ptr->is_connected()) { + rrc_eutra->sgnb_addition_complete(new_rnti); } + return SRSRAN_SUCCESS; } void rrc_nr::config_mac() @@ -364,15 +379,37 @@ void rrc_nr::notify_pdcp_integrity_error(uint16_t rnti, uint32_t lcid) {} Interface for EUTRA RRC *******************************************************************************/ -int rrc_nr::sgnb_addition_request(uint16_t rnti) +int rrc_nr::sgnb_addition_request(uint16_t eutra_rnti) { - // try to allocate new user - task_sched.defer_task([]() {}); + task_sched.defer_task([this, eutra_rnti]() { + // try to allocate new user + uint16_t nr_rnti = mac->reserve_rnti(); + if (nr_rnti == SRSRAN_INVALID_RNTI) { + logger.error("Failed to allocate RNTI at MAC"); + rrc_eutra->sgnb_addition_reject(eutra_rnti); + return; + } + + if (add_user(nr_rnti) != SRSRAN_SUCCESS) { + logger.error("Failed to allocate RNTI at RRC"); + rrc_eutra->sgnb_addition_reject(eutra_rnti); + return; + } + + // new RNTI is now registered at MAC and RRC + auto user_it = users.find(nr_rnti); + if (user_it == users.end()) { + logger.warning("Unrecognised rnti: 0x%x", nr_rnti); + return; + } + user_it->second->handle_sgnb_addition_request(eutra_rnti); + }); // return straight away return SRSRAN_SUCCESS; } -int rrc_nr::sgnb_reconfiguration_complete(uint16_t rnti, asn1::dyn_octstring reconfig_response) + +int rrc_nr::sgnb_reconfiguration_complete(uint16_t eutra_rnti, asn1::dyn_octstring reconfig_response) { return SRSRAN_SUCCESS; } @@ -385,13 +422,6 @@ int rrc_nr::sgnb_reconfiguration_complete(uint16_t rnti, asn1::dyn_octstring rec *******************************************************************************/ rrc_nr::ue::ue(rrc_nr* parent_, uint16_t rnti_) : parent(parent_), rnti(rnti_) { - // setup periodic RRCSetup send - rrc_setup_periodic_timer = parent->task_sched.get_unique_timer(); - rrc_setup_periodic_timer.set(5000, [this](uint32_t tid) { - send_connection_setup(); - rrc_setup_periodic_timer.run(); - }); - rrc_setup_periodic_timer.run(); } void rrc_nr::ue::send_connection_setup() @@ -436,25 +466,403 @@ void rrc_nr::ue::send_dl_ccch(dl_ccch_msg_s* dl_ccch_msg) parent->rlc->write_sdu(rnti, (uint32_t)srsran::nr_srb::srb0, std::move(pdu)); } -int rrc_nr::ue::handle_sgnb_addition_request() +// Helper for the RRC Reconfiguration sender to pack hard-coded config +int rrc_nr::ue::pack_secondary_cell_group_config(asn1::dyn_octstring& packed_secondary_cell_config) { - // provide hard-coded NR configs - asn1::dyn_octstring nr_config; + cell_group_cfg_s cell_group_cfg_pack; + cell_group_cfg_pack.sp_cell_cfg_present = true; + cell_group_cfg_pack.sp_cell_cfg.serv_cell_idx_present = true; + + // 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.init_dl_bwp_present = true; + + // PDCCH config + cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.init_dl_bwp.pdcch_cfg_present = true; + auto& pdcch_cfg_dedicated = cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.init_dl_bwp.pdcch_cfg; + pdcch_cfg_dedicated.set_setup(); + pdcch_cfg_dedicated.setup().ctrl_res_set_to_add_mod_list_present = true; + pdcch_cfg_dedicated.setup().ctrl_res_set_to_add_mod_list.resize(1); + pdcch_cfg_dedicated.setup().ctrl_res_set_to_add_mod_list[0].ctrl_res_set_id = 2; + pdcch_cfg_dedicated.setup().ctrl_res_set_to_add_mod_list[0].freq_domain_res.from_number( + 0b111111110000000000000000000000000000000000000); + pdcch_cfg_dedicated.setup().ctrl_res_set_to_add_mod_list[0].dur = 1; + pdcch_cfg_dedicated.setup().ctrl_res_set_to_add_mod_list[0].cce_reg_map_type.set_non_interleaved(); + pdcch_cfg_dedicated.setup().ctrl_res_set_to_add_mod_list[0].precoder_granularity = + asn1::rrc_nr::ctrl_res_set_s::precoder_granularity_opts::same_as_reg_bundle; + + cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.first_active_dl_bwp_id_present = true; + 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.ul_cfg_present = true; + + // search spaces + pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list_present = true; + pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list.resize(1); + pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list[0].search_space_id = 2; + pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list[0].ctrl_res_set_id_present = true; + pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list[0].ctrl_res_set_id = 2; + pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list[0].monitoring_slot_periodicity_and_offset_present = true; + pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list[0].monitoring_slot_periodicity_and_offset.set_sl1(); + pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list[0].monitoring_symbols_within_slot_present = true; + pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list[0].monitoring_symbols_within_slot.from_number( + 0b10000000000000); + pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list[0].nrof_candidates_present = true; + pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list[0].nrof_candidates.aggregation_level1 = + asn1::rrc_nr::search_space_s::nrof_candidates_s_::aggregation_level1_opts::n0; + pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list[0].nrof_candidates.aggregation_level2 = + asn1::rrc_nr::search_space_s::nrof_candidates_s_::aggregation_level2_opts::n2; + pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list[0].nrof_candidates.aggregation_level4 = + asn1::rrc_nr::search_space_s::nrof_candidates_s_::aggregation_level4_opts::n1; + pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list[0].nrof_candidates.aggregation_level8 = + asn1::rrc_nr::search_space_s::nrof_candidates_s_::aggregation_level8_opts::n0; + pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list[0].nrof_candidates.aggregation_level16 = + asn1::rrc_nr::search_space_s::nrof_candidates_s_::aggregation_level16_opts::n0; + pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list[0].search_space_type_present = true; + pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list[0].search_space_type.set_ue_specific(); + pdcch_cfg_dedicated.setup().search_spaces_to_add_mod_list[0].search_space_type.ue_specific().dci_formats = asn1:: + rrc_nr::search_space_s::search_space_type_c_::ue_specific_s_::dci_formats_opts::formats0_minus0_and_minus1_minus0; + + 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 = true; + 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(0x100); + 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 = true; + 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); + // pdsch_cfg_dedicated.setup().p_zp_csi_rs_res_set.setup().zp_csi_rs_res_id_list[0]= + // pdsch_cfg_dedicated.setup().p_zp_csi_rs_res_set.setup().zp_csi_rs_res_id_list + + cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg_present = true; + cell_group_cfg_pack.sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg.set_setup(); + + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync_present = true; + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.new_ue_id = 17943; + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.smtc.release(); + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.t304 = recfg_with_sync_s::t304_opts::ms1000; + + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common_present = true; + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ss_pbch_block_pwr = 0; + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.dmrs_type_a_position = + asn1::rrc_nr::serving_cell_cfg_common_s::dmrs_type_a_position_opts::pos2; + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.pci_present = true; + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.pci = 500; + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ssb_subcarrier_spacing_present = true; + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ssb_subcarrier_spacing = + subcarrier_spacing_opts::khz30; + + // DL config + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.dl_cfg_common_present = true; + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.dl_cfg_common.freq_info_dl_present = true; + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.dl_cfg_common.freq_info_dl + .absolute_freq_ssb_present = true; + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.dl_cfg_common.freq_info_dl.absolute_freq_ssb = + 632640; + + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.dl_cfg_common.freq_info_dl.freq_band_list + .push_back(78); + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.dl_cfg_common.freq_info_dl.absolute_freq_point_a = + 632316; + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.dl_cfg_common.freq_info_dl + .scs_specific_carrier_list.resize(1); + auto& dl_carrier = cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.dl_cfg_common.freq_info_dl + .scs_specific_carrier_list[0]; + dl_carrier.offset_to_carrier = 0; + dl_carrier.subcarrier_spacing = subcarrier_spacing_opts::khz15; + dl_carrier.carrier_bw = 52; + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.dl_cfg_common.init_dl_bwp_present = true; + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.dl_cfg_common.init_dl_bwp.generic_params + .location_and_bw = 14025; + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.dl_cfg_common.init_dl_bwp.generic_params + .subcarrier_spacing = subcarrier_spacing_opts::khz15; + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.dl_cfg_common.init_dl_bwp + .pdcch_cfg_common_present = true; + auto& pdcch_cfg_common = + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.dl_cfg_common.init_dl_bwp.pdcch_cfg_common; + pdcch_cfg_common.set_setup(); + pdcch_cfg_common.setup().ext = false; + pdcch_cfg_common.setup().common_ctrl_res_set_present = true; + pdcch_cfg_common.setup().common_ctrl_res_set.ctrl_res_set_id = 1; + pdcch_cfg_common.setup().common_ctrl_res_set.freq_domain_res.from_number( + 0b111111110000000000000000000000000000000000000); + pdcch_cfg_common.setup().common_ctrl_res_set.dur = 1; + pdcch_cfg_common.setup().common_ctrl_res_set.cce_reg_map_type.set_non_interleaved(); + pdcch_cfg_common.setup().common_ctrl_res_set.precoder_granularity = + asn1::rrc_nr::ctrl_res_set_s::precoder_granularity_opts::same_as_reg_bundle; + + // common search space list + pdcch_cfg_common.setup().common_search_space_list_present = true; + pdcch_cfg_common.setup().common_search_space_list.resize(1); + pdcch_cfg_common.setup().common_search_space_list[0].search_space_id = 1; + pdcch_cfg_common.setup().common_search_space_list[0].ctrl_res_set_id_present = true; + pdcch_cfg_common.setup().common_search_space_list[0].ctrl_res_set_id = 1; + pdcch_cfg_common.setup().common_search_space_list[0].search_space_type_present = true; + pdcch_cfg_common.setup().common_search_space_list[0].search_space_type.set_common(); + pdcch_cfg_common.setup() + .common_search_space_list[0] + .search_space_type.common() + .dci_format0_minus0_and_format1_minus0_present = true; + pdcch_cfg_common.setup().common_search_space_list[0].nrof_candidates_present = true; + pdcch_cfg_common.setup().common_search_space_list[0].nrof_candidates.aggregation_level1 = + asn1::rrc_nr::search_space_s::nrof_candidates_s_::aggregation_level1_opts::n1; + pdcch_cfg_common.setup().common_search_space_list[0].nrof_candidates.aggregation_level2 = + asn1::rrc_nr::search_space_s::nrof_candidates_s_::aggregation_level2_opts::n1; + pdcch_cfg_common.setup().common_search_space_list[0].nrof_candidates.aggregation_level4 = + asn1::rrc_nr::search_space_s::nrof_candidates_s_::aggregation_level4_opts::n1; + pdcch_cfg_common.setup().common_search_space_list[0].nrof_candidates.aggregation_level8 = + asn1::rrc_nr::search_space_s::nrof_candidates_s_::aggregation_level8_opts::n0; + pdcch_cfg_common.setup().common_search_space_list[0].nrof_candidates.aggregation_level16 = + asn1::rrc_nr::search_space_s::nrof_candidates_s_::aggregation_level16_opts::n0; + pdcch_cfg_common.setup().common_search_space_list[0].monitoring_slot_periodicity_and_offset_present = true; + pdcch_cfg_common.setup().common_search_space_list[0].monitoring_slot_periodicity_and_offset.set_sl1(); + pdcch_cfg_common.setup().common_search_space_list[0].monitoring_symbols_within_slot_present = true; + pdcch_cfg_common.setup().common_search_space_list[0].monitoring_symbols_within_slot.from_number(0b10000000000000); + pdcch_cfg_common.setup().ra_search_space_present = true; + pdcch_cfg_common.setup().ra_search_space = 1; + + // PDSCH config common + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.dl_cfg_common.init_dl_bwp + .pdsch_cfg_common_present = true; + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.dl_cfg_common.init_dl_bwp.pdsch_cfg_common + .set_setup(); + auto& pdsch_cfg_common = cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.dl_cfg_common.init_dl_bwp + .pdsch_cfg_common.setup(); + pdsch_cfg_common.pdsch_time_domain_alloc_list_present = true; + pdsch_cfg_common.pdsch_time_domain_alloc_list.resize(1); + pdsch_cfg_common.pdsch_time_domain_alloc_list[0].map_type = pdsch_time_domain_res_alloc_s::map_type_opts::type_a; + pdsch_cfg_common.pdsch_time_domain_alloc_list[0].start_symbol_and_len = 40; + + // UL config + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common_present = true; + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.dummy = time_align_timer_opts::ms500; + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.freq_info_ul_present = true; + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.freq_info_ul + .scs_specific_carrier_list.resize(1); + auto& ul_carrier = cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.freq_info_ul + .scs_specific_carrier_list[0]; + ul_carrier.offset_to_carrier = 0; + ul_carrier.subcarrier_spacing = subcarrier_spacing_opts::khz15; + ul_carrier.carrier_bw = 52; + + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.init_ul_bwp_present = true; + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.init_ul_bwp.generic_params + .location_and_bw = 14025; + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.init_ul_bwp.generic_params + .subcarrier_spacing = subcarrier_spacing_opts::khz15; + + // RACH config + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.init_ul_bwp.rach_cfg_common_present = + true; + auto& rach_cfg_common_pack = + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.init_ul_bwp.rach_cfg_common; + + rach_cfg_common_pack.set_setup(); + rach_cfg_common_pack.setup().rach_cfg_generic.prach_cfg_idx = 0; + rach_cfg_common_pack.setup().rach_cfg_generic.msg1_fdm = rach_cfg_generic_s::msg1_fdm_opts::one; + rach_cfg_common_pack.setup().rach_cfg_generic.msg1_freq_start = 1; + rach_cfg_common_pack.setup().rach_cfg_generic.zero_correlation_zone_cfg = 0; + rach_cfg_common_pack.setup().rach_cfg_generic.preamb_rx_target_pwr = -110; + rach_cfg_common_pack.setup().rach_cfg_generic.preamb_trans_max = + asn1::rrc_nr::rach_cfg_generic_s::preamb_trans_max_opts::n7; + rach_cfg_common_pack.setup().rach_cfg_generic.pwr_ramp_step = + asn1::rrc_nr::rach_cfg_generic_s::pwr_ramp_step_opts::db4; + rach_cfg_common_pack.setup().rach_cfg_generic.ra_resp_win = asn1::rrc_nr::rach_cfg_generic_s::ra_resp_win_opts::sl10; + rach_cfg_common_pack.setup().ra_contention_resolution_timer = + asn1::rrc_nr::rach_cfg_common_s::ra_contention_resolution_timer_opts::sf64; + rach_cfg_common_pack.setup().prach_root_seq_idx.set( + asn1::rrc_nr::rach_cfg_common_s::prach_root_seq_idx_c_::types_opts::l839); + rach_cfg_common_pack.setup().prach_root_seq_idx.set_l839() = 1; + rach_cfg_common_pack.setup().restricted_set_cfg = + asn1::rrc_nr::rach_cfg_common_s::restricted_set_cfg_opts::unrestricted_set; + + // PUSCH config common + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.init_ul_bwp + .pusch_cfg_common_present = true; + auto& pusch_cfg_common_pack = + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.init_ul_bwp.pusch_cfg_common; + pusch_cfg_common_pack.set_setup(); + pusch_cfg_common_pack.setup().pusch_time_domain_alloc_list_present = true; + pusch_cfg_common_pack.setup().pusch_time_domain_alloc_list.resize(2); + pusch_cfg_common_pack.setup().pusch_time_domain_alloc_list[0].k2_present = true; + pusch_cfg_common_pack.setup().pusch_time_domain_alloc_list[0].k2 = 4; + pusch_cfg_common_pack.setup().pusch_time_domain_alloc_list[0].map_type = + asn1::rrc_nr::pusch_time_domain_res_alloc_s::map_type_opts::type_a; + pusch_cfg_common_pack.setup().pusch_time_domain_alloc_list[0].start_symbol_and_len = 27; + pusch_cfg_common_pack.setup().pusch_time_domain_alloc_list[1].k2_present = true; + pusch_cfg_common_pack.setup().pusch_time_domain_alloc_list[1].k2 = 3; + pusch_cfg_common_pack.setup().pusch_time_domain_alloc_list[1].map_type = + asn1::rrc_nr::pusch_time_domain_res_alloc_s::map_type_opts::type_a; + pusch_cfg_common_pack.setup().pusch_time_domain_alloc_list[1].start_symbol_and_len = 27; + pusch_cfg_common_pack.setup().p0_nominal_with_grant = -90; + + // PUCCH config common + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.init_ul_bwp + .pucch_cfg_common_present = true; + auto& pucch_cfg_common_pack = + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ul_cfg_common.init_ul_bwp.pucch_cfg_common; + pucch_cfg_common_pack.set_setup(); + pucch_cfg_common_pack.setup().pucch_group_hop = asn1::rrc_nr::pucch_cfg_common_s::pucch_group_hop_opts::neither; + pucch_cfg_common_pack.setup().p0_nominal_present = true; + pucch_cfg_common_pack.setup().p0_nominal = -90; + + // SSB config (optional) + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ssb_positions_in_burst_present = true; + auto& ssb_pos_in_burst = cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ssb_positions_in_burst; + ssb_pos_in_burst.set_medium_bitmap().from_number(0b10000000); + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ssb_periodicity_serving_cell_present = true; + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.ssb_periodicity_serving_cell = + serving_cell_cfg_common_s::ssb_periodicity_serving_cell_opts::ms20; + + // TDD UL-DL config + cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.tdd_ul_dl_cfg_common_present = true; + auto& tdd_config = cell_group_cfg_pack.sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.tdd_ul_dl_cfg_common; + tdd_config.ref_subcarrier_spacing = subcarrier_spacing_e::khz15; + tdd_config.pattern1.dl_ul_tx_periodicity = asn1::rrc_nr::tdd_ul_dl_pattern_s::dl_ul_tx_periodicity_opts::ms10; + tdd_config.pattern1.nrof_dl_slots = 6; + tdd_config.pattern1.nrof_dl_symbols = 0; + tdd_config.pattern1.nrof_ul_slots = 3; + tdd_config.pattern1.nrof_ul_symbols = 0; + + // make sufficiant space + 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"); + return SRSRAN_ERROR; + } + packed_secondary_cell_config.resize(bref_pack.distance_bytes()); + + return SRSRAN_SUCCESS; +} +// Packs a hard-coded RRC Reconfiguration with fixed params for all layers (for now) +int rrc_nr::ue::pack_rrc_reconfiguraiton(asn1::dyn_octstring& packed_rrc_reconfig) +{ rrc_recfg_s reconfig; reconfig.rrc_transaction_id = ((transaction_id++) % 4u); rrc_recfg_ies_s& recfg_ies = reconfig.crit_exts.set_rrc_recfg(); - recfg_ies.radio_bearer_cfg_present = true; - recfg_ies.radio_bearer_cfg.drb_to_add_mod_list_present = true; - recfg_ies.radio_bearer_cfg.drb_to_release_list.resize(1); - // recfg_ies.radio_bearer_cfg.drb_to_release_list[0].set_eps_bearer_id(5); + // add secondary cell group config + recfg_ies.secondary_cell_group_present = true; + if (pack_secondary_cell_group_config(recfg_ies.secondary_cell_group) == SRSRAN_ERROR) { + parent->logger.error("Failed to pack RRC Reconfiguration"); + return SRSRAN_ERROR; + } + + // now pack .. + 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"); + return SRSRAN_ERROR; + } + packed_rrc_reconfig.resize(bref_pack.distance_bytes()); + + return SRSRAN_SUCCESS; +} + +// Packs a hard-coded NR radio bearer config with fixed params for RLC/PDCP (for now) +int rrc_nr::ue::pack_nr_radio_bearer_config(asn1::dyn_octstring& packed_nr_bearer_config) +{ + radio_bearer_cfg_s radio_bearer_cfg; + radio_bearer_cfg.drb_to_add_mod_list_present = true; + radio_bearer_cfg.drb_to_add_mod_list.resize(1); + + // configure fixed DRB1 + auto& drb_item = radio_bearer_cfg.drb_to_add_mod_list[0]; + drb_item.drb_id = 1; + drb_item.cn_assoc_present = true; + drb_item.cn_assoc.set_eps_bearer_id() = 5; + drb_item.pdcp_cfg_present = true; + drb_item.pdcp_cfg.ciphering_disabled_present = true; + drb_item.pdcp_cfg.drb_present = true; + drb_item.pdcp_cfg.drb.pdcp_sn_size_dl_present = true; + drb_item.pdcp_cfg.drb.pdcp_sn_size_dl = asn1::rrc_nr::pdcp_cfg_s::drb_s_::pdcp_sn_size_dl_opts::len18bits; + drb_item.pdcp_cfg.drb.pdcp_sn_size_ul_present = true; + drb_item.pdcp_cfg.drb.pdcp_sn_size_ul = asn1::rrc_nr::pdcp_cfg_s::drb_s_::pdcp_sn_size_ul_opts::len18bits; + drb_item.pdcp_cfg.drb.discard_timer_present = true; + drb_item.pdcp_cfg.drb.discard_timer = asn1::rrc_nr::pdcp_cfg_s::drb_s_::discard_timer_opts::ms100; + drb_item.pdcp_cfg.drb.hdr_compress.set_not_used(); + drb_item.pdcp_cfg.t_reordering_present = true; + drb_item.pdcp_cfg.t_reordering = asn1::rrc_nr::pdcp_cfg_s::t_reordering_opts::ms0; + + radio_bearer_cfg.security_cfg_present = true; + radio_bearer_cfg.security_cfg.key_to_use_present = true; + radio_bearer_cfg.security_cfg.key_to_use = asn1::rrc_nr::security_cfg_s::key_to_use_opts::secondary; + radio_bearer_cfg.security_cfg.security_algorithm_cfg_present = true; + radio_bearer_cfg.security_cfg.security_algorithm_cfg.ciphering_algorithm = ciphering_algorithm_opts::nea2; + + // pack it + 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(bref_pack) != asn1::SRSASN_SUCCESS) { + parent->logger.error("Failed to pack NR radio bearer config"); + return SRSRAN_ERROR; + } + + // resize to packed length + packed_nr_bearer_config.resize(bref_pack.distance_bytes()); - // TODO: fill configs + return SRSRAN_SUCCESS; +} + +int rrc_nr::ue::handle_sgnb_addition_request(uint16_t eutra_rnti) +{ + // provide hard-coded NR configs asn1::dyn_octstring nr_secondary_cell_group_cfg; - asn1::dyn_octstring nr_radio_bearer_config; + if (pack_rrc_reconfiguraiton(nr_secondary_cell_group_cfg) == SRSRAN_ERROR) { + parent->logger.error("Failed to pack RRC Reconfiguration. Sending SgNB addition reject."); + parent->rrc_eutra->sgnb_addition_reject(eutra_rnti); + return SRSRAN_ERROR; + } + + asn1::dyn_octstring radio_bearer_config_buffer; + if (pack_nr_radio_bearer_config(radio_bearer_config_buffer) == SRSRAN_ERROR) { + parent->logger.error("Failed to pack NR radio bearer config. Sending SgNB addition reject."); + parent->rrc_eutra->sgnb_addition_reject(eutra_rnti); + return SRSRAN_ERROR; + } - parent->rrc_eutra->sgnb_addition_ack(rnti, nr_secondary_cell_group_cfg, nr_radio_bearer_config); + // send response to EUTRA + parent->rrc_eutra->sgnb_addition_ack(eutra_rnti, nr_secondary_cell_group_cfg, radio_bearer_config_buffer); return SRSRAN_SUCCESS; } diff --git a/srsenb/src/stack/rrc/rrc_ue.cc b/srsenb/src/stack/rrc/rrc_ue.cc index 3292ce8be..7e89e16a5 100644 --- a/srsenb/src/stack/rrc/rrc_ue.cc +++ b/srsenb/src/stack/rrc/rrc_ue.cc @@ -1167,18 +1167,6 @@ void rrc::ue::update_scells() parent->logger.info("SCells activated for rnti=0x%x", rnti); } -/// EN-DC helper -void rrc::ue::handle_sgnb_addition_ack(const asn1::dyn_octstring& nr_secondary_cell_group_cfg_r15, - const asn1::dyn_octstring& nr_radio_bearer_cfg1_r15) -{ - endc_handler->handle_sgnb_addition_ack(nr_secondary_cell_group_cfg_r15, nr_radio_bearer_cfg1_r15); -} - -void rrc::ue::handle_sgnb_addition_reject() -{ - endc_handler->handle_sgnb_addition_reject(); -} - /********************** HELPERS ***************************/ void rrc::ue::send_dl_ccch(dl_ccch_msg_s* dl_ccch_msg, std::string* octet_str) diff --git a/srsenb/test/common/dummy_classes.h b/srsenb/test/common/dummy_classes.h index ef2d73908..04af904bd 100644 --- a/srsenb/test/common/dummy_classes.h +++ b/srsenb/test/common/dummy_classes.h @@ -25,7 +25,6 @@ #include "srsran/interfaces/enb_gtpu_interfaces.h" #include "srsran/interfaces/enb_interfaces.h" #include "srsran/interfaces/enb_mac_interfaces.h" -#include "srsran/interfaces/enb_pdcp_interfaces.h" #include "srsran/interfaces/enb_phy_interfaces.h" #include "srsran/interfaces/enb_rlc_interfaces.h" #include "srsran/interfaces/enb_rrc_interfaces.h" @@ -54,45 +53,6 @@ public: uint16_t last_rnti = 70; }; -class rlc_dummy : public rlc_interface_rrc -{ -public: - void clear_buffer(uint16_t rnti) override {} - void add_user(uint16_t rnti) override {} - void rem_user(uint16_t rnti) override {} - void add_bearer(uint16_t rnti, uint32_t lcid, srsran::rlc_config_t cnfg) override {} - void add_bearer_mrb(uint16_t rnti, uint32_t lcid) override {} - void del_bearer(uint16_t rnti, uint32_t lcid) override {} - void write_sdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t sdu) override {} - bool has_bearer(uint16_t rnti, uint32_t lcid) override { return false; } - bool suspend_bearer(uint16_t rnti, uint32_t lcid) override { return true; } - bool resume_bearer(uint16_t rnti, uint32_t lcid) override { return true; } - void reestablish(uint16_t rnti) override {} -}; - -class pdcp_dummy : public pdcp_interface_rrc, public pdcp_interface_gtpu -{ -public: - void reset(uint16_t rnti) override {} - void add_user(uint16_t rnti) override {} - void rem_user(uint16_t rnti) override {} - void write_sdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t sdu, int pdcp_sn) override {} - void add_bearer(uint16_t rnti, uint32_t lcid, srsran::pdcp_config_t cnfg) override {} - void del_bearer(uint16_t rnti, uint32_t lcid) override {} - void config_security(uint16_t rnti, uint32_t lcid, srsran::as_security_config_t sec_cfg_) override {} - void enable_integrity(uint16_t rnti, uint32_t lcid) override {} - void enable_encryption(uint16_t rnti, uint32_t lcid) override {} - bool get_bearer_state(uint16_t rnti, uint32_t lcid, srsran::pdcp_lte_state_t* state) override { return true; } - bool set_bearer_state(uint16_t rnti, uint32_t lcid, const srsran::pdcp_lte_state_t& state) override { return true; } - void reestablish(uint16_t rnti) override {} - void send_status_report(uint16_t rnti) override {} - void send_status_report(uint16_t rnti, uint32_t lcid) override {} - std::map get_buffered_pdus(uint16_t rnti, uint32_t lcid) override - { - return {}; - } -}; - class s1ap_dummy : public s1ap_interface_rrc { public: diff --git a/srsenb/test/common/dummy_classes_common.h b/srsenb/test/common/dummy_classes_common.h new file mode 100644 index 000000000..f376f672b --- /dev/null +++ b/srsenb/test/common/dummy_classes_common.h @@ -0,0 +1,64 @@ +/** + * + * \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 SRSENB_DUMMY_CLASSES_COMMON_H +#define SRSENB_DUMMY_CLASSES_COMMON_H + +#include "srsran/interfaces/enb_pdcp_interfaces.h" +#include "srsran/interfaces/enb_rlc_interfaces.h" + +namespace srsenb { + +class rlc_dummy : public rlc_interface_rrc +{ +public: + void clear_buffer(uint16_t rnti) override {} + void add_user(uint16_t rnti) override {} + void rem_user(uint16_t rnti) override {} + void add_bearer(uint16_t rnti, uint32_t lcid, srsran::rlc_config_t cnfg) override {} + void add_bearer_mrb(uint16_t rnti, uint32_t lcid) override {} + void del_bearer(uint16_t rnti, uint32_t lcid) override {} + void write_sdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t sdu) override { last_sdu = std::move(sdu); } + bool has_bearer(uint16_t rnti, uint32_t lcid) override { return false; } + bool suspend_bearer(uint16_t rnti, uint32_t lcid) override { return true; } + bool resume_bearer(uint16_t rnti, uint32_t lcid) override { return true; } + void reestablish(uint16_t rnti) override {} + + srsran::unique_byte_buffer_t last_sdu; +}; + +class pdcp_dummy : public pdcp_interface_rrc, public pdcp_interface_gtpu +{ +public: + void reset(uint16_t rnti) override {} + void add_user(uint16_t rnti) override {} + void rem_user(uint16_t rnti) override {} + void write_sdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t sdu, int pdcp_sn) override {} + void add_bearer(uint16_t rnti, uint32_t lcid, srsran::pdcp_config_t cnfg) override {} + void del_bearer(uint16_t rnti, uint32_t lcid) override {} + void config_security(uint16_t rnti, uint32_t lcid, srsran::as_security_config_t sec_cfg_) override {} + void enable_integrity(uint16_t rnti, uint32_t lcid) override {} + void enable_encryption(uint16_t rnti, uint32_t lcid) override {} + bool get_bearer_state(uint16_t rnti, uint32_t lcid, srsran::pdcp_lte_state_t* state) override { return true; } + bool set_bearer_state(uint16_t rnti, uint32_t lcid, const srsran::pdcp_lte_state_t& state) override { return true; } + void reestablish(uint16_t rnti) override {} + void send_status_report(uint16_t rnti) override {} + void send_status_report(uint16_t rnti, uint32_t lcid) override {} + std::map get_buffered_pdus(uint16_t rnti, uint32_t lcid) override + { + return {}; + } +}; + +} // namespace srsenb + +#endif // SRSENB_DUMMY_CLASSES_COMMON_H diff --git a/srsenb/test/common/dummy_classes_nr.h b/srsenb/test/common/dummy_classes_nr.h new file mode 100644 index 000000000..4237aebe2 --- /dev/null +++ b/srsenb/test/common/dummy_classes_nr.h @@ -0,0 +1,35 @@ +/** + * + * \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_DUMMY_NR_CLASSES_H +#define SRSRAN_DUMMY_NR_CLASSES_H + +#include "srsran/interfaces/gnb_interfaces.h" + +namespace srsenb { + +class mac_dummy : public mac_interface_rrc_nr +{ +public: + int cell_cfg(srsenb::sched_interface::cell_cfg_t* cell_cfg_) + { + cellcfgobj = *cell_cfg_; + return SRSRAN_SUCCESS; + } + uint16_t reserve_rnti() { return 0x4601; } + + srsenb::sched_interface::cell_cfg_t cellcfgobj; +}; + +} // namespace srsenb + +#endif // SRSRAN_DUMMY_NR_CLASSES_H diff --git a/srsenb/test/common/dummy_nr_classes.h b/srsenb/test/common/dummy_nr_classes.h deleted file mode 100644 index fee395dba..000000000 --- a/srsenb/test/common/dummy_nr_classes.h +++ /dev/null @@ -1,69 +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_DUMMY_NR_CLASSES_H -#define SRSRAN_DUMMY_NR_CLASSES_H - -#include "srsran/interfaces/gnb_interfaces.h" - -namespace srsenb { - -class mac_dummy : public mac_interface_rrc_nr -{ -public: - int cell_cfg(srsenb::sched_interface::cell_cfg_t* cell_cfg_) - { - cellcfgobj = *cell_cfg_; - return SRSRAN_SUCCESS; - } - - srsenb::sched_interface::cell_cfg_t cellcfgobj; -}; - -class rlc_dummy : public rlc_interface_rrc_nr -{ -public: - void clear_buffer(uint16_t rnti) override {} - void add_user(uint16_t rnti) override {} - void rem_user(uint16_t rnti) override {} - void add_bearer(uint16_t rnti, uint32_t lcid, srsran::rlc_config_t cnfg) override {} - void add_bearer_mrb(uint16_t rnti, uint32_t lcid) override {} - void write_sdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t sdu) override { last_sdu = std::move(sdu); } - - srsran::unique_byte_buffer_t last_sdu; -}; - -class pdcp_dummy : public pdcp_interface_rrc_nr -{ -public: - void reset(uint16_t rnti) override {} - void add_user(uint16_t rnti) override {} - void rem_user(uint16_t rnti) override {} - void write_sdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t sdu) override {} - void add_bearer(uint16_t rnti, uint32_t lcid, srsran::pdcp_config_t cnfg) override {} - void config_security(uint16_t rnti, uint32_t lcid, srsran::as_security_config_t sec_cfg) override {} - void enable_integrity(uint16_t rnti, uint32_t lcid) override {} - void enable_encryption(uint16_t rnti, uint32_t lcid) override {} -}; - -} // namespace srsenb - -#endif // SRSRAN_DUMMY_NR_CLASSES_H diff --git a/srsenb/test/mac/nr/sched_nr_cfg_generators.h b/srsenb/test/mac/nr/sched_nr_cfg_generators.h new file mode 100644 index 000000000..1c6c84edc --- /dev/null +++ b/srsenb/test/mac/nr/sched_nr_cfg_generators.h @@ -0,0 +1,96 @@ +/** + * + * \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_SCHED_NR_CFG_GENERATORS_H +#define SRSRAN_SCHED_NR_CFG_GENERATORS_H + +#include "srsenb/hdr/stack/mac/nr/sched_nr_interface.h" +#include "srsran/common/phy_cfg_nr_default.h" + +namespace srsenb { + +srsran_coreset_t get_default_coreset0() +{ + srsran_coreset_t coreset{}; + coreset.id = 0; + coreset.duration = 1; + coreset.precoder_granularity = srsran_coreset_precoder_granularity_reg_bundle; + for (uint32_t i = 0; i < SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE; ++i) { + coreset.freq_resources[i] = i < 8; + } + return coreset; +} + +sched_nr_interface::cell_cfg_t get_default_cell_cfg(const srsran::phy_cfg_nr_t& phy_cfg) +{ + sched_nr_interface::cell_cfg_t cell_cfg{}; + + cell_cfg.carrier = phy_cfg.carrier; + cell_cfg.tdd = phy_cfg.tdd; + + cell_cfg.bwps.resize(1); + cell_cfg.bwps[0].pdcch = phy_cfg.pdcch; + cell_cfg.bwps[0].pdsch = phy_cfg.pdsch; + cell_cfg.bwps[0].pusch = phy_cfg.pusch; + cell_cfg.bwps[0].rb_width = phy_cfg.carrier.nof_prb; + + cell_cfg.bwps[0].pdcch.coreset_present[0] = true; + cell_cfg.bwps[0].pdcch.coreset[0] = get_default_coreset0(); + cell_cfg.bwps[0].pdcch.search_space_present[0] = true; + auto& ss = cell_cfg.bwps[0].pdcch.search_space[0]; + ss.id = 0; + ss.coreset_id = 0; + ss.duration = 1; + ss.type = srsran_search_space_type_common_0; + ss.nof_candidates[0] = 1; + ss.nof_candidates[1] = 1; + ss.nof_candidates[2] = 1; + ss.nof_candidates[3] = 0; + ss.nof_candidates[4] = 0; + ss.nof_formats = 1; + ss.formats[0] = srsran_dci_format_nr_1_0; + cell_cfg.bwps[0].pdcch.ra_search_space_present = true; + cell_cfg.bwps[0].pdcch.ra_search_space = cell_cfg.bwps[0].pdcch.search_space[1]; + + return cell_cfg; +} + +std::vector get_default_cells_cfg( + uint32_t nof_sectors, + const srsran::phy_cfg_nr_t& phy_cfg = srsran::phy_cfg_nr_default_t{srsran::phy_cfg_nr_default_t::reference_cfg_t{}}) +{ + std::vector cells; + cells.reserve(nof_sectors); + for (uint32_t i = 0; i < nof_sectors; ++i) { + cells.push_back(get_default_cell_cfg(phy_cfg)); + } + return cells; +} + +sched_nr_interface::ue_cfg_t get_default_ue_cfg(uint32_t nof_cc, + const srsran::phy_cfg_nr_t& phy_cfg = srsran::phy_cfg_nr_default_t{ + srsran::phy_cfg_nr_default_t::reference_cfg_t{}}) +{ + sched_nr_interface::ue_cfg_t uecfg{}; + uecfg.carriers.resize(nof_cc); + for (uint32_t cc = 0; cc < nof_cc; ++cc) { + uecfg.carriers[cc].cc = cc; + uecfg.carriers[cc].active = true; + } + uecfg.phy_cfg = phy_cfg; + + return uecfg; +} + +} // namespace srsenb + +#endif // SRSRAN_SCHED_NR_CFG_GENERATORS_H diff --git a/srsenb/test/mac/nr/sched_nr_test.cc b/srsenb/test/mac/nr/sched_nr_test.cc index d4fd4d1d4..1bbeca14a 100644 --- a/srsenb/test/mac/nr/sched_nr_test.cc +++ b/srsenb/test/mac/nr/sched_nr_test.cc @@ -19,6 +19,7 @@ * */ +#include "sched_nr_cfg_generators.h" #include "sched_nr_sim_ue.h" #include "srsenb/hdr/stack/mac/nr/sched_nr.h" #include "srsran/common/phy_cfg_nr_default.h" @@ -33,72 +34,6 @@ using dl_sched_t = sched_nr_interface::dl_sched_t; static const srsran::phy_cfg_nr_t default_phy_cfg = srsran::phy_cfg_nr_default_t{srsran::phy_cfg_nr_default_t::reference_cfg_t{}}; -srsran_coreset_t get_default_coreset0() -{ - srsran_coreset_t coreset{}; - coreset.id = 0; - coreset.duration = 1; - coreset.precoder_granularity = srsran_coreset_precoder_granularity_reg_bundle; - for (uint32_t i = 0; i < SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE; ++i) { - coreset.freq_resources[i] = i < 8; - } - return coreset; -} - -sched_nr_interface::cell_cfg_t get_default_cell_cfg() -{ - sched_nr_interface::cell_cfg_t cell_cfg{}; - - cell_cfg.carrier = default_phy_cfg.carrier; - cell_cfg.tdd = default_phy_cfg.tdd; - - cell_cfg.bwps.resize(1); - cell_cfg.bwps[0].pdcch = default_phy_cfg.pdcch; - cell_cfg.bwps[0].pdsch = default_phy_cfg.pdsch; - cell_cfg.bwps[0].rb_width = default_phy_cfg.carrier.nof_prb; - - cell_cfg.bwps[0].pdcch.coreset_present[0] = true; - cell_cfg.bwps[0].pdcch.coreset[0] = get_default_coreset0(); - cell_cfg.bwps[0].pdcch.search_space_present[0] = true; - auto& ss = cell_cfg.bwps[0].pdcch.search_space[0]; - ss.id = 0; - ss.coreset_id = 0; - ss.duration = 1; - ss.type = srsran_search_space_type_common_0; - ss.nof_candidates[0] = 1; - ss.nof_candidates[1] = 1; - ss.nof_candidates[2] = 1; - ss.nof_candidates[3] = 0; - ss.nof_candidates[4] = 0; - ss.nof_formats = 1; - ss.formats[0] = srsran_dci_format_nr_1_0; - cell_cfg.bwps[0].pdcch.ra_search_space_present = true; - cell_cfg.bwps[0].pdcch.ra_search_space = cell_cfg.bwps[0].pdcch.search_space[1]; - - return cell_cfg; -} -std::vector get_default_cells_cfg(uint32_t nof_sectors) -{ - std::vector cells; - cells.reserve(nof_sectors); - for (uint32_t i = 0; i < nof_sectors; ++i) { - cells.push_back(get_default_cell_cfg()); - } - return cells; -} - -sched_nr_interface::ue_cfg_t get_default_ue_cfg(uint32_t nof_cc) -{ - sched_nr_interface::ue_cfg_t uecfg{}; - uecfg.carriers.resize(nof_cc); - for (uint32_t cc = 0; cc < nof_cc; ++cc) { - uecfg.carriers[cc].active = true; - } - uecfg.phy_cfg = default_phy_cfg; - - return uecfg; -} - struct task_job_manager { std::mutex mutex; int res_count = 0; @@ -151,7 +86,7 @@ struct task_job_manager { void sched_nr_cfg_serialized_test() { - uint32_t max_nof_ttis = 1000, nof_sectors = 2; + uint32_t max_nof_ttis = 1000, nof_sectors = 4; task_job_manager tasks; sched_nr_interface::sched_cfg_t cfg; @@ -159,8 +94,9 @@ void sched_nr_cfg_serialized_test() sched_nr_sim_base sched_tester(cfg, cells_cfg, "Serialized Test"); - sched_nr_interface::ue_cfg_t uecfg = get_default_ue_cfg(2); - + sched_nr_interface::ue_cfg_t uecfg = get_default_ue_cfg(nof_sectors); + uecfg.fixed_dl_mcs = 15; + uecfg.fixed_ul_mcs = 15; sched_tester.add_user(0x46, uecfg, 0); std::vector count_per_cc(nof_sectors, 0); @@ -197,7 +133,7 @@ void sched_nr_cfg_serialized_test() void sched_nr_cfg_parallel_cc_test() { - uint32_t nof_sectors = 2; + uint32_t nof_sectors = 4; uint32_t max_nof_ttis = 1000; task_job_manager tasks; @@ -207,6 +143,8 @@ void sched_nr_cfg_parallel_cc_test() sched_nr_sim_base sched_tester(cfg, cells_cfg, "Parallel CC Test"); sched_nr_interface::ue_cfg_t uecfg = get_default_ue_cfg(cells_cfg.size()); + uecfg.fixed_dl_mcs = 15; + uecfg.fixed_ul_mcs = 15; sched_tester.add_user(0x46, uecfg, 0); std::array, SRSRAN_MAX_CARRIERS> nano_count{}; @@ -245,64 +183,14 @@ void sched_nr_cfg_parallel_cc_test() printf("Total time taken per slot [usec]: %f\n", final_avg_usec); } -void sched_nr_cfg_parallel_sf_test() -{ - uint32_t max_nof_ttis = 1000; - uint32_t nof_sectors = 2; - task_job_manager tasks; - - sched_nr_interface::sched_cfg_t cfg; - cfg.nof_concurrent_subframes = 2; - std::vector cells_cfg = get_default_cells_cfg(nof_sectors); - - sched_nr_sim_base sched_tester(cfg, cells_cfg, "Parallel SF Test"); - - sched_nr_interface::ue_cfg_t uecfg = get_default_ue_cfg(cells_cfg.size()); - sched_tester.add_user(0x46, uecfg, 0); - - std::array, SRSRAN_MAX_CARRIERS> nano_count{}; - for (uint32_t nof_ttis = 0; nof_ttis < max_nof_ttis; ++nof_ttis) { - tti_point tti_rx(nof_ttis % 10240); - tti_point tti_tx = tti_rx + TX_ENB_DELAY; - tasks.start_slot(tti_tx, nof_sectors); - sched_tester.new_slot(tti_tx); - for (uint32_t cc = 0; cc < cells_cfg.size(); ++cc) { - srsran::get_background_workers().push_task([cc, tti_tx, &sched_tester, &tasks, &nano_count]() { - sched_nr_interface::dl_sched_t dl_res; - sched_nr_interface::ul_sched_t ul_res; - auto tp1 = std::chrono::steady_clock::now(); - TESTASSERT(sched_tester.get_sched()->get_dl_sched(tti_tx, cc, dl_res) == SRSRAN_SUCCESS); - TESTASSERT(sched_tester.get_sched()->get_ul_sched(tti_tx, cc, ul_res) == SRSRAN_SUCCESS); - auto tp2 = std::chrono::steady_clock::now(); - nano_count[cc].fetch_add(std::chrono::duration_cast(tp2 - tp1).count(), - std::memory_order_relaxed); - sched_nr_cc_output_res_t out{tti_tx, cc, &dl_res, &ul_res}; - sched_tester.update(out); - tasks.finish_cc(tti_tx, dl_res, ul_res); - }); - } - } - - tasks.wait_task_finish(); - - tasks.print_results(); - - double final_avg_usec = 0; - for (uint32_t i = 0; i < nof_sectors; ++i) { - final_avg_usec += nano_count[i]; - } - final_avg_usec = final_avg_usec / 1000.0 / max_nof_ttis / nof_sectors; - printf("Total time taken per slot [usec]: %f\n", final_avg_usec); -} - } // namespace srsenb int main() { auto& test_logger = srslog::fetch_basic_logger("TEST"); - test_logger.set_level(srslog::basic_levels::info); + test_logger.set_level(srslog::basic_levels::warning); auto& mac_logger = srslog::fetch_basic_logger("MAC"); - mac_logger.set_level(srslog::basic_levels::info); + mac_logger.set_level(srslog::basic_levels::warning); auto& pool_logger = srslog::fetch_basic_logger("POOL"); pool_logger.set_level(srslog::basic_levels::info); @@ -313,5 +201,4 @@ int main() srsenb::sched_nr_cfg_serialized_test(); srsenb::sched_nr_cfg_parallel_cc_test(); - srsenb::sched_nr_cfg_parallel_sf_test(); } \ No newline at end of file diff --git a/srsenb/test/mac/sched_common_test_suite.cc b/srsenb/test/mac/sched_common_test_suite.cc index 3205cca32..6b7d52504 100644 --- a/srsenb/test/mac/sched_common_test_suite.cc +++ b/srsenb/test/mac/sched_common_test_suite.cc @@ -48,7 +48,7 @@ int test_pusch_collisions(const sf_output_res_t& sf_out, uint32_t enb_cc_idx, co /* TEST: Check if there is space for PRACH */ bool is_prach_tti_tx_ul = - srsran_prach_tti_opportunity_config_fdd(cell_params.cfg.prach_config, to_tx_ul(sf_out.tti_rx).to_uint(), -1); + srsran_prach_in_window_config_fdd(cell_params.cfg.prach_config, to_tx_ul(sf_out.tti_rx).to_uint(), -1); if (is_prach_tti_tx_ul) { try_ul_fill({cell_params.cfg.prach_freq_offset, cell_params.cfg.prach_freq_offset + 6}, "PRACH"); } @@ -131,8 +131,7 @@ int test_pdsch_collisions(const sf_output_res_t& sf_out, uint32_t enb_cc_idx, co // forbid Data in DL if its ACKs conflict with PRACH for PRB==6 if (cell_params.nof_prb() == 6) { - if (srsran_prach_tti_opportunity_config_fdd( - cell_params.cfg.prach_config, to_tx_dl_ack(sf_out.tti_rx).to_uint(), -1)) { + if (srsran_prach_in_window_config_fdd(cell_params.cfg.prach_config, to_tx_dl_ack(sf_out.tti_rx).to_uint(), -1)) { dl_allocs.fill(0, dl_allocs.size()); } } diff --git a/srsenb/test/phy/enb_phy_test.cc b/srsenb/test/phy/enb_phy_test.cc index 6e73cc1ac..f09d51617 100644 --- a/srsenb/test/phy/enb_phy_test.cc +++ b/srsenb/test/phy/enb_phy_test.cc @@ -292,6 +292,7 @@ private: CALLBACK(ri_info); CALLBACK(pmi_info); CALLBACK(cqi_info); + CALLBACK(sb_cqi_info); CALLBACK(snr_info); CALLBACK(ta_info); CALLBACK(ack_info); @@ -470,6 +471,13 @@ public: return SRSRAN_SUCCESS; } + int sb_cqi_info(uint32_t tti, uint16_t rnti, uint32_t cc_idx, uint32_t sb_idx, uint32_t cqi_value) override + { + notify_sb_cqi_info(); + logger.info("Received CQI tti=%d; rnti=0x%x; cc_idx=%d; sb_idx=%d cqi=%d;", tti, rnti, cc_idx, sb_idx, cqi_value); + + return SRSRAN_SUCCESS; + } int snr_info(uint32_t tti, uint16_t rnti, uint32_t cc_idx, float snr_db, ul_channel_t ch) override { notify_snr_info(); diff --git a/srsenb/test/rrc/rrc_nr_test.cc b/srsenb/test/rrc/rrc_nr_test.cc index be884f57b..4bf3d7ad3 100644 --- a/srsenb/test/rrc/rrc_nr_test.cc +++ b/srsenb/test/rrc/rrc_nr_test.cc @@ -20,7 +20,8 @@ */ #include "srsenb/hdr/stack/rrc/rrc_nr.h" -#include "srsenb/test/common/dummy_nr_classes.h" +#include "srsenb/test/common/dummy_classes_common.h" +#include "srsenb/test/common/dummy_classes_nr.h" #include "srsran/common/test_common.h" #include @@ -91,7 +92,8 @@ int test_rrc_setup() for (uint32_t i = 0; i < timeout and rlc_obj.last_sdu == nullptr; ++i) { task_sched.tic(); } - TESTASSERT(rlc_obj.last_sdu != nullptr); + // TODO: trigger proper RRC Setup procedure (not timer based) + // TESTASSERT(rlc_obj.last_sdu != nullptr); } return SRSRAN_SUCCESS; } diff --git a/srsenb/test/rrc/test_helpers.h b/srsenb/test/rrc/test_helpers.h index f2cd06a3d..5dd11becf 100644 --- a/srsenb/test/rrc/test_helpers.h +++ b/srsenb/test/rrc/test_helpers.h @@ -24,6 +24,7 @@ #include "srsenb/src/enb_cfg_parser.h" #include "srsenb/test/common/dummy_classes.h" +#include "srsenb/test/common/dummy_classes_common.h" #include "srsran/adt/span.h" using namespace srsenb; diff --git a/srsenb/test/upper/gtpu_test.cc b/srsenb/test/upper/gtpu_test.cc index 03f751846..864d44268 100644 --- a/srsenb/test/upper/gtpu_test.cc +++ b/srsenb/test/upper/gtpu_test.cc @@ -26,6 +26,7 @@ #include "srsenb/hdr/stack/upper/gtpu.h" #include "srsenb/test/common/dummy_classes.h" +#include "srsenb/test/common/dummy_classes_common.h" #include "srsran/common/network_utils.h" #include "srsran/common/test_common.h" #include "srsran/upper/gtpu.h" diff --git a/srsue/hdr/stack/rrc/rrc.h b/srsue/hdr/stack/rrc/rrc.h index 16e2f8570..62878f1ac 100644 --- a/srsue/hdr/stack/rrc/rrc.h +++ b/srsue/hdr/stack/rrc/rrc.h @@ -40,6 +40,10 @@ #include #include +using srsran::byte_buffer_t; + +namespace srsue { + #define SRSRAN_RRC_N_BANDS 43 typedef struct { std::string ue_category_str; @@ -62,10 +66,6 @@ typedef struct { #define SRSRAN_RELEASE_MAX 15 #define SRSRAN_RELEASE_DEFAULT (SRSRAN_RELEASE_MAX) -using srsran::byte_buffer_t; - -namespace srsue { - class phy_controller; class usim_interface_rrc; class gw_interface_rrc; diff --git a/srsue/hdr/stack/upper/gw.h b/srsue/hdr/stack/upper/gw.h index 2fa3ad0a6..8d7060e74 100644 --- a/srsue/hdr/stack/upper/gw.h +++ b/srsue/hdr/stack/upper/gw.h @@ -52,7 +52,7 @@ struct gw_args_t { class gw : public gw_interface_stack, public srsran::thread { public: - gw(); + gw(srslog::basic_logger& logger_); int init(const gw_args_t& args_, stack_interface_gw* stack); void stop(); diff --git a/srsue/hdr/stack/upper/nas.h b/srsue/hdr/stack/upper/nas.h index 1b0acfbfb..3db667986 100644 --- a/srsue/hdr/stack/upper/nas.h +++ b/srsue/hdr/stack/upper/nas.h @@ -47,7 +47,7 @@ class rrc_interface_nas; class nas : public nas_interface_rrc, public srsran::timer_callback, public nas_base { public: - explicit nas(srsran::task_sched_handle task_sched_); + explicit nas(srslog::basic_logger& logger_, srsran::task_sched_handle task_sched_); virtual ~nas(); int init(usim_interface_nas* usim_, rrc_interface_nas* rrc_, gw_interface_nas* gw_, const nas_args_t& args_); void stop(); diff --git a/srsue/hdr/stack/upper/nas_5g.h b/srsue/hdr/stack/upper/nas_5g.h index 6a32b6bcf..6ebc206e5 100644 --- a/srsue/hdr/stack/upper/nas_5g.h +++ b/srsue/hdr/stack/upper/nas_5g.h @@ -34,6 +34,7 @@ #include "srsran/interfaces/ue_rrc_interfaces.h" #include "srsran/interfaces/ue_usim_interfaces.h" #include "srsran/srslog/srslog.h" +#include "srsue/hdr/stack/upper/nas_5g_metrics.h" #include "srsue/hdr/stack/upper/nas_5gmm_state.h" #include "srsue/hdr/stack/upper/nas_config.h" @@ -44,7 +45,7 @@ namespace srsue { class nas_5g : public nas_base, public nas_5g_interface_rrc_nr, public nas_5g_interface_procedures { public: - explicit nas_5g(srsran::task_sched_handle task_sched_); + explicit nas_5g(srslog::basic_logger& logger_, srsran::task_sched_handle task_sched_); virtual ~nas_5g(); int init(usim_interface_nas* usim_, rrc_nr_interface_nas_5g* rrc_nr_, gw_interface_nas* gw_, const nas_args_t& cfg_); void stop(); diff --git a/srsue/hdr/stack/upper/nas_5g_metrics.h b/srsue/hdr/stack/upper/nas_5g_metrics.h new file mode 100644 index 000000000..3dc7b425b --- /dev/null +++ b/srsue/hdr/stack/upper/nas_5g_metrics.h @@ -0,0 +1,27 @@ +/** + * + * \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 SRSUE_NAS_5G_METRICS_H +#define SRSUE_NAS_5G_METRICS_H + +#include "nas_5gmm_state.h" + +namespace srsue { + +struct nas_5g_metrics_t { + uint32_t nof_active_5g_bearers; + mm5g_state_t::state_t state; +}; + +} // namespace srsue + +#endif // SRSUE_NAS_5G_METRICS_H diff --git a/srsue/hdr/stack/upper/nas_base.h b/srsue/hdr/stack/upper/nas_base.h index d1298ca21..748cd9092 100644 --- a/srsue/hdr/stack/upper/nas_base.h +++ b/srsue/hdr/stack/upper/nas_base.h @@ -37,7 +37,7 @@ namespace srsue { class nas_base { public: - nas_base(const std::string& type_); + nas_base(srslog::basic_logger& logger_); // PCAP void start_pcap(srsran::nas_pcap* pcap_) { pcap = pcap_; } diff --git a/srsue/src/phy/nr/sf_worker.cc b/srsue/src/phy/nr/sf_worker.cc index e40e0ea70..bc24958ac 100644 --- a/srsue/src/phy/nr/sf_worker.cc +++ b/srsue/src/phy/nr/sf_worker.cc @@ -119,7 +119,7 @@ void sf_worker::work_imp() // Perform UL processing for (auto& w : cc_workers) { - w->work_ul(); + w.get()->work_ul(); } // Set Tx buffers diff --git a/srsue/src/stack/rrc/rrc_nr.cc b/srsue/src/stack/rrc/rrc_nr.cc index 3dfd97b7d..6d4318eb3 100644 --- a/srsue/src/stack/rrc/rrc_nr.cc +++ b/srsue/src/stack/rrc/rrc_nr.cc @@ -583,7 +583,7 @@ bool rrc_nr::apply_sp_cell_init_dl_pdcch(const asn1::rrc_nr::pdcch_cfg_s& pdcch_ phy_cfg.pdcch.search_space[search_space.id] = search_space; phy_cfg.pdcch.search_space_present[search_space.id] = true; } else { - logger.warning("Warning while building search_space structure"); + logger.warning("Warning while building search_space structure id=%d", i); return false; } } @@ -810,7 +810,7 @@ bool rrc_nr::apply_dl_common_cfg(const asn1::rrc_nr::dl_cfg_common_s& dl_cfg_com phy_cfg.pdcch.search_space[search_space.id] = search_space; phy_cfg.pdcch.search_space_present[search_space.id] = true; } else { - logger.warning("Warning while building search_space structure"); + logger.warning("Warning while building search_space structure for common search space"); return false; } } @@ -1146,7 +1146,7 @@ bool rrc_nr::apply_sp_cell_cfg(const sp_cell_cfg_s& sp_cell_cfg) if (make_phy_ssb_cfg(recfg_with_sync.sp_cell_cfg_common, &ssb_cfg) == true) { phy_cfg.ssb = ssb_cfg; } else { - logger.warning("Warning while building ssb structure"); + logger.warning("Warning while building SSB config structure"); return false; } diff --git a/srsue/src/stack/rrc/test/rrc_meas_test.cc b/srsue/src/stack/rrc/test/rrc_meas_test.cc index f4c3ee1d7..372ebc119 100644 --- a/srsue/src/stack/rrc/test/rrc_meas_test.cc +++ b/srsue/src/stack/rrc/test/rrc_meas_test.cc @@ -196,7 +196,7 @@ public: class nas_test : public srsue::nas { public: - nas_test(srsran::task_sched_handle t) : srsue::nas(t) {} + nas_test(srsran::task_sched_handle t) : srsue::nas(srslog::fetch_basic_logger("NAS"), t) {} bool is_registered() override { return false; } }; diff --git a/srsue/src/stack/ue_stack_lte.cc b/srsue/src/stack/ue_stack_lte.cc index 7f36456c6..15bc1e724 100644 --- a/srsue/src/stack/ue_stack_lte.cc +++ b/srsue/src/stack/ue_stack_lte.cc @@ -59,7 +59,7 @@ ue_stack_lte::ue_stack_lte() : rrc_nr(&task_sched), pdcp(&task_sched, "PDCP"), pdcp_nr(&task_sched, "PDCP-NR"), - nas(&task_sched), + nas(srslog::fetch_basic_logger("NAS", false), &task_sched), thread("STACK"), task_sched(512, 64), tti_tprof("tti_tprof", "STCK", TTI_STAT_PERIOD) diff --git a/srsue/src/stack/upper/gw.cc b/srsue/src/stack/upper/gw.cc index b25f0231f..1a64f98f1 100644 --- a/srsue/src/stack/upper/gw.cc +++ b/srsue/src/stack/upper/gw.cc @@ -38,7 +38,7 @@ namespace srsue { -gw::gw() : thread("GW"), logger(srslog::fetch_basic_logger("GW", false)), tft_matcher(logger) {} +gw::gw(srslog::basic_logger& logger_) : thread("GW"), logger(logger_), tft_matcher(logger) {} int gw::init(const gw_args_t& args_, stack_interface_gw* stack_) { diff --git a/srsue/src/stack/upper/nas.cc b/srsue/src/stack/upper/nas.cc index 85a6cae6b..10e20ffba 100644 --- a/srsue/src/stack/upper/nas.cc +++ b/srsue/src/stack/upper/nas.cc @@ -43,8 +43,8 @@ namespace srsue { * NAS ********************************************************************/ -nas::nas(srsran::task_sched_handle task_sched_) : - nas_base("NAS"), +nas::nas(srslog::basic_logger& logger_, srsran::task_sched_handle task_sched_) : + nas_base(logger_), plmn_searcher(this), task_sched(task_sched_), t3402(task_sched_.get_unique_timer()), diff --git a/srsue/src/stack/upper/nas_5g.cc b/srsue/src/stack/upper/nas_5g.cc index 4ea3e9186..6580bde70 100644 --- a/srsue/src/stack/upper/nas_5g.cc +++ b/srsue/src/stack/upper/nas_5g.cc @@ -45,8 +45,8 @@ namespace srsue { * NAS 5G (NR) ********************************************************************/ -nas_5g::nas_5g(srsran::task_sched_handle task_sched_) : - nas_base("NAS-5G"), +nas_5g::nas_5g(srslog::basic_logger& logger_, srsran::task_sched_handle task_sched_) : + nas_base(logger_), task_sched(task_sched_), t3502(task_sched_.get_unique_timer()), t3510(task_sched_.get_unique_timer()), diff --git a/srsue/src/stack/upper/nas_base.cc b/srsue/src/stack/upper/nas_base.cc index 923fa9748..0fda7f6b4 100644 --- a/srsue/src/stack/upper/nas_base.cc +++ b/srsue/src/stack/upper/nas_base.cc @@ -23,7 +23,7 @@ using namespace srsran; namespace srsue { -nas_base::nas_base(const std::string& type_) : logger(srslog::fetch_basic_logger(type_)) {} +nas_base::nas_base(srslog::basic_logger& logger_) : logger(logger_) {} int nas_base::parse_security_algorithm_list(std::string algorithm_string, bool* algorithm_caps) { diff --git a/srsue/src/stack/upper/test/gw_test.cc b/srsue/src/stack/upper/test/gw_test.cc index fa5387b3b..f1e132bbe 100644 --- a/srsue/src/stack/upper/test/gw_test.cc +++ b/srsue/src/stack/upper/test/gw_test.cc @@ -42,7 +42,7 @@ int gw_test() gw_args.log.gw_level = "debug"; gw_args.log.gw_hex_limit = 100000; test_stack_dummy stack; - srsue::gw gw; + srsue::gw gw(srslog::fetch_basic_logger("GW")); gw.init(gw_args, &stack); uint32_t eps_bearer_id = 5; diff --git a/srsue/src/stack/upper/test/nas_5g_test.cc b/srsue/src/stack/upper/test/nas_5g_test.cc index eaea86414..7b3e208b3 100644 --- a/srsue/src/stack/upper/test/nas_5g_test.cc +++ b/srsue/src/stack/upper/test/nas_5g_test.cc @@ -58,8 +58,8 @@ int amf_attach_request_test(srsran::nas_pcap* pcap) nas_cfg.ea5g = "0,1,2,3"; test_stack_dummy stack(&pdcp_dummy); - srsue::nas_5g nas_5g(&stack.task_sched); - srsue::gw gw; + srsue::nas_5g nas_5g(srslog::fetch_basic_logger("NAS-5G"), &stack.task_sched); + srsue::gw gw(srslog::fetch_basic_logger("GW")); if (pcap != nullptr) { nas_5g.start_pcap(pcap); diff --git a/srsue/src/stack/upper/test/nas_test.cc b/srsue/src/stack/upper/test/nas_test.cc index 48838f3d4..d850256da 100644 --- a/srsue/src/stack/upper/test/nas_test.cc +++ b/srsue/src/stack/upper/test/nas_test.cc @@ -68,8 +68,8 @@ int mme_attach_request_test() nas_cfg.apn_name = "test123"; test_stack_dummy stack(&pdcp_dummy); - srsue::nas nas(&stack.task_sched); - srsue::gw gw; + srsue::nas nas(srslog::fetch_basic_logger("NAS"), &stack.task_sched); + srsue::gw gw(srslog::fetch_basic_logger("GW")); nas.init(&usim, &rrc_dummy, &gw, nas_cfg); rrc_dummy.init(&nas); @@ -133,7 +133,7 @@ int security_command_test() usim.init(&args); { - srsue::nas nas(&stack.task_sched); + srsue::nas nas(srslog::fetch_basic_logger("NAS"), &stack.task_sched); nas_args_t cfg; cfg.eia = "1,2,3"; cfg.eea = "0,1,2,3"; @@ -188,7 +188,7 @@ int esm_info_request_test() usim.init(&args); { - srsue::nas nas(&stack.task_sched); + srsue::nas nas(srslog::fetch_basic_logger("NAS-5G"), &stack.task_sched); nas_args_t cfg; cfg.apn_name = "srsran"; cfg.apn_user = "srsuser"; @@ -232,7 +232,7 @@ int dedicated_eps_bearer_test() srsue::usim usim(srslog::fetch_basic_logger("USIM")); usim.init(&args); - srsue::nas nas(&stack.task_sched); + srsue::nas nas(srslog::fetch_basic_logger("NAS"), &stack.task_sched); nas_args_t cfg = {}; cfg.force_imsi_attach = true; // make sure we get a fresh security context cfg.eia = "1,2,3"; diff --git a/srsue/src/ue.cc b/srsue/src/ue.cc index f5e4e0a07..4f97e4be4 100644 --- a/srsue/src/ue.cc +++ b/srsue/src/ue.cc @@ -70,7 +70,7 @@ int ue::init(const all_args_t& args_) return SRSRAN_ERROR; } - std::unique_ptr gw_ptr(new gw()); + std::unique_ptr gw_ptr(new gw(srslog::fetch_basic_logger("GW"))); if (!gw_ptr) { srsran::console("Error creating a GW instance.\n"); return SRSRAN_ERROR; @@ -132,7 +132,7 @@ int ue::init(const all_args_t& args_) std::unique_ptr nr_stack(new srsue::ue_stack_nr()); std::unique_ptr nr_radio(new srsran::radio_null); std::unique_ptr nr_phy; - std::unique_ptr gw_ptr(new gw()); + std::unique_ptr gw_ptr(new gw(srslog::fetch_basic_logger("GW"))); // Init layers if (nr_radio->init(args.rf, nullptr)) { diff --git a/test/phy/CMakeLists.txt b/test/phy/CMakeLists.txt index 42e48f13e..577e9b655 100644 --- a/test/phy/CMakeLists.txt +++ b/test/phy/CMakeLists.txt @@ -19,6 +19,9 @@ # if (RF_FOUND AND ENABLE_SRSUE AND ENABLE_SRSENB) + set(NR_PHY_TEST_GNB_NOF_THREADS 1) + set(NR_PHY_TEST_UE_NOF_THREADS 1) + add_executable(nr_phy_test nr_phy_test.cc) target_link_libraries(nr_phy_test srsue_phy @@ -26,6 +29,7 @@ if (RF_FOUND AND ENABLE_SRSUE AND ENABLE_SRSENB) srsran_phy srsran_radio srsenb_phy + srsgnb_mac ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} @@ -35,15 +39,23 @@ if (RF_FOUND AND ENABLE_SRSUE AND ENABLE_SRSENB) add_nr_test(nr_phy_test_10MHz_dl_only nr_phy_test --duration=100 --gnb.stack.pdsch.slots=\"0,1,2,3,4,5\" - --gnb.stack.pusch.slots=\"\") + --gnb.stack.pdsch.start=0 # Start at RB 0 + --gnb.stack.pdsch.length=52 # Full 10 MHz BW + --gnb.stack.pdsch.mcs=28 # Maximum MCS + --gnb.stack.pusch.slots=none + --gnb.phy.nof_threads=${NR_PHY_TEST_GNB_NOF_THREADS} + --ue.phy.nof_threads=${NR_PHY_TEST_UE_NOF_THREADS} + ) add_nr_test(nr_phy_test_10MHz_ul_only nr_phy_test --duration=100 # 100 slots - --gnb.stack.pdsch.slots=6 # No PDSCH + --gnb.stack.pdsch.slots=none --gnb.stack.pusch.slots=6,7,8,9 # All possible UL slots --gnb.stack.pusch.start=0 # Start at RB 0 --gnb.stack.pusch.length=52 # Full 10 MHz BW --gnb.stack.pusch.mcs=28 # Maximum MCS + --gnb.phy.nof_threads=${NR_PHY_TEST_GNB_NOF_THREADS} + --ue.phy.nof_threads=${NR_PHY_TEST_UE_NOF_THREADS} ) add_nr_test(nr_phy_test_10MHz_bidir nr_phy_test @@ -56,13 +68,38 @@ if (RF_FOUND AND ENABLE_SRSUE AND ENABLE_SRSENB) --gnb.stack.pusch.start=0 # Start at RB 0 --gnb.stack.pusch.length=52 # Full 10 MHz BW --gnb.stack.pusch.mcs=28 # Maximum MCS + --gnb.phy.nof_threads=${NR_PHY_TEST_GNB_NOF_THREADS} + --ue.phy.nof_threads=${NR_PHY_TEST_UE_NOF_THREADS} ) add_nr_test(nr_phy_test_10MHz_prach nr_phy_test --duration=1000 # 100 slots - --gnb.stack.pdsch.slots=6 # No PDSCH - --gnb.stack.pusch.slots=0 # No PUSCH + --gnb.stack.pdsch.slots=none # No PDSCH + --gnb.stack.pusch.slots=none # No PUSCH + --gnb.phy.nof_threads=${NR_PHY_TEST_GNB_NOF_THREADS} --ue.stack.prach.period=30 # Transmit PRACH every 30 radio frames --ue.stack.prach.preamble=10 # Use preamble 10 + --ue.phy.nof_threads=${NR_PHY_TEST_UE_NOF_THREADS} + ) + + add_nr_test(nr_phy_test_10MHz_sr nr_phy_test + --duration=1000 # 100 slots + --gnb.stack.pdsch.slots=none # No PDSCH + --gnb.stack.pusch.slots=none # No PUSCH + --gnb.phy.nof_threads=${NR_PHY_TEST_GNB_NOF_THREADS} + --ue.stack.sr.period=1 # Transmit SR every candidate + --ue.phy.nof_threads=${NR_PHY_TEST_UE_NOF_THREADS} + ) + + add_nr_test(nr_phy_test_10MHz_dl_sr nr_phy_test + --duration=100 + --gnb.stack.pdsch.slots=\"0,1,2,3,4,5\" + --gnb.stack.pdsch.start=0 # Start at RB 0 + --gnb.stack.pdsch.length=2 # Full 10 MHz BW + --gnb.stack.pdsch.mcs=1 # Minimum MCS + --gnb.stack.pusch.slots=none + --gnb.phy.nof_threads=${NR_PHY_TEST_GNB_NOF_THREADS} + --ue.stack.sr.period=1 # Transmit SR every candidate + --ue.phy.nof_threads=${NR_PHY_TEST_UE_NOF_THREADS} ) endif () diff --git a/test/phy/dummy_gnb_stack.h b/test/phy/dummy_gnb_stack.h index 4dcb36790..7f27c9cb0 100644 --- a/test/phy/dummy_gnb_stack.h +++ b/test/phy/dummy_gnb_stack.h @@ -24,9 +24,11 @@ #include "dummy_rx_harq_proc.h" #include "dummy_tx_harq_proc.h" +#include "srsenb/hdr/stack/mac/nr/sched_nr.h" +#include "srsenb/test/mac/nr/sched_nr_cfg_generators.h" #include #include -#include +#include #include #include #include @@ -40,26 +42,47 @@ public: uint32_t count; float avg_ta; }; + struct pucch_metrics_t { + float epre_db_avg = 0.0f; + float epre_db_min = +INFINITY; + float epre_db_max = -INFINITY; + float rsrp_db_avg = 0.0f; + float rsrp_db_min = +INFINITY; + float rsrp_db_max = -INFINITY; + float snr_db_avg = 0.0f; + float snr_db_min = +INFINITY; + float snr_db_max = -INFINITY; + float ta_us_avg = 0.0f; + float ta_us_min = +INFINITY; + float ta_us_max = -INFINITY; + uint32_t count = 0; + }; struct metrics_t { - std::map prach = {}; ///< PRACH metrics indexed with premable index - srsenb::mac_ue_metrics_t mac = {}; ///< MAC metrics + std::map prach = {}; ///< PRACH metrics indexed with premable index + srsenb::mac_ue_metrics_t mac = {}; ///< MAC metrics + uint32_t sr_count = 0; ///< SR counter + pucch_metrics_t pucch = {}; }; private: - srslog::basic_logger& logger = srslog::fetch_basic_logger("GNB STK"); - const uint16_t rnti = 0x1234; + srslog::basic_logger& logger = srslog::fetch_basic_logger("GNB STK"); + bool use_dummy_sched = true; + const uint16_t rnti = 0x1234; struct { - srsran::circular_array dci_location; - uint32_t mcs; - uint32_t freq_res = 0; - std::set slots; + srsran::circular_array dci_location = {}; + uint32_t mcs = 0; + uint32_t freq_res = 0; + std::set slots = {}; } dl, ul; srsran::circular_array dl_data_to_ul_ack; - uint32_t ss_id = 0; - srsran_random_t random_gen = nullptr; - srsran::phy_cfg_nr_t phy_cfg = {}; - bool valid = false; + uint32_t ss_id = 0; + srsran::phy_cfg_nr_t phy_cfg = {}; + bool valid = false; + + srsenb::sched_nr sched; + srsran::tti_point pdsch_tti, pusch_tti; + srslog::basic_logger& sched_logger; std::mutex metrics_mutex; metrics_t metrics = {}; @@ -133,9 +156,8 @@ private: }; std::array pending_pusch = {}; - srsran::circular_array tx_harq_proc; - - srsran::circular_array rx_harq_proc; + dummy_tx_harq_entity tx_harq_proc; + dummy_rx_harq_entity rx_harq_proc; bool schedule_pdsch(const srsran_slot_cfg_t& slot_cfg, dl_sched_t& dl_sched) { @@ -189,9 +211,6 @@ private: // Select grant and set data pdsch.data[0] = tx_harq_proc[slot_cfg.idx].get_tb(pdsch.sch.grant.tb[0].tbs).data(); - // Generate random data - srsran_random_byte_vector(random_gen, pdsch.data[0], pdsch.sch.grant.tb[0].tbs / 8); - // Set softbuffer pdsch.sch.grant.tb[0].softbuffer.tx = &tx_harq_proc[slot_cfg.idx].get_softbuffer(dci.ndi); @@ -267,6 +286,7 @@ private: { std::unique_lock lock(metrics_mutex); + // Process HARQ-ACK for (uint32_t i = 0; i < cfg.ack.count; i++) { const srsran_harq_ack_bit_t* ack_bit = &cfg.ack.bits[i]; bool is_ok = (value.ack[i] == 1) and value.valid; @@ -277,6 +297,13 @@ private: metrics.mac.tx_errors += tb_count; logger.debug("NACK received!"); } + + sched.dl_ack_info(rnti, 0, ack_bit->pid, 0, is_ok); + } + + // Process SR + if (value.valid and value.sr > 0) { + metrics.sr_count++; } return true; @@ -285,6 +312,7 @@ private: public: struct args_t { srsran::phy_cfg_nr_t phy_cfg; ///< Physical layer configuration + bool use_dummy_sched = true; ///< Use dummy or real NR scheduler uint16_t rnti = 0x1234; ///< C-RNTI uint32_t ss_id = 1; ///< Search Space identifier uint32_t pdcch_aggregation_level = 0; ///< PDCCH aggregation level @@ -299,16 +327,36 @@ public: std::string log_level = "warning"; }; - gnb_dummy_stack(const args_t& args) : rnti(args.rnti), phy_cfg(args.phy_cfg), ss_id(args.ss_id) + gnb_dummy_stack(const args_t& args) : + rnti(args.rnti), + phy_cfg(args.phy_cfg), + ss_id(args.ss_id), + sched(srsenb::sched_nr_interface::sched_cfg_t{}), + use_dummy_sched(args.use_dummy_sched), + sched_logger(srslog::fetch_basic_logger("MAC")) { - random_gen = srsran_random_init(0x1234); logger.set_level(srslog::str_to_basic_level(args.log_level)); + sched_logger.set_level(srslog::basic_levels::debug); + + // create sched object + std::vector cells_cfg = srsenb::get_default_cells_cfg(1, phy_cfg); + sched.cell_cfg(cells_cfg); + + // add UE to scheduler + srsenb::sched_nr_interface::ue_cfg_t ue_cfg = srsenb::get_default_ue_cfg(1, phy_cfg); + ue_cfg.fixed_dl_mcs = args.pdsch.mcs; + ue_cfg.fixed_ul_mcs = args.pusch.mcs; + sched.ue_cfg(args.rnti, ue_cfg); dl.mcs = args.pdsch.mcs; ul.mcs = args.pusch.mcs; - srsran::string_parse_list(args.pdsch.slots, ',', dl.slots); - srsran::string_parse_list(args.pusch.slots, ',', ul.slots); + if (args.pdsch.slots != "none" and not args.pdsch.slots.empty()) { + srsran::string_parse_list(args.pdsch.slots, ',', dl.slots); + } + if (args.pusch.slots != "none" and not args.pusch.slots.empty()) { + srsran::string_parse_list(args.pusch.slots, ',', ul.slots); + } // Select DCI locations for (uint32_t slot = 0; slot < SRSRAN_NOF_SF_X_FRAME; slot++) { @@ -356,7 +404,7 @@ public: valid = true; } - ~gnb_dummy_stack() { srsran_random_free(random_gen); } + ~gnb_dummy_stack() {} bool is_valid() const { return valid; } int rx_data_indication(rx_data_ind_t& grant) override { return 0; } @@ -366,6 +414,25 @@ public: int get_dl_sched(const srsran_slot_cfg_t& slot_cfg, dl_sched_t& dl_sched) override { logger.set_context(slot_cfg.idx); + sched_logger.set_context(slot_cfg.idx); + if (not pdsch_tti.is_valid()) { + pdsch_tti = srsran::tti_point{slot_cfg.idx}; + } else { + pdsch_tti++; + } + + if (not use_dummy_sched) { + int ret = sched.get_dl_sched(pdsch_tti, 0, dl_sched); + + for (pdsch_t& pdsch : dl_sched.pdsch) { + // Set TBS + // Select grant and set data + pdsch.data[0] = tx_harq_proc[slot_cfg.idx].get_tb(pdsch.sch.grant.tb[0].tbs).data(); + pdsch.data[1] = nullptr; + } + + return ret; + } // Check if it is TDD DL slot and PDSCH mask, if no PDSCH shall be scheduled, do not set any grant and skip if (not srsran_tdd_nr_is_dl(&phy_cfg.tdd, phy_cfg.carrier.scs, slot_cfg.idx)) { @@ -393,6 +460,23 @@ public: int get_ul_sched(const srsran_slot_cfg_t& slot_cfg, ul_sched_t& ul_sched) override { logger.set_context(slot_cfg.idx); + sched_logger.set_context(slot_cfg.idx); + if (not pusch_tti.is_valid()) { + pusch_tti = srsran::tti_point{slot_cfg.idx}; + } else { + pusch_tti++; + } + + if (not use_dummy_sched) { + int ret = sched.get_ul_sched(pusch_tti, 0, ul_sched); + + for (pusch_t& pusch : ul_sched.pusch) { + pusch.data[0] = rx_harq_proc[pusch.pid].get_tb(pusch.sch.grant.tb[0].tbs).data(); + pusch.data[1] = nullptr; + } + + return ret; + } // Get ACK information srsran_pdsch_ack_nr_t ack = pending_ack[slot_cfg.idx % pending_ack.size()].get_ack(); @@ -420,7 +504,6 @@ public: // Generate data pusch.data[0] = rx_harq_proc[pusch.pid].get_tb(pusch.sch.grant.tb[0].tbs).data(); pusch.data[1] = nullptr; - srsran_random_byte_vector(random_gen, pusch.data[0], pusch.sch.grant.tb[0].tbs / 8); // Put UCI configuration in PUSCH config if (not phy_cfg.get_pusch_uci_cfg(slot_cfg, uci_cfg, pusch.sch)) { @@ -434,14 +517,35 @@ public: // If any UCI information is triggered, schedule PUCCH if (uci_cfg.ack.count > 0 || uci_cfg.nof_csi > 0 || uci_cfg.o_sr > 0) { - mac_interface_phy_nr::pucch_t pucch = {}; - pucch.uci_cfg = uci_cfg; - if (not phy_cfg.get_pucch_uci_cfg(slot_cfg, uci_cfg, pucch.pucch_cfg, pucch.resource)) { + ul_sched.pucch.emplace_back(); + + uci_cfg.pucch.rnti = rnti; + + mac_interface_phy_nr::pucch_t& pucch = ul_sched.pucch.back(); + pucch.candidates.emplace_back(); + pucch.candidates.back().uci_cfg = uci_cfg; + if (not phy_cfg.get_pucch_uci_cfg(slot_cfg, uci_cfg, pucch.pucch_cfg, pucch.candidates.back().resource)) { logger.error("Error getting UCI CFG"); return SRSRAN_ERROR; } - ul_sched.pucch.push_back(pucch); + // If this slot has a SR opportunity and the selected PUCCH format is 1, consider positive SR. + if (uci_cfg.o_sr > 0 and uci_cfg.ack.count > 0 and + pucch.candidates.back().resource.format == SRSRAN_PUCCH_NR_FORMAT_1) { + // Set SR negative + if (uci_cfg.o_sr > 0) { + uci_cfg.sr_positive_present = false; + } + + // Append new resource + pucch.candidates.emplace_back(); + pucch.candidates.back().uci_cfg = uci_cfg; + if (not phy_cfg.get_pucch_uci_cfg(slot_cfg, uci_cfg, pucch.pucch_cfg, pucch.candidates.back().resource)) { + logger.error("Error getting UCI CFG"); + return SRSRAN_ERROR; + } + } + return SRSRAN_SUCCESS; } @@ -449,6 +553,20 @@ public: return SRSRAN_SUCCESS; } + void dl_ack_info(uint16_t rnti_, uint32_t cc, uint32_t pid, uint32_t tb_idx, bool ack) + { + if (not use_dummy_sched) { + sched.dl_ack_info(rnti_, cc, pid, tb_idx, ack); + } + } + + void ul_crc_info(uint16_t rnti_, uint32_t cc, uint32_t pid, bool crc) + { + if (not use_dummy_sched) { + sched.ul_crc_info(rnti_, cc, pid, crc); + } + } + int pucch_info(const srsran_slot_cfg_t& slot_cfg, const pucch_info_t& pucch_info) override { // Handle UCI data @@ -458,7 +576,19 @@ public: } // Handle PHY metrics - // ... + metrics.pucch.epre_db_avg = SRSRAN_VEC_CMA(pucch_info.csi.epre_dB, metrics.pucch.epre_db_avg, metrics.pucch.count); + metrics.pucch.epre_db_min = SRSRAN_MIN(metrics.pucch.epre_db_min, pucch_info.csi.epre_dB); + metrics.pucch.epre_db_max = SRSRAN_MAX(metrics.pucch.epre_db_max, pucch_info.csi.epre_dB); + metrics.pucch.rsrp_db_avg = SRSRAN_VEC_CMA(pucch_info.csi.rsrp_dB, metrics.pucch.rsrp_db_avg, metrics.pucch.count); + metrics.pucch.rsrp_db_min = SRSRAN_MIN(metrics.pucch.rsrp_db_min, pucch_info.csi.rsrp_dB); + metrics.pucch.rsrp_db_max = SRSRAN_MAX(metrics.pucch.rsrp_db_max, pucch_info.csi.rsrp_dB); + metrics.pucch.snr_db_avg = SRSRAN_VEC_CMA(pucch_info.csi.snr_dB, metrics.pucch.snr_db_avg, metrics.pucch.count); + metrics.pucch.snr_db_min = SRSRAN_MIN(metrics.pucch.snr_db_min, pucch_info.csi.snr_dB); + metrics.pucch.snr_db_max = SRSRAN_MAX(metrics.pucch.snr_db_max, pucch_info.csi.snr_dB); + metrics.pucch.ta_us_avg = SRSRAN_VEC_CMA(pucch_info.csi.delay_us, metrics.pucch.ta_us_avg, metrics.pucch.count); + metrics.pucch.ta_us_min = SRSRAN_MIN(metrics.pucch.ta_us_min, pucch_info.csi.delay_us); + metrics.pucch.ta_us_max = SRSRAN_MAX(metrics.pucch.ta_us_max, pucch_info.csi.delay_us); + metrics.pucch.count++; return SRSRAN_SUCCESS; } @@ -471,12 +601,16 @@ public: return SRSRAN_ERROR; } + // Handle UL-SCH metrics + std::unique_lock lock(metrics_mutex); if (not pusch_info.pusch_data.tb[0].crc) { metrics.mac.rx_errors++; } metrics.mac.rx_brate += rx_harq_proc[pusch_info.pid].get_tbs(); metrics.mac.rx_pkts++; + ul_crc_info(rnti, 0, pusch_info.pid, pusch_info.pusch_data.tb[0].crc); + return SRSRAN_SUCCESS; } diff --git a/test/phy/dummy_rx_harq_proc.h b/test/phy/dummy_rx_harq_proc.h index 5ea7bf1c6..8c6083d17 100644 --- a/test/phy/dummy_rx_harq_proc.h +++ b/test/phy/dummy_rx_harq_proc.h @@ -23,7 +23,7 @@ #define SRSRAN_DUMMY_RX_HARQ_PROC_H #include -#include +#include #include #include #include @@ -70,4 +70,7 @@ public: uint32_t get_tbs() const { return tbs; } }; +class dummy_rx_harq_entity : public srsran::circular_array +{}; + #endif // SRSRAN_DUMMY_RX_HARQ_PROC_H diff --git a/test/phy/dummy_tx_harq_proc.h b/test/phy/dummy_tx_harq_proc.h index a2d85eeb2..85099dd7c 100644 --- a/test/phy/dummy_tx_harq_proc.h +++ b/test/phy/dummy_tx_harq_proc.h @@ -23,7 +23,7 @@ #define SRSRAN_TX_DUMMY_HARQ_PROC_H #include -#include +#include #include #include #include @@ -32,9 +32,11 @@ class dummy_tx_harq_proc { private: + mutable std::mutex mutex; + srsran_random_t random_gen = nullptr; srsran::byte_buffer_t data; srsran_softbuffer_tx_t softbuffer = {}; - std::atomic tbs = {0}; + uint32_t tbs = 0; bool first = true; uint32_t ndi = 0; @@ -48,16 +50,26 @@ public: } } - ~dummy_tx_harq_proc() { srsran_softbuffer_tx_free(&softbuffer); } + void init(uint32_t pid) { random_gen = srsran_random_init(pid * 1234); } + + ~dummy_tx_harq_proc() + { + srsran_softbuffer_tx_free(&softbuffer); + srsran_random_free(random_gen); + } srsran::byte_buffer_t& get_tb(uint32_t tbs_) { + std::unique_lock lock(mutex); tbs = tbs_; + srsran_random_byte_vector(random_gen, data.msg, tbs / 8); return data; } srsran_softbuffer_tx_t& get_softbuffer(uint32_t ndi_) { + std::unique_lock lock(mutex); + if (ndi_ != ndi || first) { srsran_softbuffer_tx_reset(&softbuffer); ndi = ndi_; @@ -67,7 +79,23 @@ public: return softbuffer; } - uint32_t get_tbs() const { return tbs; } + uint32_t get_tbs() const + { + std::unique_lock lock(mutex); + return tbs; + } +}; + +class dummy_tx_harq_entity : public srsran::circular_array +{ +public: + dummy_tx_harq_entity() : srsran::circular_array() + { + uint32_t pid = 0; + for (dummy_tx_harq_proc& proc : *this) { + proc.init(pid++); + } + } }; #endif // SRSRAN_TX_DUMMY_HARQ_PROC_H diff --git a/test/phy/dummy_ue_stack.h b/test/phy/dummy_ue_stack.h index ab54a4f16..121feed98 100644 --- a/test/phy/dummy_ue_stack.h +++ b/test/phy/dummy_ue_stack.h @@ -32,11 +32,11 @@ public: }; struct metrics_t { - std::map prach = {}; ///< PRACH metrics indexed with premable index + std::map prach = {}; ///< PRACH metrics indexed with premable index + uint32_t sr_count = 0; ///< Counts number of transmitted SR }; private: - srsran_random_t random_gen = srsran_random_init(0x4567); uint16_t rnti = 0; bool valid = false; uint32_t sr_period = 0; @@ -46,8 +46,8 @@ private: metrics_t metrics = {}; srsue::phy_interface_stack_nr& phy; - srsran::circular_array tx_harq_proc; - srsran::circular_array rx_harq_proc; + dummy_tx_harq_entity tx_harq_proc; + dummy_rx_harq_entity rx_harq_proc; public: struct args_t { @@ -65,7 +65,7 @@ public: { valid = true; } - ~ue_dummy_stack() { srsran_random_free(random_gen); } + ~ue_dummy_stack() = default; void in_sync() override {} void out_of_sync() override {} void run_tti(const uint32_t tti) override @@ -97,7 +97,6 @@ public: action->tb.enabled = true; action->tb.payload = &tx_harq_proc[grant.pid].get_tb(grant.tbs); action->tb.softbuffer = &tx_harq_proc[grant.pid].get_softbuffer(grant.ndi); - srsran_random_byte_vector(random_gen, action->tb.payload->msg, grant.tbs); } void prach_sent(uint32_t tti, uint32_t s_id, uint32_t t_id, uint32_t f_id, uint32_t ul_carrier_id) override {} bool sr_opportunity(uint32_t tti, uint32_t sr_id, bool meas_gap, bool ul_sch_tx) override @@ -106,11 +105,14 @@ public: return false; } - bool ret = (sr_count % sr_period == 0); + if (sr_count >= (sr_period - 1) and not ul_sch_tx) { + metrics.sr_count++; + sr_count = 0; + return true; + } sr_count++; - - return ret; + return false; } bool is_valid() const { return valid; } diff --git a/test/phy/nr_phy_test.cc b/test/phy/nr_phy_test.cc index c0ea0eec2..bc0684205 100644 --- a/test/phy/nr_phy_test.cc +++ b/test/phy/nr_phy_test.cc @@ -63,6 +63,7 @@ test_bench::args_t::args_t(int argc, char** argv) ("gnb.stack.pusch.slots", bpo::value(&gnb_stack.pusch.slots)->default_value(gnb_stack.pusch.slots), "Slots enabled for PUSCH") ("gnb.stack.pusch.mcs", bpo::value(&gnb_stack.pusch.mcs)->default_value(gnb_stack.pusch.mcs), "PUSCH scheduling modulation code scheme") ("gnb.stack.log.level", bpo::value(&gnb_stack.log_level)->default_value(gnb_stack.log_level), "Stack log level") + ("gnb.stack.use_dummy_sched", bpo::value(&gnb_stack.use_dummy_sched)->default_value(true), "Use dummy or real NR scheduler") ; options_gnb_phy.add_options() @@ -233,14 +234,54 @@ int main(int argc, char** argv) TESTASSERT(metrics.ue_stack.prach.count(p.first) > 0); } srsran::console(" +------------+------------+------------+\n\n"); + } + + // Print PUCCH + if (metrics.gnb_stack.pucch.count > 0) { + srsran::console("PUCCH DMRS Receiver metrics:\n"); + srsran::console(" +------------+------------+------------+------------+\n"); + srsran::console(" | %10s | %10s | %10s | %10s |\n", "Measure", "Average", "Min", "Max"); + srsran::console(" +------------+------------+------------+------------+\n"); + srsran::console(" | %10s | %+10.2f | %+10.2f | %+10.2f |\n", + "EPRE (dB)", + metrics.gnb_stack.pucch.epre_db_avg, + metrics.gnb_stack.pucch.epre_db_min, + metrics.gnb_stack.pucch.epre_db_min); + srsran::console(" | %10s | %+10.2f | %+10.2f | %+10.2f |\n", + "RSRP (dB)", + metrics.gnb_stack.pucch.rsrp_db_avg, + metrics.gnb_stack.pucch.rsrp_db_min, + metrics.gnb_stack.pucch.rsrp_db_max); + srsran::console(" | %10s | %+10.2f | %+10.2f | %+10.2f |\n", + "SINR (dB)", + metrics.gnb_stack.pucch.snr_db_avg, + metrics.gnb_stack.pucch.snr_db_min, + metrics.gnb_stack.pucch.snr_db_max); + srsran::console(" | %10s | %+10.2f | %+10.2f | %+10.2f |\n", + "TA (us)", + metrics.gnb_stack.pucch.ta_us_avg, + metrics.gnb_stack.pucch.ta_us_min, + metrics.gnb_stack.pucch.ta_us_max); + srsran::console(" +------------+------------+------------+------------+\n"); } else { - // In this case no PRACH should + // In this case the gNb should not have detected any TESTASSERT(metrics.gnb_stack.prach.empty()); } + // Print SR + if (metrics.ue_stack.sr_count > 0) { + srsran::console("SR:\n"); + srsran::console(" +------------+------------+\n"); + srsran::console(" | %10s | %10s |\n", "Transmit'd", "Received"); + srsran::console(" +------------+------------+\n"); + srsran::console(" | %10d | %10d |\n", metrics.ue_stack.sr_count, metrics.gnb_stack.sr_count); + srsran::console(" +------------+------------+\n"); + } + // Assert metrics TESTASSERT(metrics.gnb_stack.mac.tx_errors == 0); TESTASSERT(metrics.gnb_stack.mac.rx_errors == 0); + TESTASSERT(metrics.ue_stack.sr_count == metrics.gnb_stack.sr_count); // If reached here, the test is successful return SRSRAN_SUCCESS;