SRSENB: refactored PHY common UE database

This commit is contained in:
Xavier Arteaga 2020-02-18 18:09:28 +01:00 committed by Xavier Arteaga
parent 2fc0832f05
commit f35ed14f76
11 changed files with 921 additions and 564 deletions

View File

@ -509,9 +509,9 @@ struct phy_cfg_t {
void set_defaults() void set_defaults()
{ {
ZERO_OBJECT(ul_cfg); ul_cfg = {};
ZERO_OBJECT(dl_cfg); dl_cfg = {};
ZERO_OBJECT(prach_cfg); prach_cfg = {};
// CommonConfig defaults for non-zero values // CommonConfig defaults for non-zero values
ul_cfg.pucch.delta_pucch_shift = 1; ul_cfg.pucch.delta_pucch_shift = 1;
@ -552,9 +552,9 @@ struct phy_cfg_t {
ul_cfg.pucch.sr_configured = false; ul_cfg.pucch.sr_configured = false;
} }
srslte_dl_cfg_t dl_cfg; srslte_dl_cfg_t dl_cfg = {};
srslte_ul_cfg_t ul_cfg; srslte_ul_cfg_t ul_cfg = {};
srslte_prach_cfg_t prach_cfg; srslte_prach_cfg_t prach_cfg = {};
}; };
struct mbsfn_sf_cfg_t { struct mbsfn_sf_cfg_t {

View File

@ -42,7 +42,7 @@ public:
cf_t* get_buffer_tx(uint32_t antenna_idx); cf_t* get_buffer_tx(uint32_t antenna_idx);
void set_tti(uint32_t tti); void set_tti(uint32_t tti);
int add_rnti(uint16_t rnti, bool is_temporal); int add_rnti(uint16_t rnti, bool is_pcell, bool is_temporal);
void rem_rnti(uint16_t rnti); void rem_rnti(uint16_t rnti);
uint32_t get_nof_rnti(); uint32_t get_nof_rnti();
@ -53,7 +53,6 @@ public:
int read_pucch_d(cf_t* pusch_d); int read_pucch_d(cf_t* pusch_d);
void start_plot(); void start_plot();
void set_config_dedicated(uint16_t rnti, const srslte::phy_cfg_t& dedicated);
void work_ul(const srslte_ul_sf_cfg_t& ul_sf, stack_interface_phy_lte::ul_sched_t& ul_grants); void work_ul(const srslte_ul_sf_cfg_t& ul_sf, stack_interface_phy_lte::ul_sched_t& ul_grants);
void work_dl(const srslte_dl_sf_cfg_t& dl_sf_cfg, void work_dl(const srslte_dl_sf_cfg_t& dl_sf_cfg,
stack_interface_phy_lte::dl_sched_t& dl_grants, stack_interface_phy_lte::dl_sched_t& dl_grants,
@ -74,9 +73,6 @@ private:
int encode_pdcch_ul(stack_interface_phy_lte::ul_sched_grant_t* grants, uint32_t nof_grants); int encode_pdcch_ul(stack_interface_phy_lte::ul_sched_grant_t* grants, uint32_t nof_grants);
int decode_pucch(); int decode_pucch();
void send_uci_data(uint16_t rnti, srslte_uci_cfg_t* uci_cfg, srslte_uci_value_t* uci_value);
bool fill_uci_cfg(uint16_t rnti, bool aperiodic_cqi_request, srslte_uci_cfg_t* uci_cfg);
/* Common objects */ /* Common objects */
srslte::log* log_h = nullptr; srslte::log* log_h = nullptr;
phy_common* phy = nullptr; phy_common* phy = nullptr;
@ -85,7 +81,6 @@ private:
cf_t* signal_buffer_rx[SRSLTE_MAX_PORTS] = {}; cf_t* signal_buffer_rx[SRSLTE_MAX_PORTS] = {};
cf_t* signal_buffer_tx[SRSLTE_MAX_PORTS] = {}; cf_t* signal_buffer_tx[SRSLTE_MAX_PORTS] = {};
uint32_t tti_rx = 0, tti_tx_dl = 0, tti_tx_ul = 0; uint32_t tti_rx = 0, tti_tx_dl = 0, tti_tx_ul = 0;
uint32_t t_rx = 0, t_tx_dl = 0, t_tx_ul = 0;
srslte_enb_dl_t enb_dl = {}; srslte_enb_dl_t enb_dl = {};
srslte_enb_ul_t enb_ul = {}; srslte_enb_ul_t enb_ul = {};
@ -99,32 +94,23 @@ private:
class ue class ue
{ {
public: public:
ue(uint16_t id, phy_common* phy) explicit ue(uint16_t rnti_, bool pcell_) : rnti(rnti_), pcell(pcell_)
{ {
// Copy common configuartion // Do nothing
ul_cfg = phy->ul_cfg_com;
dl_cfg = phy->dl_cfg_com;
// Fill RNTI
rnti = id;
dl_cfg.pdsch.rnti = rnti;
ul_cfg.pusch.rnti = rnti;
ul_cfg.pucch.rnti = rnti;
} }
bool is_grant_available = false; bool is_grant_available = false;
srslte_phich_grant_t phich_grant = {}; srslte_phich_grant_t phich_grant = {};
srslte_dl_cfg_t dl_cfg = {};
srslte_ul_cfg_t ul_cfg = {};
void metrics_read(phy_metrics_t* metrics); void metrics_read(phy_metrics_t* metrics);
void metrics_dl(uint32_t mcs); void metrics_dl(uint32_t mcs);
void metrics_ul(uint32_t mcs, float rssi, float sinr, float turbo_iters); void metrics_ul(uint32_t mcs, float rssi, float sinr, float turbo_iters);
bool is_pcell() { return pcell; };
private: private:
uint32_t rnti = 0; uint32_t rnti = 0;
phy_metrics_t metrics = {}; phy_metrics_t metrics = {};
bool pcell;
}; };
// Component carrier index // Component carrier index

View File

@ -23,6 +23,7 @@
#define SRSENB_PHCH_COMMON_H #define SRSENB_PHCH_COMMON_H
#include "phy_interfaces.h" #include "phy_interfaces.h"
#include "srsenb/hdr/phy/phy_ue_db.h"
#include "srslte/common/gen_mch_tables.h" #include "srslte/common/gen_mch_tables.h"
#include "srslte/common/interfaces_common.h" #include "srslte/common/interfaces_common.h"
#include "srslte/common/log.h" #include "srslte/common/log.h"
@ -42,7 +43,7 @@ namespace srsenb {
class phy_common class phy_common
{ {
public: public:
phy_common(uint32_t nof_workers); explicit phy_common(uint32_t nof_workers);
~phy_common(); ~phy_common();
void set_nof_workers(uint32_t nof_workers); void set_nof_workers(uint32_t nof_workers);
@ -132,110 +133,10 @@ public:
stack_interface_phy_lte::ul_sched_list_t ul_grants[TTIMOD_SZ] = {}; stack_interface_phy_lte::ul_sched_list_t ul_grants[TTIMOD_SZ] = {};
stack_interface_phy_lte::dl_sched_list_t dl_grants[TTIMOD_SZ] = {}; stack_interface_phy_lte::dl_sched_list_t dl_grants[TTIMOD_SZ] = {};
// Map of pending ACKs for each user
typedef struct {
srslte_uci_cfg_ack_t ack[SRSLTE_MAX_CARRIERS];
} pending_ack_t;
class common_ue
{
public:
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;
/** /**
* Adds or modifies a user in the UE database setting. This function requires a list of cells indexes for the UE. The * UE Database object, direct public access, all PHY threads should be able to access this attribute directly
* 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); phy_ue_db ue_db;
/**
* Removes a whole UE entry from the UE database
*
* @param rnti identifier of the UE
*/
void ue_db_rem_rnti(uint16_t rnti);
/**
* 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);
srslte_ra_tb_t ue_db_get_last_ul_tb(uint16_t rnti, uint32_t pid);
void configure_mbsfn(phy_interface_stack_lte::phy_cfg_mbsfn_t* cfg); void configure_mbsfn(phy_interface_stack_lte::phy_cfg_mbsfn_t* cfg);
void build_mch_table(); void build_mch_table();
@ -251,22 +152,17 @@ private:
uint32_t nof_workers = 0; uint32_t nof_workers = 0;
uint32_t max_workers = 0; uint32_t max_workers = 0;
std::mutex user_mutex = {}; bool have_mtch_stop = false;
pthread_mutex_t mtch_mutex = {};
bool have_mtch_stop = false; pthread_cond_t mtch_cvar = {};
pthread_mutex_t mtch_mutex = {}; phy_interface_stack_lte::phy_cfg_mbsfn_t mbsfn = {};
pthread_cond_t mtch_cvar = {}; bool sib13_configured = false;
phy_interface_stack_lte::phy_cfg_mbsfn_t mbsfn = {}; bool mcch_configured = false;
bool sib13_configured = false; uint8_t mch_table[40] = {};
bool mcch_configured = false; uint8_t mcch_table[10] = {};
uint8_t mch_table[40] = {}; uint32_t mch_period_stop = 0;
uint8_t mcch_table[10] = {};
uint32_t mch_period_stop = 0;
uint8_t mch_sf_idx_lut[10] = {};
bool is_mch_subframe(srslte_mbsfn_cfg_t* cfg, uint32_t phy_tti); bool is_mch_subframe(srslte_mbsfn_cfg_t* cfg, uint32_t phy_tti);
bool is_mcch_subframe(srslte_mbsfn_cfg_t* cfg, uint32_t phy_tti); bool is_mcch_subframe(srslte_mbsfn_cfg_t* cfg, uint32_t phy_tti);
void add_rnti(uint16_t rnti);
}; };
} // namespace srsenb } // namespace srsenb

247
srsenb/hdr/phy/phy_ue_db.h Normal file
View File

@ -0,0 +1,247 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE 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.
*
* srsLTE 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 SRSENB_PHY_UE_DB_H_
#define SRSENB_PHY_UE_DB_H_
#include "phy_interfaces.h"
#include <map>
#include <mutex>
#include <srslte/interfaces/enb_interfaces.h>
#include <srslte/srslte.h>
namespace srsenb {
class phy_ue_db
{
private:
/**
* SCell Configuration state indicates whether the SCell has been configured from the RRC set and activated from the
* MAC layer.
*
* Initially the the state is default and it goes to deactivated as soon as it is configured from RRC, then it can
* transition to active as soon as the MAC indicates so.
*
* +---------+ Set SCell Configuration +-------------+ SCell activation +--------+
* | Default | --------------------------->| Deactivated |--------------------->| Active |
* +---------+ +-------------+ +--------+
* ^ ^ ^ | |
* | | | | |
* --+ | | SCell deactivation | |
* | +---------------------------------+ |
* | Reconfigure SCell |
* | Remove SCell configuration |
* +-----------------------------------------------------------------------------+
*/
typedef enum {
scell_state_default = 0, ///< Default values, not configured, not active
scell_state_deactivated, ///< Configured from RRC but not activated
scell_state_active ///< PCell or activated from MAC
} scell_state_t;
/**
* SCell information for the UE database
*/
typedef struct {
scell_state_t state = scell_state_default; ///< Configuration state
uint32_t cc_idx = 0; ///< Corresponding eNb cell/carrier index
uint8_t last_ri = 0; ///< Last reported rank indicator
srslte_ra_tb_t last_tb[SRSLTE_MAX_HARQ_PROC] = {}; ///< Stores last PUSCH Resource allocation
srslte::phy_cfg_t phy_cfg; ///< Configuration, it has a default constructor
} scell_info_t;
/**
* UE object stored in the PHY common database
*/
struct common_ue {
srslte_pdsch_ack_t pdsch_ack[TTIMOD_SZ] = {}; ///< Pending acknowledgements for this SCell
scell_info_t scell_info[SRSLTE_MAX_CARRIERS]; ///< SCell information, indexed by scell_idx
};
/**
* UE database indexed by RNTI
*/
std::map<uint16_t, common_ue> ue_db;
/**
* Concurrency protection mutex, allowed modifications from const methods.
*/
mutable std::mutex mutex;
/**
* Stack interface
*/
stack_interface_phy_lte* stack = nullptr;
/**
* Cell list
*/
const phy_cell_cfg_list_t* cell_cfg_list = nullptr;
/**
* Internal RNTI addition, it is not thread safe protected
*
* @param rnti identifier of the UE
*/
inline void _add_rnti(uint16_t rnti);
/**
* Internal pending ACK clear for a given RNTI and TTI, it is not thread safe protected
*
* @param tti is the given TTI (requires assertion prior to call)
* @param rnti identifier of the UE (requires assertion prior to call)
*/
inline void _clear_tti_pending_rnti(uint32_t tti, uint16_t rnti);
/**
* Helper method to set the constant attributes of a given RNTI after the configuration is set
*
* @param rnti identifier of the UE (requires assertion prior to call)
*/
inline void _set_config_rnti(uint16_t rnti);
/**
* Gets the SCell index for a given RNTI and a eNb cell/carrier. It returns the SCell index (0 if PCell) if the cc_idx
* 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.
* @return the SCell index as described above.
*/
inline uint32_t _get_scell_idx(uint16_t rnti, uint32_t cc_idx) const;
public:
/**
* Initialises the UE database with the stack and cell list
* @param stack_ptr points to the stack (read/write)
* @param cell_cfg_list_ points to the cell configuration list (read only)
*/
void init(stack_interface_phy_lte* stack_ptr, const phy_cell_cfg_list_t& cell_cfg_list_)
{
stack = stack_ptr;
cell_cfg_list = &cell_cfg_list_;
}
/**
* Adds or modifies a user in the UE database setting. This function requires the physical layer configuration coming
* from the RRC in order to extract cross carrier information such as channel quality reporting configuration. 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 phy_rrc_dedicated_list List of the eNb physical layer configuration coming for the RRC
*/
void addmod_rnti(uint16_t rnti, const phy_interface_rrc_lte::phy_rrc_dedicated_list_t& phy_rrc_dedicated_list);
/**
* Removes a whole UE entry from the UE database
*
* @param rnti identifier of the UE
*/
void rem_rnti(uint16_t rnti);
/**
* Activates or deactivates configured SCells for a given RNTI and SCell index (UE SCell index), index 0 is reserved
* for PCell
* @param rnti identifier of the UE
* @param scell_idx
* @param activate
*/
void activate_deactivate_scell(uint16_t rnti, uint32_t scell_idx, bool activate);
/**
* Get the current physical layer configuration for an RNTI and an eNb cell/carrier
*
* @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;
/**
* Removes all the pending ACKs of all the RNTIs for a given TTI
*
* @param tti is the given TTI to clear
*/
void 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 set_ack_pending(uint32_t tti, uint32_t 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.
* @param tti the current UL reception TTI
* @param cc_idx the eNb cell/carrier where the UL receiption is happening
* @param rnti is the UE identifier
* @param aperiodic_cqi_request indicates if aperiodic CQI was requested
* @param uci_cfg brings the UCI configuration
* @return true if UCI decoding is required and false otherwise
*/
bool fill_uci_cfg(uint32_t tti,
uint32_t cc_idx,
uint16_t rnti,
bool aperiodic_cqi_request,
srslte_uci_cfg_t& uci_cfg) const;
/**
* Sends the decoded Uplink Control Information by PUCCH or PUSCH to MAC
* @param tti the current TTI
* @param rnti is the UE identifier
* @param uci_cfg is the UCI configuration
* @param uci_value is the UCI received value
*/
void send_uci_data(uint32_t tti,
uint16_t rnti,
uint32_t cc_idx,
const srslte_uci_cfg_t& uci_cfg,
const srslte_uci_value_t& uci_value);
/**
* Set the latest UL Transport Block resource allocation for a given RNTI, eNb cell/carrier and UL HARQ process
* identifier.
*
* @param rnti the UE temporal ID
* @param cc_idx the cell/carrier origin of the transmission
* @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);
/**
* Get the latest UL Transport Block resource allocation for a given RNTI, eNb cell/carrier and UL HARQ process
* identifier. It returns the resource allocation if the RNTI and cell/eNb are valid, otherwise it will return an
* default Resource allocation (all zeros by default).
*
* @param rnti the UE temporal ID
* @param cc_idx the cell/carrier origin of the transmission
* @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;
};
} // namespace srsenb
#endif // SRSENB_PHY_UE_DB_H_

View File

@ -42,7 +42,7 @@ public:
cf_t* get_buffer_rx(uint32_t cc_idx, uint32_t antenna_idx); 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); void set_time(uint32_t tti, uint32_t tx_worker_cnt, srslte_timestamp_t tx_time);
int add_rnti(uint16_t rnti, uint32_t cc_idx, bool is_temporal); int add_rnti(uint16_t rnti, uint32_t cc_idx, bool is_pcell, bool is_temporal);
void rem_rnti(uint16_t rnti); void rem_rnti(uint16_t rnti);
uint32_t get_nof_rnti(); uint32_t get_nof_rnti();
@ -53,8 +53,6 @@ public:
int read_pucch_d(cf_t* pusch_d); int read_pucch_d(cf_t* pusch_d);
void start_plot(); void start_plot();
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]); uint32_t get_metrics(phy_metrics_t metrics[ENB_METRICS_MAX_USERS]);
private: private:

View File

@ -126,14 +126,14 @@ void cc_worker::init(phy_common* phy_, srslte::log* log_h_, uint32_t cc_idx_)
} }
/* Setup SI-RNTI in PHY */ /* Setup SI-RNTI in PHY */
add_rnti(SRSLTE_SIRNTI, false); add_rnti(SRSLTE_SIRNTI, false, false);
/* Setup P-RNTI in PHY */ /* Setup P-RNTI in PHY */
add_rnti(SRSLTE_PRNTI, false); add_rnti(SRSLTE_PRNTI, false, false);
/* Setup RA-RNTI in PHY */ /* Setup RA-RNTI in PHY */
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
add_rnti(1 + i, false); add_rnti(1 + i, false, false);
} }
if (srslte_softbuffer_tx_init(&temp_mbsfn_softbuffer, nof_prb)) { if (srslte_softbuffer_tx_init(&temp_mbsfn_softbuffer, nof_prb)) {
@ -177,13 +177,9 @@ void cc_worker::set_tti(uint32_t tti_)
tti_rx = tti_; tti_rx = tti_;
tti_tx_dl = TTI_TX(tti_rx); tti_tx_dl = TTI_TX(tti_rx);
tti_tx_ul = TTI_RX_ACK(tti_rx); tti_tx_ul = TTI_RX_ACK(tti_rx);
t_tx_dl = TTIMOD(tti_tx_dl);
t_rx = TTIMOD(tti_rx);
t_tx_ul = TTIMOD(tti_tx_ul);
} }
int cc_worker::add_rnti(uint16_t rnti, bool is_temporal) int cc_worker::add_rnti(uint16_t rnti, bool is_pcell, bool is_temporal)
{ {
if (!is_temporal && !ue_db.count(rnti)) { if (!is_temporal && !ue_db.count(rnti)) {
@ -198,7 +194,7 @@ int cc_worker::add_rnti(uint16_t rnti, bool is_temporal)
mutex.lock(); mutex.lock();
// Create user unless already exists // Create user unless already exists
if (!ue_db.count(rnti)) { if (!ue_db.count(rnti)) {
ue_db[rnti] = new ue(rnti, phy); ue_db[rnti] = new ue(rnti, is_pcell);
} }
mutex.unlock(); mutex.unlock();
@ -246,22 +242,6 @@ uint32_t cc_worker::get_nof_rnti()
return ue_db.size(); return ue_db.size();
} }
void cc_worker::set_config_dedicated(uint16_t rnti, const srslte::phy_cfg_t& dedicated)
{
std::lock_guard<std::mutex> lock(mutex);
if (ue_db.count(rnti)) {
ue_db[rnti]->ul_cfg = dedicated.ul_cfg;
ue_db[rnti]->ul_cfg.pucch.threshold_format1 = SRSLTE_PUCCH_DEFAULT_THRESHOLD_FORMAT1;
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);
}
}
void cc_worker::work_ul(const srslte_ul_sf_cfg_t& ul_sf_cfg, stack_interface_phy_lte::ul_sched_t& ul_grants) void cc_worker::work_ul(const srslte_ul_sf_cfg_t& ul_sf_cfg, stack_interface_phy_lte::ul_sched_t& ul_grants)
{ {
std::lock_guard<std::mutex> lock(mutex); std::lock_guard<std::mutex> lock(mutex);
@ -313,126 +293,28 @@ void cc_worker::work_dl(const srslte_dl_sf_cfg_t& dl_sf_cfg,
srslte_enb_dl_gen_signal(&enb_dl); srslte_enb_dl_gen_signal(&enb_dl);
} }
bool cc_worker::fill_uci_cfg(uint16_t rnti, bool aperiodic_cqi_request, srslte_uci_cfg_t* uci_cfg)
{
bool uci_required = false;
bzero(uci_cfg, sizeof(srslte_uci_cfg_t));
// Check if SR opportunity (will only be used in PUCCH)
uci_cfg->is_scheduling_request_tti = (srslte_ue_ul_sr_send_tti(&ue_db[rnti]->ul_cfg.pucch, tti_rx) == 1);
uci_required |= uci_cfg->is_scheduling_request_tti;
// 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;
}
}
// Get pending CQI reports for this TTI
if (srslte_enb_dl_gen_cqi_periodic(
&enb_dl.cell, &ue_db[rnti]->dl_cfg, tti_rx, phy->ue_db_get_ri(rnti), &uci_cfg->cqi)) {
uci_required = true;
} else if (aperiodic_cqi_request) {
srslte_enb_dl_gen_cqi_aperiodic(&enb_dl.cell, &ue_db[rnti]->dl_cfg, phy->ue_db_get_ri(rnti), &uci_cfg->cqi);
uci_required = true;
}
return uci_required;
}
void cc_worker::send_uci_data(uint16_t rnti, srslte_uci_cfg_t* uci_cfg, srslte_uci_value_t* uci_value)
{
// Notify SR
if (uci_cfg->is_scheduling_request_tti && uci_value->scheduling_request) {
phy->stack->sr_detected(tti_rx, rnti);
}
/* If only one ACK is required, it can be for TB0 or TB1 */
uint32_t ack_idx = 0;
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++;
}
}
}
// Notify CQI only if CRC is valid
if (uci_value->cqi.data_crc) {
if (uci_cfg->cqi.data_enable) {
uint8_t cqi_value = 0;
switch (uci_cfg->cqi.type) {
case SRSLTE_CQI_TYPE_WIDEBAND:
cqi_value = uci_value->cqi.wideband.wideband_cqi;
break;
case SRSLTE_CQI_TYPE_SUBBAND:
cqi_value = uci_value->cqi.subband.subband_cqi;
break;
case SRSLTE_CQI_TYPE_SUBBAND_HL:
cqi_value = uci_value->cqi.subband_hl.wideband_cqi_cw0;
break;
case SRSLTE_CQI_TYPE_SUBBAND_UE:
cqi_value = uci_value->cqi.subband_ue.wideband_cqi;
break;
}
phy->stack->cqi_info(tti_rx, rnti, 0, cqi_value);
}
if (uci_cfg->cqi.ri_len) {
phy->stack->ri_info(tti_rx, 0, rnti, uci_value->ri);
phy->ue_db_set_ri(rnti, uci_value->ri);
}
if (uci_cfg->cqi.pmi_present) {
uint8_t pmi_value = 0;
switch (uci_cfg->cqi.type) {
case SRSLTE_CQI_TYPE_WIDEBAND:
pmi_value = uci_value->cqi.wideband.pmi;
break;
case SRSLTE_CQI_TYPE_SUBBAND_HL:
pmi_value = uci_value->cqi.subband_hl.pmi;
break;
default:
Error("CQI type=%d not implemented for PMI\n", uci_cfg->cqi.type);
break;
}
phy->stack->pmi_info(tti_rx, rnti, 0, pmi_value);
}
}
}
int cc_worker::decode_pusch(stack_interface_phy_lte::ul_sched_grant_t* grants, uint32_t nof_pusch) int cc_worker::decode_pusch(stack_interface_phy_lte::ul_sched_grant_t* grants, uint32_t nof_pusch)
{ {
srslte_pusch_res_t pusch_res; srslte_pusch_res_t pusch_res;
for (uint32_t i = 0; i < nof_pusch; i++) { for (uint32_t i = 0; i < nof_pusch; i++) {
uint16_t rnti = grants[i].dci.rnti; // Get grant itself and RNTI
auto& ul_grant = grants[i];
uint16_t rnti = ul_grant.dci.rnti;
if (rnti) { if (rnti) {
// Get UE configuration
srslte::phy_cfg_t phy_cfg = phy->ue_db.get_config(rnti, cc_idx);
srslte_ul_cfg_t& ul_cfg = phy_cfg.ul_cfg;
// mark this tti as having an ul dci to avoid pucch // mark this tti as having an ul dci to avoid pucch
ue_db[rnti]->is_grant_available = true; ue_db[rnti]->is_grant_available = true;
fill_uci_cfg(rnti, grants->dci.cqi_request, &ue_db[rnti]->ul_cfg.pusch.uci_cfg); // Fill UCI configuration
phy->ue_db.fill_uci_cfg(tti_rx, cc_idx, rnti, grants->dci.cqi_request, phy_cfg.ul_cfg.pucch.uci_cfg);
// Compute UL grant // Compute UL grant
srslte_pusch_grant_t* grant = &ue_db[rnti]->ul_cfg.pusch.grant; srslte_pusch_grant_t& grant = phy_cfg.ul_cfg.pusch.grant;
if (srslte_ra_ul_dci_to_grant(&enb_ul.cell, &ul_sf, &ue_db[rnti]->ul_cfg.hopping, &grants[i].dci, grant)) { if (srslte_ra_ul_dci_to_grant(&enb_ul.cell, &ul_sf, &ul_cfg.hopping, &ul_grant.dci, &grant)) {
Error("Computing PUSCH dci\n"); Error("Computing PUSCH dci\n");
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
@ -441,25 +323,25 @@ int cc_worker::decode_pusch(stack_interface_phy_lte::ul_sched_grant_t* grants, u
// Handle Format0 adaptive retx // Handle Format0 adaptive retx
// Use last TBS for this TB in case of mcs>28 // Use last TBS for this TB in case of mcs>28
if (grants[i].dci.tb.mcs_idx > 28) { if (ul_grant.dci.tb.mcs_idx > 28) {
grant->tb = phy->ue_db_get_last_ul_tb(rnti, ul_pid); grant.tb = phy->ue_db.get_last_ul_tb(rnti, cc_idx, ul_pid);
Info("RETX: mcs=%d, old_tbs=%d pid=%d\n", grants[i].dci.tb.mcs_idx, grant->tb.tbs, ul_pid); Info("RETX: mcs=%d, old_tbs=%d pid=%d\n", grants[i].dci.tb.mcs_idx, grant.tb.tbs, ul_pid);
} }
phy->ue_db_set_last_ul_tb(rnti, ul_pid, grant->tb); phy->ue_db.set_last_ul_tb(rnti, cc_idx, ul_pid, grant.tb);
// Run PUSCH decoder // Run PUSCH decoder
pusch_res = {}; pusch_res = {};
ue_db[rnti]->ul_cfg.pusch.softbuffers.rx = grants[i].softbuffer_rx; ul_cfg.pusch.softbuffers.rx = grants[i].softbuffer_rx;
pusch_res.data = grants[i].data; pusch_res.data = grants[i].data;
if (pusch_res.data) { if (pusch_res.data) {
if (srslte_enb_ul_get_pusch(&enb_ul, &ul_sf, &ue_db[rnti]->ul_cfg.pusch, &pusch_res)) { if (srslte_enb_ul_get_pusch(&enb_ul, &ul_sf, &ul_cfg.pusch, &pusch_res)) {
Error("Decoding PUSCH\n"); Error("Decoding PUSCH\n");
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
} }
// Save PHICH scheduling for this user. Each user can have just 1 PUSCH dci per TTI // Save PHICH scheduling for this user. Each user can have just 1 PUSCH dci per TTI
ue_db[rnti]->phich_grant.n_prb_lowest = grant->n_prb_tilde[0]; ue_db[rnti]->phich_grant.n_prb_lowest = grant.n_prb_tilde[0];
ue_db[rnti]->phich_grant.n_dmrs = grants[i].dci.n_dmrs; ue_db[rnti]->phich_grant.n_dmrs = grants[i].dci.n_dmrs;
float snr_db = enb_ul.chest_res.snr_db; float snr_db = enb_ul.chest_res.snr_db;
@ -479,18 +361,18 @@ int cc_worker::decode_pusch(stack_interface_phy_lte::ul_sched_grant_t* grants, u
} }
// Send UCI data to MAC // Send UCI data to MAC
send_uci_data(rnti, &ue_db[rnti]->ul_cfg.pusch.uci_cfg, &pusch_res.uci); phy->ue_db.send_uci_data(tti_rx, rnti, cc_idx, ul_cfg.pusch.uci_cfg, pusch_res.uci);
// Notify MAC new received data and HARQ Indication value // Notify MAC new received data and HARQ Indication value
if (pusch_res.data) { if (pusch_res.data) {
phy->stack->crc_info(tti_rx, rnti, cc_idx, grant->tb.tbs / 8, pusch_res.crc); phy->stack->crc_info(tti_rx, rnti, cc_idx, grant.tb.tbs / 8, pusch_res.crc);
// Save metrics stats // Save metrics stats
ue_db[rnti]->metrics_ul(grants[i].dci.tb.mcs_idx, 0, snr_db, pusch_res.avg_iterations_block); ue_db[rnti]->metrics_ul(grants[i].dci.tb.mcs_idx, 0, snr_db, pusch_res.avg_iterations_block);
// Logging // Logging
char str[512]; char str[512];
srslte_pusch_rx_info(&ue_db[rnti]->ul_cfg.pusch, &pusch_res, str, 512); srslte_pusch_rx_info(&ul_cfg.pusch, &pusch_res, str, 512);
Info("PUSCH: %s, snr=%.1f dB\n", str, snr_db); Info("PUSCH: %s, snr=%.1f dB\n", str, snr_db);
} }
} }
@ -500,24 +382,25 @@ int cc_worker::decode_pusch(stack_interface_phy_lte::ul_sched_grant_t* grants, u
int cc_worker::decode_pucch() int cc_worker::decode_pucch()
{ {
srslte_pucch_res_t pucch_res; srslte_pucch_res_t pucch_res = {};
ZERO_OBJECT(pucch_res);
for (auto& iter : ue_db) { for (auto& iter : ue_db) {
auto rnti = (uint16_t)iter.first; auto rnti = (uint16_t)iter.first;
auto phy_cfg = phy->ue_db.get_config(rnti, cc_idx);
auto& ul_cfg = phy_cfg.ul_cfg;
// If it's a User RNTI and doesn't have PUSCH grant in this TTI // If it's a User RNTI and doesn't have PUSCH grant in this TTI
if (SRSLTE_RNTI_ISUSER(rnti) && !ue_db[rnti]->is_grant_available) { if (SRSLTE_RNTI_ISUSER(rnti) && !ue_db[rnti]->is_grant_available && ue_db[rnti]->is_pcell()) {
// Check if user needs to receive PUCCH // Check if user needs to receive PUCCH
if (fill_uci_cfg(rnti, false, &ue_db[rnti]->ul_cfg.pucch.uci_cfg)) { if (phy->ue_db.fill_uci_cfg(tti_rx, cc_idx, rnti, false, ul_cfg.pucch.uci_cfg)) {
// Decode PUCCH // Decode PUCCH
if (srslte_enb_ul_get_pucch(&enb_ul, &ul_sf, &ue_db[rnti]->ul_cfg.pucch, &pucch_res)) { if (srslte_enb_ul_get_pucch(&enb_ul, &ul_sf, &ul_cfg.pucch, &pucch_res)) {
ERROR("Error getting PUCCH\n"); ERROR("Error getting PUCCH\n");
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
// Notify MAC of RL status (skip SR subframes) // Notify MAC of RL status (skip SR subframes)
if (!ue_db[rnti]->ul_cfg.pucch.uci_cfg.is_scheduling_request_tti) { if (!ul_cfg.pucch.uci_cfg.is_scheduling_request_tti) {
if (pucch_res.correlation < PUCCH_RL_CORR_TH) { if (pucch_res.correlation < PUCCH_RL_CORR_TH) {
Debug("PUCCH: Radio-Link failure corr=%.1f\n", pucch_res.correlation); Debug("PUCCH: Radio-Link failure corr=%.1f\n", pucch_res.correlation);
phy->stack->rl_failure(rnti); phy->stack->rl_failure(rnti);
@ -527,12 +410,12 @@ int cc_worker::decode_pucch()
} }
// Send UCI data to MAC // Send UCI data to MAC
send_uci_data(rnti, &ue_db[rnti]->ul_cfg.pucch.uci_cfg, &pucch_res.uci_data); phy->ue_db.send_uci_data(tti_rx, rnti, cc_idx, ul_cfg.pucch.uci_cfg, pucch_res.uci_data);
// Logging // Logging
char str[512]; char str[512];
srslte_pucch_rx_info(&ue_db[rnti]->ul_cfg.pucch, &pucch_res.uci_data, str, 512); srslte_pucch_rx_info(&ul_cfg.pucch, &pucch_res.uci_data, str, 512);
Info("PUCCH: %s, corr=%.1f\n", str, pucch_res.correlation); Info("PUCCH: cc=%d; %s, corr=%.1f\n", cc_idx, str, pucch_res.correlation);
} }
} }
} }
@ -627,22 +510,24 @@ 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) */ /* Scales the Resources Elements affected by the power allocation (p_b) */
// srslte_enb_dl_prepare_power_allocation(&enb_dl); // srslte_enb_dl_prepare_power_allocation(&enb_dl);
for (uint32_t i = 0; i < nof_grants; i++) { for (uint32_t i = 0; i < nof_grants; i++) {
uint16_t rnti = grants[i].dci.rnti; uint16_t rnti = grants[i].dci.rnti;
auto phy_cfg = phy->ue_db.get_config(rnti, cc_idx);
srslte_dl_cfg_t& dl_cfg = phy_cfg.dl_cfg;
if (rnti && ue_db.count(rnti)) { if (rnti && ue_db.count(rnti)) {
// Compute DL grant // Compute DL grant
if (srslte_ra_dl_dci_to_grant( if (srslte_ra_dl_dci_to_grant(&enb_dl.cell, &dl_sf, dl_cfg.tm, false, &grants[i].dci, &dl_cfg.pdsch.grant)) {
&enb_dl.cell, &dl_sf, ue_db[rnti]->dl_cfg.tm, false, &grants[i].dci, &ue_db[rnti]->dl_cfg.pdsch.grant)) {
Error("Computing DL grant\n"); Error("Computing DL grant\n");
} }
// Set soft buffer // Set soft buffer
for (uint32_t j = 0; j < SRSLTE_MAX_CODEWORDS; j++) { for (uint32_t j = 0; j < SRSLTE_MAX_CODEWORDS; j++) {
ue_db[rnti]->dl_cfg.pdsch.softbuffers.tx[j] = grants[i].softbuffer_tx[j]; dl_cfg.pdsch.softbuffers.tx[j] = grants[i].softbuffer_tx[j];
} }
// Encode PDSCH // Encode PDSCH
if (srslte_enb_dl_put_pdsch(&enb_dl, &ue_db[rnti]->dl_cfg.pdsch, grants[i].data)) { if (srslte_enb_dl_put_pdsch(&enb_dl, &dl_cfg.pdsch, grants[i].data)) {
Error("Error putting PDSCH %d\n", i); Error("Error putting PDSCH %d\n", i);
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
@ -650,13 +535,13 @@ int cc_worker::encode_pdsch(stack_interface_phy_lte::dl_sched_grant_t* grants, u
// Save pending ACK // Save pending ACK
if (SRSLTE_RNTI_ISUSER(rnti)) { if (SRSLTE_RNTI_ISUSER(rnti)) {
// Push whole DCI // Push whole DCI
phy->ue_db_set_ack_pending(tti_tx_ul, cc_idx, grants[i].dci); phy->ue_db.set_ack_pending(tti_tx_ul, cc_idx, grants[i].dci);
} }
if (LOG_THIS(rnti)) { if (LOG_THIS(rnti)) {
// Logging // Logging
char str[512]; char str[512];
srslte_pdsch_tx_info(&ue_db[rnti]->dl_cfg.pdsch, str, 512); srslte_pdsch_tx_info(&dl_cfg.pdsch, str, 512);
Info("PDSCH: cc=%d, %s, tti_tx_dl=%d\n", cc_idx, str, tti_tx_dl); Info("PDSCH: cc=%d, %s, tti_tx_dl=%d\n", cc_idx, str, tti_tx_dl);
} }

View File

@ -195,11 +195,15 @@ uint32_t phy::tti_to_subf(uint32_t tti)
int phy::add_rnti(uint16_t rnti, uint32_t pcell_index, bool is_temporal) int phy::add_rnti(uint16_t rnti, uint32_t pcell_index, bool is_temporal)
{ {
if (SRSLTE_RNTI_ISUSER(rnti)) { if (SRSLTE_RNTI_ISUSER(rnti)) {
workers_common.ue_db_addmod_rnti(rnti, {pcell_index}); // Create default PHY configuration with the desired PCell index
phy_interface_rrc_lte::phy_rrc_dedicated_list_t phy_rrc_dedicated_list(1);
phy_rrc_dedicated_list[0].cc_idx = pcell_index;
workers_common.ue_db.addmod_rnti(rnti, phy_rrc_dedicated_list);
} }
for (uint32_t i = 0; i < nof_workers; i++) { for (uint32_t i = 0; i < nof_workers; i++) {
if (workers[i].add_rnti(rnti, pcell_index, is_temporal)) { if (workers[i].add_rnti(rnti, pcell_index, true, is_temporal)) {
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
} }
@ -210,7 +214,7 @@ int phy::add_rnti(uint16_t rnti, uint32_t pcell_index, bool is_temporal)
void phy::rem_rnti(uint16_t rnti) void phy::rem_rnti(uint16_t rnti)
{ {
if (SRSLTE_RNTI_ISUSER(rnti)) { if (SRSLTE_RNTI_ISUSER(rnti)) {
workers_common.ue_db_rem_rnti(rnti); workers_common.ue_db.rem_rnti(rnti);
} }
for (uint32_t i = 0; i < nof_workers; i++) { for (uint32_t i = 0; i < nof_workers; i++) {
workers[i].rem_rnti(rnti); workers[i].rem_rnti(rnti);
@ -224,7 +228,10 @@ void phy::set_mch_period_stop(uint32_t stop)
void phy::set_activation_deactivation_scell(uint16_t rnti, bool activation[SRSLTE_MAX_CARRIERS]) void phy::set_activation_deactivation_scell(uint16_t rnti, bool activation[SRSLTE_MAX_CARRIERS])
{ {
Info("Set activation/deactivation not implemented\n"); // Iterate all elements except 0 that is reserved for primary cell
for (uint32_t scell_idx = 1; scell_idx < SRSLTE_MAX_CARRIERS; scell_idx++) {
workers_common.ue_db.activate_deactivate_scell(rnti, scell_idx, activation[scell_idx]);
}
} }
void phy::get_metrics(phy_metrics_t metrics[ENB_METRICS_MAX_USERS]) void phy::get_metrics(phy_metrics_t metrics[ENB_METRICS_MAX_USERS])
@ -261,28 +268,21 @@ void phy::get_metrics(phy_metrics_t metrics[ENB_METRICS_MAX_USERS])
void phy::set_config_dedicated(uint16_t rnti, const phy_rrc_dedicated_list_t& dedicated_list) void phy::set_config_dedicated(uint16_t rnti, const phy_rrc_dedicated_list_t& dedicated_list)
{ {
// Create list, empty by default // Update UE Database
std::vector<uint32_t> scell_idx_list; workers_common.ue_db.addmod_rnti(rnti, dedicated_list);
// Iterate over the list and add the RNTIs
for (uint32_t scell_idx = 0; scell_idx < dedicated_list.size(); scell_idx++) {
auto& config = dedicated_list[scell_idx];
for (const auto& config : dedicated_list) {
// Configure only if active, ignore otherwise // Configure only if active, ignore otherwise
if (config.configured) { if (scell_idx != 0 && config.configured) {
// Set PCell/SCell index in list // Add RNTI to workers
scell_idx_list.push_back(config.cc_idx);
// Configure workers
for (uint32_t w = 0; w < nof_workers; w++) { for (uint32_t w = 0; w < nof_workers; w++) {
// Add RNTI to worker workers[w].add_rnti(rnti, config.cc_idx, false, false);
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) void phy::configure_mbsfn(sib_type2_s* sib2, sib_type13_r9_s* sib13, mcch_msg_s mcch)

View File

@ -46,7 +46,7 @@ using namespace asn1::rrc;
namespace srsenb { namespace srsenb {
phy_common::phy_common(uint32_t max_workers_) : tx_sem(max_workers_), cell_list() phy_common::phy_common(uint32_t max_workers_) : tx_sem(max_workers_), cell_list(), ue_db()
{ {
params.max_prach_offset_us = 20; params.max_prach_offset_us = 20;
max_workers = max_workers_; max_workers = max_workers_;
@ -109,6 +109,9 @@ bool phy_common::init(const phy_cell_cfg_list_t& cell_list_,
is_first_tx = true; is_first_tx = true;
// Set UE PHY data-base stack
ue_db.init(stack, cell_list);
reset(); reset();
return true; return true;
} }
@ -158,194 +161,6 @@ void phy_common::worker_end(uint32_t tti,
stack->tti_clock(); stack->tti_clock();
} }
void phy_common::ue_db_clear_tti_pending_ack(uint32_t tti)
{
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_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 (auto& pending_ack : common_ue_db[rnti].pending_ack) {
pending_ack = {};
}
}
void phy_common::ue_db_rem_rnti(uint16_t rnti)
{
std::lock_guard<std::mutex> lock(user_mutex);
if (!common_ue_db.count(rnti)) {
common_ue_db.erase(rnti);
}
}
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);
// 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]; // Assume it has been zero'ed for the TTI
// 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_dci_format_max_tb(dci.format); 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++;
}
}
}
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])
{
std::lock_guard<std::mutex> lock(user_mutex);
// 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);
if (common_ue_db.count(rnti)) {
common_ue_db[rnti].ri = ri;
}
}
uint8_t phy_common::ue_db_get_ri(uint16_t rnti)
{
std::lock_guard<std::mutex> lock(user_mutex);
uint8_t ret = 0;
if (common_ue_db.count(rnti)) {
ret = common_ue_db[rnti].ri;
}
return ret;
}
void phy_common::ue_db_set_last_ul_tb(uint16_t rnti, uint32_t pid, srslte_ra_tb_t tb)
{
std::lock_guard<std::mutex> lock(user_mutex);
if (!common_ue_db.count(rnti)) {
add_rnti(rnti);
}
common_ue_db[rnti].last_tb[pid % SRSLTE_MAX_HARQ_PROC] = tb;
}
srslte_ra_tb_t phy_common::ue_db_get_last_ul_tb(uint16_t rnti, uint32_t pid)
{
std::lock_guard<std::mutex> lock(user_mutex);
srslte_ra_tb_t ret = {};
if (common_ue_db.count(rnti)) {
ret = common_ue_db[rnti].last_tb[pid % SRSLTE_FDD_NOF_HARQ];
}
return ret;
}
void phy_common::set_mch_period_stop(uint32_t stop) void phy_common::set_mch_period_stop(uint32_t stop)
{ {
pthread_mutex_lock(&mtch_mutex); pthread_mutex_lock(&mtch_mutex);

504
srsenb/src/phy/phy_ue_db.cc Normal file
View File

@ -0,0 +1,504 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE 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.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include "srsenb/hdr/phy/phy_ue_db.h"
using namespace srsenb;
inline void phy_ue_db::_add_rnti(uint16_t rnti)
{
// Private function not mutexed
// Assert RNTI does NOT exist
if (ue_db.count(rnti)) {
return;
}
// Create new UE by accesing it
ue_db[rnti].scell_info[0] = {};
// Get UE
common_ue& ue = ue_db[rnti];
// Load default values to PCell
ue.scell_info[0].phy_cfg.set_defaults();
// Set constant configuration fields
_set_config_rnti(rnti);
// PCell shall be active by default
ue.scell_info[0].state = scell_state_active;
// Iterate all pending ACK
for (uint32_t tti = 0; tti < TTIMOD_SZ; tti++) {
_clear_tti_pending_rnti(tti, rnti);
}
}
inline void phy_ue_db::_clear_tti_pending_rnti(uint32_t tti, uint16_t rnti)
{
// Private function not mutexed, no need to assert RNTI or TTI
// Get UE
common_ue& ue = ue_db[rnti];
srslte_pdsch_ack_t& pdsch_ack = ue.pdsch_ack[tti];
// Reset ACK information
pdsch_ack = {};
uint32_t nof_active_cc = 0;
for (auto& scell_info : ue.scell_info) {
if (scell_info.state == scell_state_active) {
nof_active_cc++;
}
}
// Copy essentials
pdsch_ack.transmission_mode = ue.scell_info[0].phy_cfg.dl_cfg.tm;
pdsch_ack.nof_cc = nof_active_cc;
pdsch_ack.ack_nack_feedback_mode = ue.scell_info[0].phy_cfg.ul_cfg.pucch.ack_nack_feedback_mode;
pdsch_ack.simul_cqi_ack = ue.scell_info[0].phy_cfg.ul_cfg.pucch.simul_cqi_ack;
}
inline void phy_ue_db::_set_config_rnti(uint16_t rnti)
{
// Private function not mutexed, no need to assert RNTI or TTI
// Get UE
common_ue& ue = ue_db[rnti];
// Iterate all cells/carriers
for (auto& scell_info : ue.scell_info) {
scell_info.phy_cfg.dl_cfg.pdsch.rnti = rnti;
scell_info.phy_cfg.ul_cfg.pucch.rnti = rnti;
scell_info.phy_cfg.ul_cfg.pusch.rnti = rnti;
scell_info.phy_cfg.ul_cfg.pucch.threshold_format1 = SRSLTE_PUCCH_DEFAULT_THRESHOLD_FORMAT1;
scell_info.phy_cfg.ul_cfg.pucch.threshold_data_valid_format1a = SRSLTE_PUCCH_DEFAULT_THRESHOLD_FORMAT1A;
scell_info.phy_cfg.ul_cfg.pucch.threshold_data_valid_format2 = SRSLTE_PUCCH_DEFAULT_THRESHOLD_FORMAT2;
}
}
inline uint32_t phy_ue_db::_get_scell_idx(uint16_t rnti, uint32_t cc_idx) const
{
uint32_t scell_idx = 0;
const common_ue& ue = ue_db.at(rnti);
for (scell_idx = 0; scell_idx < SRSLTE_MAX_CARRIERS; scell_idx++) {
const scell_info_t& scell_info = ue.scell_info[scell_idx];
if (scell_info.cc_idx == cc_idx && scell_info.state != scell_state_deactivated) {
return scell_idx;
}
}
return scell_idx;
}
void phy_ue_db::clear_tti_pending_ack(uint32_t tti)
{
std::lock_guard<std::mutex> lock(mutex);
// Iterate all UEs
for (auto& iter : ue_db) {
_clear_tti_pending_rnti(TTIMOD(tti), iter.first);
}
}
void phy_ue_db::addmod_rnti(uint16_t rnti,
const phy_interface_rrc_lte::phy_rrc_dedicated_list_t& phy_rrc_dedicated_list)
{
std::lock_guard<std::mutex> lock(mutex);
// Create new user if did not exist
if (!ue_db.count(rnti)) {
_add_rnti(rnti);
}
// Get UE by reference
common_ue& ue = ue_db[rnti];
// Iterate PHY RRC configuration for each cell/carrier
for (uint32_t scell_idx = 0; scell_idx < phy_rrc_dedicated_list.size() && scell_idx < SRSLTE_MAX_CARRIERS;
scell_idx++) {
auto& phy_rrc_dedicated = phy_rrc_dedicated_list[scell_idx];
// Configured, add/modify entry in the scell_info map
auto& scell_info = ue.scell_info[scell_idx];
if (phy_rrc_dedicated.configured) {
// Set SCell information
scell_info.cc_idx = phy_rrc_dedicated.cc_idx;
scell_info.phy_cfg = phy_rrc_dedicated.phy_cfg;
// Set constant configuration fields
_set_config_rnti(rnti);
// Set SCell state, all deactivated by default except PCell
scell_info.state = scell_idx == 0 ? scell_state_active : scell_state_deactivated;
} else {
// Cell without configuration shall be default
scell_info.state = scell_state_default;
}
}
// Iterate the rest of SCells
for (uint32_t scell_idx = phy_rrc_dedicated_list.size(); scell_idx < SRSLTE_MAX_CARRIERS; scell_idx++) {
// Set state of these to default
ue.scell_info[scell_idx].state = scell_state_default;
}
}
void phy_ue_db::rem_rnti(uint16_t rnti)
{
std::lock_guard<std::mutex> lock(mutex);
if (ue_db.count(rnti)) {
ue_db.erase(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_scell_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 scell_idx = _get_scell_idx(RNTI, CC_IDX); \
if (scell_idx == SRSLTE_MAX_CARRIERS) { \
ERROR("Corrupted SCell index %d for RNTI x%x and cell/carrier index %d\n", scell_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 SCell is active */ \
auto& scell_info = ue_db.at(RNTI).scell_info[_get_scell_idx(RNTI, CC_IDX)]; \
if (scell_info.state != scell_state_active) { \
ERROR("Failed to assert active cell/carrier %d for RNTI x%x", CC_IDX, RNTI); \
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_scell_idx(RNTI, CC_IDX) != 0) { \
return RET; \
} \
} while (false)
#define UE_DB_ASSERT_SCELL(RNTI, SCELL_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 (SCELL_IDX >= SRSLTE_MAX_CARRIERS) { \
ERROR("Out-of-bounds SCell index %d for RNTI x%x.\n", SCELL_IDX, RNTI); \
return RET; \
} \
} while (false)
#define UE_DB_ASSERT_ACTIVE_SCELL(RNTI, SCELL_IDX, RET) \
do { \
/* Assert RNTI exists and eNb cell/carrier is configured */ \
UE_DB_ASSERT_SCELL(RNTI, SCELL_IDX, RET); \
\
/* Check SCell is active */ \
auto& scell_info = ue_db.at(RNTI).scell_info[SCELL_IDX]; \
if (scell_info.state != scell_state_active) { \
ERROR("Failed to assert active SCell %d for RNTI x%x", SCELL_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 scell_idx, bool activate)
{
// Assert RNTI and SCell are valid
UE_DB_ASSERT_SCELL(rnti, scell_idx, /* void */);
auto& scell_info = ue_db[rnti].scell_info[scell_idx];
// If scell is default only complain
if (activate and scell_info.state == scell_state_default) {
ERROR("RNTI x%x SCell %d has received an activation MAC command but it was not configured\n", rnti, scell_idx);
return;
}
// Set scell state
scell_info.state = (activate) ? scell_state_active : scell_state_deactivated;
}
srslte::phy_cfg_t phy_ue_db::get_config(uint16_t rnti, uint32_t cc_idx) const
{
std::lock_guard<std::mutex> lock(mutex);
UE_DB_ASSERT_ACTIVE_CELL(rnti, cc_idx, {});
return ue_db.at(rnti).scell_info[_get_scell_idx(rnti, cc_idx)].phy_cfg;
}
void phy_ue_db::set_ack_pending(uint32_t tti, uint32_t cc_idx, const srslte_dci_dl_t& dci)
{
std::lock_guard<std::mutex> lock(mutex);
// Assert rnti and cell exits and it is active
UE_DB_ASSERT_ACTIVE_CELL(dci.rnti, cc_idx, /* void */);
common_ue& ue = ue_db[dci.rnti];
uint32_t scell_idx = _get_scell_idx(dci.rnti, cc_idx);
srslte_pdsch_ack_cc_t& pdsch_ack_cc = ue.pdsch_ack[TTIMOD(tti)].cc[scell_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.n_cce = dci.location.ncce;
pdsch_ack_m.resource.tpc_for_pucch = dci.tpc_pucch;
// Set TB info
for (uint32_t i = 0; i < srslte_dci_format_max_tb(dci.format); i++) {
if (SRSLTE_DCI_IS_TB_EN(dci.tb[i])) {
pdsch_ack_m.value[i] = true;
pdsch_ack_m.k++;
}
}
}
bool phy_ue_db::fill_uci_cfg(uint32_t tti,
uint32_t cc_idx,
uint16_t rnti,
bool aperiodic_cqi_request,
srslte_uci_cfg_t& uci_cfg) const
{
std::lock_guard<std::mutex> lock(mutex);
// Assert rnti and cell exits and it is active
UE_DB_ASSERT_PCELL(rnti, cc_idx, false);
// Assert Cell List configuration
UE_DB_ASSERT_CELL_LIST_CFG(false);
const auto& ue = ue_db.at(rnti);
const auto& pcell_cfg = ue.scell_info[0].phy_cfg;
bool uci_required = false;
uci_cfg = {};
// Check if SR opportunity (will only be used in PUCCH)
uci_cfg.is_scheduling_request_tti = (srslte_ue_ul_sr_send_tti(&pcell_cfg.ul_cfg.pucch, tti) == 1);
uci_required |= uci_cfg.is_scheduling_request_tti;
// Get pending CQI reports for this TTI, stops at first CC reporting
bool periodic_cqi_required = false;
for (uint32_t scell_idx = 0; scell_idx < SRSLTE_MAX_CARRIERS and not periodic_cqi_required; scell_idx++) {
const scell_info_t& scell_info = ue.scell_info[scell_idx];
const srslte_dl_cfg_t& dl_cfg = scell_info.phy_cfg.dl_cfg;
if (scell_info.state == scell_state_active) {
const srslte_cell_t& cell = cell_cfg_list->at(scell_info.cc_idx).cell;
// Check if CQI report is required
periodic_cqi_required = srslte_enb_dl_gen_cqi_periodic(&cell, &dl_cfg, tti, scell_info.last_ri, &uci_cfg.cqi);
// Save SCell index for using it after
uci_cfg.cqi.scell_index = scell_idx;
}
}
uci_required |= periodic_cqi_required;
// If no periodic CQI report required, check aperiodic reporting
if ((not periodic_cqi_required) and aperiodic_cqi_request) {
// Aperiodic only supported for PCell
const scell_info_t& pcell_info = ue.scell_info[0];
const srslte_cell_t& cell = cell_cfg_list->at(pcell_info.cc_idx).cell;
const srslte_dl_cfg_t& dl_cfg = pcell_info.phy_cfg.dl_cfg;
uci_required = srslte_enb_dl_gen_cqi_aperiodic(&cell, &dl_cfg, pcell_info.last_ri, &uci_cfg.cqi);
}
// Get pending ACKs from PDSCH
srslte_dl_sf_cfg_t dl_sf_cfg = {};
dl_sf_cfg.tti = tti;
const srslte_cell_t& cell = cell_cfg_list->at(ue.scell_info[0].cc_idx).cell;
srslte_enb_dl_gen_ack(&cell, &dl_sf_cfg, &ue.pdsch_ack[TTIMOD(tti)], &uci_cfg);
uci_required |= (srslte_uci_cfg_total_ack(&uci_cfg) > 0);
// Return whether UCI needs to be decoded
return uci_required;
}
void phy_ue_db::send_uci_data(uint32_t tti,
uint16_t rnti,
uint32_t cc_idx,
const srslte_uci_cfg_t& uci_cfg,
const srslte_uci_value_t& uci_value)
{
std::lock_guard<std::mutex> lock(mutex);
// Assert UE RNTI database entry and eNb cell/carrier must be primary cell
UE_DB_ASSERT_PCELL(rnti, cc_idx, /* void */);
// Assert Stack
UE_DB_ASSERT_STACK(/* void */);
// Notify SR
if (uci_cfg.is_scheduling_request_tti && uci_value.scheduling_request) {
stack->sr_detected(tti, rnti);
}
// Get UE
common_ue& ue = ue_db.at(rnti);
// Get ACK info
srslte_pdsch_ack_t& pdsch_ack = ue.pdsch_ack[TTIMOD(tti)];
srslte_enb_dl_get_ack(&cell_cfg_list->at(ue.scell_info[0].cc_idx).cell, &uci_value, &pdsch_ack);
// Iterate over the ACK information
for (uint32_t scell_idx = 0; scell_idx < SRSLTE_MAX_CARRIERS; scell_idx++) {
const srslte_pdsch_ack_cc_t& pdsch_ack_cc = pdsch_ack.cc[scell_idx];
for (uint32_t m = 0; m < pdsch_ack_cc.M; m++) {
if (pdsch_ack_cc.m[m].present) {
for (uint32_t tb = 0; tb < pdsch_ack_cc.m[m].k; tb++) {
stack->ack_info(tti, rnti, ue.scell_info[scell_idx].cc_idx, tb, pdsch_ack_cc.m[m].value[tb] == 1);
}
}
}
}
// Assert the SCell exists and it is active
UE_DB_ASSERT_ACTIVE_SCELL(rnti, uci_cfg.cqi.scell_index, /* void */);
// Get CQI carrier index
auto& cqi_scell_info = ue_db.at(rnti).scell_info[uci_cfg.cqi.scell_index];
uint32_t cqi_cc_idx = cqi_scell_info.cc_idx;
// Notify CQI only if CRC is valid
if (uci_value.cqi.data_crc) {
// Channel quality indicator itself
if (uci_cfg.cqi.data_enable) {
uint8_t cqi_value = 0;
switch (uci_cfg.cqi.type) {
case SRSLTE_CQI_TYPE_WIDEBAND:
cqi_value = uci_value.cqi.wideband.wideband_cqi;
break;
case SRSLTE_CQI_TYPE_SUBBAND:
cqi_value = uci_value.cqi.subband.subband_cqi;
break;
case SRSLTE_CQI_TYPE_SUBBAND_HL:
cqi_value = uci_value.cqi.subband_hl.wideband_cqi_cw0;
break;
case SRSLTE_CQI_TYPE_SUBBAND_UE:
cqi_value = uci_value.cqi.subband_ue.wideband_cqi;
break;
}
stack->cqi_info(tti, rnti, cqi_cc_idx, cqi_value);
}
// Rank indicator (TM3 and TM4)
if (uci_cfg.cqi.ri_len) {
stack->ri_info(tti, cqi_cc_idx, rnti, uci_value.ri);
cqi_scell_info.last_ri = uci_value.ri;
}
// Precoding Matrix indicator (TM4)
if (uci_cfg.cqi.pmi_present) {
uint8_t pmi_value = 0;
switch (uci_cfg.cqi.type) {
case SRSLTE_CQI_TYPE_WIDEBAND:
pmi_value = uci_value.cqi.wideband.pmi;
break;
case SRSLTE_CQI_TYPE_SUBBAND_HL:
pmi_value = uci_value.cqi.subband_hl.pmi;
break;
default:
ERROR("CQI type=%d not implemented for PMI\n", uci_cfg.cqi.type);
break;
}
stack->pmi_info(tti, rnti, cqi_cc_idx, pmi_value);
}
}
}
void phy_ue_db::set_last_ul_tb(uint16_t rnti, uint32_t cc_idx, uint32_t pid, srslte_ra_tb_t tb)
{
std::lock_guard<std::mutex> lock(mutex);
// Assert UE DB entry
UE_DB_ASSERT_ACTIVE_CELL(rnti, cc_idx, /* void */);
// Save resource allocation
ue_db.at(rnti).scell_info[_get_scell_idx(rnti, 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
{
std::lock_guard<std::mutex> lock(mutex);
// Assert UE DB entry
UE_DB_ASSERT_ACTIVE_CELL(rnti, cc_idx, {});
// Returns the latest stored UL transmission grant
return ue_db.at(rnti).scell_info[_get_scell_idx(rnti, cc_idx)].last_tb[pid % SRSLTE_FDD_NOF_HARQ];
}

View File

@ -136,12 +136,12 @@ void sf_worker::set_time(uint32_t tti_, uint32_t tx_worker_cnt_, srslte_timestam
} }
} }
int sf_worker::add_rnti(uint16_t rnti, uint32_t cc_idx, bool is_temporal) int sf_worker::add_rnti(uint16_t rnti, uint32_t cc_idx, bool is_pcell, bool is_temporal)
{ {
int ret = SRSLTE_ERROR; int ret = SRSLTE_ERROR;
if (cc_idx < cc_workers.size()) { if (cc_idx < cc_workers.size()) {
cc_workers[cc_idx]->add_rnti(rnti, is_temporal); cc_workers[cc_idx]->add_rnti(rnti, true, is_temporal);
ret = SRSLTE_SUCCESS; ret = SRSLTE_SUCCESS;
} }
@ -160,15 +160,6 @@ uint32_t sf_worker::get_nof_rnti()
return cc_workers[0]->get_nof_rnti(); return cc_workers[0]->get_nof_rnti();
} }
void sf_worker::set_config_dedicated(uint16_t rnti, uint32_t cc_idx, const srslte::phy_cfg_t& 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());
}
}
void sf_worker::work_imp() void sf_worker::work_imp()
{ {
std::lock_guard<std::mutex> lock(work_mutex); std::lock_guard<std::mutex> lock(work_mutex);
@ -232,7 +223,7 @@ void sf_worker::work_imp()
dl_sf.non_mbsfn_region = mbsfn_cfg.non_mbsfn_region_length; dl_sf.non_mbsfn_region = mbsfn_cfg.non_mbsfn_region_length;
// Prepare for receive ACK for DL grants in t_tx_dl+4 // Prepare for receive ACK for DL grants in t_tx_dl+4
phy->ue_db_clear_tti_pending_ack(tti_tx_ul); phy->ue_db.clear_tti_pending_ack(tti_tx_ul);
// Process DL // Process DL
for (uint32_t cc = 0; cc < cc_workers.size(); cc++) { for (uint32_t cc = 0; cc < cc_workers.size(); cc++) {

View File

@ -291,9 +291,16 @@ private:
uint32_t tti; uint32_t tti;
} tti_sr_info_t; } tti_sr_info_t;
std::queue<tti_dl_info_t> tti_dl_info_sched_queue; typedef struct {
std::queue<tti_dl_info_t> tti_dl_info_ack_queue; uint32_t tti;
std::queue<tti_sr_info_t> tti_sr_info_queue; uint32_t cc_idx;
uint32_t cqi;
} tti_cqi_info_t;
std::queue<tti_dl_info_t> tti_dl_info_sched_queue;
std::queue<tti_dl_info_t> tti_dl_info_ack_queue;
std::queue<tti_sr_info_t> tti_sr_info_queue;
std::queue<tti_cqi_info_t> tti_cqi_info_queue;
public: public:
explicit dummy_stack(uint16_t rnti_) : log_h("STACK"), ue_rnti(rnti_), random_gen(srslte_random_init(0)) explicit dummy_stack(uint16_t rnti_) : log_h("STACK"), ue_rnti(rnti_), random_gen(srslte_random_init(0))
@ -302,6 +309,7 @@ public:
srslte_softbuffer_tx_init(&softbuffer_tx, SRSLTE_MAX_PRB); srslte_softbuffer_tx_init(&softbuffer_tx, SRSLTE_MAX_PRB);
srslte_softbuffer_rx_init(&softbuffer_rx, SRSLTE_MAX_PRB); srslte_softbuffer_rx_init(&softbuffer_rx, SRSLTE_MAX_PRB);
data = srslte_vec_u8_malloc(150000); data = srslte_vec_u8_malloc(150000);
memset(data, 0, 150000);
} }
~dummy_stack() ~dummy_stack()
@ -312,6 +320,8 @@ public:
if (data) { if (data) {
free(data); free(data);
} }
srslte_random_free(random_gen);
} }
int sr_detected(uint32_t tti, uint16_t rnti) override int sr_detected(uint32_t tti, uint16_t rnti) override
@ -323,6 +333,7 @@ public:
notify_sr_detected(); notify_sr_detected();
log_h.info("Received SR tti=%d; rnti=x%x\n", tti, rnti); log_h.info("Received SR tti=%d; rnti=x%x\n", tti, rnti);
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
int rach_detected(uint32_t tti, uint32_t primary_cc_idx, uint32_t preamble_idx, uint32_t time_adv) override int rach_detected(uint32_t tti, uint32_t primary_cc_idx, uint32_t preamble_idx, uint32_t time_adv) override
@ -342,8 +353,17 @@ public:
} }
int cqi_info(uint32_t tti, uint16_t rnti, uint32_t cc_idx, uint32_t cqi_value) override int cqi_info(uint32_t tti, uint16_t rnti, uint32_t cc_idx, uint32_t cqi_value) override
{ {
tti_cqi_info_t tti_cqi_info = {};
tti_cqi_info.tti = tti;
tti_cqi_info.cc_idx = cc_idx;
tti_cqi_info.cqi = cqi_value;
tti_cqi_info_queue.push(tti_cqi_info);
notify_cqi_info(); notify_cqi_info();
return 0;
log_h.info("Received CQI tti=%d; rnti=x%x; cc_idx=%d; cqi=%d;\n", tti, rnti, cc_idx, cqi_value);
return SRSLTE_SUCCESS;
} }
int snr_info(uint32_t tti, uint16_t rnti, uint32_t cc_idx, float snr_db) override int snr_info(uint32_t tti, uint16_t rnti, uint32_t cc_idx, float snr_db) override
{ {
@ -461,17 +481,21 @@ public:
while (tti_sr_info_queue.size() > 1) { while (tti_sr_info_queue.size() > 1) {
tti_sr_info_t tti_sr_info1 = tti_sr_info_queue.front(); tti_sr_info_t tti_sr_info1 = tti_sr_info_queue.front();
// Check first TTI
TESTASSERT(tti_sr_info1.tti % 20 == 0);
// POP first from queue // POP first from queue
tti_sr_info_queue.pop(); tti_sr_info_queue.pop();
// Get second, do not pop // Get second, do not pop
tti_sr_info_t& tti_sr_info2 = tti_sr_info_queue.front(); tti_sr_info_t& tti_sr_info2 = tti_sr_info_queue.front();
// Make sure the TTI difference is 20
uint32_t elapsed_tti = ((tti_sr_info2.tti + 10240) - tti_sr_info1.tti) % 10240; uint32_t elapsed_tti = ((tti_sr_info2.tti + 10240) - tti_sr_info1.tti) % 10240;
// Log SR info
log_h.info("SR: tti1=%d; tti2=%d; elapsed %d;\n", tti_sr_info1.tti, tti_sr_info2.tti, elapsed_tti);
// Check first TTI
TESTASSERT(tti_sr_info1.tti % 20 == 0);
// Make sure the TTI difference is 20
TESTASSERT(elapsed_tti == 20); TESTASSERT(elapsed_tti == 20);
} }
@ -540,7 +564,7 @@ public:
} }
// Set RNTI // Set RNTI
srslte_ue_dl_set_rnti(ue_dl, rnti); srslte_ue_dl_set_rnti(ue_dl, dedicated.dl_cfg.pdsch.rnti);
// Allocate UE UL // Allocate UE UL
auto* ue_ul = (srslte_ue_ul_t*)srslte_vec_malloc(sizeof(srslte_ue_ul_t)); auto* ue_ul = (srslte_ue_ul_t*)srslte_vec_malloc(sizeof(srslte_ue_ul_t));
@ -560,7 +584,7 @@ public:
} }
// Set RNTI // Set RNTI
srslte_ue_ul_set_rnti(ue_ul, rnti); srslte_ue_ul_set_rnti(ue_ul, dedicated.ul_cfg.pusch.rnti);
} }
// Initialise softbuffer // Initialise softbuffer
@ -604,6 +628,9 @@ public:
free(b); free(b);
} }
} }
if (tx_data) {
free(tx_data);
}
srslte_softbuffer_tx_free(&softbuffer_tx); srslte_softbuffer_tx_free(&softbuffer_tx);
} }
@ -629,9 +656,9 @@ public:
for (uint32_t i = 0; i < buffers.size(); i++) { for (uint32_t i = 0; i < buffers.size(); i++) {
srslte_dci_dl_t dci_dl[SRSLTE_MAX_DCI_MSG] = {}; srslte_dci_dl_t dci_dl[SRSLTE_MAX_DCI_MSG] = {};
srslte_ue_dl_cfg_t ue_dl_cfg = {}; srslte_ue_dl_cfg_t ue_dl_cfg = {};
// ue_dl_cfg.cfg.cqi_report.periodic_configured = true; ue_dl_cfg.cfg = dedicated.dl_cfg;
// ue_dl_cfg.cfg.cqi_report.periodic_mode = SRSLTE_CQI_MODE_12; ue_dl_cfg.cfg.cqi_report.periodic_mode = SRSLTE_CQI_MODE_12;
// ue_dl_cfg.cfg.cqi_report.pmi_idx = 16 + i; ue_dl_cfg.cfg.cqi_report.pmi_idx += i;
ue_dl_cfg.cfg.pdsch.rnti = rnti; ue_dl_cfg.cfg.pdsch.rnti = rnti;
srslte_ue_dl_decode_fft_estimate(ue_dl_v[i], &sf_dl_cfg, &ue_dl_cfg); srslte_ue_dl_decode_fft_estimate(ue_dl_v[i], &sf_dl_cfg, &ue_dl_cfg);
@ -673,7 +700,7 @@ public:
TESTASSERT(nof_ul_grants >= SRSLTE_SUCCESS); TESTASSERT(nof_ul_grants >= SRSLTE_SUCCESS);
// Generate CQI periodic if required // Generate CQI periodic if required
srslte_ue_dl_gen_cqi_periodic(ue_dl_v[i], &ue_dl_cfg, 0x0f, sf_dl_cfg.tti, &uci_data); srslte_ue_dl_gen_cqi_periodic(ue_dl_v[i], &ue_dl_cfg, 0x0f, sf_ul_cfg.tti, &uci_data);
} }
// Work UL // Work UL
@ -764,20 +791,24 @@ public:
enb_phy.add_rnti(rnti, pcell_index, false); enb_phy.add_rnti(rnti, pcell_index, false);
// Configure UE PHY // Configure UE PHY
uint32_t pcell_idx = 0; bool activation[SRSLTE_MAX_CARRIERS] = {};
uint32_t pcell_idx = 0;
srsenb::phy_interface_rrc_lte::phy_rrc_dedicated_list_t dedicated_list(4); srsenb::phy_interface_rrc_lte::phy_rrc_dedicated_list_t dedicated_list(4);
for (uint32_t i = 0; i < 4; i++) { 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].cc_idx = (i + pcell_idx) % phy_cfg.phy_cell_cfg.size(); dedicated_list[i].configured = true;
dedicated_list[i].configured = true; dedicated_list[i].phy_cfg = common_dedicated;
dedicated_list[i].phy_cfg = common_dedicated; dedicated_list[i].phy_cfg.dl_cfg.cqi_report.pmi_idx += i;
// Disable SCell stuff // Disable SCell stuff
if (i != pcell_index) { if (i != pcell_index) {
dedicated_list[i].phy_cfg.ul_cfg.pucch.sr_configured = false; dedicated_list[i].phy_cfg.ul_cfg.pucch.sr_configured = false;
} }
activation[i] = true;
} }
enb_phy.set_config_dedicated(rnti, dedicated_list); enb_phy.set_config_dedicated(rnti, dedicated_list);
enb_phy.set_activation_deactivation_scell(rnti, activation);
} }
~phy_test_bench() ~phy_test_bench()
@ -802,10 +833,10 @@ public:
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
int ret = SRSLTE_SUCCESS;
srsenb::phy_args_t phy_args; srsenb::phy_args_t phy_args;
phy_args.log.phy_level = "info"; phy_args.log.phy_level = "info";
phy_args.nof_phy_threads = 1; ///< Set number of phy threads to 1 for avoiding concurrency issues
srsenb::phy_cfg_t phy_cfg = {}; srsenb::phy_cfg_t phy_cfg = {};
for (uint32_t i = 0; i < 4; i++) { for (uint32_t i = 0; i < 4; i++) {
@ -831,24 +862,28 @@ int main(int argc, char** argv)
phy_cfg.prach_cnfg.prach_cfg_info.zero_correlation_zone_cfg = 5; phy_cfg.prach_cnfg.prach_cfg_info.zero_correlation_zone_cfg = 5;
// Set UE dedicated configuration // Set UE dedicated configuration
srslte::phy_cfg_t dedicated = {}; srslte::phy_cfg_t dedicated = {};
dedicated.ul_cfg.pucch.ack_nack_feedback_mode = SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_PUCCH3; dedicated.ul_cfg.pucch.ack_nack_feedback_mode = SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_PUCCH3;
dedicated.ul_cfg.pucch.delta_pucch_shift = 1; dedicated.ul_cfg.pucch.delta_pucch_shift = 1;
dedicated.ul_cfg.pucch.n_rb_2 = 0; dedicated.ul_cfg.pucch.n_rb_2 = 2;
dedicated.ul_cfg.pucch.N_cs = 0; dedicated.ul_cfg.pucch.N_cs = 0;
dedicated.ul_cfg.pucch.n_pucch_sr = 1; dedicated.ul_cfg.pucch.n_pucch_sr = 1;
dedicated.ul_cfg.pucch.N_pucch_1 = 2; dedicated.ul_cfg.pucch.N_pucch_1 = 2;
dedicated.ul_cfg.pucch.n_pucch_2 = 3; dedicated.ul_cfg.pucch.n_pucch_2 = 5;
dedicated.ul_cfg.pucch.simul_cqi_ack = true; dedicated.ul_cfg.pucch.simul_cqi_ack = true;
dedicated.ul_cfg.pucch.sr_configured = true; dedicated.ul_cfg.pucch.sr_configured = true;
dedicated.ul_cfg.pucch.I_sr = 5; dedicated.ul_cfg.pucch.I_sr = 5;
dedicated.dl_cfg.cqi_report.periodic_configured = true;
dedicated.dl_cfg.cqi_report.pmi_idx = 25;
dedicated.dl_cfg.cqi_report.periodic_mode = SRSLTE_CQI_MODE_20;
std::unique_ptr<phy_test_bench> test_bench = std::unique_ptr<phy_test_bench> test_bench =
std::unique_ptr<phy_test_bench>(new phy_test_bench(phy_args, phy_cfg, 0x1234, 0, dedicated)); std::unique_ptr<phy_test_bench>(new phy_test_bench(phy_args, phy_cfg, 0x1234, 0, dedicated));
for (uint32_t i = 0; i < 128; i++) { // Run Simulation
for (uint32_t i = 0; i < 256; i++) {
TESTASSERT(test_bench->run_tti() >= SRSLTE_SUCCESS); TESTASSERT(test_bench->run_tti() >= SRSLTE_SUCCESS);
} }
return ret; return SRSLTE_SUCCESS;
} }