From 47b7c1b72b5c47d5ebc862d66968ad7e4219d2c8 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Tue, 10 Mar 2020 17:21:15 +0100 Subject: [PATCH] SRSENB: remove assert macros from phy_ue_db.cc --- srsenb/hdr/phy/phy_ue_db.h | 77 ++++++++-- srsenb/src/phy/phy_ue_db.cc | 288 ++++++++++++++++++++---------------- 2 files changed, 226 insertions(+), 139 deletions(-) diff --git a/srsenb/hdr/phy/phy_ue_db.h b/srsenb/hdr/phy/phy_ue_db.h index 2739e3fe6..f6ad66c62 100644 --- a/srsenb/hdr/phy/phy_ue_db.h +++ b/srsenb/hdr/phy/phy_ue_db.h @@ -129,10 +129,69 @@ private: * is found among the configured cells/carriers. Otherwise, it returns SRSLTE_MAX_CARRIERS. * * @param rnti identifier of the UE (requires assertion prior to call) - * @param cc_idx the eNb cell/carrier index to look for in the RNTI. + * @param enb_cc_idx the eNb cell/carrier index to look for in the RNTI. * @return the SCell index as described above. */ - inline uint32_t _get_cell_idx(uint16_t rnti, uint32_t cc_idx) const; + inline uint32_t _get_ue_cc_idx(uint16_t rnti, uint32_t enb_cc_idx) const; + + /** + * Checks if a given RNTI exists in the database + * @param rnti provides UE identifier + * @return SRSLTE_SUCCESS if the indicated RNTI exists, otherwise it returns SRSLTE_ERROR + */ + inline int _assert_rnti(uint16_t rnti) const; + + /** + * Checks if an RNTI is configured to use an specified eNb cell/carrier as PCell or SCell + * @param rnti provides UE identifier + * @param enb_cc_idx provides eNb cell/carrier + * @return SRSLTE_SUCCESS if the indicated RNTI exists, otherwise it returns SRSLTE_ERROR + */ + inline int _assert_enb_cc(uint16_t rnti, uint32_t enb_cc_idx) const; + + /** + * Checks if an RNTI uses a given eNb cell/carrier as PCell + * @param rnti provides UE identifier + * @param enb_cc_idx provides eNb cell/carrier index + * @return SRSLTE_SUCCESS if the indicated eNb cell/carrier of the RNTI is a PCell, otherwise it returns SRSLTE_ERROR + */ + inline int _assert_enb_pcell(uint16_t rnti, uint32_t enb_cc_idx) const; + + /** + * Checks if an RNTI is configured to use an specified UE cell/carrier as PCell or SCell + * @param rnti provides UE identifier + * @param ue_cc_idx UE cell/carrier index that is asserted + * @return SRSLTE_SUCCESS if the indicated cell/carrier index is valid, otherwise it returns SRSLTE_ERROR + */ + inline int _assert_ue_cc(uint16_t rnti, uint32_t ue_cc_idx); + + /** + * Checks if an RNTI is configured to use an specified UE cell/carrier as PCell or SCell and it is active + * @param rnti provides UE identifier + * @param ue_cc_idx UE cell/carrier index that is asserted + * @return SRSLTE_SUCCESS if the indicated cell/carrier is active, otherwise it returns SRSLTE_ERROR + */ + inline int _assert_active_ue_cc(uint16_t rnti, uint32_t ue_cc_idx); + + /** + * Checks if an RNTI is configured to use an specified eNb cell/carrier as PCell or SCell and it is active + * @param rnti provides UE identifier + * @param enb_cc_idx UE cell/carrier index that is asserted + * @return SRSLTE_SUCCESS if the indicated eNb cell/carrier is active, otherwise it returns SRSLTE_ERROR + */ + inline int _assert_active_enb_cc(uint16_t rnti, uint32_t enb_cc_idx) const; + + /** + * Internal eNb stack assertion + * @return SRSLTE_SUCCESS if available, otherwise it returns SRSLTE_ERROR + */ + inline int _assert_stack() const; + + /** + * Internal eNb Cell list assertion + * @return SRSLTE_SUCCESS if available, otherwise it returns SRSLTE_ERROR + */ + inline int _assert_cell_list_cfg() const; public: /** @@ -166,7 +225,7 @@ public: * @param scell_idx * @param activate */ - void activate_deactivate_scell(uint16_t rnti, uint32_t scell_idx, bool activate); + void activate_deactivate_scell(uint16_t rnti, uint32_t ue_cc_idx, bool activate); /** * Get the current physical layer configuration for an RNTI and an eNb cell/carrier @@ -174,7 +233,7 @@ public: * @param rnti identifier of the UE * @param cc_idx the eNb cell/carrier identifier */ - srslte::phy_cfg_t get_config(uint16_t rnti, uint32_t cc_idx) const; + srslte::phy_cfg_t get_config(uint16_t rnti, uint32_t enb_cc_idx) const; /** * Removes all the pending ACKs of all the RNTIs for a given TTI @@ -191,7 +250,7 @@ public: * @param dci carries the Transport Block and required scheduling information * */ - void set_ack_pending(uint32_t tti, uint32_t cc_idx, const srslte_dci_dl_t& dci); + void set_ack_pending(uint32_t tti, uint32_t enb_cc_idx, const srslte_dci_dl_t& dci); /** * Fills the Uplink Control Information (UCI) configuration and returns true/false idicating if UCI bits are required. @@ -203,7 +262,7 @@ public: * @return true if UCI decoding is required and false otherwise */ bool fill_uci_cfg(uint32_t tti, - uint32_t cc_idx, + uint32_t enb_cc_idx, uint16_t rnti, bool aperiodic_cqi_request, srslte_uci_cfg_t& uci_cfg) const; @@ -217,7 +276,7 @@ public: */ void send_uci_data(uint32_t tti, uint16_t rnti, - uint32_t cc_idx, + uint32_t enb_cc_idx, const srslte_uci_cfg_t& uci_cfg, const srslte_uci_value_t& uci_value); @@ -230,7 +289,7 @@ public: * @param pid HARQ process identifier * @param tb the Resource Allocation for the PUSCH transport block */ - void set_last_ul_tb(uint16_t rnti, uint32_t cc_idx, uint32_t pid, srslte_ra_tb_t tb); + void set_last_ul_tb(uint16_t rnti, uint32_t enb_cc_idx, uint32_t pid, srslte_ra_tb_t tb); /** * Get the latest UL Transport Block resource allocation for a given RNTI, eNb cell/carrier and UL HARQ process @@ -242,7 +301,7 @@ public: * @param pid HARQ process identifier * @return the Resource Allocation for the PUSCH transport block */ - srslte_ra_tb_t get_last_ul_tb(uint16_t rnti, uint32_t cc_idx, uint32_t pid) const; + srslte_ra_tb_t get_last_ul_tb(uint16_t rnti, uint32_t enb_cc_idx, uint32_t pid) const; }; } // namespace srsenb diff --git a/srsenb/src/phy/phy_ue_db.cc b/srsenb/src/phy/phy_ue_db.cc index b7c13a58d..38e7f9ca2 100644 --- a/srsenb/src/phy/phy_ue_db.cc +++ b/srsenb/src/phy/phy_ue_db.cc @@ -110,19 +110,125 @@ inline void phy_ue_db::_set_common_config_rnti(uint16_t rnti) } } -inline uint32_t phy_ue_db::_get_cell_idx(uint16_t rnti, uint32_t cc_idx) const +inline uint32_t phy_ue_db::_get_ue_cc_idx(uint16_t rnti, uint32_t enb_cc_idx) const { - uint32_t cell_idx = 0; + uint32_t ue_cc_idx = 0; const common_ue& ue = ue_db.at(rnti); - for (cell_idx = 0; cell_idx < SRSLTE_MAX_CARRIERS; cell_idx++) { - const cell_info_t& scell_info = ue.cell_info[cell_idx]; - if (scell_info.enb_cc_idx == cc_idx && scell_info.state != cell_state_secondary_inactive) { - return cell_idx; + for (ue_cc_idx = 0; ue_cc_idx < SRSLTE_MAX_CARRIERS; ue_cc_idx++) { + const cell_info_t& scell_info = ue.cell_info[ue_cc_idx]; + if (scell_info.enb_cc_idx == enb_cc_idx and scell_info.state != cell_state_secondary_inactive) { + return ue_cc_idx; } } - return cell_idx; + return ue_cc_idx; +} + +inline int phy_ue_db::_assert_rnti(uint16_t rnti) const +{ + if (not ue_db.count(rnti)) { + ERROR("Trying to access RNTI x%x, it does not exist.\n", rnti); + return SRSLTE_ERROR; + } + + return SRSLTE_SUCCESS; +} + +inline int phy_ue_db::_assert_enb_cc(uint16_t rnti, uint32_t enb_cc_idx) const +{ + // Assert RNTI exist + if (_assert_rnti(rnti) != SRSLTE_SUCCESS) { + return SRSLTE_ERROR; + } + + // Check Component Carrier is part of UE SCell map + if (_get_ue_cc_idx(rnti, enb_cc_idx) == SRSLTE_MAX_CARRIERS) { + ERROR("Trying to access cell/carrier index %d in RNTI x%x. It does not exist.\n", enb_cc_idx, rnti); + return SRSLTE_ERROR; + } + + return SRSLTE_SUCCESS; +} + +inline int phy_ue_db::_assert_enb_pcell(uint16_t rnti, uint32_t enb_cc_idx) const +{ + if (_assert_enb_cc(rnti, enb_cc_idx) != SRSLTE_SUCCESS) { + return SRSLTE_ERROR; + } + + // Check cell is PCell + const cell_info_t& cell_info = ue_db.at(rnti).cell_info[_get_ue_cc_idx(rnti, enb_cc_idx)]; + if (cell_info.state != cell_state_primary) { + return SRSLTE_ERROR; + } + + return SRSLTE_SUCCESS; +} + +inline int phy_ue_db::_assert_ue_cc(uint16_t rnti, uint32_t ue_cc_idx) +{ + if (_assert_rnti(rnti) != SRSLTE_SUCCESS) { + return SRSLTE_ERROR; + } + + // Check SCell is active, ignore PCell state + if (ue_cc_idx == SRSLTE_MAX_CARRIERS) { + ERROR("Out-of-bounds UE cell/carrier %d for RNTI x%x.\n", ue_cc_idx, rnti); + return SRSLTE_ERROR; + } + + return SRSLTE_SUCCESS; +} + +inline int phy_ue_db::_assert_active_ue_cc(uint16_t rnti, uint32_t ue_cc_idx) +{ + if (_assert_ue_cc(rnti, ue_cc_idx) != SRSLTE_SUCCESS) { + return SRSLTE_ERROR; + } + + // Return error if not PCell or not Active SCell + auto& cell_info = ue_db.at(rnti).cell_info[ue_cc_idx]; + if (cell_info.state != cell_state_primary and cell_info.state != cell_state_secondary_active) { + ERROR("Failed to assert active UE cell/carrier %d for RNTI x%x", ue_cc_idx, rnti); + return SRSLTE_ERROR; + } + + return SRSLTE_SUCCESS; +} + +inline int phy_ue_db::_assert_active_enb_cc(uint16_t rnti, uint32_t enb_cc_idx) const +{ + if (_assert_enb_cc(rnti, enb_cc_idx) != SRSLTE_SUCCESS) { + return SRSLTE_ERROR; + } + + // Check SCell is active, ignore PCell state + auto& cell_info = ue_db.at(rnti).cell_info[_get_ue_cc_idx(rnti, enb_cc_idx)]; + if (cell_info.state != cell_state_primary and cell_info.state != cell_state_secondary_active) { + ERROR("Failed to assert active eNb cell/carrier %d for RNTI x%x", enb_cc_idx, rnti); + return SRSLTE_ERROR; + } + + return SRSLTE_SUCCESS; +} + +inline int phy_ue_db::_assert_stack() const +{ + if (not stack) { + return SRSLTE_ERROR; + } + + return SRSLTE_SUCCESS; +} + +inline int phy_ue_db::_assert_cell_list_cfg() const +{ + if (not cell_cfg_list) { + return SRSLTE_ERROR; + } + + return SRSLTE_SUCCESS; } void phy_ue_db::clear_tti_pending_ack(uint32_t tti) @@ -188,111 +294,18 @@ void phy_ue_db::rem_rnti(uint16_t rnti) } } -/** - * UE Database Assert macros. These macros avoid repeating code for asserting RNTI, eNb cell/carrier index, SCell - * indexes and so on. - * - * They are const friendly. All the methods they use of the attributes are const, so they do not modify any attribute. - */ -#define UE_DB_ASSERT_RNTI(RNTI, RET) \ - do { \ - if (not ue_db.count(RNTI)) { \ - /*ERROR("Trying to access RNTI x%x, it does not exist.\n", RNTI);*/ \ - return RET; \ - } \ - } while (false) - -#define UE_DB_ASSERT_CELL(RNTI, CC_IDX, RET) \ - do { \ - /* Check if the UE exists */ \ - UE_DB_ASSERT_RNTI(RNTI, RET); \ - \ - /* Check Component Carrier is part of UE SCell map*/ \ - if (_get_cell_idx(RNTI, CC_IDX) == SRSLTE_MAX_CARRIERS) { \ - ERROR("Trying to access cell/carrier index %d in RNTI x%x. It does not exist.\n", CC_IDX, RNTI); \ - return RET; \ - } \ - \ - /* Check SCell index is in range */ \ - const uint32_t cell_idx = _get_cell_idx(RNTI, CC_IDX); \ - if (cell_idx == SRSLTE_MAX_CARRIERS) { \ - ERROR("Corrupted Cell index %d for RNTI x%x and cell/carrier index %d\n", cell_idx, RNTI, CC_IDX); \ - return RET; \ - } \ - } while (false) - -#define UE_DB_ASSERT_ACTIVE_CELL(RNTI, CC_IDX, RET) \ - do { \ - /* Assert RNTI exists and eNb cell/carrier is configured */ \ - UE_DB_ASSERT_CELL(RNTI, CC_IDX, RET); \ - \ - /* Check Cell is active */ \ - auto& cell_info = ue_db.at(RNTI).cell_info[_get_cell_idx(RNTI, CC_IDX)]; \ - if (cell_info.state != cell_state_primary and cell_info.state != cell_state_secondary_active) { \ - return RET; \ - } \ - } while (false) - -#define UE_DB_ASSERT_PCELL(RNTI, CC_IDX, RET) \ - do { \ - /* Assert RNTI exists and eNb cell/carrier is configured */ \ - UE_DB_ASSERT_CELL(RNTI, CC_IDX, RET); \ - \ - /* CC_IDX is the RNTI PCell */ \ - if (_get_cell_idx(RNTI, CC_IDX) != 0) { \ - return RET; \ - } \ - } while (false) - -#define UE_DB_ASSERT_SCELL(RNTI, CELL_IDX, RET) \ - do { \ - /* Assert RNTI exists and eNb cell/carrier is configured */ \ - UE_DB_ASSERT_RNTI(RNTI, RET); \ - \ - /* Check SCell index is in range */ \ - if (CELL_IDX >= SRSLTE_MAX_CARRIERS) { \ - ERROR("Out-of-bounds SCell index %d for RNTI x%x.\n", CELL_IDX, RNTI); \ - return RET; \ - } \ - } while (false) - -#define UE_DB_ASSERT_ACTIVE_SCELL(RNTI, CELL_IDX, RET) \ - do { \ - /* Assert RNTI exists and eNb cell/carrier is configured */ \ - UE_DB_ASSERT_SCELL(RNTI, CELL_IDX, RET); \ - \ - /* Check SCell is active, ignore PCell state */ \ - auto& cell_info = ue_db.at(RNTI).cell_info[CELL_IDX]; \ - if (CELL_IDX != 0 && cell_info.state != cell_state_secondary_active) { \ - ERROR("Failed to assert active SCell %d for RNTI x%x", CELL_IDX, RNTI); \ - return RET; \ - } \ - } while (false) - -#define UE_DB_ASSERT_STACK(RET) \ - do { \ - if (not stack) { \ - return RET; \ - } \ - } while (false) - -#define UE_DB_ASSERT_CELL_LIST_CFG(RET) \ - do { \ - if (not cell_cfg_list) { \ - return RET; \ - } \ - } while (false) - -void phy_ue_db::activate_deactivate_scell(uint16_t rnti, uint32_t cell_idx, bool activate) +void phy_ue_db::activate_deactivate_scell(uint16_t rnti, uint32_t ue_cc_idx, bool activate) { // Assert RNTI and SCell are valid - UE_DB_ASSERT_SCELL(rnti, cell_idx, /* void */); + if (_assert_ue_cc(rnti, ue_cc_idx) != SRSLTE_SUCCESS) { + return; + } - auto& cell_info = ue_db[rnti].cell_info[cell_idx]; + cell_info_t& cell_info = ue_db[rnti].cell_info[ue_cc_idx]; // If scell is default only complain if (activate and cell_info.state == cell_state_none) { - ERROR("RNTI x%x SCell %d has received an activation MAC command but it was not configured\n", rnti, cell_idx); + ERROR("RNTI x%x SCell %d has received an activation MAC command but it was not configured\n", rnti, ue_cc_idx); return; } @@ -300,7 +313,7 @@ void phy_ue_db::activate_deactivate_scell(uint16_t rnti, uint32_t cell_idx, bool cell_info.state = (activate) ? cell_state_secondary_active : cell_state_secondary_inactive; } -srslte::phy_cfg_t phy_ue_db::get_config(uint16_t rnti, uint32_t cc_idx) const +srslte::phy_cfg_t phy_ue_db::get_config(uint16_t rnti, uint32_t enb_cc_idx) const { std::lock_guard lock(mutex); @@ -310,32 +323,35 @@ srslte::phy_cfg_t phy_ue_db::get_config(uint16_t rnti, uint32_t cc_idx) const default_cfg.ul_cfg.pusch.rnti = rnti; default_cfg.ul_cfg.pucch.rnti = rnti; - UE_DB_ASSERT_ACTIVE_CELL(rnti, cc_idx, default_cfg); + if (_assert_active_enb_cc(rnti, enb_cc_idx) != SRSLTE_SUCCESS) { + return default_cfg; + } - return ue_db.at(rnti).cell_info[_get_cell_idx(rnti, cc_idx)].phy_cfg; + return ue_db.at(rnti).cell_info[_get_ue_cc_idx(rnti, enb_cc_idx)].phy_cfg; } -void phy_ue_db::set_ack_pending(uint32_t tti, uint32_t cc_idx, const srslte_dci_dl_t& dci) +void phy_ue_db::set_ack_pending(uint32_t tti, uint32_t enb_cc_idx, const srslte_dci_dl_t& dci) { std::lock_guard lock(mutex); // Assert rnti and cell exits and it is active - UE_DB_ASSERT_ACTIVE_CELL(dci.rnti, cc_idx, /* void */); + if (_assert_active_enb_cc(dci.rnti, enb_cc_idx) != SRSLTE_SUCCESS) { + return; + } common_ue& ue = ue_db[dci.rnti]; - uint32_t scell_idx = _get_cell_idx(dci.rnti, cc_idx); + uint32_t ue_cc_idx = _get_ue_cc_idx(dci.rnti, enb_cc_idx); - srslte_pdsch_ack_cc_t& pdsch_ack_cc = ue.pdsch_ack[TTIMOD(tti)].cc[scell_idx]; + srslte_pdsch_ack_cc_t& pdsch_ack_cc = ue.pdsch_ack[TTIMOD(tti)].cc[ue_cc_idx]; pdsch_ack_cc.M = 1; ///< Hardcoded for FDD // Fill PDSCH ACK information srslte_pdsch_ack_m_t& pdsch_ack_m = pdsch_ack_cc.m[0]; ///< Assume FDD only pdsch_ack_m.present = true; - pdsch_ack_m.resource.grant_cc_idx = cc_idx; ///< Assumes no cross-carrier scheduling - pdsch_ack_m.resource.v_dai_dl = 0; ///< Ignore for FDD + pdsch_ack_m.resource.grant_cc_idx = ue_cc_idx; ///< Assumes no cross-carrier scheduling + pdsch_ack_m.resource.v_dai_dl = 0; ///< Ignore for FDD pdsch_ack_m.resource.n_cce = dci.location.ncce; pdsch_ack_m.resource.tpc_for_pucch = dci.tpc_pucch; - pdsch_ack_m.resource.grant_cc_idx = scell_idx; // Set TB info for (uint32_t i = 0; i < srslte_dci_format_max_tb(dci.format); i++) { @@ -347,7 +363,7 @@ void phy_ue_db::set_ack_pending(uint32_t tti, uint32_t cc_idx, const srslte_dci_ } bool phy_ue_db::fill_uci_cfg(uint32_t tti, - uint32_t cc_idx, + uint32_t enb_cc_idx, uint16_t rnti, bool aperiodic_cqi_request, srslte_uci_cfg_t& uci_cfg) const @@ -357,11 +373,15 @@ bool phy_ue_db::fill_uci_cfg(uint32_t tti, // Reset UCI CFG, avoid returning carrying cached information uci_cfg = {}; - // Assert rnti and cell exits and it is active - UE_DB_ASSERT_PCELL(rnti, cc_idx, false); + // Assert rnti and cell exits and it is PCell + if (_assert_enb_pcell(rnti, enb_cc_idx) != SRSLTE_SUCCESS) { + return false; + } // Assert Cell List configuration - UE_DB_ASSERT_CELL_LIST_CFG(false); + if (_assert_cell_list_cfg() != SRSLTE_SUCCESS) { + return false; + } const auto& ue = ue_db.at(rnti); const auto& pcell_cfg = ue.cell_info[0].phy_cfg; @@ -412,17 +432,21 @@ bool phy_ue_db::fill_uci_cfg(uint32_t tti, void phy_ue_db::send_uci_data(uint32_t tti, uint16_t rnti, - uint32_t cc_idx, + uint32_t enb_cc_idx, const srslte_uci_cfg_t& uci_cfg, const srslte_uci_value_t& uci_value) { std::lock_guard lock(mutex); // Assert UE RNTI database entry and eNb cell/carrier must be primary cell - UE_DB_ASSERT_PCELL(rnti, cc_idx, /* void */); + if (_assert_enb_pcell(rnti, enb_cc_idx) != SRSLTE_SUCCESS) { + return; + } // Assert Stack - UE_DB_ASSERT_STACK(/* void */); + if (_assert_stack() != SRSLTE_SUCCESS) { + return; + } // Notify SR if (uci_cfg.is_scheduling_request_tti && uci_value.scheduling_request) { @@ -449,7 +473,7 @@ void phy_ue_db::send_uci_data(uint32_t tti, } // Assert the SCell exists and it is active - UE_DB_ASSERT_ACTIVE_SCELL(rnti, uci_cfg.cqi.scell_index, /* void */); + _assert_active_ue_cc(rnti, uci_cfg.cqi.scell_index); // Get CQI carrier index auto& cqi_scell_info = ue_db.at(rnti).cell_info[uci_cfg.cqi.scell_index]; @@ -502,24 +526,28 @@ void phy_ue_db::send_uci_data(uint32_t tti, } } -void phy_ue_db::set_last_ul_tb(uint16_t rnti, uint32_t cc_idx, uint32_t pid, srslte_ra_tb_t tb) +void phy_ue_db::set_last_ul_tb(uint16_t rnti, uint32_t enb_cc_idx, uint32_t pid, srslte_ra_tb_t tb) { std::lock_guard lock(mutex); // Assert UE DB entry - UE_DB_ASSERT_ACTIVE_CELL(rnti, cc_idx, /* void */); + if (_assert_active_enb_cc(rnti, enb_cc_idx) != SRSLTE_SUCCESS) { + return; + } // Save resource allocation - ue_db.at(rnti).cell_info[_get_cell_idx(rnti, cc_idx)].last_tb[pid % SRSLTE_FDD_NOF_HARQ] = tb; + ue_db.at(rnti).cell_info[_get_ue_cc_idx(rnti, enb_cc_idx)].last_tb[pid % SRSLTE_FDD_NOF_HARQ] = tb; } -srslte_ra_tb_t phy_ue_db::get_last_ul_tb(uint16_t rnti, uint32_t cc_idx, uint32_t pid) const +srslte_ra_tb_t phy_ue_db::get_last_ul_tb(uint16_t rnti, uint32_t enb_cc_idx, uint32_t pid) const { std::lock_guard lock(mutex); // Assert UE DB entry - UE_DB_ASSERT_ACTIVE_CELL(rnti, cc_idx, {}); + if (_assert_active_enb_cc(rnti, enb_cc_idx) != SRSLTE_SUCCESS) { + return {}; + } // Returns the latest stored UL transmission grant - return ue_db.at(rnti).cell_info[_get_cell_idx(rnti, cc_idx)].last_tb[pid % SRSLTE_FDD_NOF_HARQ]; + return ue_db.at(rnti).cell_info[_get_ue_cc_idx(rnti, enb_cc_idx)].last_tb[pid % SRSLTE_FDD_NOF_HARQ]; }