mirror of https://github.com/PentHertz/srsLTE.git
SRSENB: enabled CA PUCCH decode in eNb
This commit is contained in:
parent
f10f64215e
commit
231431f569
|
@ -42,6 +42,9 @@ class mac_interface_phy_lte
|
|||
public:
|
||||
const static int MAX_GRANTS = 64;
|
||||
|
||||
/**
|
||||
* DL grant structure per UE
|
||||
*/
|
||||
typedef struct {
|
||||
srslte_dci_dl_t dci;
|
||||
srslte_dci_cfg_t dci_cfg;
|
||||
|
@ -49,12 +52,18 @@ public:
|
|||
srslte_softbuffer_tx_t* softbuffer_tx[SRSLTE_MAX_TB];
|
||||
} dl_sched_grant_t;
|
||||
|
||||
/**
|
||||
* DL Scheduling result per cell/carrier
|
||||
*/
|
||||
typedef struct {
|
||||
dl_sched_grant_t pdsch[MAX_GRANTS];
|
||||
uint32_t nof_grants;
|
||||
uint32_t cfi;
|
||||
} dl_sched_t; // per carrier
|
||||
dl_sched_grant_t pdsch[MAX_GRANTS]; //< DL Grants
|
||||
uint32_t nof_grants; //< Number of DL grants
|
||||
uint32_t cfi; //< Current CFI of the cell, it can vary across cells
|
||||
} dl_sched_t;
|
||||
|
||||
/**
|
||||
* List of DL scheduling results, one entry per cell/carrier
|
||||
*/
|
||||
typedef std::vector<dl_sched_t> dl_sched_list_t;
|
||||
|
||||
typedef struct {
|
||||
|
@ -62,6 +71,9 @@ public:
|
|||
bool ack;
|
||||
} ul_sched_ack_t;
|
||||
|
||||
/**
|
||||
* UL grant information per UE
|
||||
*/
|
||||
typedef struct {
|
||||
srslte_dci_ul_t dci;
|
||||
srslte_dci_cfg_t dci_cfg;
|
||||
|
@ -71,13 +83,19 @@ public:
|
|||
srslte_softbuffer_rx_t* softbuffer_rx;
|
||||
} ul_sched_grant_t;
|
||||
|
||||
/**
|
||||
* UL Scheduling result per cell/carrier
|
||||
*/
|
||||
typedef struct {
|
||||
ul_sched_grant_t pusch[MAX_GRANTS];
|
||||
ul_sched_ack_t phich[MAX_GRANTS];
|
||||
uint32_t nof_grants;
|
||||
uint32_t nof_phich;
|
||||
} ul_sched_t; // per carrier
|
||||
} ul_sched_t;
|
||||
|
||||
/**
|
||||
* List of UL scheduling results, one entry per cell/carrier
|
||||
*/
|
||||
typedef std::vector<ul_sched_t> ul_sched_list_t;
|
||||
|
||||
virtual int sr_detected(uint32_t tti, uint16_t rnti) = 0;
|
||||
|
@ -85,9 +103,30 @@ public:
|
|||
|
||||
virtual int ri_info(uint32_t tti, uint16_t rnti, uint32_t ri_value) = 0;
|
||||
virtual int pmi_info(uint32_t tti, uint16_t rnti, uint32_t pmi_value) = 0;
|
||||
virtual int cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value) = 0;
|
||||
|
||||
/**
|
||||
* PHY callback for for giving MAC the Channel Quality information of a given RNTI, TTI and eNb cell/carrier
|
||||
* @param tti the given TTI
|
||||
* @param rnti the UE identifier in the eNb
|
||||
* @param cqi_value the corresponding Channel Quality Information
|
||||
* @return SRSLTE_SUCCESS if no error occurs, SRSLTE_ERROR* if an error occurs
|
||||
*/
|
||||
virtual int cqi_info(uint32_t tti, uint16_t rnti, uint32_t cc_idx, uint32_t cqi_value) = 0;
|
||||
|
||||
virtual int snr_info(uint32_t tti, uint16_t rnti, float snr_db) = 0;
|
||||
virtual int ack_info(uint32_t tti, uint16_t rnti, uint32_t tb_idx, bool ack) = 0;
|
||||
|
||||
/**
|
||||
* PHY callback for giving MAC the HARQ DL ACK/NACK feedback information for a given RNTI, TTI, eNb cell/carrier and
|
||||
* Transport block.
|
||||
*
|
||||
* @param tti the given TTI
|
||||
* @param rnti the UE identifier in the eNb
|
||||
* @param cc_idx the eNb Cell/Carrier identifier
|
||||
* @param tb_idx the transport block index
|
||||
* @param ack true for ACK, false for NACK, do not call for DTX
|
||||
* @return SRSLTE_SUCCESS if no error occurs, SRSLTE_ERROR* if an error occurs
|
||||
*/
|
||||
virtual int ack_info(uint32_t tti, uint16_t rnti, uint32_t cc_idx, uint32_t tb_idx, bool ack) = 0;
|
||||
virtual int crc_info(uint32_t tti, uint16_t rnti, uint32_t nof_bytes, bool crc_res) = 0;
|
||||
|
||||
virtual int get_dl_sched(uint32_t tti, dl_sched_list_t& dl_sched_res) = 0;
|
||||
|
@ -104,8 +143,16 @@ public:
|
|||
class phy_interface_mac_lte
|
||||
{
|
||||
public:
|
||||
/* MAC adds/removes an RNTI to the list of active RNTIs */
|
||||
virtual int add_rnti(uint16_t rnti, bool is_temporal = false) = 0;
|
||||
/**
|
||||
* Interface for MAC to add or modify user in the active UE database setting. This function requires a primary cell
|
||||
* (PCell) index and a list of secondary cells (SCell) for the UE. The elements in the list SCell list must follow the
|
||||
* UE's SCell indexes order.
|
||||
*
|
||||
* @param rnti identifier of the user
|
||||
* @param pcell_index Primary cell (PCell) index
|
||||
* @param is_temporal Indicates whether the UE is temporal
|
||||
*/
|
||||
virtual int add_rnti(uint16_t rnti, uint32_t pcell_index, bool is_temporal) = 0;
|
||||
virtual void rem_rnti(uint16_t rnti) = 0;
|
||||
virtual void set_mch_period_stop(uint32_t stop) = 0;
|
||||
};
|
||||
|
@ -126,8 +173,23 @@ public:
|
|||
} phy_rrc_cfg_t;
|
||||
|
||||
virtual void
|
||||
configure_mbsfn(asn1::rrc::sib_type2_s* sib2, asn1::rrc::sib_type13_r9_s* sib13, asn1::rrc::mcch_msg_s mcch) = 0;
|
||||
virtual void set_config_dedicated(uint16_t rnti, const srslte::phy_cfg_t& dedicated) = 0;
|
||||
configure_mbsfn(asn1::rrc::sib_type2_s* sib2, asn1::rrc::sib_type13_r9_s* sib13, asn1::rrc::mcch_msg_s mcch) = 0;
|
||||
|
||||
typedef struct {
|
||||
uint32_t cc_idx = 0; ///< eNb Cell index
|
||||
srslte::phy_cfg_t phy_cfg = {}; ///< Dedicated physical layer configuration
|
||||
} phy_rrc_dedicated_t;
|
||||
|
||||
typedef std::vector<phy_rrc_dedicated_t> phy_rrc_dedicated_list_t;
|
||||
|
||||
/**
|
||||
* Sets the physical layer dedicated configuration for a given RNTI, a cell index and a secondary cell index.
|
||||
* The cc_idx indicates the eNb cell to configure and the scell_idx is the UE's cell index
|
||||
*
|
||||
* @param rnti the given RNTI
|
||||
* @param dedicated_list Physical layer configuration for the indicated eNb cell
|
||||
*/
|
||||
virtual void set_config_dedicated(uint16_t rnti, const phy_rrc_dedicated_list_t& dedicated_list) = 0;
|
||||
};
|
||||
|
||||
class mac_interface_rrc
|
||||
|
|
|
@ -33,8 +33,8 @@ typedef struct SRSLTE_API {
|
|||
} srslte_uci_value_ack_t;
|
||||
|
||||
typedef struct SRSLTE_API {
|
||||
bool pending_tb[SRSLTE_MAX_CODEWORDS];
|
||||
uint32_t nof_acks;
|
||||
bool pending_tb[SRSLTE_MAX_CODEWORDS]; //< Indicates whether there was a grant that requires an ACK/NACK
|
||||
uint32_t nof_acks; //< Number of transport blocks, deduced from transmission mode
|
||||
uint32_t ncce[SRSLTE_UCI_MAX_M];
|
||||
uint32_t N_bundle;
|
||||
uint32_t tdd_ack_M;
|
||||
|
|
|
@ -1255,45 +1255,45 @@ void srslte_pucch_rx_info(srslte_pucch_cfg_t* cfg, srslte_uci_value_t* uci_data,
|
|||
srslte_pucch_format_t srslte_pucch_select_format(srslte_pucch_cfg_t* cfg, srslte_uci_cfg_t* uci_cfg, srslte_cp_t cp)
|
||||
{
|
||||
srslte_pucch_format_t format = SRSLTE_PUCCH_FORMAT_ERROR;
|
||||
uint32_t total_ack = srslte_uci_cfg_total_ack(uci_cfg);
|
||||
|
||||
// No CQI data
|
||||
if (!uci_cfg->cqi.data_enable && uci_cfg->cqi.ri_len == 0) {
|
||||
// PUCCH Format 3 condition specified in:
|
||||
// 3GPP 36.213 10.1.2.2.2 PUCCH format 3 HARQ-ACK procedure
|
||||
if (cfg->ack_nack_feedback_mode == SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_PUCCH3 &&
|
||||
srslte_uci_cfg_total_ack(uci_cfg) > 1) {
|
||||
total_ack > uci_cfg->ack[0].nof_acks) {
|
||||
format = SRSLTE_PUCCH_FORMAT_3;
|
||||
}
|
||||
// 1-bit ACK + optional SR
|
||||
else if (srslte_uci_cfg_total_ack(uci_cfg) == 1) {
|
||||
else if (total_ack == 1) {
|
||||
format = SRSLTE_PUCCH_FORMAT_1A;
|
||||
}
|
||||
// 2-bit ACK + optional SR
|
||||
else if (srslte_uci_cfg_total_ack(uci_cfg) >= 2 && srslte_uci_cfg_total_ack(uci_cfg) <= 4) {
|
||||
else if (total_ack >= 2 && total_ack <= 4) {
|
||||
format = SRSLTE_PUCCH_FORMAT_1B; // with channel selection if > 2
|
||||
}
|
||||
// If UCI value is provided, use SR signal only, otherwise SR request opportunity
|
||||
else if (uci_cfg->is_scheduling_request_tti) {
|
||||
format = SRSLTE_PUCCH_FORMAT_1;
|
||||
} else {
|
||||
ERROR("Error selecting PUCCH format: Unsupported number of ACK bits %d\n", srslte_uci_cfg_total_ack(uci_cfg));
|
||||
ERROR("Error selecting PUCCH format: Unsupported number of ACK bits %d\n", total_ack);
|
||||
}
|
||||
}
|
||||
// CQI data
|
||||
else {
|
||||
// CQI and no ack
|
||||
if (srslte_uci_cfg_total_ack(uci_cfg) == 0) {
|
||||
if (total_ack == 0) {
|
||||
format = SRSLTE_PUCCH_FORMAT_2;
|
||||
}
|
||||
// CQI + 1-bit ACK
|
||||
else if (srslte_uci_cfg_total_ack(uci_cfg) == 1 && SRSLTE_CP_ISNORM(cp)) {
|
||||
else if (total_ack == 1 && SRSLTE_CP_ISNORM(cp)) {
|
||||
format = SRSLTE_PUCCH_FORMAT_2A;
|
||||
}
|
||||
// CQI + 2-bit ACK
|
||||
else if (srslte_uci_cfg_total_ack(uci_cfg) == 2) {
|
||||
else if (total_ack == 2) {
|
||||
format = SRSLTE_PUCCH_FORMAT_2B;
|
||||
}
|
||||
// CQI + 2-bit ACK + cyclic prefix
|
||||
else if (srslte_uci_cfg_total_ack(uci_cfg) == 1 && SRSLTE_CP_ISEXT(cp)) {
|
||||
else if (total_ack == 1 && SRSLTE_CP_ISEXT(cp)) {
|
||||
format = SRSLTE_PUCCH_FORMAT_2B;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -978,6 +978,21 @@ static void gen_ack_fdd(srslte_pdsch_ack_t* ack_info, srslte_uci_data_t* uci_dat
|
|||
if (ack_info->nof_cc == 1) {
|
||||
// If only 1 configured cell, report 1 or 2 bits depending on number of detected TB
|
||||
uci_data->cfg.ack[0].nof_acks = tb_count;
|
||||
} else if (ack_info->ack_nack_feedback_mode == SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_PUCCH3 &&
|
||||
tb_count_cc0 == tb_count) {
|
||||
// According to 3GPP 36.213 Section 10.1.2.2.2 PUCCH format 3 HARQ-ACK procedure
|
||||
// For FDD with PUCCH format 3, the UE shall use PUCCH resource n_pucch_3 or n_pucch_1 for transmission of
|
||||
// HARQ-ACK in subframe n where
|
||||
// - for a PDSCH transmission only on the primary cell indicated by the detection of a corresponding PDCCH in
|
||||
// subframe n − 4 , or for a PDCCH indicating downlink SPS release (defined in subclause 9.2) in subframe n − 4
|
||||
// on the primary cell, the UE shall use PUCCH format 1a/1b and PUCCH resource n_pucch_1.
|
||||
// - for a PDSCH transmission only on the primary cell where there is not a corresponding PDCCH detected on
|
||||
// subframe n - 4, the UE shall use PUCCH format 1a/1b and PUCCH resource n_pucch_1 where the value of n_pucch_1
|
||||
// is determined according to higher layer configuration and Table 9.2-2.
|
||||
// - for a PDSCH transmission on the secondary cell indicated by the detection of a corresponding PDCCH in
|
||||
// subframe n − 4 , the UE shall use PUCCH format 3 and PUCCH resource n_pucch_3 where the value of n PUCCH
|
||||
// is determined according to higher layer configuration and Table 10.1.2.2.2-1.
|
||||
uci_data->cfg.ack[0].nof_acks = tb_count_cc0; // So, set only PCell
|
||||
} else if (uci_data->cfg.cqi.data_enable && !ack_info->is_pusch_available) {
|
||||
// 3GPP 36.213 R.15 Section 10.1.1:
|
||||
// For FDD or for FDD-TDD and primary cell frame structure type 1 and for a UE that is configured with more than
|
||||
|
|
|
@ -51,7 +51,7 @@ public:
|
|||
std::string get_type() { return "lte"; };
|
||||
|
||||
/* MAC->PHY interface */
|
||||
int add_rnti(uint16_t rnti, bool is_temporal = false) final;
|
||||
int add_rnti(uint16_t rnti, uint32_t pcell_index, bool is_temporal) final;
|
||||
void rem_rnti(uint16_t rnti) final;
|
||||
void set_mch_period_stop(uint32_t stop) final;
|
||||
|
||||
|
@ -62,7 +62,7 @@ public:
|
|||
static uint32_t tti_to_subf(uint32_t tti);
|
||||
|
||||
void start_plot();
|
||||
void set_config_dedicated(uint16_t rnti, const srslte::phy_cfg_t& dedicated);
|
||||
void set_config_dedicated(uint16_t rnti, const phy_rrc_dedicated_list_t& dedicated_list) override;
|
||||
|
||||
void get_metrics(phy_metrics_t metrics[ENB_METRICS_MAX_USERS]);
|
||||
|
||||
|
|
|
@ -134,26 +134,104 @@ public:
|
|||
|
||||
// Map of pending ACKs for each user
|
||||
typedef struct {
|
||||
bool is_pending[TTIMOD_SZ][SRSLTE_MAX_TB];
|
||||
uint16_t n_pdcch[TTIMOD_SZ];
|
||||
srslte_uci_cfg_ack_t ack[SRSLTE_MAX_CARRIERS];
|
||||
} pending_ack_t;
|
||||
|
||||
class common_ue
|
||||
{
|
||||
public:
|
||||
pending_ack_t pending_ack = {};
|
||||
pending_ack_t pending_ack[TTIMOD_SZ] = {};
|
||||
uint8_t ri = 0;
|
||||
uint32_t pcell_idx = 0;
|
||||
srslte_ra_tb_t last_tb[SRSLTE_MAX_HARQ_PROC] = {};
|
||||
std::map<uint32_t, uint32_t> scell_map;
|
||||
};
|
||||
|
||||
std::map<uint16_t, common_ue> common_ue_db;
|
||||
|
||||
void ue_db_add_rnti(uint16_t rnti);
|
||||
/**
|
||||
* Adds or modifies a user in the UE database setting. This function requires a list of cells indexes for the UE. The
|
||||
* first element of the list must be the PCell and the rest will be SCell in the order
|
||||
*
|
||||
* @param rnti identifier of the user
|
||||
* @param cell_index_list List of the eNb cell indexes for carrier aggregation
|
||||
*/
|
||||
void ue_db_addmod_rnti(uint16_t rnti, const std::vector<uint32_t>& cell_index_list);
|
||||
|
||||
/**
|
||||
* Removes a whole UE entry from the UE database
|
||||
*
|
||||
* @param rnti identifier of the UE
|
||||
*/
|
||||
void ue_db_rem_rnti(uint16_t rnti);
|
||||
void ue_db_clear(uint32_t tti);
|
||||
void ue_db_set_ack_pending(uint32_t tti, uint16_t rnti, uint32_t tb_idx, uint32_t n_pdcch);
|
||||
bool ue_db_is_ack_pending(uint32_t tti, uint16_t rnti, uint32_t tb_idx, uint32_t* last_n_pdcch = nullptr);
|
||||
void ue_db_set_ri(uint16_t rnti, uint8_t ri);
|
||||
|
||||
/**
|
||||
* Removes all the pending ACKs of all the RNTIs for a given TTI
|
||||
*
|
||||
* @param tti is the given TTI to clear
|
||||
*/
|
||||
void ue_db_clear_tti_pending_ack(uint32_t tti);
|
||||
|
||||
/**
|
||||
* Sets the pending ACK for a given TTI in a given Component Carrier and user (RNTI is a member of the DCI)
|
||||
*
|
||||
* @param tti is the given TTI to fill
|
||||
* @param cc_idx the carrier where the DCI is scheduled
|
||||
* @param dci carries the Transport Block and required scheduling information
|
||||
*
|
||||
*/
|
||||
void ue_db_set_ack_pending(uint32_t tti, uint32_t cc_idx, const srslte_dci_dl_t& dci);
|
||||
|
||||
/**
|
||||
* Requests ACK information for a given RNTI that needs to acknowledge PDSCH transmissions in the cc_idx cell/carrier.
|
||||
*
|
||||
* @param tti is the given TTI to fill
|
||||
* @param cc_idx the carrier where the DCI is scheduled
|
||||
* @param rnti is the UE identifier
|
||||
* @param uci_cfg_ack vector pointing at the UCI configuration
|
||||
*
|
||||
*/
|
||||
void ue_db_get_ack_pending(uint32_t tti,
|
||||
uint32_t cc_idx,
|
||||
uint16_t rnti,
|
||||
srslte_uci_cfg_ack_t uci_cfg_ack[SRSLTE_MAX_CARRIERS]);
|
||||
|
||||
/**
|
||||
* Provides the number of aggregated cells for a given RNTI
|
||||
* @param rnti UE's RNTI
|
||||
* @return the number of aggregated cells if the RNTI exists, otherwise it returns 0
|
||||
*/
|
||||
uint32_t ue_db_get_nof_ca_cells(uint16_t rnti);
|
||||
|
||||
/**
|
||||
* Provides the PCell index of a given UE from its RNTI
|
||||
* @param rnti UE's RNTI
|
||||
* @return the index of the PCell if it exists, the number of cells otherwise
|
||||
*/
|
||||
uint32_t ue_db_get_cc_pcell(uint16_t rnti);
|
||||
|
||||
/**
|
||||
* Requests the eNb cell index of given RNTI from its scell_idx
|
||||
*
|
||||
* @param rnti the UE temporal ID
|
||||
* @param scell_idx the UE SCell index, use 0 for PCell index
|
||||
* @return the eNb cell index if found, the number of eNb cells otherwise
|
||||
*
|
||||
*/
|
||||
uint32_t ue_db_get_cc_scell(uint16_t rnti, uint32_t scell_idx);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param rnti
|
||||
* @param ri
|
||||
*/
|
||||
void ue_db_set_ri(uint16_t rnti, uint8_t ri);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param rnti
|
||||
* @return
|
||||
*/
|
||||
uint8_t ue_db_get_ri(uint16_t rnti);
|
||||
|
||||
void ue_db_set_last_ul_tb(uint16_t rnti, uint32_t pid, srslte_ra_tb_t tb);
|
||||
|
|
|
@ -42,7 +42,7 @@ public:
|
|||
cf_t* get_buffer_rx(uint32_t cc_idx, uint32_t antenna_idx);
|
||||
void set_time(uint32_t tti, uint32_t tx_worker_cnt, srslte_timestamp_t tx_time);
|
||||
|
||||
int add_rnti(uint16_t rnti, bool is_temporal);
|
||||
int add_rnti(uint16_t rnti, uint32_t cc_idx, bool is_temporal);
|
||||
void rem_rnti(uint16_t rnti);
|
||||
uint32_t get_nof_rnti();
|
||||
|
||||
|
@ -53,7 +53,7 @@ public:
|
|||
int read_pucch_d(cf_t* pusch_d);
|
||||
void start_plot();
|
||||
|
||||
void set_config_dedicated(uint16_t rnti, const srslte::phy_cfg_t& dedicated);
|
||||
void set_config_dedicated(uint16_t rnti, uint32_t cc_idx, const srslte::phy_cfg_t& dedicated);
|
||||
|
||||
uint32_t get_metrics(phy_metrics_t metrics[ENB_METRICS_MAX_USERS]);
|
||||
|
||||
|
|
|
@ -69,11 +69,14 @@ public:
|
|||
}
|
||||
int ri_info(uint32_t tti, uint16_t rnti, uint32_t ri_value) final { return mac.ri_info(tti, rnti, ri_value); }
|
||||
int pmi_info(uint32_t tti, uint16_t rnti, uint32_t pmi_value) final { return mac.pmi_info(tti, rnti, pmi_value); }
|
||||
int cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value) final { return mac.cqi_info(tti, rnti, cqi_value); }
|
||||
int snr_info(uint32_t tti, uint16_t rnti, float snr_db) final { return mac.snr_info(tti, rnti, snr_db); }
|
||||
int ack_info(uint32_t tti, uint16_t rnti, uint32_t tb_idx, bool ack) final
|
||||
int cqi_info(uint32_t tti, uint16_t rnti, uint32_t cc_idx, uint32_t cqi_value) final
|
||||
{
|
||||
return mac.ack_info(tti, rnti, tb_idx, ack);
|
||||
return mac.cqi_info(tti, rnti, cc_idx, cqi_value);
|
||||
}
|
||||
int snr_info(uint32_t tti, uint16_t rnti, float snr_db) final { return mac.snr_info(tti, rnti, snr_db); }
|
||||
int ack_info(uint32_t tti, uint16_t rnti, uint32_t cc_idx, uint32_t tb_idx, bool ack) final
|
||||
{
|
||||
return mac.ack_info(tti, rnti, cc_idx, tb_idx, ack);
|
||||
}
|
||||
int crc_info(uint32_t tti, uint16_t rnti, uint32_t nof_bytes, bool crc_res) final
|
||||
{
|
||||
|
|
|
@ -58,9 +58,9 @@ public:
|
|||
|
||||
int ri_info(uint32_t tti, uint16_t rnti, uint32_t ri_value);
|
||||
int pmi_info(uint32_t tti, uint16_t rnti, uint32_t pmi_value);
|
||||
int cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value);
|
||||
int cqi_info(uint32_t tti, uint16_t rnti, uint32_t cc_idx, uint32_t cqi_value) override;
|
||||
int snr_info(uint32_t tti, uint16_t rnti, float snr);
|
||||
int ack_info(uint32_t tti, uint16_t rnti, uint32_t tb_idx, bool ack);
|
||||
int ack_info(uint32_t tti, uint16_t rnti, uint32_t cc_idx, uint32_t tb_idx, bool ack) override;
|
||||
int crc_info(uint32_t tti, uint16_t rnti, uint32_t nof_bytes, bool crc_res);
|
||||
|
||||
int get_dl_sched(uint32_t tti, dl_sched_list_t& dl_sched_res);
|
||||
|
|
|
@ -186,7 +186,7 @@ void cc_worker::set_tti(uint32_t tti_)
|
|||
int cc_worker::add_rnti(uint16_t rnti, bool is_temporal)
|
||||
{
|
||||
|
||||
if (!is_temporal) {
|
||||
if (!is_temporal && !ue_db.count(rnti)) {
|
||||
if (srslte_enb_dl_add_rnti(&enb_dl, rnti)) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -252,7 +252,10 @@ void cc_worker::set_config_dedicated(uint16_t rnti, const srslte::phy_cfg_t& ded
|
|||
|
||||
if (ue_db.count(rnti)) {
|
||||
ue_db[rnti]->ul_cfg = dedicated.ul_cfg;
|
||||
ue_db[rnti]->ul_cfg.pucch.rnti = rnti;
|
||||
ue_db[rnti]->ul_cfg.pusch.rnti = rnti;
|
||||
ue_db[rnti]->dl_cfg = dedicated.dl_cfg;
|
||||
ue_db[rnti]->dl_cfg.pdsch.rnti = rnti;
|
||||
} else {
|
||||
Error("Setting config dedicated: rnti=0x%x does not exist\n", rnti);
|
||||
}
|
||||
|
@ -320,14 +323,17 @@ bool cc_worker::fill_uci_cfg(uint16_t rnti, bool aperiodic_cqi_request, srslte_u
|
|||
|
||||
uci_required |= uci_cfg->is_scheduling_request_tti;
|
||||
|
||||
// Get pending ACKs with an associated PUSCH transmission
|
||||
// TODO: Use ue_dl procedures to compute uci_ack_cfg for TDD and CA
|
||||
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
|
||||
uci_cfg->ack[cc_idx].pending_tb[tb] = phy->ue_db_is_ack_pending(tti_rx, rnti, tb, &uci_cfg->ack[cc_idx].ncce[0]);
|
||||
Debug("ACK: is pending tti=%d, mod=%d, value=%d\n", tti_rx, TTIMOD(tti_rx), uci_cfg->ack[cc_idx].pending_tb[tb]);
|
||||
if (uci_cfg->ack[cc_idx].pending_tb[tb]) {
|
||||
uci_cfg->ack[cc_idx].nof_acks++;
|
||||
uci_required = true;
|
||||
// Get pending ACKs from PDSCH
|
||||
phy->ue_db_get_ack_pending(tti_rx, cc_idx, rnti, uci_cfg->ack);
|
||||
uint32_t nof_total_ack = srslte_uci_cfg_total_ack(uci_cfg);
|
||||
uci_required |= (nof_total_ack != 0);
|
||||
|
||||
// if UCI is required and the PCell is not the only cell
|
||||
if (uci_required && nof_total_ack != uci_cfg->ack[0].nof_acks) {
|
||||
// More than one carrier requires ACKs
|
||||
for (uint32_t cc = 0; cc < phy->ue_db_get_nof_ca_cells(rnti); cc++) {
|
||||
// Assume all aggregated carriers are on the same transmission mode
|
||||
uci_cfg->ack[cc].nof_acks = (ue_db[rnti]->dl_cfg.tm < SRSLTE_TM3) ? 1 : 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -352,12 +358,20 @@ void cc_worker::send_uci_data(uint16_t rnti, srslte_uci_cfg_t* uci_cfg, srslte_u
|
|||
|
||||
/* If only one ACK is required, it can be for TB0 or TB1 */
|
||||
uint32_t ack_idx = 0;
|
||||
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
|
||||
if (uci_cfg->ack[cc_idx].pending_tb[tb]) {
|
||||
bool ack = uci_value->ack.ack_value[ack_idx];
|
||||
bool valid = uci_value->ack.valid;
|
||||
phy->stack->ack_info(tti_rx, rnti, tb, ack && valid);
|
||||
ack_idx++;
|
||||
for (uint32_t ue_scell_idx = 0; ue_scell_idx < SRSLTE_MAX_CARRIERS; ue_scell_idx++) {
|
||||
uint32_t cc_ack_idx = phy->ue_db_get_cc_scell(rnti, ue_scell_idx);
|
||||
if (cc_ack_idx < phy->get_nof_carriers()) {
|
||||
|
||||
// For each transport block...
|
||||
for (uint32_t tb = 0; tb < uci_cfg->ack[ue_scell_idx].nof_acks; tb++) {
|
||||
// Check if the SCell ACK was pending
|
||||
if (uci_cfg->ack[ue_scell_idx].pending_tb[tb]) {
|
||||
bool ack = uci_value->ack.ack_value[ack_idx];
|
||||
bool valid = uci_value->ack.valid;
|
||||
phy->stack->ack_info(tti_rx, rnti, cc_ack_idx, tb, ack && valid);
|
||||
}
|
||||
ack_idx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -379,7 +393,7 @@ void cc_worker::send_uci_data(uint16_t rnti, srslte_uci_cfg_t* uci_cfg, srslte_u
|
|||
cqi_value = uci_value->cqi.subband_ue.wideband_cqi;
|
||||
break;
|
||||
}
|
||||
phy->stack->cqi_info(tti_rx, rnti, cqi_value);
|
||||
phy->stack->cqi_info(tti_rx, rnti, 0, cqi_value);
|
||||
}
|
||||
if (uci_cfg->cqi.ri_len) {
|
||||
phy->stack->ri_info(tti_rx, rnti, uci_value->ri);
|
||||
|
@ -611,13 +625,9 @@ int cc_worker::encode_pdsch(stack_interface_phy_lte::dl_sched_grant_t* grants, u
|
|||
|
||||
/* Scales the Resources Elements affected by the power allocation (p_b) */
|
||||
// srslte_enb_dl_prepare_power_allocation(&enb_dl);
|
||||
|
||||
// Prepare for receive ACK for DL grants in t_tx_dl+4
|
||||
phy->ue_db_clear(tti_tx_ul);
|
||||
|
||||
for (uint32_t i = 0; i < nof_grants; i++) {
|
||||
uint16_t rnti = grants[i].dci.rnti;
|
||||
if (rnti) {
|
||||
if (rnti && ue_db.count(rnti)) {
|
||||
|
||||
// Compute DL grant
|
||||
if (srslte_ra_dl_dci_to_grant(
|
||||
|
@ -638,14 +648,8 @@ int cc_worker::encode_pdsch(stack_interface_phy_lte::dl_sched_grant_t* grants, u
|
|||
|
||||
// Save pending ACK
|
||||
if (SRSLTE_RNTI_ISUSER(rnti)) {
|
||||
/* For each TB */
|
||||
for (uint32_t tb_idx = 0; tb_idx < SRSLTE_MAX_TB; tb_idx++) {
|
||||
/* If TB enabled, set pending ACK */
|
||||
if (ue_db[rnti]->dl_cfg.pdsch.grant.tb[tb_idx].enabled) {
|
||||
Debug("ACK: set pending tti=%d, mod=%d\n", tti_tx_ul, TTIMOD(tti_tx_ul));
|
||||
phy->ue_db_set_ack_pending(tti_tx_ul, rnti, tb_idx, grants[i].dci.location.ncce);
|
||||
}
|
||||
}
|
||||
// Push whole DCI
|
||||
phy->ue_db_set_ack_pending(tti_tx_ul, cc_idx, grants[i].dci);
|
||||
}
|
||||
|
||||
if (LOG_THIS(rnti)) {
|
||||
|
@ -657,6 +661,8 @@ int cc_worker::encode_pdsch(stack_interface_phy_lte::dl_sched_grant_t* grants, u
|
|||
|
||||
// Save metrics stats
|
||||
ue_db[rnti]->metrics_dl(grants[i].dci.tb[0].mcs_idx);
|
||||
} else {
|
||||
ERROR("RNTI (x%x) not found in Component Carrier worker %d\n", rnti, cc_idx);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -192,17 +192,18 @@ uint32_t phy::tti_to_subf(uint32_t tti)
|
|||
}
|
||||
|
||||
/***** MAC->PHY interface **********/
|
||||
int phy::add_rnti(uint16_t rnti, bool is_temporal)
|
||||
int phy::add_rnti(uint16_t rnti, uint32_t pcell_index, bool is_temporal)
|
||||
{
|
||||
if (SRSLTE_RNTI_ISUSER(rnti)) {
|
||||
workers_common.ue_db_add_rnti(rnti);
|
||||
workers_common.ue_db_addmod_rnti(rnti, {pcell_index});
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < nof_workers; i++) {
|
||||
if (workers[i].add_rnti(rnti, is_temporal)) {
|
||||
if (workers[i].add_rnti(rnti, pcell_index, is_temporal)) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -253,11 +254,29 @@ void phy::get_metrics(phy_metrics_t metrics[ENB_METRICS_MAX_USERS])
|
|||
|
||||
/***** RRC->PHY interface **********/
|
||||
|
||||
void phy::set_config_dedicated(uint16_t rnti, const srslte::phy_cfg_t& dedicated)
|
||||
void phy::set_config_dedicated(uint16_t rnti, const phy_rrc_dedicated_list_t& dedicated_list)
|
||||
{
|
||||
for (uint32_t i = 0; i < nof_workers; i++) {
|
||||
workers[i].set_config_dedicated(rnti, dedicated);
|
||||
// Create list
|
||||
std::vector<uint32_t> scell_idx_list(dedicated_list.size());
|
||||
|
||||
for (uint32_t i = 0; i < dedicated_list.size(); i++) {
|
||||
auto& config = dedicated_list[i];
|
||||
|
||||
// Set SCell index in list
|
||||
scell_idx_list[i] = config.cc_idx;
|
||||
|
||||
// Configure workers
|
||||
for (uint32_t w = 0; w < nof_workers; w++) {
|
||||
// Add RNTI to worker
|
||||
workers[w].add_rnti(rnti, config.cc_idx, false);
|
||||
|
||||
// Configure RNTI
|
||||
workers[w].set_config_dedicated(rnti, config.cc_idx, config.phy_cfg);
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, set UE database
|
||||
workers_common.ue_db_addmod_rnti(rnti, scell_idx_list);
|
||||
}
|
||||
|
||||
void phy::configure_mbsfn(sib_type2_s* sib2, sib_type13_r9_s* sib13, mcch_msg_s mcch)
|
||||
|
|
|
@ -158,31 +158,44 @@ void phy_common::worker_end(uint32_t tti,
|
|||
stack->tti_clock();
|
||||
}
|
||||
|
||||
void phy_common::ue_db_clear(uint32_t tti)
|
||||
void phy_common::ue_db_clear_tti_pending_ack(uint32_t tti)
|
||||
{
|
||||
for (auto iter = common_ue_db.begin(); iter != common_ue_db.end(); ++iter) {
|
||||
pending_ack_t* p = &((common_ue*)&iter->second)->pending_ack;
|
||||
for (uint32_t tb_idx = 0; tb_idx < SRSLTE_MAX_TB; tb_idx++) {
|
||||
p->is_pending[TTIMOD(tti)][tb_idx] = false;
|
||||
}
|
||||
std::lock_guard<std::mutex> lock(user_mutex);
|
||||
|
||||
for (auto& iter : common_ue_db) {
|
||||
common_ue& ue = iter.second;
|
||||
|
||||
// Reset all pending ACKs in all carriers
|
||||
ue.pending_ack[TTIMOD(tti)] = {};
|
||||
}
|
||||
}
|
||||
|
||||
void phy_common::ue_db_add_rnti(uint16_t rnti)
|
||||
void phy_common::ue_db_addmod_rnti(uint16_t rnti, const std::vector<uint32_t>& cell_index_list)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(user_mutex);
|
||||
|
||||
// Create new user if did not exist
|
||||
if (!common_ue_db.count(rnti)) {
|
||||
add_rnti(rnti);
|
||||
}
|
||||
|
||||
// Get UE by reference
|
||||
common_ue& ue = common_ue_db[rnti];
|
||||
|
||||
// Clear SCell map to avoid overlap from previous calls
|
||||
ue.scell_map.clear();
|
||||
|
||||
// Add SCells to map
|
||||
for (uint32_t i = 0; i < cell_index_list.size(); i++) {
|
||||
common_ue_db[rnti].scell_map[cell_index_list[i]] = i;
|
||||
}
|
||||
}
|
||||
|
||||
// Private function not mutexed
|
||||
void phy_common::add_rnti(uint16_t rnti)
|
||||
{
|
||||
for (int i = 0; i < TTIMOD_SZ; i++) {
|
||||
for (uint32_t tb_idx = 0; tb_idx < SRSLTE_MAX_TB; tb_idx++) {
|
||||
common_ue_db[rnti].pending_ack.is_pending[i][tb_idx] = false;
|
||||
}
|
||||
for (auto& pending_ack : common_ue_db[rnti].pending_ack) {
|
||||
pending_ack = {};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -194,30 +207,108 @@ void phy_common::ue_db_rem_rnti(uint16_t rnti)
|
|||
}
|
||||
}
|
||||
|
||||
void phy_common::ue_db_set_ack_pending(uint32_t tti, uint16_t rnti, uint32_t tb_idx, uint32_t last_n_pdcch)
|
||||
void phy_common::ue_db_set_ack_pending(uint32_t tti, uint32_t cc_idx, const srslte_dci_dl_t& dci)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(user_mutex);
|
||||
if (common_ue_db.count(rnti)) {
|
||||
common_ue_db[rnti].pending_ack.is_pending[TTIMOD(tti)][tb_idx] = true;
|
||||
common_ue_db[rnti].pending_ack.n_pdcch[TTIMOD(tti)] = (uint16_t)last_n_pdcch;
|
||||
|
||||
// Check if the UE exists
|
||||
if (!common_ue_db.count(dci.rnti)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check Component Carrier is part of UE SCell map
|
||||
common_ue& ue = common_ue_db[dci.rnti];
|
||||
if (!ue.scell_map.count(cc_idx)) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t scell_idx = ue.scell_map[cc_idx];
|
||||
uint32_t tti_idx = TTIMOD(tti);
|
||||
pending_ack_t& pending_ack = ue.pending_ack[tti_idx];
|
||||
|
||||
// Set DCI info
|
||||
pending_ack.ack[scell_idx].grant_cc_idx = scell_idx; // No cross carrier scheduling supported
|
||||
pending_ack.ack[scell_idx].ncce[0] = dci.location.ncce;
|
||||
|
||||
// Set TB info
|
||||
for (uint32_t i = 0; i < SRSLTE_MAX_TB; i++) {
|
||||
if (SRSLTE_DCI_IS_TB_EN(dci.tb[i])) {
|
||||
pending_ack.ack[scell_idx].pending_tb[i] = true;
|
||||
pending_ack.ack[scell_idx].nof_acks++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool phy_common::ue_db_is_ack_pending(uint32_t tti, uint16_t rnti, uint32_t tb_idx, uint32_t* last_n_pdcch)
|
||||
void phy_common::ue_db_get_ack_pending(uint32_t tti,
|
||||
uint32_t cc_idx,
|
||||
uint16_t rnti,
|
||||
srslte_uci_cfg_ack_t uci_cfg_ack[SRSLTE_MAX_CARRIERS])
|
||||
{
|
||||
bool ret = false;
|
||||
std::lock_guard<std::mutex> lock(user_mutex);
|
||||
if (common_ue_db.count(rnti)) {
|
||||
ret = common_ue_db[rnti].pending_ack.is_pending[TTIMOD(tti)][tb_idx];
|
||||
common_ue_db[rnti].pending_ack.is_pending[TTIMOD(tti)][tb_idx] = false;
|
||||
|
||||
if (ret && last_n_pdcch) {
|
||||
*last_n_pdcch = common_ue_db[rnti].pending_ack.n_pdcch[TTIMOD(tti)];
|
||||
// Check if the UE exists
|
||||
if (!common_ue_db.count(rnti)) {
|
||||
return;
|
||||
}
|
||||
|
||||
common_ue& ue = common_ue_db[rnti];
|
||||
uint32_t tti_idx = TTIMOD(tti);
|
||||
|
||||
// Check Component Carrier is the UE PCell
|
||||
if (common_ue_db[rnti].pcell_idx == cc_idx) {
|
||||
srslte_uci_cfg_ack_t* pending_acks = ue.pending_ack[tti_idx].ack;
|
||||
|
||||
for (uint32_t i = 0; i < SRSLTE_MAX_CARRIERS; i++) {
|
||||
// Copy pending acks
|
||||
uci_cfg_ack[i] = pending_acks[i];
|
||||
|
||||
// Reset stored pending acks
|
||||
pending_acks[i] = {};
|
||||
}
|
||||
} else {
|
||||
for (uint32_t i = 0; i < SRSLTE_MAX_CARRIERS; i++) {
|
||||
// Set all to zeros, equivalent to no UCI data
|
||||
uci_cfg_ack[i] = {};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t phy_common::ue_db_get_nof_ca_cells(uint16_t rnti)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(user_mutex);
|
||||
auto ret = 0;
|
||||
if (common_ue_db.count(rnti)) {
|
||||
ret = common_ue_db[rnti].scell_map.size();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t phy_common::ue_db_get_cc_pcell(uint16_t rnti)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(user_mutex);
|
||||
auto ret = static_cast<uint32_t>(cell_list.size());
|
||||
if (common_ue_db.count(rnti)) {
|
||||
ret = common_ue_db[rnti].pcell_idx;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t phy_common::ue_db_get_cc_scell(uint16_t rnti, uint32_t scell_idx)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(user_mutex);
|
||||
|
||||
if (common_ue_db.count(rnti)) {
|
||||
auto& ue = common_ue_db[rnti];
|
||||
for (auto& it : ue.scell_map) {
|
||||
if (it.second == scell_idx) {
|
||||
return it.first;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return static_cast<uint32_t>(cell_list.size());
|
||||
}
|
||||
|
||||
void phy_common::ue_db_set_ri(uint16_t rnti, uint8_t ri)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(user_mutex);
|
||||
|
|
|
@ -136,12 +136,16 @@ void sf_worker::set_time(uint32_t tti_, uint32_t tx_worker_cnt_, srslte_timestam
|
|||
}
|
||||
}
|
||||
|
||||
int sf_worker::add_rnti(uint16_t rnti, bool is_temporal)
|
||||
int sf_worker::add_rnti(uint16_t rnti, uint32_t cc_idx, bool is_temporal)
|
||||
{
|
||||
for (auto& w : cc_workers) {
|
||||
w->add_rnti(rnti, is_temporal);
|
||||
int ret = SRSLTE_ERROR;
|
||||
|
||||
if (cc_idx < cc_workers.size()) {
|
||||
cc_workers[cc_idx]->add_rnti(rnti, is_temporal);
|
||||
ret = SRSLTE_SUCCESS;
|
||||
}
|
||||
return SRSLTE_SUCCESS;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void sf_worker::rem_rnti(uint16_t rnti)
|
||||
|
@ -156,10 +160,12 @@ uint32_t sf_worker::get_nof_rnti()
|
|||
return cc_workers[0]->get_nof_rnti();
|
||||
}
|
||||
|
||||
void sf_worker::set_config_dedicated(uint16_t rnti, const srslte::phy_cfg_t& dedicated)
|
||||
void sf_worker::set_config_dedicated(uint16_t rnti, uint32_t cc_idx, const srslte::phy_cfg_t& dedicated)
|
||||
{
|
||||
for (auto& w : cc_workers) {
|
||||
w->set_config_dedicated(rnti, dedicated);
|
||||
if (cc_idx < cc_workers.size()) {
|
||||
cc_workers[cc_idx]->set_config_dedicated(rnti, dedicated);
|
||||
} else {
|
||||
log_h->error("cc_idx %d exceeds the number of carriers (%ld)\n", cc_idx, cc_workers.size());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -226,6 +232,9 @@ void sf_worker::work_imp()
|
|||
dl_sf.sf_type = sf_type;
|
||||
dl_sf.non_mbsfn_region = mbsfn_cfg.non_mbsfn_region_length;
|
||||
|
||||
// Prepare for receive ACK for DL grants in t_tx_dl+4
|
||||
phy->ue_db_clear_tti_pending_ack(tti_tx_ul);
|
||||
|
||||
// Process DL
|
||||
for (uint32_t cc = 0; cc < cc_workers.size(); cc++) {
|
||||
cc_workers[cc]->work_dl(dl_sf, phy->dl_grants[t_tx_dl][cc], phy->ul_grants[t_tx_ul][cc], &mbsfn_cfg);
|
||||
|
|
|
@ -207,7 +207,7 @@ int mac::ue_cfg(uint16_t rnti, sched_interface::ue_cfg_t* cfg)
|
|||
ue_db[rnti]->is_phy_added = true;
|
||||
Info("Registering rnti=0x%x to PHY...\n", rnti);
|
||||
// Register new user in PHY
|
||||
if (phy_h->add_rnti(rnti)) {
|
||||
if (phy_h->add_rnti(rnti, 0, false)) {
|
||||
Error("Registering new ue rnti=0x%x to PHY\n", rnti);
|
||||
}
|
||||
Info("Done registering rnti=0x%x to PHY...\n", rnti);
|
||||
|
@ -304,10 +304,9 @@ void mac::rl_ok(uint16_t rnti)
|
|||
pthread_rwlock_unlock(&rwlock);
|
||||
}
|
||||
|
||||
int mac::ack_info(uint32_t tti, uint16_t rnti, uint32_t tb_idx, bool ack)
|
||||
int mac::ack_info(uint32_t tti, uint16_t rnti, uint32_t cc_idx, uint32_t tb_idx, bool ack)
|
||||
{
|
||||
// TODO: add cc_idx to interface
|
||||
uint32_t cc_idx = 0;
|
||||
pthread_rwlock_rdlock(&rwlock);
|
||||
log_h->step(tti);
|
||||
uint32_t nof_bytes = scheduler.dl_ack_info(tti, rnti, cc_idx, tb_idx, ack);
|
||||
|
@ -388,10 +387,8 @@ int mac::pmi_info(uint32_t tti, uint16_t rnti, uint32_t pmi_value)
|
|||
return ret;
|
||||
}
|
||||
|
||||
int mac::cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value)
|
||||
int mac::cqi_info(uint32_t tti, uint16_t rnti, uint32_t cc_idx, uint32_t cqi_value)
|
||||
{
|
||||
// TODO: add cc_idx to interface
|
||||
uint32_t cc_idx = 0;
|
||||
log_h->step(tti);
|
||||
int ret = -1;
|
||||
|
||||
|
@ -484,7 +481,7 @@ int mac::rach_detected(uint32_t tti, uint32_t enb_cc_idx, uint32_t preamble_idx,
|
|||
rrc_h->add_user(rnti, ue_cfg);
|
||||
|
||||
// Add temporal rnti to the PHY
|
||||
if (phy_h->add_rnti(rnti, true)) {
|
||||
if (phy_h->add_rnti(rnti, enb_cc_idx, true)) {
|
||||
Error("Registering temporal-rnti=0x%x to PHY\n", rnti);
|
||||
}
|
||||
|
||||
|
|
|
@ -121,7 +121,7 @@ public:
|
|||
configure_mbsfn(asn1::rrc::sib_type2_s* sib2, asn1::rrc::sib_type13_r9_s* sib13, asn1::rrc::mcch_msg_s mcch) override
|
||||
{
|
||||
}
|
||||
void set_config_dedicated(uint16_t rnti, const srslte::phy_cfg_t& dedicated) override {}
|
||||
void set_config_dedicated(uint16_t rnti, const phy_rrc_dedicated_list_t& dedicated_list) override {}
|
||||
};
|
||||
|
||||
class gtpu_dummy : public gtpu_interface_rrc
|
||||
|
|
|
@ -57,7 +57,7 @@ private:
|
|||
{ \
|
||||
std::unique_lock<std::mutex> lock(mutex); \
|
||||
cvar.notify_all(); \
|
||||
log_h.info(#NAME " received\n"); \
|
||||
log_h.debug(#NAME " received\n"); \
|
||||
received_##NAME = true; \
|
||||
}
|
||||
|
||||
|
@ -69,7 +69,6 @@ private:
|
|||
srslte::log_filter log_h;
|
||||
std::vector<srslte_ringbuffer_t*> ringbuffers_tx;
|
||||
std::vector<srslte_ringbuffer_t*> ringbuffers_rx;
|
||||
srslte_timestamp_t ts_tx = {};
|
||||
srslte_timestamp_t ts_rx = {};
|
||||
double rx_srate = 0.0;
|
||||
bool running = true;
|
||||
|
@ -98,13 +97,13 @@ private:
|
|||
CALLBACK(get_info);
|
||||
|
||||
public:
|
||||
dummy_radio(uint32_t nof_channels) : log_h("RADIO")
|
||||
explicit dummy_radio(uint32_t nof_channels) : log_h("RADIO")
|
||||
{
|
||||
log_h.set_level("info");
|
||||
|
||||
// Allocate receive ring buffer
|
||||
for (uint32_t i = 0; i < nof_channels; i++) {
|
||||
srslte_ringbuffer_t* rb = (srslte_ringbuffer_t*)srslte_vec_malloc(sizeof(srslte_ringbuffer_t));
|
||||
auto* rb = (srslte_ringbuffer_t*)srslte_vec_malloc(sizeof(srslte_ringbuffer_t));
|
||||
if (!rb) {
|
||||
ERROR("Allocating ring buffer\n");
|
||||
}
|
||||
|
@ -118,7 +117,7 @@ public:
|
|||
|
||||
// Allocate transmit ring buffer
|
||||
for (uint32_t i = 0; i < nof_channels; i++) {
|
||||
srslte_ringbuffer_t* rb = (srslte_ringbuffer_t*)srslte_vec_malloc(sizeof(srslte_ringbuffer_t));
|
||||
auto* rb = (srslte_ringbuffer_t*)srslte_vec_malloc(sizeof(srslte_ringbuffer_t));
|
||||
if (!rb) {
|
||||
ERROR("Allocating ring buffer\n");
|
||||
}
|
||||
|
@ -191,9 +190,6 @@ public:
|
|||
err = srslte_ringbuffer_write(ringbuffers_tx[i], buffer[i], nbytes);
|
||||
}
|
||||
|
||||
// Copy new timestamp
|
||||
ts_tx = tx_time;
|
||||
|
||||
// Notify call
|
||||
notify_tx();
|
||||
|
||||
|
@ -257,6 +253,8 @@ public:
|
|||
class dummy_stack : public srsenb::stack_interface_phy_lte
|
||||
{
|
||||
private:
|
||||
static constexpr float prob_dl_grant = 0.50f;
|
||||
|
||||
std::mutex mutex;
|
||||
std::condition_variable cvar;
|
||||
srslte::log_filter log_h;
|
||||
|
@ -265,6 +263,7 @@ private:
|
|||
srslte_softbuffer_rx_t softbuffer_rx = {};
|
||||
uint8_t* data = nullptr;
|
||||
uint16_t ue_rnti = 0;
|
||||
srslte_random_t random_gen = nullptr;
|
||||
|
||||
CALLBACK(sr_detected);
|
||||
CALLBACK(rach_detected);
|
||||
|
@ -282,8 +281,17 @@ private:
|
|||
CALLBACK(rl_ok);
|
||||
CALLBACK(tti_clock);
|
||||
|
||||
typedef struct {
|
||||
uint32_t tti;
|
||||
uint32_t cc_idx;
|
||||
uint32_t tb_idx;
|
||||
} tti_dl_info_t;
|
||||
|
||||
std::queue<tti_dl_info_t> tti_dl_info_sched_queue;
|
||||
std::queue<tti_dl_info_t> tti_dl_info_ack_queue;
|
||||
|
||||
public:
|
||||
dummy_stack(uint16_t rnti_) : log_h("STACK"), ue_rnti(rnti_)
|
||||
explicit dummy_stack(uint16_t rnti_) : log_h("STACK"), ue_rnti(rnti_), random_gen(srslte_random_init(0))
|
||||
{
|
||||
log_h.set_level("info");
|
||||
srslte_softbuffer_tx_init(&softbuffer_tx, SRSLTE_MAX_PRB);
|
||||
|
@ -321,7 +329,7 @@ public:
|
|||
notify_pmi_info();
|
||||
return 0;
|
||||
}
|
||||
int cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value) override
|
||||
int cqi_info(uint32_t tti, uint16_t rnti, uint32_t cc_idx, uint32_t cqi_value) override
|
||||
{
|
||||
notify_cqi_info();
|
||||
return 0;
|
||||
|
@ -331,8 +339,16 @@ public:
|
|||
notify_snr_info();
|
||||
return 0;
|
||||
}
|
||||
int ack_info(uint32_t tti, uint16_t rnti, uint32_t tb_idx, bool ack) override
|
||||
int ack_info(uint32_t tti, uint16_t rnti, uint32_t cc_idx, uint32_t tb_idx, bool ack) override
|
||||
{
|
||||
// Push grant info in queue
|
||||
tti_dl_info_t tti_dl_info = {};
|
||||
tti_dl_info.tti = tti;
|
||||
tti_dl_info.cc_idx = cc_idx;
|
||||
tti_dl_info.tb_idx = 0;
|
||||
tti_dl_info_ack_queue.push(tti_dl_info);
|
||||
|
||||
log_h.info("Received ACK tti=%d; rnti=x%x; cc=%d; tb=%d; ack=%d;\n", tti, rnti, cc_idx, tb_idx, ack);
|
||||
notify_ack_info();
|
||||
return 0;
|
||||
}
|
||||
|
@ -343,30 +359,52 @@ public:
|
|||
}
|
||||
int get_dl_sched(uint32_t tti, dl_sched_list_t& dl_sched_res) override
|
||||
{
|
||||
// Notify test engine
|
||||
notify_get_dl_sched();
|
||||
|
||||
// Wait for UE
|
||||
tti_sync.wait();
|
||||
|
||||
for (auto& dl_sched : dl_sched_res) {
|
||||
dl_sched.cfi = 1;
|
||||
dl_sched.nof_grants = 1;
|
||||
dl_sched.pdsch[0].softbuffer_tx[0] = &softbuffer_tx;
|
||||
dl_sched.pdsch[0].softbuffer_tx[1] = &softbuffer_tx;
|
||||
dl_sched.pdsch[0].dci.location.ncce = 0;
|
||||
dl_sched.pdsch[0].dci.location.L = 1;
|
||||
dl_sched.pdsch[0].dci.type0_alloc.rbg_bitmask = 0xffffffff;
|
||||
dl_sched.pdsch[0].dci.rnti = ue_rnti;
|
||||
dl_sched.pdsch[0].dci.alloc_type = SRSLTE_RA_ALLOC_TYPE0;
|
||||
dl_sched.pdsch[0].dci.tb[0].cw_idx = 0;
|
||||
dl_sched.pdsch[0].dci.tb[0].mcs_idx = 27;
|
||||
dl_sched.pdsch[0].dci.tb[0].rv = 0;
|
||||
dl_sched.pdsch[0].dci.tb[0].ndi = 0;
|
||||
dl_sched.pdsch[0].data[0] = data;
|
||||
dl_sched.pdsch[0].data[1] = data;
|
||||
dl_sched.pdsch[0].dci.format = SRSLTE_DCI_FORMAT1;
|
||||
}
|
||||
for (uint32_t cc_idx = 0; cc_idx < dl_sched_res.size(); cc_idx++) {
|
||||
auto& dl_sched = dl_sched_res[cc_idx];
|
||||
|
||||
// Notify test engine
|
||||
notify_get_dl_sched();
|
||||
// Required
|
||||
dl_sched.cfi = 1;
|
||||
|
||||
// Random decision on whether transmit or not
|
||||
if (srslte_random_uniform_real_dist(random_gen, 0, 1) < prob_dl_grant) {
|
||||
dl_sched.nof_grants = 1;
|
||||
dl_sched.pdsch[0].softbuffer_tx[0] = &softbuffer_tx;
|
||||
dl_sched.pdsch[0].softbuffer_tx[1] = &softbuffer_tx;
|
||||
dl_sched.pdsch[0].dci.location.ncce = 0;
|
||||
dl_sched.pdsch[0].dci.location.L = 1;
|
||||
dl_sched.pdsch[0].dci.type0_alloc.rbg_bitmask = 0xffffffff;
|
||||
dl_sched.pdsch[0].dci.rnti = ue_rnti;
|
||||
dl_sched.pdsch[0].dci.alloc_type = SRSLTE_RA_ALLOC_TYPE0;
|
||||
dl_sched.pdsch[0].dci.tb[0].cw_idx = 0;
|
||||
dl_sched.pdsch[0].dci.tb[0].mcs_idx = 27;
|
||||
dl_sched.pdsch[0].dci.tb[0].rv = 0;
|
||||
dl_sched.pdsch[0].dci.tb[0].ndi = false;
|
||||
dl_sched.pdsch[0].dci.tb[1].cw_idx = 1;
|
||||
dl_sched.pdsch[0].dci.tb[1].mcs_idx = 0;
|
||||
dl_sched.pdsch[0].dci.tb[1].rv = 1;
|
||||
dl_sched.pdsch[0].dci.tb[1].ndi = false;
|
||||
dl_sched.pdsch[0].data[0] = data;
|
||||
dl_sched.pdsch[0].data[1] = data;
|
||||
dl_sched.pdsch[0].dci.format = SRSLTE_DCI_FORMAT1;
|
||||
|
||||
// Push grant info in queue
|
||||
tti_dl_info_t tti_dl_info = {};
|
||||
tti_dl_info.tti = tti;
|
||||
tti_dl_info.cc_idx = cc_idx;
|
||||
tti_dl_info.tb_idx = 0;
|
||||
|
||||
// Push to queue
|
||||
tti_dl_info_sched_queue.push(tti_dl_info);
|
||||
} else {
|
||||
dl_sched.nof_grants = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -388,6 +426,28 @@ public:
|
|||
notify_tti_clock();
|
||||
tti_sync.increase();
|
||||
}
|
||||
int run_tti()
|
||||
{
|
||||
// Check ACKs match with grants
|
||||
while (!tti_dl_info_ack_queue.empty()) {
|
||||
// Get both Info
|
||||
tti_dl_info_t& tti_dl_sched = tti_dl_info_sched_queue.front();
|
||||
tti_dl_info_t& tti_dl_ack = tti_dl_info_ack_queue.front();
|
||||
|
||||
// Calculate ACK TTI
|
||||
tti_dl_sched.tti = (tti_dl_sched.tti + FDD_HARQ_DELAY_MS) % 10240;
|
||||
|
||||
// Assert that ACKs have been received
|
||||
TESTASSERT(tti_dl_sched.tti == tti_dl_ack.tti);
|
||||
TESTASSERT(tti_dl_sched.cc_idx == tti_dl_ack.cc_idx);
|
||||
TESTASSERT(tti_dl_sched.tb_idx == tti_dl_ack.tb_idx);
|
||||
|
||||
tti_dl_info_sched_queue.pop();
|
||||
tti_dl_info_ack_queue.pop();
|
||||
}
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
};
|
||||
|
||||
class dummy_ue
|
||||
|
@ -412,7 +472,7 @@ public:
|
|||
uint16_t rnti_,
|
||||
const srslte::phy_cfg_t& dedicated_) :
|
||||
radio(&_radio),
|
||||
log_h("UE PHY"),
|
||||
log_h("UE PHY", nullptr, true),
|
||||
dedicated(dedicated_)
|
||||
{
|
||||
// Calculate subframe length
|
||||
|
@ -487,10 +547,13 @@ public:
|
|||
memset(tx_data, 0, 150000);
|
||||
|
||||
// Push HARQ delay to radio
|
||||
for (uint32_t i = 0; i < FDD_HARQ_DELAY_MS; i++) {
|
||||
for (uint32_t i = 0; i < TX_DELAY; i++) {
|
||||
radio->write_rx(buffers, sf_len);
|
||||
sf_ul_cfg.tti = (sf_ul_cfg.tti + 1) % 10240; // Advance UL TTI too
|
||||
}
|
||||
for (uint32_t i = 0; i < FDD_HARQ_DELAY_MS; i++) {
|
||||
radio->write_rx(buffers, sf_len);
|
||||
}
|
||||
}
|
||||
|
||||
~dummy_ue()
|
||||
|
@ -521,6 +584,9 @@ public:
|
|||
int ret = SRSLTE_SUCCESS;
|
||||
srslte_uci_data_t uci_data = {};
|
||||
|
||||
// Set logging TTI
|
||||
log_h.step(sf_dl_cfg.tti);
|
||||
|
||||
uci_data.cfg = dedicated.ul_cfg.pucch.uci_cfg;
|
||||
|
||||
srslte_pdsch_ack_t pdsch_ack = {};
|
||||
|
@ -634,21 +700,25 @@ private:
|
|||
srslte::log_filter log_h;
|
||||
srslte::logger_stdout logger_stdout;
|
||||
uint32_t nof_carriers = 0;
|
||||
srslte::phy_cfg_t common_dedicated = {};
|
||||
uint16_t rnti = 0;
|
||||
|
||||
public:
|
||||
phy_test_bench(srsenb::phy_args_t& phy_args,
|
||||
srsenb::phy_cfg_t& phy_cfg,
|
||||
uint16_t rnti,
|
||||
const srslte::phy_cfg_t& dedicated) :
|
||||
uint16_t rnti_,
|
||||
uint32_t pcell_index,
|
||||
const srslte::phy_cfg_t& dedicated_) :
|
||||
log_h("TEST BENCH"),
|
||||
stack(rnti),
|
||||
stack(rnti_),
|
||||
rnti(rnti_),
|
||||
radio(phy_cfg.phy_cell_cfg.size()),
|
||||
enb_phy(&logger_stdout),
|
||||
ue_phy(radio, phy_cfg.phy_cell_cfg, rnti, dedicated)
|
||||
ue_phy(radio, phy_cfg.phy_cell_cfg, rnti_, dedicated_),
|
||||
nof_carriers(static_cast<uint32_t>(phy_cfg.phy_cell_cfg.size())),
|
||||
common_dedicated(dedicated_)
|
||||
{
|
||||
|
||||
nof_carriers = phy_cfg.phy_cell_cfg.size();
|
||||
|
||||
// Always info
|
||||
log_h.set_level("info");
|
||||
|
||||
|
@ -656,10 +726,17 @@ public:
|
|||
enb_phy.init(phy_args, phy_cfg, &radio, &stack);
|
||||
|
||||
// Add rnti to enb
|
||||
enb_phy.add_rnti(rnti, false);
|
||||
enb_phy.add_rnti(rnti, pcell_index, false);
|
||||
|
||||
// Configure UE PHY
|
||||
enb_phy.set_config_dedicated(rnti, dedicated);
|
||||
uint32_t pcell_idx = 0;
|
||||
srsenb::phy_interface_rrc_lte::phy_rrc_dedicated_list_t dedicated_list(4);
|
||||
for (uint32_t i = 0; i < 4; i++) {
|
||||
common_dedicated.dl_cfg.cqi_report.pmi_idx = 16 + i;
|
||||
dedicated_list[i].cc_idx = (i + pcell_idx) % phy_cfg.phy_cell_cfg.size();
|
||||
dedicated_list[i].phy_cfg = common_dedicated;
|
||||
}
|
||||
enb_phy.set_config_dedicated(rnti, dedicated_list);
|
||||
}
|
||||
|
||||
~phy_test_bench()
|
||||
|
@ -676,6 +753,7 @@ public:
|
|||
|
||||
TESTASSERT(!stack.get_received_rl_failure());
|
||||
TESTASSERT(ue_phy.run_tti() >= SRSLTE_SUCCESS);
|
||||
TESTASSERT(stack.run_tti() >= SRSLTE_SUCCESS);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -723,7 +801,7 @@ int main(int argc, char** argv)
|
|||
dedicated.ul_cfg.pucch.simul_cqi_ack = true;
|
||||
|
||||
std::unique_ptr<phy_test_bench> test_bench =
|
||||
std::unique_ptr<phy_test_bench>(new phy_test_bench(phy_args, phy_cfg, 0x1234, dedicated));
|
||||
std::unique_ptr<phy_test_bench>(new phy_test_bench(phy_args, phy_cfg, 0x1234, 0, dedicated));
|
||||
|
||||
for (uint32_t i = 0; i < 32; i++) {
|
||||
TESTASSERT(test_bench->run_tti() >= SRSLTE_SUCCESS);
|
||||
|
|
Loading…
Reference in New Issue