mirror of https://github.com/pvnis/srsRAN_4G.git
Refactored gNb PHY
parent
c4e13f70a2
commit
8378c85ec4
@ -1,69 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2021 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SRSENB_NR_CC_WORKER_H
|
||||
#define SRSENB_NR_CC_WORKER_H
|
||||
|
||||
#include "phy_nr_state.h"
|
||||
#include "srsenb/hdr/phy/phy_interfaces.h"
|
||||
#include "srsran/interfaces/gnb_interfaces.h"
|
||||
#include "srsran/interfaces/rrc_nr_interface_types.h"
|
||||
#include "srsran/phy/enb/enb_dl_nr.h"
|
||||
#include "srsran/srslog/srslog.h"
|
||||
#include "srsran/srsran.h"
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
namespace srsenb {
|
||||
namespace nr {
|
||||
|
||||
class cc_worker
|
||||
{
|
||||
public:
|
||||
struct args_t {
|
||||
uint32_t cc_idx = 0;
|
||||
srsran_carrier_nr_t carrier = {};
|
||||
srsran_enb_dl_nr_args_t dl = {};
|
||||
};
|
||||
|
||||
cc_worker(const args_t& args, srslog::basic_logger& logger, phy_nr_state& phy_state_);
|
||||
~cc_worker();
|
||||
|
||||
void set_tti(uint32_t tti);
|
||||
|
||||
cf_t* get_tx_buffer(uint32_t antenna_idx);
|
||||
cf_t* get_rx_buffer(uint32_t antenna_idx);
|
||||
uint32_t get_buffer_len();
|
||||
|
||||
bool work_dl(stack_interface_phy_nr::dl_sched_t& dl_grants, stack_interface_phy_nr::ul_sched_t& ul_grants);
|
||||
bool work_ul();
|
||||
|
||||
private:
|
||||
int encode_pdsch(stack_interface_phy_nr::dl_sched_grant_t* grants, uint32_t nof_grants);
|
||||
int encode_pdcch_dl(stack_interface_phy_nr::dl_sched_grant_t* grants, uint32_t nof_grants);
|
||||
|
||||
uint32_t nof_tx_antennas = 0;
|
||||
srsran_slot_cfg_t dl_slot_cfg = {};
|
||||
srsran_slot_cfg_t ul_slot_cfg = {};
|
||||
uint32_t cc_idx = 0;
|
||||
std::array<cf_t*, SRSRAN_MAX_PORTS> tx_buffer = {};
|
||||
std::array<cf_t*, SRSRAN_MAX_PORTS> rx_buffer = {};
|
||||
uint32_t buffer_sz = 0;
|
||||
phy_nr_state& phy_state;
|
||||
srsran_enb_dl_nr_t gnb_dl = {};
|
||||
srslog::basic_logger& logger;
|
||||
};
|
||||
|
||||
} // namespace nr
|
||||
} // namespace srsenb
|
||||
|
||||
#endif // SRSENB_NR_CC_WORKER_H
|
@ -1,103 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2020 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SRSENB_PHY_NR_UE_DB_H_
|
||||
#define SRSENB_PHY_NR_UE_DB_H_
|
||||
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <srsenb/hdr/phy/phy_interfaces.h>
|
||||
#include <srsran/adt/circular_array.h>
|
||||
#include <srsran/interfaces/gnb_interfaces.h>
|
||||
#include <srsran/interfaces/rrc_nr_interface_types.h>
|
||||
|
||||
namespace srsenb {
|
||||
namespace nr {
|
||||
|
||||
class phy_nr_state
|
||||
{
|
||||
private:
|
||||
/**
|
||||
* UE object stored in the PHY common database
|
||||
*/
|
||||
struct common_ue {
|
||||
srsran::phy_cfg_nr_t cfg;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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_nr& stack;
|
||||
|
||||
/**
|
||||
* Cell list
|
||||
*/
|
||||
const phy_cell_cfg_list_nr_t& cell_cfg_list;
|
||||
|
||||
/**
|
||||
* Internal RNTI addition, it is not thread safe protected
|
||||
*
|
||||
* @param rnti identifier of the UE
|
||||
* @return SRSRAN_SUCCESS if the RNTI is not duplicated and is added successfully, SRSRAN_ERROR code if it exists
|
||||
*/
|
||||
inline int _add_rnti(uint16_t rnti);
|
||||
|
||||
/**
|
||||
* Checks if a given RNTI exists in the database
|
||||
* @param rnti provides UE identifier
|
||||
* @return SRSRAN_SUCCESS if the indicated RNTI exists, otherwise it returns SRSRAN_ERROR
|
||||
*/
|
||||
inline int _assert_rnti(uint16_t rnti) const;
|
||||
|
||||
/**
|
||||
* Internal eNb general configuration getter, returns default configuration if the UE does not exist in the given cell
|
||||
*
|
||||
* @param rnti provides UE identifier
|
||||
* @param[out] phy_cfg The PHY configuration of the indicated UE for the indicated eNb carrier/call index.
|
||||
* @return SRSRAN_SUCCESS if provided context is correct, SRSRAN_ERROR code otherwise
|
||||
*/
|
||||
inline int _get_rnti_config(uint16_t rnti, srsran::phy_cfg_nr_t& phy_cfg) const;
|
||||
|
||||
public:
|
||||
phy_nr_state(const phy_cell_cfg_list_nr_t& cell_cfg_list_, stack_interface_phy_nr& stack_);
|
||||
|
||||
void addmod_rnti(uint16_t rnti, const srsran::phy_cfg_nr_t& phy_cfg);
|
||||
|
||||
/**
|
||||
* Removes a whole UE entry from the UE database
|
||||
*
|
||||
* @param rnti identifier of the UE
|
||||
* @return SRSRAN_SUCCESS if provided RNTI exists, SRSRAN_ERROR code otherwise
|
||||
*/
|
||||
int rem_rnti(uint16_t rnti);
|
||||
|
||||
int get_config(uint16_t rnti, srsran::phy_cfg_nr_t& phy_cfg);
|
||||
|
||||
const phy_cell_cfg_list_nr_t& get_carrier_list() const { return cell_cfg_list; }
|
||||
|
||||
stack_interface_phy_nr& get_stack() { return stack; }
|
||||
};
|
||||
|
||||
} // namespace nr
|
||||
} // namespace srsenb
|
||||
|
||||
#endif // SRSENB_PHY_NR_UE_DB_H_
|
@ -1,66 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2021 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SRSENB_NR_PHCH_WORKER_H
|
||||
#define SRSENB_NR_PHCH_WORKER_H
|
||||
|
||||
#include "cc_worker.h"
|
||||
#include "srsran/common/thread_pool.h"
|
||||
#include "srsran/interfaces/phy_common_interface.h"
|
||||
#include "srsran/srslog/srslog.h"
|
||||
|
||||
namespace srsenb {
|
||||
namespace nr {
|
||||
|
||||
/**
|
||||
* The sf_worker class handles the PHY processing, UL and DL procedures associated with 1 subframe.
|
||||
* It contains multiple cc_worker objects, one for each component carrier which may be executed in
|
||||
* one or multiple threads.
|
||||
*
|
||||
* A sf_worker object is executed by a thread within the thread_pool.
|
||||
*/
|
||||
|
||||
class sf_worker final : public srsran::thread_pool::worker
|
||||
{
|
||||
public:
|
||||
sf_worker(srsran::phy_common_interface& common_, phy_nr_state& phy_state_, srslog::basic_logger& logger);
|
||||
~sf_worker();
|
||||
|
||||
/* Functions used by main PHY thread */
|
||||
cf_t* get_buffer_rx(uint32_t cc_idx, uint32_t antenna_idx);
|
||||
cf_t* get_buffer_tx(uint32_t cc_idx, uint32_t antenna_idx);
|
||||
uint32_t get_buffer_len();
|
||||
void set_time(const uint32_t& tti, const srsran::rf_timestamp_t& timestamp);
|
||||
|
||||
private:
|
||||
/* Inherited from thread_pool::worker. Function called every subframe to run the DL/UL processing */
|
||||
void work_imp() override;
|
||||
|
||||
std::vector<std::unique_ptr<cc_worker> > cc_workers;
|
||||
|
||||
srsran::phy_common_interface& common;
|
||||
phy_nr_state& phy_state;
|
||||
srslog::basic_logger& logger;
|
||||
srsran_slot_cfg_t dl_slot_cfg = {};
|
||||
srsran_slot_cfg_t ul_slot_cfg = {};
|
||||
srsran::rf_timestamp_t tx_time = {};
|
||||
uint32_t sf_len = 0;
|
||||
|
||||
// Temporal attributes
|
||||
srsran_softbuffer_tx_t softbuffer_tx = {};
|
||||
std::vector<uint8_t> data;
|
||||
};
|
||||
|
||||
} // namespace nr
|
||||
} // namespace srsenb
|
||||
|
||||
#endif // SRSENB_NR_PHCH_WORKER_H
|
@ -0,0 +1,90 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2021 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SRSENB_NR_SLOT_WORKER_H
|
||||
#define SRSENB_NR_SLOT_WORKER_H
|
||||
|
||||
#include "srsran/common/thread_pool.h"
|
||||
#include "srsran/interfaces/gnb_interfaces.h"
|
||||
#include "srsran/interfaces/phy_common_interface.h"
|
||||
#include "srsran/srslog/srslog.h"
|
||||
#include "srsran/srsran.h"
|
||||
|
||||
namespace srsenb {
|
||||
namespace nr {
|
||||
|
||||
/**
|
||||
* The slot_worker class handles the PHY processing, UL and DL procedures associated with 1 slot.
|
||||
*
|
||||
* A slot_worker object is executed by a thread within the thread_pool.
|
||||
*/
|
||||
|
||||
class slot_worker final : public srsran::thread_pool::worker
|
||||
{
|
||||
public:
|
||||
struct args_t {
|
||||
uint32_t cell_index = 0;
|
||||
srsran_carrier_nr_t carrier = {};
|
||||
uint32_t nof_tx_ports = 1;
|
||||
uint32_t nof_rx_ports = 1;
|
||||
uint32_t pusch_max_nof_iter = 10;
|
||||
srsran_pdcch_cfg_nr_t pdcch_cfg = {}; ///< PDCCH configuration
|
||||
};
|
||||
|
||||
slot_worker(srsran::phy_common_interface& common_, stack_interface_phy_nr& stack_, srslog::basic_logger& logger);
|
||||
~slot_worker();
|
||||
|
||||
bool init(const args_t& args);
|
||||
|
||||
/* Functions used by main PHY thread */
|
||||
cf_t* get_buffer_rx(uint32_t antenna_idx);
|
||||
cf_t* get_buffer_tx(uint32_t antenna_idx);
|
||||
uint32_t get_buffer_len();
|
||||
void set_time(const uint32_t& tti, const srsran::rf_timestamp_t& timestamp);
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Inherited from thread_pool::worker. Function called every slot to run the DL/UL processing
|
||||
*/
|
||||
void work_imp() override;
|
||||
|
||||
/**
|
||||
* @brief Retrieves the scheduling results for the UL processing and performs reception
|
||||
* @return True if no error occurs, false otherwise
|
||||
*/
|
||||
bool work_ul();
|
||||
|
||||
/**
|
||||
* @brief Retrieves the scheduling results for the DL processing and performs transmission
|
||||
* @return True if no error occurs, false otherwise
|
||||
*/
|
||||
bool work_dl();
|
||||
|
||||
srsran::phy_common_interface& common;
|
||||
stack_interface_phy_nr& stack;
|
||||
srslog::basic_logger& logger;
|
||||
|
||||
uint32_t sf_len = 0;
|
||||
uint32_t cell_index = 0;
|
||||
srsran_slot_cfg_t dl_slot_cfg = {};
|
||||
srsran_slot_cfg_t ul_slot_cfg = {};
|
||||
srsran_pdcch_cfg_nr_t pdcch_cfg = {};
|
||||
srsran::rf_timestamp_t tx_time = {};
|
||||
srsran_enb_dl_nr_t gnb_dl = {};
|
||||
std::vector<cf_t*> tx_buffer; ///< Baseband transmit buffers
|
||||
std::vector<cf_t*> rx_buffer; ///< Baseband receive buffers
|
||||
};
|
||||
|
||||
} // namespace nr
|
||||
} // namespace srsenb
|
||||
|
||||
#endif // SRSENB_NR_PHCH_WORKER_H
|
@ -1,186 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2021 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "srsenb/hdr/phy/nr/cc_worker.h"
|
||||
#include "srsran/srsran.h"
|
||||
|
||||
namespace srsenb {
|
||||
namespace nr {
|
||||
cc_worker::cc_worker(const args_t& args, srslog::basic_logger& log, phy_nr_state& phy_state_) :
|
||||
cc_idx(args.cc_idx),
|
||||
phy_state(phy_state_),
|
||||
logger(log),
|
||||
nof_tx_antennas(args.dl.nof_tx_antennas)
|
||||
{
|
||||
cf_t* buffer_c[SRSRAN_MAX_PORTS] = {};
|
||||
|
||||
// Allocate buffers
|
||||
buffer_sz = SRSRAN_SF_LEN_PRB(args.dl.nof_max_prb);
|
||||
for (uint32_t i = 0; i < args.dl.nof_tx_antennas; i++) {
|
||||
tx_buffer[i] = srsran_vec_cf_malloc(buffer_sz);
|
||||
rx_buffer[i] = srsran_vec_cf_malloc(buffer_sz);
|
||||
buffer_c[i] = tx_buffer[i];
|
||||
}
|
||||
|
||||
if (srsran_enb_dl_nr_init(&gnb_dl, buffer_c, &args.dl)) {
|
||||
ERROR("Error initiating GNB DL NR");
|
||||
return;
|
||||
}
|
||||
|
||||
if (srsran_enb_dl_nr_set_carrier(&gnb_dl, &args.carrier) < SRSRAN_SUCCESS) {
|
||||
ERROR("Error setting carrier");
|
||||
}
|
||||
}
|
||||
|
||||
cc_worker::~cc_worker()
|
||||
{
|
||||
srsran_enb_dl_nr_free(&gnb_dl);
|
||||
for (cf_t* p : rx_buffer) {
|
||||
if (p != nullptr) {
|
||||
free(p);
|
||||
}
|
||||
}
|
||||
for (cf_t* p : tx_buffer) {
|
||||
if (p != nullptr) {
|
||||
free(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cc_worker::set_tti(uint32_t tti)
|
||||
{
|
||||
ul_slot_cfg.idx = tti;
|
||||
dl_slot_cfg.idx = TTI_ADD(tti, FDD_HARQ_DELAY_UL_MS);
|
||||
}
|
||||
|
||||
cf_t* cc_worker::get_tx_buffer(uint32_t antenna_idx)
|
||||
{
|
||||
if (antenna_idx >= nof_tx_antennas) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return tx_buffer.at(antenna_idx);
|
||||
}
|
||||
|
||||
cf_t* cc_worker::get_rx_buffer(uint32_t antenna_idx)
|
||||
{
|
||||
if (antenna_idx >= nof_tx_antennas) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return rx_buffer.at(antenna_idx);
|
||||
}
|
||||
|
||||
uint32_t cc_worker::get_buffer_len()
|
||||
{
|
||||
return tx_buffer.size();
|
||||
}
|
||||
|
||||
int cc_worker::encode_pdcch_dl(stack_interface_phy_nr::dl_sched_grant_t* grants, uint32_t nof_grants)
|
||||
{
|
||||
for (uint32_t i = 0; i < nof_grants; i++) {
|
||||
uint16_t rnti = grants->dci.ctx.rnti;
|
||||
|
||||
// Get PHY config for UE
|
||||
srsran::phy_cfg_nr_t cfg = {};
|
||||
if (phy_state.get_config(rnti, cfg) < SRSRAN_SUCCESS) {
|
||||
logger.error("Invalid RNTI 0x%x", rnti);
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
srsran_dci_cfg_nr_t dci_cfg = cfg.get_dci_cfg();
|
||||
if (srsran_enb_dl_nr_set_pdcch_config(&gnb_dl, &cfg.pdcch, &dci_cfg) < SRSRAN_SUCCESS) {
|
||||
logger.error("Invalid CORESET setting");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
// Put actual DCI
|
||||
if (srsran_enb_dl_nr_pdcch_put(&gnb_dl, &dl_slot_cfg, &grants[i].dci) < SRSRAN_SUCCESS) {
|
||||
ERROR("Error putting PDCCH");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
if (logger.info.enabled()) {
|
||||
std::array<char, 512> str = {};
|
||||
srsran_dci_dl_nr_to_str(&gnb_dl.dci, &grants[i].dci, str.data(), (uint32_t)str.size());
|
||||
if (logger.info.enabled()) {
|
||||
logger.info("PDCCH: cc=%d %s tti_tx=%d", cc_idx, str.data(), dl_slot_cfg.idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
int cc_worker::encode_pdsch(stack_interface_phy_nr::dl_sched_grant_t* grants, uint32_t nof_grants)
|
||||
{
|
||||
for (uint32_t i = 0; i < nof_grants; i++) {
|
||||
// Get PHY config for UE
|
||||
srsran::phy_cfg_nr_t cfg = {};
|
||||
if (phy_state.get_config(grants[i].dci.ctx.rnti, cfg) < SRSRAN_SUCCESS) {
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
// Compute DL grant
|
||||
srsran_sch_cfg_nr_t pdsch_cfg = {};
|
||||
if (srsran_ra_dl_dci_to_grant_nr(
|
||||
&gnb_dl.carrier, &dl_slot_cfg, &cfg.pdsch, &grants[i].dci, &pdsch_cfg, &pdsch_cfg.grant) < SRSRAN_SUCCESS) {
|
||||
ERROR("Computing DL grant");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
// Set soft buffer
|
||||
for (uint32_t j = 0; j < SRSRAN_MAX_CODEWORDS; j++) {
|
||||
pdsch_cfg.grant.tb[j].softbuffer.tx = grants[i].softbuffer_tx[j];
|
||||
}
|
||||
|
||||
if (srsran_enb_dl_nr_pdsch_put(&gnb_dl, &dl_slot_cfg, &pdsch_cfg, grants[i].data) < SRSRAN_SUCCESS) {
|
||||
ERROR("Error putting PDSCH");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
// Logging
|
||||
if (logger.info.enabled()) {
|
||||
char str[512];
|
||||
srsran_enb_dl_nr_pdsch_info(&gnb_dl, &pdsch_cfg, str, sizeof(str));
|
||||
logger.info("PDSCH: cc=%d, %s tti_tx=%d", cc_idx, str, dl_slot_cfg.idx);
|
||||
}
|
||||
}
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
bool cc_worker::work_ul()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cc_worker::work_dl(stack_interface_phy_nr::dl_sched_t& dl_grants, stack_interface_phy_nr::ul_sched_t& ul_grants)
|
||||
{
|
||||
// Reset resource grid
|
||||
if (srsran_enb_dl_nr_base_zero(&gnb_dl) < SRSRAN_SUCCESS) {
|
||||
ERROR("Error setting base to zero");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
// Put DL grants to resource grid. PDSCH data will be encoded as well.
|
||||
encode_pdcch_dl(dl_grants.pdsch, dl_grants.nof_grants);
|
||||
encode_pdsch(dl_grants.pdsch, dl_grants.nof_grants);
|
||||
|
||||
// Generate signal
|
||||
srsran_enb_dl_nr_gen_signal(&gnb_dl);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace nr
|
||||
} // namespace srsenb
|
@ -1,85 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2021 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "srsenb/hdr/phy/nr/phy_nr_state.h"
|
||||
|
||||
namespace srsenb {
|
||||
namespace nr {
|
||||
|
||||
int phy_nr_state::_add_rnti(uint16_t rnti)
|
||||
{
|
||||
if (ue_db.count(rnti) > 0) {
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
// Access UE to create
|
||||
// Set defaults
|
||||
ue_db[rnti] = {};
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
int phy_nr_state::_assert_rnti(uint16_t rnti) const
|
||||
{
|
||||
return ue_db.count(rnti) > 0 ? SRSRAN_SUCCESS : SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
int phy_nr_state::_get_rnti_config(uint16_t rnti, srsran::phy_cfg_nr_t& phy_cfg) const
|
||||
{
|
||||
if (_assert_rnti(rnti) < SRSRAN_SUCCESS) {
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
phy_cfg = ue_db.at(rnti).cfg;
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
phy_nr_state::phy_nr_state(const phy_cell_cfg_list_nr_t& cell_cfg_list_, stack_interface_phy_nr& stack_) :
|
||||
cell_cfg_list(cell_cfg_list_),
|
||||
stack(stack_)
|
||||
{}
|
||||
|
||||
void phy_nr_state::addmod_rnti(uint16_t rnti, const srsran::phy_cfg_nr_t& phy_cfg)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
|
||||
// Create UE if it does not exist
|
||||
if (_assert_rnti(rnti) < SRSRAN_SUCCESS) {
|
||||
_add_rnti(rnti);
|
||||
}
|
||||
|
||||
// Set UE configuration
|
||||
ue_db[rnti].cfg = phy_cfg;
|
||||
}
|
||||
int phy_nr_state::rem_rnti(uint16_t rnti)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
|
||||
if (_assert_rnti(rnti) < SRSRAN_SUCCESS) {
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
ue_db.erase(rnti);
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
int phy_nr_state::get_config(uint16_t rnti, srsran::phy_cfg_nr_t& phy_cfg)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
|
||||
return _get_rnti_config(rnti, phy_cfg);
|
||||
}
|
||||
|
||||
} // namespace nr
|
||||
} // namespace srsenb
|
@ -1,125 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2021 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "srsenb/hdr/phy/nr/sf_worker.h"
|
||||
|
||||
namespace srsenb {
|
||||
namespace nr {
|
||||
sf_worker::sf_worker(srsran::phy_common_interface& common_, phy_nr_state& phy_state_, srslog::basic_logger& logger_) :
|
||||
common(common_),
|
||||
phy_state(phy_state_),
|
||||
logger(logger_)
|
||||
{
|
||||
// Set subframe length
|
||||
sf_len = SRSRAN_SF_LEN_PRB_NR(phy_state.get_carrier_list()[0].carrier.nof_prb);
|
||||
|
||||
const phy_cell_cfg_list_nr_t& carrier_list = phy_state.get_carrier_list();
|
||||
for (uint32_t i = 0; i < (uint32_t)carrier_list.size(); i++) {
|
||||
cc_worker::args_t cc_args = {};
|
||||
cc_args.cc_idx = i;
|
||||
cc_args.carrier = carrier_list[i].carrier;
|
||||
cc_args.dl.nof_tx_antennas = 1;
|
||||
cc_args.dl.nof_max_prb = cc_args.carrier.nof_prb;
|
||||
cc_args.dl.pdsch.max_prb = cc_args.carrier.nof_prb;
|
||||
cc_args.dl.pdsch.max_layers = 1;
|
||||
|
||||
cc_worker* w = new cc_worker(cc_args, logger_, phy_state);
|
||||
cc_workers.push_back(std::unique_ptr<cc_worker>(w));
|
||||
}
|
||||
|
||||
if (srsran_softbuffer_tx_init_guru(&softbuffer_tx, SRSRAN_SCH_NR_MAX_NOF_CB_LDPC, SRSRAN_LDPC_MAX_LEN_ENCODED_CB) <
|
||||
SRSRAN_SUCCESS) {
|
||||
ERROR("Error init soft-buffer");
|
||||
return;
|
||||
}
|
||||
data.resize(SRSRAN_SCH_NR_MAX_NOF_CB_LDPC * SRSRAN_LDPC_MAX_LEN_ENCODED_CB / 8);
|
||||
srsran_vec_u8_zero(data.data(), SRSRAN_SCH_NR_MAX_NOF_CB_LDPC * SRSRAN_LDPC_MAX_LEN_ENCODED_CB / 8);
|
||||
snprintf((char*)data.data(), SRSRAN_SCH_NR_MAX_NOF_CB_LDPC * SRSRAN_LDPC_MAX_LEN_ENCODED_CB / 8, "hello world!");
|
||||
}
|
||||
|
||||
sf_worker::~sf_worker()
|
||||
{
|
||||
srsran_softbuffer_tx_free(&softbuffer_tx);
|
||||
}
|
||||
|
||||
cf_t* sf_worker::get_buffer_rx(uint32_t cc_idx, uint32_t antenna_idx)
|
||||
{
|
||||
if (cc_idx >= cc_workers.size()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return cc_workers.at(cc_idx)->get_rx_buffer(antenna_idx);
|
||||
}
|
||||
|
||||
cf_t* sf_worker::get_buffer_tx(uint32_t cc_idx, uint32_t antenna_idx)
|
||||
{
|
||||
if (cc_idx >= cc_workers.size()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return cc_workers.at(cc_idx)->get_tx_buffer(antenna_idx);
|
||||
}
|
||||
|
||||
uint32_t sf_worker::get_buffer_len()
|
||||
{
|
||||
return cc_workers.at(0)->get_buffer_len();
|
||||
}
|
||||
|
||||
void sf_worker::set_time(const uint32_t& tti, const srsran::rf_timestamp_t& timestamp)
|
||||
{
|
||||
logger.set_context(tti);
|
||||
for (auto& w : cc_workers) {
|
||||
w->set_tti(tti);
|
||||
}
|
||||
ul_slot_cfg.idx = tti;
|
||||
dl_slot_cfg.idx = TTI_ADD(tti, FDD_HARQ_DELAY_UL_MS);
|
||||
tx_time.copy(timestamp);
|
||||
}
|
||||
|
||||
void sf_worker::work_imp()
|
||||
{
|
||||
// Get Transmission buffers
|
||||
srsran::rf_buffer_t tx_buffer = {};
|
||||
for (uint32_t cc = 0; cc < (uint32_t)phy_state.get_carrier_list().size(); cc++) {
|
||||
tx_buffer.set(cc, 0, 1, cc_workers[cc]->get_tx_buffer(0));
|
||||
}
|
||||
|
||||
// Set number of samples
|
||||
tx_buffer.set_nof_samples(sf_len);
|
||||
|
||||
// Get UL Scheduling
|
||||
mac_interface_phy_nr::ul_sched_list_t ul_sched_list = {};
|
||||
ul_sched_list.resize(1);
|
||||
if (phy_state.get_stack().get_ul_sched(ul_slot_cfg.idx, ul_sched_list) < SRSRAN_SUCCESS) {
|
||||
logger.error("DL Scheduling error");
|
||||
common.worker_end(this, true, tx_buffer, tx_time, true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get DL scheduling
|
||||
mac_interface_phy_nr::dl_sched_list_t dl_sched_list = {};
|
||||
dl_sched_list.resize(1);
|
||||
if (phy_state.get_stack().get_dl_sched(ul_slot_cfg.idx, dl_sched_list) < SRSRAN_SUCCESS) {
|
||||
logger.error("DL Scheduling error");
|
||||
common.worker_end(this, true, tx_buffer, tx_time, true);
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto& w : cc_workers) {
|
||||
w->work_dl(dl_sched_list[0], ul_sched_list[0]);
|
||||
}
|
||||
|
||||
common.worker_end(this, true, tx_buffer, tx_time, true);
|
||||
}
|
||||
|
||||
} // namespace nr
|
||||
} // namespace srsenb
|
@ -0,0 +1,262 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2021 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "srsenb/hdr/phy/nr/slot_worker.h"
|
||||
#include <srsran/common/common.h>
|
||||
|
||||
namespace srsenb {
|
||||
namespace nr {
|
||||
slot_worker::slot_worker(srsran::phy_common_interface& common_,
|
||||
stack_interface_phy_nr& stack_,
|
||||
srslog::basic_logger& logger_) :
|
||||
common(common_), stack(stack_), logger(logger_)
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
bool slot_worker::init(const args_t& args)
|
||||
{
|
||||
// Calculate subframe length
|
||||
sf_len = SRSRAN_SF_LEN_PRB_NR(args.carrier.nof_prb);
|
||||
|
||||
// Copy common configurations
|
||||
cell_index = args.cell_index;
|
||||
pdcch_cfg = args.pdcch_cfg;
|
||||
|
||||
// Allocate Tx buffers
|
||||
tx_buffer.resize(args.nof_tx_ports);
|
||||
for (uint32_t i = 0; i < args.nof_tx_ports; i++) {
|
||||
tx_buffer[i] = srsran_vec_cf_malloc(sf_len);
|
||||
if (tx_buffer[i] == nullptr) {
|
||||
logger.error("Error allocating Tx buffer");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate Tx buffers
|
||||
rx_buffer.resize(args.nof_rx_ports);
|
||||
for (uint32_t i = 0; i < args.nof_rx_ports; i++) {
|
||||
rx_buffer[i] = srsran_vec_cf_malloc(sf_len);
|
||||
if (rx_buffer[i] == nullptr) {
|
||||
logger.error("Error allocating Rx buffer");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare DL arguments
|
||||
srsran_enb_dl_nr_args_t dl_args = {};
|
||||
dl_args.pdsch.measure_time = true;
|
||||
dl_args.pdsch.max_layers = args.carrier.max_mimo_layers;
|
||||
dl_args.pdsch.max_prb = args.carrier.nof_prb;
|
||||
dl_args.nof_tx_antennas = args.nof_tx_ports;
|
||||
dl_args.nof_max_prb = args.carrier.nof_prb;
|
||||
|
||||
// Initialise DL
|
||||
if (srsran_enb_dl_nr_init(&gnb_dl, tx_buffer.data(), &dl_args) < SRSRAN_SUCCESS) {
|
||||
logger.error("Error gNb PHY init");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set gNb carrier
|
||||
if (srsran_enb_dl_nr_set_carrier(&gnb_dl, &args.carrier) < SRSRAN_SUCCESS) {
|
||||
logger.error("Error setting carrier");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
slot_worker::~slot_worker()
|
||||
{
|
||||
for (auto& b : tx_buffer) {
|
||||
if (b) {
|
||||
free(b);
|
||||
b = nullptr;
|
||||
}
|
||||
}
|
||||
for (auto& b : rx_buffer) {
|
||||
if (b) {
|
||||
free(b);
|
||||
b = nullptr;
|
||||
}
|
||||
}
|
||||
srsran_enb_dl_nr_free(&gnb_dl);
|
||||
}
|
||||
|
||||
cf_t* slot_worker::get_buffer_rx(uint32_t antenna_idx)
|
||||
{
|
||||
if (antenna_idx >= (uint32_t)rx_buffer.size()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return rx_buffer[antenna_idx];
|
||||
}
|
||||
|
||||
cf_t* slot_worker::get_buffer_tx(uint32_t antenna_idx)
|
||||
{
|
||||
if (antenna_idx >= (uint32_t)tx_buffer.size()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return tx_buffer[antenna_idx];
|
||||
}
|
||||
|
||||
uint32_t slot_worker::get_buffer_len()
|
||||
{
|
||||
return sf_len;
|
||||
}
|
||||
|
||||
void slot_worker::set_time(const uint32_t& tti, const srsran::rf_timestamp_t& timestamp)
|
||||
{
|
||||
logger.set_context(tti);
|
||||
ul_slot_cfg.idx = tti;
|
||||
dl_slot_cfg.idx = TTI_ADD(tti, FDD_HARQ_DELAY_UL_MS);
|
||||
tx_time.copy(timestamp);
|
||||
}
|
||||
|
||||
bool slot_worker::work_ul()
|
||||
{
|
||||
stack_interface_phy_nr::ul_sched_t ul_sched = {};
|
||||
if (stack.get_ul_sched(ul_slot_cfg, ul_sched) < SRSRAN_SUCCESS) {
|
||||
logger.error("Error retrieving UL scheduling");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Decode PUCCH
|
||||
for (uint32_t i = 0; i < ul_sched.uci_count; i++) {
|
||||
const stack_interface_phy_nr::uci_t& uci = ul_sched.uci[i];
|
||||
// ...
|
||||
}
|
||||
|
||||
// Decode PUSCH
|
||||
for (uint32_t i = 0; i < ul_sched.pusch_count; i++) {
|
||||
const stack_interface_phy_nr::pusch_t& pusch = ul_sched.pusch[i];
|
||||
// ...
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool slot_worker::work_dl()
|
||||
{
|
||||
stack_interface_phy_nr::dl_sched_t dl_sched = {};
|
||||
if (stack.get_dl_sched(ul_slot_cfg, dl_sched) < SRSRAN_SUCCESS) {
|
||||
logger.error("Error retrieving DL scheduling");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Encode PDCCH for DL transmissions
|
||||
for (uint32_t i = 0; i < dl_sched.pdcch_dl_count; i++) {
|
||||
// Select PDCCH from scheduler result
|
||||
const stack_interface_phy_nr::pdcch_dl_t& pdcch = dl_sched.pdcch_dl[i];
|
||||
|
||||
// Set PDCCH configuration, including DCI dedicated
|
||||
if (srsran_enb_dl_nr_set_pdcch_config(&gnb_dl, &pdcch_cfg, &pdcch.dci_cfg) < SRSRAN_SUCCESS) {
|
||||
logger.error("PDCCH: Error setting DL configuration");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Put PDCCH message
|
||||
if (srsran_enb_dl_nr_pdcch_put_dl(&gnb_dl, &dl_slot_cfg, &pdcch.dci) < SRSRAN_SUCCESS) {
|
||||
logger.error("PDCCH: Error putting DL message");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Log PDCCH information
|
||||
if (logger.info.enabled()) {
|
||||
std::array<char, 512> str = {};
|
||||
srsran_enb_dl_nr_pdcch_dl_info(&gnb_dl, &pdcch.dci, str.data(), (uint32_t)str.size());
|
||||
logger.info("PDCCH: cc=%d %s tti_tx=%d", cell_index, str.data(), dl_slot_cfg.idx);
|
||||
}
|
||||
}
|
||||
|
||||
// Encode PDCCH for UL transmissions
|
||||
for (uint32_t i = 0; i < dl_sched.pdcch_ul_count; i++) {
|
||||
// Select PDCCH from scheduler result
|
||||
const stack_interface_phy_nr::pdcch_ul_t& pdcch = dl_sched.pdcch_ul[i];
|
||||
|
||||
// Set PDCCH configuration, including DCI dedicated
|
||||
if (srsran_enb_dl_nr_set_pdcch_config(&gnb_dl, &pdcch_cfg, &pdcch.dci_cfg) < SRSRAN_SUCCESS) {
|
||||
logger.error("PDCCH: Error setting DL configuration");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Put PDCCH message
|
||||
if (srsran_enb_dl_nr_pdcch_put_ul(&gnb_dl, &dl_slot_cfg, &pdcch.dci) < SRSRAN_SUCCESS) {
|
||||
logger.error("PDCCH: Error putting DL message");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Log PDCCH information
|
||||
if (logger.info.enabled()) {
|
||||
std::array<char, 512> str = {};
|
||||
srsran_enb_dl_nr_pdcch_ul_info(&gnb_dl, &pdcch.dci, str.data(), (uint32_t)str.size());
|
||||
logger.info("PDCCH: cc=%d %s tti_tx=%d", cell_index, str.data(), dl_slot_cfg.idx);
|
||||
}
|
||||
}
|
||||
|
||||
// Encode PDSCH
|
||||
for (uint32_t i = 0; i < dl_sched.pdsch_count; i++) {
|
||||
// Select PDSCH from scheduler result
|
||||
stack_interface_phy_nr::pdsch_t& pdsch = dl_sched.pdsch[i];
|
||||
|
||||
// Put PDSCH message
|
||||
if (srsran_enb_dl_nr_pdsch_put(&gnb_dl, &dl_slot_cfg, &pdsch.sch, pdsch.data.data()) < SRSRAN_SUCCESS) {
|
||||
logger.error("PDSCH: Error putting DL message");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Log PDSCH information
|
||||
if (logger.info.enabled()) {
|
||||
std::array<char, 512> str = {};
|
||||
srsran_enb_dl_nr_pdsch_info(&gnb_dl, &pdsch.sch, str.data(), (uint32_t)str.size());
|
||||
logger.info("PDSCH: cc=%d %s tti_tx=%d", cell_index, str.data(), dl_slot_cfg.idx);
|
||||
}
|
||||
}
|
||||
|
||||
// Generate baseband signal
|
||||
srsran_enb_dl_nr_gen_signal(&gnb_dl);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void slot_worker::work_imp()
|
||||
{
|
||||
// Inform Scheduler about new slot
|
||||
stack.sf_indication(dl_slot_cfg.idx);
|
||||
|
||||
// Get Transmission buffers
|
||||
srsran::rf_buffer_t tx_rf_buffer = {};
|
||||
for (uint32_t i = 0; i < (uint32_t)tx_buffer.size(); i++) {
|
||||
tx_rf_buffer.set(i, tx_buffer[i]);
|
||||
}
|
||||
|
||||
// Set number of samples
|
||||
tx_rf_buffer.set_nof_samples(sf_len);
|
||||
|
||||
// Process uplink
|
||||
if (not work_ul()) {
|
||||
common.worker_end(this, false, tx_rf_buffer, tx_time, true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Process downlink
|
||||
if (not work_dl()) {
|
||||
common.worker_end(this, false, tx_rf_buffer, tx_time, true);
|
||||
return;
|
||||
}
|
||||
|
||||
common.worker_end(this, true, tx_rf_buffer, tx_time, true);
|
||||
}
|
||||
|
||||
} // namespace nr
|
||||
} // namespace srsenb
|
@ -0,0 +1,239 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2021 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SRSRAN_DUMMY_GNB_STACK_H
|
||||
#define SRSRAN_DUMMY_GNB_STACK_H
|
||||
|
||||
#include <srsran/adt/circular_array.h>
|
||||
#include <srsran/interfaces/gnb_interfaces.h>
|
||||
#include <srsran/interfaces/rrc_nr_interface_types.h>
|
||||
|
||||
class gnb_dummy_stack : public srsenb::stack_interface_phy_nr
|
||||
{
|
||||
private:
|
||||
srslog::basic_logger& logger = srslog::fetch_basic_logger("GNB STK");
|
||||
const uint16_t rnti = 0x1234;
|
||||
const uint32_t mcs = 1;
|
||||
srsran::circular_array<srsran_dci_location_t, SRSRAN_NOF_SF_X_FRAME> dci_dl_location;
|
||||
srsran::circular_array<srsran_dci_location_t, SRSRAN_NOF_SF_X_FRAME> dci_ul_location;
|
||||
srsran::circular_array<uint32_t, SRSRAN_NOF_SF_X_FRAME> dl_data_to_ul_ack;
|
||||
srsran_search_space_t ss = {};
|
||||
srsran_dci_format_nr_t dci_format_ul = SRSRAN_DCI_FORMAT_NR_COUNT;
|
||||
srsran_dci_format_nr_t dci_format_dl = SRSRAN_DCI_FORMAT_NR_COUNT;
|
||||
uint32_t dl_freq_res = 0;
|
||||
uint32_t dl_time_res = 0;
|
||||
srsran_random_t random_gen = nullptr;
|
||||
srsran::phy_cfg_nr_t phy_cfg = {};
|
||||
bool valid = false;
|
||||
|
||||
struct dummy_harq_proc {
|
||||
static const uint32_t MAX_TB_SZ = SRSRAN_LDPC_MAX_LEN_CB * SRSRAN_SCH_NR_MAX_NOF_CB_LDPC;
|
||||
std::vector<uint8_t> data;
|
||||
srsran_softbuffer_tx_t softbuffer = {};
|
||||
|
||||
dummy_harq_proc()
|
||||
{
|
||||
// Allocate data
|
||||
data.resize(MAX_TB_SZ);
|
||||
|
||||
// Initialise softbuffer
|
||||
if (srsran_softbuffer_tx_init_guru(&softbuffer, SRSRAN_SCH_NR_MAX_NOF_CB_LDPC, SRSRAN_LDPC_MAX_LEN_ENCODED_CB) <
|
||||
SRSRAN_SUCCESS) {
|
||||
ERROR("Error Tx buffer");
|
||||
}
|
||||
}
|
||||
|
||||
~dummy_harq_proc() { srsran_softbuffer_tx_free(&softbuffer); }
|
||||
};
|
||||
srsran::circular_array<dummy_harq_proc, SRSRAN_MAX_HARQ_PROC_DL_NR> tx_harq_proc;
|
||||
|
||||
public:
|
||||
struct args_t {
|
||||
srsran::phy_cfg_nr_t phy_cfg; ///< Physical layer configuration
|
||||
uint16_t rnti = 0x1234; ///< C-RNTI
|
||||
uint32_t mcs = 10; ///< Modulation code scheme
|
||||
uint32_t ss_id = 1; ///< Search Space identifier
|
||||
uint32_t pdcch_aggregation_level = 0; ///< PDCCH aggregation level
|
||||
uint32_t pdcch_dl_candidate_index = 0; ///< PDCCH DL DCI candidate index
|
||||
uint32_t pdcch_ul_candidate_index = 0; ///< PDCCH UL DCI candidate index
|
||||
uint32_t dl_start_rb = 0; ///< Start resource block
|
||||
uint32_t dl_length_rb = 0l; ///< Number of resource blocks
|
||||
uint32_t dl_time_res = 0; ///< PDSCH time resource
|
||||
};
|
||||
|
||||
gnb_dummy_stack(args_t args) : mcs(args.mcs), rnti(args.rnti), dl_time_res(args.dl_time_res), phy_cfg(args.phy_cfg)
|
||||
{
|
||||
random_gen = srsran_random_init(0x1234);
|
||||
|
||||
// Select search space
|
||||
if (args.ss_id >= SRSRAN_UE_DL_NR_MAX_NOF_SEARCH_SPACE) {
|
||||
logger.error("Search Space Id (%d) is out-of-range (%d)", args.ss_id, SRSRAN_UE_DL_NR_MAX_NOF_SEARCH_SPACE);
|
||||
return;
|
||||
}
|
||||
if (not args.phy_cfg.pdcch.search_space_present[args.ss_id]) {
|
||||
logger.error("Search Space Id (%d) is not present", args.ss_id);
|
||||
return;
|
||||
}
|
||||
ss = args.phy_cfg.pdcch.search_space[args.ss_id];
|
||||
|
||||
// Select CORESET
|
||||
if (ss.coreset_id >= SRSRAN_UE_DL_NR_MAX_NOF_CORESET) {
|
||||
logger.error("CORESET Id (%d) is out-of-range (%d)", ss.coreset_id, SRSRAN_UE_DL_NR_MAX_NOF_CORESET);
|
||||
return;
|
||||
}
|
||||
if (not args.phy_cfg.pdcch.coreset_present[ss.coreset_id]) {
|
||||
logger.error("CORESET Id (%d) is not present", args.ss_id);
|
||||
return;
|
||||
}
|
||||
const srsran_coreset_t& coreset = args.phy_cfg.pdcch.coreset[ss.coreset_id];
|
||||
|
||||
// Select DCI locations
|
||||
for (uint32_t slot = 0; slot < SRSRAN_NOF_SF_X_FRAME; slot++) {
|
||||
std::array<uint32_t, SRSRAN_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR> ncce = {};
|
||||
int n = srsran_pdcch_nr_locations_coreset(&coreset, &ss, rnti, args.pdcch_aggregation_level, slot++, ncce.data());
|
||||
if (n < SRSRAN_SUCCESS) {
|
||||
logger.error(
|
||||
"Error generating locations for slot %d and aggregation level %d", slot, args.pdcch_aggregation_level);
|
||||
return;
|
||||
}
|
||||
uint32_t nof_candidates = (uint32_t)n;
|
||||
|
||||
// DCI DL
|
||||
if (args.pdcch_dl_candidate_index >= nof_candidates or
|
||||
args.pdcch_dl_candidate_index >= SRSRAN_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR) {
|
||||
logger.error("Candidate index %d exceeds the number of candidates %d for aggregation level %d",
|
||||
args.pdcch_dl_candidate_index,
|
||||
n,
|
||||
args.pdcch_aggregation_level);
|
||||
return;
|
||||
}
|
||||
dci_dl_location[slot].L = args.pdcch_aggregation_level;
|
||||
dci_dl_location[slot].ncce = ncce[args.pdcch_dl_candidate_index];
|
||||
|
||||
// DCI UL
|
||||
if (args.pdcch_ul_candidate_index >= nof_candidates or
|
||||
args.pdcch_ul_candidate_index >= SRSRAN_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR) {
|
||||
logger.error("Candidate index %d exceeds the number of candidates %d for aggregation level %d",
|
||||
args.pdcch_ul_candidate_index,
|
||||
n,
|
||||
args.pdcch_aggregation_level);
|
||||
return;
|
||||
}
|
||||
dci_ul_location[slot].L = args.pdcch_aggregation_level;
|
||||
dci_ul_location[slot].ncce = ncce[args.pdcch_ul_candidate_index];
|
||||
}
|
||||
|
||||
// Select DCI formats
|
||||
for (uint32_t i = 0; i < ss.nof_formats; i++) {
|
||||
// Select DL format
|
||||
if (ss.formats[i] == srsran_dci_format_nr_1_0 or ss.formats[i] == srsran_dci_format_nr_1_1) {
|
||||
dci_format_dl = ss.formats[i];
|
||||
}
|
||||
|
||||
// Select DL format
|
||||
if (ss.formats[i] == srsran_dci_format_nr_0_0 or ss.formats[i] == srsran_dci_format_nr_0_1) {
|
||||
dci_format_ul = ss.formats[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Validate that a DCI format is selected
|
||||
if (dci_format_dl == SRSRAN_DCI_FORMAT_NR_COUNT or dci_format_ul == SRSRAN_DCI_FORMAT_NR_COUNT) {
|
||||
logger.error("Missing valid DL or UL DCI format in search space");
|
||||
return;
|
||||
}
|
||||
|
||||
// Select DL frequency domain resources
|
||||
dl_freq_res = srsran_ra_nr_type1_riv(args.phy_cfg.carrier.nof_prb, args.dl_start_rb, args.dl_length_rb);
|
||||
|
||||
// Setup DL Data to ACK timing
|
||||
for (uint32_t i = 0; i < SRSRAN_NOF_SF_X_FRAME; i++) {
|
||||
dl_data_to_ul_ack[i] = args.phy_cfg.harq_ack.dl_data_to_ul_ack[i % SRSRAN_MAX_NOF_DL_DATA_TO_UL];
|
||||
}
|
||||
|
||||
// If reached this point the configuration is valid
|
||||
valid = true;
|
||||
}
|
||||
|
||||
~gnb_dummy_stack() { srsran_random_free(random_gen); }
|
||||
bool is_valid() const { return valid; }
|
||||
|
||||
int sf_indication(const uint32_t tti) override { return 0; }
|
||||
int rx_data_indication(rx_data_ind_t& grant) override { return 0; }
|
||||
|
||||
int slot_indication(const srsran_slot_cfg_t& slot_cfg) override { return 0; }
|
||||
|
||||
int get_dl_sched(const srsran_slot_cfg_t& slot_cfg, dl_sched_t& dl_sched) override
|
||||
{
|
||||
// Check if it is TDD DL slot and PDSCH mask, if no PDSCH shall be scheduled, do not set any grant and skip
|
||||
if (not srsran_tdd_nr_is_dl(&phy_cfg.tdd, phy_cfg.carrier.scs, slot_cfg.idx)) {
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
// Select PDCCH and PDSCH from scheduling results
|
||||
pdcch_dl_t& pdcch = dl_sched.pdcch_dl[0];
|
||||
pdsch_t& pdsch = dl_sched.pdsch[0];
|
||||
|
||||
// Select grant and set data
|
||||
pdsch.data[0] = tx_harq_proc[slot_cfg.idx].data.data();
|
||||
|
||||
// Second TB is not used
|
||||
pdsch.data[1] = nullptr;
|
||||
|
||||
// Generate random data
|
||||
srsran_random_byte_vector(random_gen, pdsch.data[0], SRSRAN_LDPC_MAX_LEN_CB * SRSRAN_SCH_NR_MAX_NOF_CB_LDPC / 8);
|
||||
|
||||
// Fill DCI configuration
|
||||
pdcch.dci_cfg = phy_cfg.get_dci_cfg();
|
||||
|
||||
// Fill DCI
|
||||
srsran_dci_dl_nr_t& dci = pdcch.dci;
|
||||
dci.ctx.location = dci_dl_location[slot_cfg.idx];
|
||||
dci.ctx.ss_type = ss.type;
|
||||
dci.ctx.coreset_id = ss.coreset_id;
|
||||
dci.ctx.rnti_type = srsran_rnti_type_c;
|
||||
dci.ctx.format = dci_format_dl;
|
||||
dci.ctx.rnti = rnti;
|
||||
dci.freq_domain_assigment = dl_freq_res;
|
||||
dci.time_domain_assigment = dl_time_res;
|
||||
dci.mcs = mcs;
|
||||
dci.rv = 0;
|
||||
dci.ndi = (slot_cfg.idx / SRSRAN_NOF_SF_X_FRAME) % 2;
|
||||
dci.pid = slot_cfg.idx % SRSRAN_NOF_SF_X_FRAME;
|
||||
dci.dai = slot_cfg.idx % SRSRAN_NOF_SF_X_FRAME;
|
||||
dci.tpc = 1;
|
||||
dci.pucch_resource = 0;
|
||||
dci.harq_feedback = dl_data_to_ul_ack[TTI_TX(slot_cfg.idx)];
|
||||
|
||||
// It currently support only one grant
|
||||
dl_sched.pdcch_dl_count = 1;
|
||||
dl_sched.pdsch_count = 1;
|
||||
|
||||
// Create PDSCH configuration
|
||||
if (srsran_ra_dl_dci_to_grant_nr(&phy_cfg.carrier, &slot_cfg, &phy_cfg.pdsch, &dci, &pdsch.sch, &pdsch.sch.grant) <
|
||||
SRSRAN_SUCCESS) {
|
||||
logger.error("Error converting DCI to grant");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
// Set softbuffer
|
||||
pdsch.sch.grant.tb[0].softbuffer.tx = &tx_harq_proc[slot_cfg.idx].softbuffer;
|
||||
|
||||
// Reset Tx softbuffer always
|
||||
srsran_softbuffer_tx_reset(pdsch.sch.grant.tb[0].softbuffer.tx);
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
int get_ul_sched(const srsran_slot_cfg_t& slot_cfg, ul_sched_t& ul_sched) override { return 0; }
|
||||
};
|
||||
|
||||
#endif // SRSRAN_DUMMY_GNB_STACK_H
|
Loading…
Reference in New Issue