mirror of https://github.com/PentHertz/srsLTE.git
SRSENB: refactored PHY common UE database
This commit is contained in:
parent
2fc0832f05
commit
f35ed14f76
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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_
|
|
@ -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:
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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];
|
||||||
|
}
|
|
@ -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++) {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue