mirror of https://github.com/PentHertz/srsLTE.git
Refactored gNb PHY
This commit is contained in:
parent
c4e13f70a2
commit
8378c85ec4
|
@ -212,52 +212,50 @@ class mac_interface_phy_nr
|
|||
public:
|
||||
const static int MAX_GRANTS = 64;
|
||||
|
||||
/**
|
||||
* DL grant structure per UE
|
||||
*/
|
||||
struct dl_sched_grant_t {
|
||||
srsran_dci_dl_nr_t dci = {};
|
||||
uint8_t* data[SRSRAN_MAX_TB] = {};
|
||||
srsran_softbuffer_tx_t* softbuffer_tx[SRSRAN_MAX_TB] = {};
|
||||
struct pdcch_dl_t {
|
||||
srsran_dci_cfg_nr_t dci_cfg = {};
|
||||
srsran_dci_dl_nr_t dci = {};
|
||||
};
|
||||
|
||||
struct pdcch_ul_t {
|
||||
srsran_dci_cfg_nr_t dci_cfg = {};
|
||||
srsran_dci_ul_nr_t dci = {};
|
||||
};
|
||||
|
||||
struct pdsch_t {
|
||||
srsran_sch_cfg_nr_t sch = {}; ///< PDSCH configuration
|
||||
std::array<uint8_t*, SRSRAN_MAX_TB> data = {}; ///< Data pointer
|
||||
};
|
||||
|
||||
/**
|
||||
* DL Scheduling result per cell/carrier
|
||||
*/
|
||||
struct dl_sched_t {
|
||||
dl_sched_grant_t pdsch[MAX_GRANTS]; //< DL Grants
|
||||
uint32_t nof_grants; //< Number of DL grants
|
||||
std::array<pdcch_dl_t, MAX_GRANTS> pdcch_dl;
|
||||
uint32_t pdcch_dl_count = 0;
|
||||
std::array<pdcch_ul_t, MAX_GRANTS> pdcch_ul;
|
||||
uint32_t pdcch_ul_count = 0;
|
||||
std::array<pdsch_t, MAX_GRANTS> pdsch;
|
||||
uint32_t pdsch_count = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* List of DL scheduling results, one entry per cell/carrier
|
||||
*/
|
||||
typedef std::vector<dl_sched_t> dl_sched_list_t;
|
||||
|
||||
/**
|
||||
* UL grant structure per UE
|
||||
*/
|
||||
struct ul_sched_grant_t {
|
||||
srsran_dci_ul_nr_t dci = {};
|
||||
uint8_t* data = nullptr;
|
||||
srsran_softbuffer_rx_t* softbuffer_rx = nullptr;
|
||||
struct pusch_t {
|
||||
srsran_sch_cfg_nr_t sch = {}; ///< PUSCH configuration
|
||||
std::array<uint8_t*, SRSRAN_MAX_TB> data = {}; ///< Data pointer
|
||||
std::array<srsran_softbuffer_tx_t*, SRSRAN_MAX_TB> softbuffer_tx = {}; ///< Tx Softbuffer
|
||||
};
|
||||
|
||||
struct uci_t {
|
||||
srsran_uci_cfg_nr_t cfg;
|
||||
};
|
||||
|
||||
/**
|
||||
* UL Scheduling result per cell/carrier
|
||||
*/
|
||||
struct ul_sched_t {
|
||||
ul_sched_grant_t pusch[MAX_GRANTS]; //< UL Grants
|
||||
uint32_t nof_grants; //< Number of UL grants
|
||||
std::array<pusch_t, MAX_GRANTS> pusch;
|
||||
uint32_t pusch_count = 0;
|
||||
std::array<uci_t, MAX_GRANTS> uci;
|
||||
uint32_t uci_count;
|
||||
};
|
||||
|
||||
/**
|
||||
* List of UL scheduling results, one entry per cell/carrier
|
||||
*/
|
||||
typedef std::vector<ul_sched_t> ul_sched_list_t;
|
||||
|
||||
virtual int get_dl_sched(uint32_t tti, dl_sched_list_t& dl_sched_res) = 0;
|
||||
virtual int get_ul_sched(uint32_t tti, ul_sched_list_t& ul_sched_res) = 0;
|
||||
virtual int slot_indication(const srsran_slot_cfg_t& slot_cfg) = 0;
|
||||
virtual int get_dl_sched(const srsran_slot_cfg_t& slot_cfg, dl_sched_t& dl_sched) = 0;
|
||||
virtual int get_ul_sched(const srsran_slot_cfg_t& slot_cfg, ul_sched_t& ul_sched) = 0;
|
||||
};
|
||||
|
||||
class stack_interface_phy_nr : public mac_interface_phy_nr, public srsran::stack_interface_phy_nr
|
||||
|
|
|
@ -57,8 +57,13 @@ SRSRAN_API int srsran_enb_dl_nr_base_zero(srsran_enb_dl_nr_t* q);
|
|||
|
||||
SRSRAN_API void srsran_enb_dl_nr_gen_signal(srsran_enb_dl_nr_t* q);
|
||||
|
||||
SRSRAN_API int
|
||||
srsran_enb_dl_nr_pdcch_put(srsran_enb_dl_nr_t* q, const srsran_slot_cfg_t* slot_cfg, const srsran_dci_dl_nr_t* dci_dl);
|
||||
SRSRAN_API int srsran_enb_dl_nr_pdcch_put_dl(srsran_enb_dl_nr_t* q,
|
||||
const srsran_slot_cfg_t* slot_cfg,
|
||||
const srsran_dci_dl_nr_t* dci_dl);
|
||||
|
||||
SRSRAN_API int srsran_enb_dl_nr_pdcch_put_ul(srsran_enb_dl_nr_t* q,
|
||||
const srsran_slot_cfg_t* slot_cfg,
|
||||
const srsran_dci_ul_nr_t* dci_ul);
|
||||
|
||||
SRSRAN_API int srsran_enb_dl_nr_pdsch_put(srsran_enb_dl_nr_t* q,
|
||||
const srsran_slot_cfg_t* slot,
|
||||
|
@ -68,4 +73,10 @@ SRSRAN_API int srsran_enb_dl_nr_pdsch_put(srsran_enb_dl_nr_t* q,
|
|||
SRSRAN_API int
|
||||
srsran_enb_dl_nr_pdsch_info(const srsran_enb_dl_nr_t* q, const srsran_sch_cfg_nr_t* cfg, char* str, uint32_t str_len);
|
||||
|
||||
SRSRAN_API int
|
||||
srsran_enb_dl_nr_pdcch_dl_info(const srsran_enb_dl_nr_t* q, const srsran_dci_dl_nr_t* dci, char* str, uint32_t str_len);
|
||||
|
||||
SRSRAN_API int
|
||||
srsran_enb_dl_nr_pdcch_ul_info(const srsran_enb_dl_nr_t* q, const srsran_dci_ul_nr_t* dci, char* str, uint32_t str_len);
|
||||
|
||||
#endif // SRSRAN_ENB_DL_NR_H
|
||||
|
|
|
@ -180,20 +180,15 @@ int srsran_enb_dl_nr_base_zero(srsran_enb_dl_nr_t* q)
|
|||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
int srsran_enb_dl_nr_pdcch_put(srsran_enb_dl_nr_t* q,
|
||||
const srsran_slot_cfg_t* slot_cfg,
|
||||
const srsran_dci_dl_nr_t* dci_dl)
|
||||
static int
|
||||
enb_dl_nr_pdcch_put_msg(srsran_enb_dl_nr_t* q, const srsran_slot_cfg_t* slot_cfg, const srsran_dci_msg_nr_t* dci_msg)
|
||||
{
|
||||
if (q == NULL || slot_cfg == NULL || dci_dl == NULL) {
|
||||
return SRSRAN_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
|
||||
if (dci_dl->ctx.coreset_id >= SRSRAN_UE_DL_NR_MAX_NOF_CORESET ||
|
||||
!q->pdcch_cfg.coreset_present[dci_dl->ctx.coreset_id]) {
|
||||
ERROR("Invalid CORESET ID %d", dci_dl->ctx.coreset_id);
|
||||
if (dci_msg->ctx.coreset_id >= SRSRAN_UE_DL_NR_MAX_NOF_CORESET ||
|
||||
!q->pdcch_cfg.coreset_present[dci_msg->ctx.coreset_id]) {
|
||||
ERROR("Invalid CORESET ID %d", dci_msg->ctx.coreset_id);
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
srsran_coreset_t* coreset = &q->pdcch_cfg.coreset[dci_dl->ctx.coreset_id];
|
||||
srsran_coreset_t* coreset = &q->pdcch_cfg.coreset[dci_msg->ctx.coreset_id];
|
||||
|
||||
if (srsran_pdcch_nr_set_carrier(&q->pdcch, &q->carrier, coreset) < SRSRAN_SUCCESS) {
|
||||
ERROR("Error setting PDCCH carrier/CORESET");
|
||||
|
@ -201,11 +196,31 @@ int srsran_enb_dl_nr_pdcch_put(srsran_enb_dl_nr_t* q,
|
|||
}
|
||||
|
||||
// Put DMRS
|
||||
if (srsran_dmrs_pdcch_put(&q->carrier, coreset, slot_cfg, &dci_dl->ctx.location, q->sf_symbols[0]) < SRSRAN_SUCCESS) {
|
||||
if (srsran_dmrs_pdcch_put(&q->carrier, coreset, slot_cfg, &dci_msg->ctx.location, q->sf_symbols[0]) <
|
||||
SRSRAN_SUCCESS) {
|
||||
ERROR("Error putting PDCCH DMRS");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
// PDCCH Encode
|
||||
if (srsran_pdcch_nr_encode(&q->pdcch, dci_msg, q->sf_symbols[0]) < SRSRAN_SUCCESS) {
|
||||
ERROR("Error encoding PDCCH");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
INFO("DCI DL NR: L=%d; ncce=%d;", dci_msg->ctx.location.L, dci_msg->ctx.location.ncce);
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
int srsran_enb_dl_nr_pdcch_put_dl(srsran_enb_dl_nr_t* q,
|
||||
const srsran_slot_cfg_t* slot_cfg,
|
||||
const srsran_dci_dl_nr_t* dci_dl)
|
||||
{
|
||||
if (q == NULL || slot_cfg == NULL || dci_dl == NULL) {
|
||||
return SRSRAN_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
|
||||
// Pack DCI
|
||||
srsran_dci_msg_nr_t dci_msg = {};
|
||||
if (srsran_dci_nr_dl_pack(&q->dci, dci_dl, &dci_msg) < SRSRAN_SUCCESS) {
|
||||
|
@ -213,15 +228,29 @@ int srsran_enb_dl_nr_pdcch_put(srsran_enb_dl_nr_t* q,
|
|||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
// PDCCH Encode
|
||||
if (srsran_pdcch_nr_encode(&q->pdcch, &dci_msg, q->sf_symbols[0]) < SRSRAN_SUCCESS) {
|
||||
ERROR("Error encoding PDCCH");
|
||||
INFO("DCI DL NR: L=%d; ncce=%d;", dci_dl->ctx.location.L, dci_dl->ctx.location.ncce);
|
||||
|
||||
return enb_dl_nr_pdcch_put_msg(q, slot_cfg, &dci_msg);
|
||||
}
|
||||
|
||||
int srsran_enb_dl_nr_pdcch_put_ul(srsran_enb_dl_nr_t* q,
|
||||
const srsran_slot_cfg_t* slot_cfg,
|
||||
const srsran_dci_ul_nr_t* dci_ul)
|
||||
{
|
||||
if (q == NULL || slot_cfg == NULL || dci_ul == NULL) {
|
||||
return SRSRAN_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
|
||||
// Pack DCI
|
||||
srsran_dci_msg_nr_t dci_msg = {};
|
||||
if (srsran_dci_nr_ul_pack(&q->dci, dci_ul, &dci_msg) < SRSRAN_SUCCESS) {
|
||||
ERROR("Error packing UL DCI");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
INFO("DCI DL NR: L=%d; ncce=%d;", dci_dl->ctx.location.L, dci_dl->ctx.location.ncce);
|
||||
INFO("DCI DL NR: L=%d; ncce=%d;", dci_ul->ctx.location.L, dci_ul->ctx.location.ncce);
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
return enb_dl_nr_pdcch_put_msg(q, slot_cfg, &dci_msg);
|
||||
}
|
||||
|
||||
int srsran_enb_dl_nr_pdsch_put(srsran_enb_dl_nr_t* q,
|
||||
|
@ -252,3 +281,29 @@ int srsran_enb_dl_nr_pdsch_info(const srsran_enb_dl_nr_t* q,
|
|||
|
||||
return len;
|
||||
}
|
||||
|
||||
int srsran_enb_dl_nr_pdcch_dl_info(const srsran_enb_dl_nr_t* q,
|
||||
const srsran_dci_dl_nr_t* dci,
|
||||
char* str,
|
||||
uint32_t str_len)
|
||||
{
|
||||
int len = 0;
|
||||
|
||||
// Append PDCCH info
|
||||
len += srsran_dci_dl_nr_to_str(&q->dci, dci, &str[len], str_len - len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int srsran_enb_dl_nr_pdcch_ul_info(const srsran_enb_dl_nr_t* q,
|
||||
const srsran_dci_ul_nr_t* dci,
|
||||
char* str,
|
||||
uint32_t str_len)
|
||||
{
|
||||
int len = 0;
|
||||
|
||||
// Append PDCCH info
|
||||
len += srsran_dci_ul_nr_to_str(&q->dci, dci, &str[len], str_len - len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
|
|
@ -170,7 +170,7 @@ static int work_gnb_dl(srsran_enb_dl_nr_t* enb_dl,
|
|||
dci_dl.rv = 0;
|
||||
|
||||
// Put actual DCI
|
||||
if (srsran_enb_dl_nr_pdcch_put(enb_dl, slot, &dci_dl) < SRSRAN_SUCCESS) {
|
||||
if (srsran_enb_dl_nr_pdcch_put_dl(enb_dl, slot, &dci_dl) < SRSRAN_SUCCESS) {
|
||||
ERROR("Error putting PDCCH");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -13,40 +13,42 @@
|
|||
#ifndef SRSENB_NR_WORKER_POOL_H
|
||||
#define SRSENB_NR_WORKER_POOL_H
|
||||
|
||||
#include "phy_nr_state.h"
|
||||
#include "sf_worker.h"
|
||||
#include "slot_worker.h"
|
||||
#include "srsenb/hdr/phy/phy_interfaces.h"
|
||||
#include "srsran/common/thread_pool.h"
|
||||
#include "srsran/interfaces/gnb_interfaces.h"
|
||||
|
||||
namespace srsenb {
|
||||
namespace nr {
|
||||
|
||||
class worker_pool
|
||||
{
|
||||
srsran::thread_pool pool;
|
||||
std::vector<std::unique_ptr<sf_worker> > workers;
|
||||
phy_nr_state phy_state;
|
||||
srsran::phy_common_interface& common;
|
||||
stack_interface_phy_nr& stack;
|
||||
srslog::sink& log_sink;
|
||||
srsran::thread_pool pool;
|
||||
std::vector<std::unique_ptr<slot_worker> > workers;
|
||||
|
||||
public:
|
||||
struct args_t {
|
||||
uint32_t nof_workers = 3;
|
||||
uint32_t prio = 52;
|
||||
std::string log_level = "info";
|
||||
uint32_t log_hex_limit = 64;
|
||||
std::string log_id_preamble = "";
|
||||
uint32_t nof_phy_threads = 3;
|
||||
uint32_t prio = 52;
|
||||
std::string log_level = "info";
|
||||
uint32_t log_hex_limit = 64;
|
||||
std::string log_id_preamble = "";
|
||||
uint32_t pusch_max_nof_iter = 10;
|
||||
};
|
||||
sf_worker* operator[](std::size_t pos) { return workers.at(pos).get(); }
|
||||
slot_worker* operator[](std::size_t pos) { return workers.at(pos).get(); }
|
||||
|
||||
worker_pool(const phy_cell_cfg_list_nr_t& cell_list,
|
||||
const args_t& args,
|
||||
srsran::phy_common_interface& common,
|
||||
worker_pool(srsran::phy_common_interface& common,
|
||||
stack_interface_phy_nr& stack,
|
||||
srslog::sink& log_sink);
|
||||
sf_worker* wait_worker(uint32_t tti);
|
||||
sf_worker* wait_worker_id(uint32_t id);
|
||||
void start_worker(sf_worker* w);
|
||||
void stop();
|
||||
bool addmod_rnti(uint16_t rnti, const srsran::phy_cfg_nr_t& phy_cfg);
|
||||
srslog::sink& log_sink,
|
||||
uint32_t max_workers);
|
||||
bool init(const args_t& args, const phy_cell_cfg_list_nr_t& cell_list);
|
||||
slot_worker* wait_worker(uint32_t tti);
|
||||
slot_worker* wait_worker_id(uint32_t id);
|
||||
void start_worker(slot_worker* w);
|
||||
void stop();
|
||||
};
|
||||
|
||||
} // namespace nr
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include "srsran/asn1/rrc/rr_common.h"
|
||||
#include "srsran/common/interfaces_common.h"
|
||||
#include "srsran/phy/channel/channel.h"
|
||||
#include "srsran/phy/common/phy_common_nr.h"
|
||||
#include "srsran/srsran.h"
|
||||
#include <inttypes.h>
|
||||
#include <vector>
|
||||
|
||||
|
@ -34,14 +34,15 @@ struct phy_cell_cfg_t {
|
|||
};
|
||||
|
||||
struct phy_cell_cfg_nr_t {
|
||||
srsran_carrier_nr_t carrier;
|
||||
uint32_t rf_port;
|
||||
uint32_t cell_id;
|
||||
double dl_freq_hz;
|
||||
double ul_freq_hz;
|
||||
uint32_t root_seq_idx;
|
||||
uint32_t num_ra_preambles;
|
||||
float gain_db;
|
||||
srsran_carrier_nr_t carrier;
|
||||
uint32_t rf_port;
|
||||
uint32_t cell_id;
|
||||
double dl_freq_hz;
|
||||
double ul_freq_hz;
|
||||
uint32_t root_seq_idx;
|
||||
uint32_t num_ra_preambles;
|
||||
float gain_db;
|
||||
srsran_pdcch_cfg_nr_t pdcch = {}; ///< Common CORESET and Search Space configuration
|
||||
};
|
||||
|
||||
typedef std::vector<phy_cell_cfg_t> phy_cell_cfg_list_t;
|
||||
|
@ -51,18 +52,18 @@ struct phy_args_t {
|
|||
std::string type;
|
||||
srsran::phy_log_args_t log;
|
||||
|
||||
float max_prach_offset_us = 10;
|
||||
int pusch_max_its = 10;
|
||||
bool pusch_8bit_decoder = false;
|
||||
float tx_amplitude = 1.0f;
|
||||
uint32_t nof_phy_threads = 1;
|
||||
std::string equalizer_mode = "mmse";
|
||||
float estimator_fil_w = 1.0f;
|
||||
bool pusch_meas_epre = true;
|
||||
bool pusch_meas_evm = false;
|
||||
bool pusch_meas_ta = true;
|
||||
bool pucch_meas_ta = true;
|
||||
uint32_t nof_prach_threads = 1;
|
||||
float max_prach_offset_us = 10;
|
||||
int pusch_max_its = 10;
|
||||
bool pusch_8bit_decoder = false;
|
||||
float tx_amplitude = 1.0f;
|
||||
uint32_t nof_phy_threads = 1;
|
||||
std::string equalizer_mode = "mmse";
|
||||
float estimator_fil_w = 1.0f;
|
||||
bool pusch_meas_epre = true;
|
||||
bool pusch_meas_evm = false;
|
||||
bool pusch_meas_ta = true;
|
||||
bool pucch_meas_ta = true;
|
||||
uint32_t nof_prach_threads = 1;
|
||||
bool extended_cp = false;
|
||||
srsran::channel::args_t dl_channel_args;
|
||||
srsran::channel::args_t ul_channel_args;
|
||||
|
|
|
@ -55,12 +55,12 @@ public:
|
|||
bool get_metrics(srsenb::stack_metrics_t* metrics) final;
|
||||
|
||||
// GW srsue stack_interface_gw dummy interface
|
||||
bool is_registered() { return true; };
|
||||
bool start_service_request() { return true; };
|
||||
bool is_registered() override { return true; };
|
||||
bool start_service_request() override { return true; };
|
||||
|
||||
// PHY->MAC interface
|
||||
int sf_indication(const uint32_t tti);
|
||||
int rx_data_indication(rx_data_ind_t& grant);
|
||||
int sf_indication(const uint32_t tti) override;
|
||||
int rx_data_indication(rx_data_ind_t& grant) override;
|
||||
|
||||
// Temporary GW interface
|
||||
void write_sdu(uint32_t lcid, srsran::unique_byte_buffer_t sdu);
|
||||
|
@ -71,9 +71,11 @@ public:
|
|||
// MAC interface to trigger processing of received PDUs
|
||||
void process_pdus() final;
|
||||
|
||||
void toggle_padding() { srsran::console("padding not available for NR\n"); }
|
||||
int get_dl_sched(uint32_t tti, dl_sched_list_t& dl_sched_res) override;
|
||||
int get_ul_sched(uint32_t tti, ul_sched_list_t& ul_sched_res) override;
|
||||
void toggle_padding() override { srsran::console("padding not available for NR\n"); }
|
||||
|
||||
int slot_indication(const srsran_slot_cfg_t& slot_cfg) override;
|
||||
int get_dl_sched(const srsran_slot_cfg_t& slot_cfg, dl_sched_t& dl_sched) override;
|
||||
int get_ul_sched(const srsran_slot_cfg_t& slot_cfg, ul_sched_t& ul_sched) override;
|
||||
|
||||
private:
|
||||
void run_thread() final;
|
||||
|
|
|
@ -65,8 +65,9 @@ public:
|
|||
int rx_data_indication(stack_interface_phy_nr::rx_data_ind_t& grant);
|
||||
|
||||
void process_pdus();
|
||||
int get_dl_sched(uint32_t tti, dl_sched_list_t& dl_sched_res) override;
|
||||
int get_ul_sched(uint32_t tti, ul_sched_list_t& ul_sched_res) override;
|
||||
int slot_indication(const srsran_slot_cfg_t& slot_cfg) override;
|
||||
int get_dl_sched(const srsran_slot_cfg_t& slot_cfg, dl_sched_t& dl_sched) override;
|
||||
int get_ul_sched(const srsran_slot_cfg_t& slot_cfg, ul_sched_t& ul_sched) override;
|
||||
|
||||
private:
|
||||
void get_dl_config(const uint32_t tti,
|
||||
|
|
|
@ -10,10 +10,8 @@ set(SOURCES
|
|||
lte/cc_worker.cc
|
||||
lte/sf_worker.cc
|
||||
lte/worker_pool.cc
|
||||
nr/cc_worker.cc
|
||||
nr/sf_worker.cc
|
||||
nr/slot_worker.cc
|
||||
nr/worker_pool.cc
|
||||
nr/phy_nr_state.cc
|
||||
phy.cc
|
||||
phy_common.cc
|
||||
phy_ue_db.cc
|
||||
|
|
|
@ -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
|
|
@ -14,40 +14,58 @@
|
|||
namespace srsenb {
|
||||
namespace nr {
|
||||
|
||||
worker_pool::worker_pool(const phy_cell_cfg_list_nr_t& cell_list,
|
||||
const args_t& args,
|
||||
srsran::phy_common_interface& common,
|
||||
stack_interface_phy_nr& stack,
|
||||
srslog::sink& log_sink) :
|
||||
pool(args.nof_workers),
|
||||
phy_state(cell_list, stack)
|
||||
worker_pool::worker_pool(srsran::phy_common_interface& common_,
|
||||
stack_interface_phy_nr& stack_,
|
||||
srslog::sink& log_sink_,
|
||||
uint32_t max_workers) :
|
||||
pool(max_workers), common(common_), stack(stack_), log_sink(log_sink_)
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
bool worker_pool::init(const args_t& args, const phy_cell_cfg_list_nr_t& cell_list)
|
||||
{
|
||||
// Add workers to workers pool and start threads
|
||||
srslog::basic_levels log_level = srslog::str_to_basic_level(args.log_level);
|
||||
for (uint32_t i = 0; i < args.nof_workers; i++) {
|
||||
for (uint32_t i = 0; i < args.nof_phy_threads; i++) {
|
||||
auto& log = srslog::fetch_basic_logger(fmt::format("{}PHY{}-NR", args.log_id_preamble, i), log_sink);
|
||||
log.set_level(log_level);
|
||||
log.set_hex_dump_max_size(args.log_hex_limit);
|
||||
|
||||
auto w = new sf_worker(common, phy_state, log);
|
||||
auto w = new slot_worker(common, stack, log);
|
||||
pool.init_worker(i, w, args.prio);
|
||||
workers.push_back(std::unique_ptr<sf_worker>(w));
|
||||
workers.push_back(std::unique_ptr<slot_worker>(w));
|
||||
|
||||
slot_worker::args_t w_args = {};
|
||||
uint32_t cell_index = 0;
|
||||
w_args.cell_index = cell_index;
|
||||
w_args.carrier = cell_list[cell_index].carrier;
|
||||
w_args.nof_tx_ports = cell_list[cell_index].carrier.max_mimo_layers;
|
||||
w_args.nof_rx_ports = cell_list[cell_index].carrier.max_mimo_layers;
|
||||
w_args.pusch_max_nof_iter = args.pusch_max_nof_iter;
|
||||
w_args.pdcch_cfg = cell_list[cell_index].pdcch;
|
||||
|
||||
if (not w->init(w_args)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void worker_pool::start_worker(sf_worker* w)
|
||||
void worker_pool::start_worker(slot_worker* w)
|
||||
{
|
||||
pool.start_worker(w);
|
||||
}
|
||||
|
||||
sf_worker* worker_pool::wait_worker(uint32_t tti)
|
||||
slot_worker* worker_pool::wait_worker(uint32_t tti)
|
||||
{
|
||||
return (sf_worker*)pool.wait_worker(tti);
|
||||
return (slot_worker*)pool.wait_worker(tti);
|
||||
}
|
||||
|
||||
sf_worker* worker_pool::wait_worker_id(uint32_t id)
|
||||
slot_worker* worker_pool::wait_worker_id(uint32_t id)
|
||||
{
|
||||
return (sf_worker*)pool.wait_worker_id(id);
|
||||
return (slot_worker*)pool.wait_worker_id(id);
|
||||
}
|
||||
|
||||
void worker_pool::stop()
|
||||
|
@ -55,12 +73,5 @@ void worker_pool::stop()
|
|||
pool.stop();
|
||||
}
|
||||
|
||||
bool worker_pool::addmod_rnti(uint16_t rnti, const srsran::phy_cfg_nr_t& phy_cfg)
|
||||
{
|
||||
phy_state.addmod_rnti(rnti, phy_cfg);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace nr
|
||||
} // namespace srsenb
|
|
@ -124,7 +124,7 @@ void txrx::run_thread()
|
|||
}
|
||||
}
|
||||
|
||||
nr::sf_worker* nr_worker = nullptr;
|
||||
nr::slot_worker* nr_worker = nullptr;
|
||||
if (worker_com->get_nof_carriers_nr() > 0) {
|
||||
nr_worker = nr_workers->wait_worker(tti);
|
||||
if (nr_worker == nullptr) {
|
||||
|
@ -144,12 +144,14 @@ void txrx::run_thread()
|
|||
buffer.set(rf_port, p, worker_com->get_nof_ports(0), lte_worker->get_buffer_rx(cc_lte, p));
|
||||
}
|
||||
}
|
||||
for (uint32_t cc_nr = 0; cc_nr < worker_com->get_nof_carriers_lte(); cc_nr++, cc++) {
|
||||
for (uint32_t cc_nr = 0; cc_nr < worker_com->get_nof_carriers_nr(); cc_nr++, cc++) {
|
||||
uint32_t rf_port = worker_com->get_rf_port(cc);
|
||||
|
||||
for (uint32_t p = 0; p < worker_com->get_nof_ports(cc); p++) {
|
||||
// WARNING: The number of ports for all cells must be the same
|
||||
buffer.set(rf_port, p, worker_com->get_nof_ports(0), nr_worker->get_buffer_rx(cc_nr, p));
|
||||
// WARNING:
|
||||
// - The number of ports for all cells must be the same
|
||||
// - Only one NR cell is currently supported
|
||||
buffer.set(rf_port, p, worker_com->get_nof_ports(0), nr_worker->get_buffer_rx(p));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -182,13 +182,17 @@ bool gnb_stack_nr::has_active_radio_bearer(uint32_t eps_bearer_id)
|
|||
{
|
||||
return (eps_bearer_id == args.coreless.drb_lcid);
|
||||
}
|
||||
int gnb_stack_nr::get_dl_sched(uint32_t tti, mac_interface_phy_nr::dl_sched_list_t& dl_sched_res)
|
||||
int gnb_stack_nr::slot_indication(const srsran_slot_cfg_t& slot_cfg)
|
||||
{
|
||||
return m_mac->get_dl_sched(tti, dl_sched_res);
|
||||
return m_mac->slot_indication(slot_cfg);
|
||||
}
|
||||
int gnb_stack_nr::get_ul_sched(uint32_t tti, mac_interface_phy_nr::ul_sched_list_t& ul_sched_res)
|
||||
int gnb_stack_nr::get_dl_sched(const srsran_slot_cfg_t& slot_cfg, dl_sched_t& dl_sched)
|
||||
{
|
||||
return m_mac->get_ul_sched(tti, ul_sched_res);
|
||||
return m_mac->get_dl_sched(slot_cfg, dl_sched);
|
||||
}
|
||||
int gnb_stack_nr::get_ul_sched(const srsran_slot_cfg_t& slot_cfg, ul_sched_t& ul_sched)
|
||||
{
|
||||
return m_mac->get_ul_sched(slot_cfg, ul_sched);
|
||||
}
|
||||
|
||||
} // namespace srsenb
|
||||
|
|
|
@ -267,11 +267,16 @@ int mac_nr::cell_cfg(srsenb::sched_interface::cell_cfg_t* cell_cfg)
|
|||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
int mac_nr::get_dl_sched(uint32_t tti, mac_interface_phy_nr::dl_sched_list_t& dl_sched_res)
|
||||
int mac_nr::slot_indication(const srsran_slot_cfg_t& slot_cfg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int mac_nr::get_ul_sched(uint32_t tti, mac_interface_phy_nr::ul_sched_list_t& ul_sched_res)
|
||||
|
||||
int mac_nr::get_dl_sched(const srsran_slot_cfg_t& slot_cfg, dl_sched_t& dl_sched)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int mac_nr::get_ul_sched(const srsran_slot_cfg_t& slot_cfg, ul_sched_t& ul_sched)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -11,9 +11,9 @@
|
|||
*/
|
||||
|
||||
#include "srsran/common/threads.h"
|
||||
#include "srsran/phy/common/phy_common.h"
|
||||
#include "srsran/phy/utils/random.h"
|
||||
#include "srsran/srslog/srslog.h"
|
||||
#include "srsran/srsran.h"
|
||||
#include <boost/program_options.hpp>
|
||||
#include <boost/program_options/options_description.hpp>
|
||||
#include <boost/program_options/parsers.hpp>
|
||||
|
@ -22,7 +22,6 @@
|
|||
#include <srsenb/hdr/phy/phy.h>
|
||||
#include <srsran/common/string_helpers.h>
|
||||
#include <srsran/common/test_common.h>
|
||||
#include <srsran/phy/phch/pusch_cfg.h>
|
||||
|
||||
static inline bool dl_ack_value(uint32_t ue_cc_idx, uint32_t tti)
|
||||
{
|
||||
|
|
|
@ -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
|
|
@ -23,13 +23,14 @@ class phy_common : public srsran::phy_common_interface
|
|||
{
|
||||
private:
|
||||
const uint32_t RINGBUFFER_TIMEOUT_MS = 10;
|
||||
bool quit = false;
|
||||
std::atomic<bool> quit = {false};
|
||||
srslog::basic_logger& logger;
|
||||
double srate_hz;
|
||||
uint64_t write_ts = 0;
|
||||
uint64_t read_ts = 0;
|
||||
std::vector<cf_t> zero_buffer; ///< Zero buffer for Tx
|
||||
std::vector<cf_t> sink_buffer; ///< Dummy buffer for Rx
|
||||
std::mutex ringbuffers_mutex;
|
||||
std::vector<srsran_ringbuffer_t> ringbuffers;
|
||||
srsran::tti_semaphore<void*> semaphore;
|
||||
|
||||
|
@ -145,9 +146,7 @@ public:
|
|||
uint32_t nof_channels = 1;
|
||||
|
||||
args_t(double srate_hz_, uint32_t buffer_sz_ms_, uint32_t nof_channels_) :
|
||||
srate_hz(srate_hz_),
|
||||
buffer_sz_ms(buffer_sz_ms_),
|
||||
nof_channels(nof_channels_)
|
||||
srate_hz(srate_hz_), buffer_sz_ms(buffer_sz_ms_), nof_channels(nof_channels_)
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -186,6 +185,9 @@ public:
|
|||
// Synchronize worker
|
||||
semaphore.wait(h);
|
||||
|
||||
// Protect internal buffers and states
|
||||
std::unique_lock<std::mutex> lock(ringbuffers_mutex);
|
||||
|
||||
uint64_t tx_ts = srsran_timestamp_uint64(&tx_time.get(0), srate_hz);
|
||||
|
||||
// Check transmit timestamp is not in the past
|
||||
|
@ -213,6 +215,9 @@ public:
|
|||
|
||||
void read(std::vector<cf_t*>& buffers, uint32_t nof_samples, srsran::rf_timestamp_t& timestamp)
|
||||
{
|
||||
// Protect internal buffers and states
|
||||
std::unique_lock<std::mutex> lock(ringbuffers_mutex);
|
||||
|
||||
// Detect if zero padding is necessary
|
||||
if (read_ts + nof_samples > write_ts) {
|
||||
uint32_t nof_zero_pading = (uint32_t)((read_ts + nof_samples) - write_ts);
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include "dummy_gnb_stack.h"
|
||||
#include "srsran/common/test_common.h"
|
||||
#include "test_bench.h"
|
||||
|
||||
|
@ -18,18 +19,13 @@ test_bench::args_t::args_t(int argc, char** argv)
|
|||
// Flag configuration as valid
|
||||
valid = true;
|
||||
|
||||
cell_list.resize(1);
|
||||
cell_list[0].carrier.nof_prb = 52;
|
||||
cell_list[0].carrier.max_mimo_layers = 1;
|
||||
cell_list[0].carrier.pci = 500;
|
||||
|
||||
phy_cfg.carrier = cell_list[0].carrier;
|
||||
|
||||
phy_cfg.carrier.nof_prb = 52;
|
||||
phy_cfg.carrier.max_mimo_layers = 1;
|
||||
phy_cfg.carrier.pci = 500;
|
||||
phy_cfg.carrier.absolute_frequency_point_a = 633928;
|
||||
phy_cfg.carrier.absolute_frequency_ssb = 634176;
|
||||
phy_cfg.carrier.offset_to_carrier = 0;
|
||||
phy_cfg.carrier.scs = srsran_subcarrier_spacing_15kHz;
|
||||
phy_cfg.carrier.nof_prb = 52;
|
||||
|
||||
phy_cfg.ssb.periodicity_ms = 5;
|
||||
phy_cfg.ssb.position_in_burst[0] = true;
|
||||
|
@ -212,8 +208,15 @@ test_bench::args_t::args_t(int argc, char** argv)
|
|||
phy_cfg.harq_ack.dl_data_to_ul_ack[4] = 4;
|
||||
phy_cfg.harq_ack.dl_data_to_ul_ack[5] = 12;
|
||||
phy_cfg.harq_ack.dl_data_to_ul_ack[6] = 11;
|
||||
phy_cfg.harq_ack.harq_ack_codebook = srsran_pdsch_harq_ack_codebook_dynamic;
|
||||
|
||||
phy_cfg.prach.freq_offset = 2;
|
||||
|
||||
cell_list.resize(1);
|
||||
cell_list[0].carrier = phy_cfg.carrier;
|
||||
cell_list[0].rf_port = 0;
|
||||
cell_list[0].cell_id = 0;
|
||||
cell_list[0].pdcch = phy_cfg.pdcch;
|
||||
}
|
||||
|
||||
class ue_dummy_stack : public srsue::stack_interface_phy_nr
|
||||
|
@ -262,220 +265,6 @@ public:
|
|||
bool is_valid() const { return valid; }
|
||||
};
|
||||
|
||||
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;
|
||||
const srsran::circular_array<bool, SRSRAN_NOF_SF_X_FRAME> pdsch_mask;
|
||||
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;
|
||||
bool valid = false;
|
||||
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;
|
||||
|
||||
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
|
||||
srsran::circular_array<bool, SRSRAN_NOF_SF_X_FRAME> pdsch_mask = {}; ///< PDSCH scheduling mask
|
||||
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) :
|
||||
pdsch_mask(args.pdsch_mask),
|
||||
mcs(args.mcs),
|
||||
rnti(args.rnti),
|
||||
dl_time_res(args.dl_time_res)
|
||||
{
|
||||
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 get_dl_sched(uint32_t tti, dl_sched_list_t& dl_sched_res) override
|
||||
{
|
||||
// Check input
|
||||
if (dl_sched_res.size() == 0) {
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
// Check PDSCH mask, if no PDSCH shall be scheduled, do not set any grant and skip
|
||||
if (not pdsch_mask[tti]) {
|
||||
dl_sched_res[0].nof_grants = 0;
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
// Select grant and set data
|
||||
dl_sched_grant_t& grant = dl_sched_res[0].pdsch[0];
|
||||
grant.data[0] = tx_harq_proc[tti].data.data();
|
||||
grant.softbuffer_tx[0] = &tx_harq_proc[tti].softbuffer;
|
||||
|
||||
// Second TB is not used
|
||||
grant.data[1] = nullptr;
|
||||
grant.softbuffer_tx[1] = nullptr;
|
||||
|
||||
// Reset Tx softbuffer always
|
||||
srsran_softbuffer_tx_reset(grant.softbuffer_tx[0]);
|
||||
|
||||
// Generate random data
|
||||
srsran_random_byte_vector(random_gen, grant.data[0], SRSRAN_LDPC_MAX_LEN_CB * SRSRAN_SCH_NR_MAX_NOF_CB_LDPC / 8);
|
||||
|
||||
// It currently support only one grant
|
||||
dl_sched_res[0].nof_grants = 1;
|
||||
|
||||
// Fill DCI
|
||||
srsran_dci_dl_nr_t& dci = grant.dci;
|
||||
dci.ctx.location = dci_dl_location[tti];
|
||||
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 = (tti / SRSRAN_NOF_SF_X_FRAME) % 2;
|
||||
dci.pid = tti % SRSRAN_NOF_SF_X_FRAME;
|
||||
dci.dai = tti % SRSRAN_NOF_SF_X_FRAME;
|
||||
dci.tpc = 1;
|
||||
dci.pucch_resource = 0;
|
||||
dci.harq_feedback = dl_data_to_ul_ack[tti];
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
int get_ul_sched(uint32_t tti, ul_sched_list_t& ul_sched_res) override { return 0; }
|
||||
};
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
srslog::init();
|
||||
|
@ -484,7 +273,7 @@ int main(int argc, char** argv)
|
|||
test_bench::args_t args(argc, argv);
|
||||
args.gnb_args.log_id_preamble = "GNB/";
|
||||
args.gnb_args.log_level = "warning";
|
||||
args.gnb_args.nof_workers = 1;
|
||||
args.gnb_args.nof_phy_threads = 1;
|
||||
args.ue_args.log.id_preamble = " UE/";
|
||||
args.ue_args.log.phy_level = "warning";
|
||||
args.ue_args.log.phy_hex_limit = 0;
|
||||
|
@ -505,12 +294,9 @@ int main(int argc, char** argv)
|
|||
gnb_dummy_stack::args_t gnb_stack_args = {};
|
||||
gnb_stack_args.rnti = 0x1234;
|
||||
gnb_stack_args.mcs = 10;
|
||||
for (bool& mask : gnb_stack_args.pdsch_mask) {
|
||||
mask = true;
|
||||
}
|
||||
gnb_stack_args.phy_cfg = args.phy_cfg;
|
||||
gnb_stack_args.dl_start_rb = 0;
|
||||
gnb_stack_args.dl_length_rb = args.phy_cfg.carrier.nof_prb;
|
||||
gnb_stack_args.phy_cfg = args.phy_cfg;
|
||||
gnb_stack_args.dl_start_rb = 0;
|
||||
gnb_stack_args.dl_length_rb = args.phy_cfg.carrier.nof_prb;
|
||||
|
||||
// Create GNB stack
|
||||
gnb_dummy_stack gnb_stack(gnb_stack_args);
|
||||
|
|
|
@ -33,7 +33,6 @@ private:
|
|||
public:
|
||||
struct args_t {
|
||||
double srate_hz = 11.52e6;
|
||||
uint32_t nof_threads = 6;
|
||||
uint32_t nof_channels = 1;
|
||||
uint32_t buffer_sz_ms = 10;
|
||||
bool valid = false;
|
||||
|
@ -48,18 +47,20 @@ public:
|
|||
};
|
||||
|
||||
test_bench(const args_t& args, srsenb::stack_interface_phy_nr& gnb_stack, srsue::stack_interface_phy_nr& ue_stack) :
|
||||
ue_phy(args.nof_threads),
|
||||
gnb_phy(args.cell_list, args.gnb_args, gnb_phy_com, gnb_stack, srslog::get_default_sink()),
|
||||
ue_phy(args.ue_args.nof_phy_threads),
|
||||
gnb_phy(gnb_phy_com, gnb_stack, srslog::get_default_sink(), args.gnb_args.nof_phy_threads),
|
||||
ue_phy_com(phy_common::args_t(args.srate_hz, args.buffer_sz_ms, args.nof_channels),
|
||||
srslog::fetch_basic_logger(UE_PHY_COM_LOG_NAME, srslog::get_default_sink(), false)),
|
||||
gnb_phy_com(phy_common::args_t(args.srate_hz, args.buffer_sz_ms, args.nof_channels),
|
||||
srslog::fetch_basic_logger(GNB_PHY_COM_LOG_NAME, srslog::get_default_sink(), false))
|
||||
srslog::fetch_basic_logger(GNB_PHY_COM_LOG_NAME, srslog::get_default_sink(), false)),
|
||||
sf_sz((uint32_t)std::round(args.srate_hz * 1e-3))
|
||||
{
|
||||
srslog::fetch_basic_logger(UE_PHY_COM_LOG_NAME).set_level(srslog::str_to_basic_level(args.phy_com_log_level));
|
||||
srslog::fetch_basic_logger(GNB_PHY_COM_LOG_NAME).set_level(srslog::str_to_basic_level(args.phy_com_log_level));
|
||||
|
||||
// Calculate subframe length
|
||||
sf_sz = (uint32_t)std::round(args.srate_hz * 1e-3);
|
||||
if (not gnb_phy.init(args.gnb_args, args.cell_list)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialise UE PHY
|
||||
if (not ue_phy.init(args.ue_args, ue_phy_com, &ue_stack, 31)) {
|
||||
|
@ -71,11 +72,6 @@ public:
|
|||
return;
|
||||
}
|
||||
|
||||
// Set UE configuration in gNb
|
||||
if (not gnb_phy.addmod_rnti(args.rnti, args.phy_cfg)) {
|
||||
return;
|
||||
}
|
||||
|
||||
initialised = true;
|
||||
}
|
||||
|
||||
|
@ -92,7 +88,7 @@ public:
|
|||
bool run_tti()
|
||||
{
|
||||
// Get gNb worker
|
||||
srsenb::nr::sf_worker* gnb_worker = gnb_phy.wait_worker(tti);
|
||||
srsenb::nr::slot_worker* gnb_worker = gnb_phy.wait_worker(tti);
|
||||
if (gnb_worker == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
@ -100,7 +96,7 @@ public:
|
|||
// Feed gNb the UE transmitted signal
|
||||
srsran::rf_timestamp_t gnb_time = {};
|
||||
std::vector<cf_t*> gnb_rx_buffers(1);
|
||||
gnb_rx_buffers[0] = gnb_worker->get_buffer_rx(0, 0);
|
||||
gnb_rx_buffers[0] = gnb_worker->get_buffer_rx(0);
|
||||
ue_phy_com.read(gnb_rx_buffers, sf_sz, gnb_time);
|
||||
|
||||
// Set gNb time
|
||||
|
|
Loading…
Reference in New Issue