Merge branch 'next' into agpl_next

# Conflicts:
#	srsenb/test/common/dummy_nr_classes.h
master
Codebot 3 years ago committed by Your Name
commit a8ef3ba6b2

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

@ -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<srsran::mac_pcap> 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

@ -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;
/**

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

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

@ -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<uint8_t*, SRSRAN_MAX_TB> 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<pucch_candidate_t, MAX_PUCCH_CANDIDATES> 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 {

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -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 <stdbool.h>
#include <stdint.h>
@ -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);

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

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

@ -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<srsran::mac_pcap>(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;
}

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

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

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

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

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

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

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

@ -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<srsran::mac_pcap> pcap = nullptr;
mac_nr_args_t args = {};
srslog::basic_logger& logger;
bool started = false;
std::atomic<bool> 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<uint16_t, std::unique_ptr<ue_nr>, SRSENB_MAX_UES> ue_db;
std::atomic<uint16_t> ue_counter;
// BCH buffers
struct sib_info_t {
uint32_t index;
@ -112,15 +121,8 @@ private:
std::vector<sib_info_t> 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<srsran::unique_byte_buffer_t> ue_tx_buffer;
srsran::block_queue<srsran::unique_byte_buffer_t>
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<uint32_t> detected_rachs;
};
} // namespace srsenb

@ -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<ue_event_manager> pending_events;
// management of Sched Result buffering
std::unique_ptr<sched_result_manager> pending_results;
// management of cell resources
std::vector<std::unique_ptr<sched_nr_impl::serv_cell_ctxt> > cells;
std::vector<std::unique_ptr<sched_nr_impl::serv_cell_manager> > cells;
};
} // namespace srsenb

@ -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<bwp_ctxt, SCHED_NR_MAX_BWP_PER_CELL> bwps;
using feedback_callback_t = srsran::move_callback<void(ue_carrier&)>;
explicit serv_cell_manager(const sched_cell_params& cell_cfg_);
explicit serv_cell_ctxt(const sched_cell_params& cell_cfg_);
srsran::bounded_vector<bwp_ctxt, SCHED_NR_MAX_BWP_PER_CELL> 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

@ -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_time_cfg> pusch_ra_list;
bwp_params(const cell_cfg_t& cell, const sched_cfg_t& sched_cfg_, uint32_t cc, uint32_t bwp_id);
};

@ -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<tx_harq_softbuffer> 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 <typename Predicate>
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);

@ -72,9 +72,7 @@ public:
srsran::bounded_vector<bwp_cfg_t, SCHED_NR_MAX_BWP_PER_CELL> 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<ue_cc_cfg_t, SCHED_NR_MAX_CARRIERS> 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;
};

@ -81,6 +81,10 @@ private:
srsran::bounded_vector<bwp_slot_grid, TTIMOD_SZ> 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;

@ -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<void(ue_carrier&)> 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<srsran::move_callback<void(ue_carrier&)> > 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<std::unique_ptr<ue_carrier>, SCHED_NR_MAX_CARRIERS> carriers;
private:
@ -113,11 +108,11 @@ private:
bool pending_sr = false;
int current_idx = 0;
std::array<ue_cfg_t, 4> ue_cfgs;
ue_cfg_t ue_cfg;
};
using ue_map_t = srsran::static_circular_map<uint16_t, std::unique_ptr<ue>, SCHED_NR_MAX_USERS>;
using ue_map_t = srsran::static_circular_map<uint16_t, std::unique_ptr<ue>, SCHED_NR_MAX_USERS>;
using slot_ue_map_t = srsran::static_circular_map<uint16_t, slot_ue, SCHED_NR_MAX_USERS>;
} // namespace sched_nr_impl

@ -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(ue_carrier&)>;
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<feedback_t> pending_feedback, tmp_feedback_to_run;
srsran::static_circular_map<uint16_t, slot_ue, SCHED_NR_MAX_USERS> 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<std::unique_ptr<serv_cell_manager> > 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<void()> 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<void()> 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<std::unique_ptr<serv_cell_manager> > cells;
srslog::basic_logger& logger;
struct ue_event_t {
uint16_t rnti;
srsran::move_callback<void()> callback;
};
std::mutex event_mutex;
srsran::deque<ue_event_t> next_slot_events, slot_events;
std::vector<std::unique_ptr<slot_worker_ctxt> > slot_worker_ctxts;
struct cc_context {
std::condition_variable cvar;
bool waiting = false;
slot_cc_worker worker;
srsran::bounded_vector<serv_cell_ctxt, SCHED_NR_MAX_CARRIERS> 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<int> worker_count{0}; // variable shared across slot_cc_workers
std::vector<std::unique_ptr<cc_context> > cc_worker_list;
};
} // namespace sched_nr_impl

@ -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 <mutex>
#include <vector>
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<bool> 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<srsran::unique_byte_buffer_t> ue_tx_buffer;
srsran::block_queue<srsran::unique_byte_buffer_t>
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

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

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

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

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

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

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

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

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

@ -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<idle_st, wait_sgnb_add_req_resp, wait_recfg_comp, wait_prach_nr> states{this,
idle_st{},
wait_sgnb_add_req_resp{},
wait_recfg_comp{},
wait_prach_nr{}};
state_list<idle_st, wait_sgnb_add_req_resp, prepare_recfg, wait_recfg_comp, wait_prach_nr>
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 >
// +-----------------------+-----------------------+------------------------+----------------------------+-------------------------+
>;

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

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

@ -229,10 +229,10 @@ void parse_args(all_args_t* args, int argc, char* argv[])
("expert.equalizer_mode", bpo::value<string>(&args->phy.equalizer_mode)->default_value("mmse"), "Equalizer mode")
("expert.estimator_fil_w", bpo::value<float>(&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<bool>(&use_standard_lte_rates)->default_value(false), "Whether to use default LTE sample rates instead of shorter variants.")
("expert.report_json_enable", bpo::value<bool>(&args->general.report_json_enable)->default_value(false), "Write eNB report to JSON file")
("expert.report_json_filename", bpo::value<string>(&args->general.report_json_filename)->default_value("/tmp/enb_report.json"), "Report JSON filename")
("expert.alarms_log_enable", bpo::value<bool>(&args->general.alarms_log_enable)->default_value(false), "Log alarms")
("expert.alarms_filename", bpo::value<string>(&args->general.alarms_filename)->default_value("/tmp/enb_alarms.log"), "Alarms filename")
("expert.report_json_enable", bpo::value<bool>(&args->general.report_json_enable)->default_value(false), "Write eNB report to JSON file (default disabled)")
("expert.report_json_filename", bpo::value<string>(&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<bool>(&args->general.alarms_log_enable)->default_value(false), "Enable Alarms logging (default diabled)")
("expert.alarms_filename", bpo::value<string>(&args->general.alarms_filename)->default_value("/tmp/enb_alarms.log"), "Alarms logging filename (default /tmp/alarms.log)")
("expert.tracing_enable", bpo::value<bool>(&args->general.tracing_enable)->default_value(false), "Events tracing")
("expert.tracing_filename", bpo::value<string>(&args->general.tracing_filename)->default_value("/tmp/enb_tracing.log"), "Tracing events filename")
("expert.tracing_buffcapacity", bpo::value<std::size_t>(&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<string>(&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<uint32_t>(&args->stack.mac.nof_prealloc_ues)->default_value(8), "Number of UE resources to preallocate during eNB initialization")
("expert.lcid_padding", bpo::value<int>(&args->stack.mac.lcid_padding)->default_value(3), "LCID on which to put MAC padding")
("expert.max_mac_dl_kos", bpo::value<uint32_t>(&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<uint32_t>(&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<uint32_t>(&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<uint32_t>(&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<uint32_t>(&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<uint32_t>(&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<bool>(&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<uint32_t>(&args->stack.s1ap.ts1_reloc_overall_timeout)->default_value(10000), "S1AP TS 36.413 TS1RelocOverall Expiry Timeout value in milliseconds")
("expert.rlf_min_ul_snr_estim", bpo::value<int>(&args->stack.mac.rlf_min_ul_snr_estim)->default_value(-2), "SNR threshold in dB below which the eNB is notified with rlf ko.")
// eMBMS section
("embms.enable", bpo::value<bool>(&args->stack.embms.enable)->default_value(false), "Enables MBMS in the eNB")
("embms.m1u_multiaddr", bpo::value<string>(&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<uint16_t>(&args->phy.vnf_args.bind_port)->default_value(3333), "Bind port")
("log.vnf_level", bpo::value<string>(&args->phy.vnf_args.log_level), "VNF log level")
("log.vnf_hex_limit", bpo::value<int>(&args->phy.vnf_args.log_hex_limit), "VNF log hex dump limit")
// Arguments for coreless operation
("coreless.ip_devname", bpo::value<string>(&args->stack.coreless.gw_args.tun_dev_name)->default_value("tun1"), "Name of the TUN device")
("coreless.ip_address", bpo::value<string>(&args->stack.coreless.ip_addr)->default_value("192.168.1.1"), "IP address of the TUN device")
("coreless.ip_netmask", bpo::value<string>(&args->stack.coreless.gw_args.tun_dev_netmask)->default_value("255.255.255.0"), "Netmask of the TUN device")
("coreless.drb_lcid", bpo::value<uint8_t>(&args->stack.coreless.drb_lcid)->default_value(4), "LCID of the dummy DRB")
("coreless.rnti", bpo::value<uint16_t >(&args->stack.coreless.rnti)->default_value(1234), "RNTI of the dummy user")
;
;
// Positional options - config file location
bpo::options_description position("Positional options");

@ -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<stack_interface_phy_nr::pucch_info_t, stack_interface_phy_nr::MAX_PUCCH_CANDIDATES>
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<char, 512> 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());
}

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

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

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

@ -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<ue> ptr = std::unique_ptr<ue>{
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));

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

@ -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 <pthread.h>
#include <string.h>
#include <strings.h>
@ -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<srsran::mac_pcap>(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<srsran::avg_time_stats> 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_nr> ue_ptr = std::unique_ptr<ue_nr>(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

@ -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<void()>;
using callback_list = srsran::deque<callback_t>;
public:
explicit ue_event_manager(ue_map_t& ue_db_) : ue_db(ue_db_) {}
void push_event(srsran::move_callback<void()> event)
{
std::lock_guard<std::mutex> lock(common_mutex);
common_events.push_back(std::move(event));
}
void push_cc_feedback(uint16_t rnti, uint32_t cc, srsran::move_callback<void(ue_carrier&)> event)
{
std::lock_guard<std::mutex> 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<std::mutex> 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<void(ue_carrier&)> callback;
};
srsran::deque<ue_feedback> feedback_list;
callback_list common_events_tmp;
srsran::deque<ue_feedback> 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_cfg_t> 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_cfg_t> 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, ...) \

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

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

@ -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<DciDlOrUl, srsran_dci_dl_nr_t>::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<DciDlOrUl, srsran_dci_dl_nr_t>::value ? static_cast<harq_proc*>(ue.h_dl)
: static_cast<harq_proc*>(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);

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

@ -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<void(ue_carrier&)> 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;

@ -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<std::mutex> 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<std::mutex> 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<std::unique_ptr<serv_cell_manager> > 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<void()> ev)
{
return *slot_worker_ctxts[tti_rx.to_uint() % slot_worker_ctxts.size()];
std::lock_guard<std::mutex> 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<void()> 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<std::mutex> 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<std::condition_variable*, SRSRAN_MAX_CARRIERS> waiting_cvars;
{
std::lock_guard<std::mutex> db_lock(ue_db_mutex);
process_feedback();
std::unique_lock<std::mutex> 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<std::mutex> 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<int>(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<int>(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<std::mutex> lock(ue_db_mutex);
// Signal the release of slot if it is the last worker that finished its own generation
std::unique_lock<std::mutex> 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<std::mutex> 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");
}
}
}
}

@ -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 <bitset>
#include <inttypes.h>
#include <iostream>
#include <string.h>
#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<std::mutex> 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<std::mutex> 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<int, SRSRAN_MAX_CARRIERS> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> lock(metrics_mutex);
ue_metrics.nof_tti++;
}
} // namespace srsenb

@ -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<std::mutex> lock(sched_mutex);

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

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

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

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

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

@ -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();
}
/*******************************************************************************

@ -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<prepare_recfg>()) {
// 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

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

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

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

@ -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<uint32_t, srsran::unique_byte_buffer_t> get_buffered_pdus(uint16_t rnti, uint32_t lcid) override
{
return {};
}
};
class s1ap_dummy : public s1ap_interface_rrc
{
public:

@ -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<uint32_t, srsran::unique_byte_buffer_t> get_buffered_pdus(uint16_t rnti, uint32_t lcid) override
{
return {};
}
};
} // namespace srsenb
#endif // SRSENB_DUMMY_CLASSES_COMMON_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

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

@ -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<sched_nr_interface::cell_cfg_t> 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<sched_nr_interface::cell_cfg_t> 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

@ -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<sched_nr_interface::cell_cfg_t> get_default_cells_cfg(uint32_t nof_sectors)
{
std::vector<sched_nr_interface::cell_cfg_t> 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<long> 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<std::atomic<long>, 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<sched_nr_interface::cell_cfg_t> 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<std::atomic<long>, 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<std::chrono::nanoseconds>(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();
}

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

@ -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();

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

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

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

@ -40,6 +40,10 @@
#include <math.h>
#include <queue>
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;

@ -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();

@ -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();

@ -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();

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

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

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

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

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

Loading…
Cancel
Save