From d49734b1bc81ec2c1cbe0d4ffe2ad5b440d76c5e Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 21 Jun 2021 07:59:57 +0200 Subject: [PATCH] SRSENB: Refactor to accomodate 5G NR --- .../srsran/interfaces/gnb_interfaces.h | 29 +- srsenb/hdr/phy/nr/cc_worker.h | 51 +- srsenb/hdr/phy/nr/phy_nr_state.h | 101 ++++ srsenb/hdr/phy/nr/sf_worker.h | 7 +- srsenb/hdr/phy/nr/worker_pool.h | 18 +- srsenb/hdr/phy/phy.h | 10 +- srsenb/hdr/stack/gnb_stack_nr.h | 2 + srsenb/hdr/stack/mac/mac_nr.h | 6 +- srsenb/src/phy/CMakeLists.txt | 5 +- srsenb/src/phy/nr/cc_worker.cc | 66 +- srsenb/src/phy/nr/phy_nr_state.cc | 79 +++ srsenb/src/phy/nr/sf_worker.cc | 71 +-- srsenb/src/phy/nr/worker_pool.cc | 29 +- srsenb/src/phy/phy.cc | 10 +- srsenb/src/phy/txrx.cc | 16 +- srsenb/src/stack/gnb_stack_nr.cc | 8 + srsenb/src/stack/mac/nr/mac_nr.cc | 8 + srsue/hdr/phy/nr/sf_worker.h | 9 +- srsue/src/phy/nr/sf_worker.cc | 12 +- test/phy/CMakeLists.txt | 4 +- test/phy/dummy_phy_common.h | 233 ++++++++ test/phy/nr_dl_flood.cc | 563 ++++++++++++++++++ test/phy/nr_phy_test.cc | 113 ---- test/phy/test_bench.h | 131 ++++ 24 files changed, 1297 insertions(+), 284 deletions(-) create mode 100644 srsenb/hdr/phy/nr/phy_nr_state.h create mode 100644 srsenb/src/phy/nr/phy_nr_state.cc create mode 100644 test/phy/dummy_phy_common.h create mode 100644 test/phy/nr_dl_flood.cc delete mode 100644 test/phy/nr_phy_test.cc create mode 100644 test/phy/test_bench.h diff --git a/lib/include/srsran/interfaces/gnb_interfaces.h b/lib/include/srsran/interfaces/gnb_interfaces.h index 91eae09c4..f8f41b677 100644 --- a/lib/include/srsran/interfaces/gnb_interfaces.h +++ b/lib/include/srsran/interfaces/gnb_interfaces.h @@ -224,15 +224,40 @@ public: /** * DL Scheduling result per cell/carrier */ - typedef struct { + struct dl_sched_t { dl_sched_grant_t pdsch[MAX_GRANTS]; //< DL Grants uint32_t nof_grants; //< Number of DL grants - } dl_sched_t; + }; /** * List of DL scheduling results, one entry per cell/carrier */ typedef std::vector 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; + }; + + /** + * 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 + }; + + /** + * List of UL scheduling results, one entry per cell/carrier + */ + typedef std::vector 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; }; class stack_interface_phy_nr : public mac_interface_phy_nr, public srsran::stack_interface_phy_nr diff --git a/srsenb/hdr/phy/nr/cc_worker.h b/srsenb/hdr/phy/nr/cc_worker.h index 26667f1f4..e08eaf961 100644 --- a/srsenb/hdr/phy/nr/cc_worker.h +++ b/srsenb/hdr/phy/nr/cc_worker.h @@ -13,6 +13,7 @@ #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" @@ -25,56 +26,40 @@ namespace srsenb { namespace nr { -struct phy_nr_args_t { - uint32_t nof_carriers = 1; - uint32_t nof_ports = 1; - srsran_enb_dl_nr_args_t dl = {}; -}; - -class phy_nr_state -{ -public: - phy_cell_cfg_list_nr_t cell_list = {}; - phy_nr_args_t args; - srsran::phy_cfg_nr_t cfg; - - phy_nr_state() - { - args.nof_carriers = 1; - args.dl.nof_max_prb = 100; - args.dl.nof_tx_antennas = 1; - args.dl.pdsch.measure_evm = true; - args.dl.pdsch.measure_time = true; - args.dl.pdsch.sch.disable_simd = false; - } -}; - class cc_worker { public: - cc_worker(uint32_t cc_idx, srslog::basic_logger& logger, phy_nr_state& phy_state_); + 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(); - bool set_carrier(const srsran_carrier_nr_t* carrier); 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(const srsran_slot_cfg_t& dl_slot_cfg, stack_interface_phy_nr::dl_sched_t& dl_grants); + 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); - srsran_slot_cfg_t dl_slot_cfg = {}; - uint32_t cc_idx = 0; - std::array tx_buffer = {}; - std::array rx_buffer = {}; - uint32_t buffer_sz = 0; + 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 tx_buffer = {}; + std::array rx_buffer = {}; + uint32_t buffer_sz = 0; phy_nr_state& phy_state; - srsran_enb_dl_nr_t enb_dl = {}; + srsran_enb_dl_nr_t gnb_dl = {}; srslog::basic_logger& logger; }; diff --git a/srsenb/hdr/phy/nr/phy_nr_state.h b/srsenb/hdr/phy/nr/phy_nr_state.h new file mode 100644 index 000000000..ac1783374 --- /dev/null +++ b/srsenb/hdr/phy/nr/phy_nr_state.h @@ -0,0 +1,101 @@ +/** + * + * \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 +#include +#include +#include +#include +#include + +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 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); + + 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_ diff --git a/srsenb/hdr/phy/nr/sf_worker.h b/srsenb/hdr/phy/nr/sf_worker.h index 2c41a6eb6..0d4b16501 100644 --- a/srsenb/hdr/phy/nr/sf_worker.h +++ b/srsenb/hdr/phy/nr/sf_worker.h @@ -35,13 +35,11 @@ public: sf_worker(srsran::phy_common_interface& common_, phy_nr_state& phy_state_, srslog::basic_logger& logger); ~sf_worker(); - bool set_carrier_unlocked(uint32_t cc_idx, const srsran_carrier_nr_t* carrier_); - /* 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_tti(uint32_t tti); + 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 */ @@ -52,6 +50,9 @@ private: 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 = {}; // Temporal attributes srsran_softbuffer_tx_t softbuffer_tx = {}; diff --git a/srsenb/hdr/phy/nr/worker_pool.h b/srsenb/hdr/phy/nr/worker_pool.h index 37df6bb33..9c99d2e38 100644 --- a/srsenb/hdr/phy/nr/worker_pool.h +++ b/srsenb/hdr/phy/nr/worker_pool.h @@ -13,6 +13,7 @@ #ifndef SRSENB_NR_WORKER_POOL_H #define SRSENB_NR_WORKER_POOL_H +#include "phy_nr_state.h" #include "sf_worker.h" #include "srsenb/hdr/phy/phy_interfaces.h" #include "srsran/common/thread_pool.h" @@ -27,14 +28,19 @@ class worker_pool phy_nr_state phy_state; public: + struct args_t { + uint32_t nof_workers = 3; + uint32_t prio = 52; + std::string log_level = "info"; + uint32_t log_hex_limit = 64; + }; sf_worker* operator[](std::size_t pos) { return workers.at(pos).get(); } - worker_pool(uint32_t max_workers); - bool init(const phy_cell_cfg_list_nr_t& cell_list, - const phy_args_t& args, - srsran::phy_common_interface& common, - srslog::sink& log_sink, - int prio); + 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); sf_worker* wait_worker(uint32_t tti); sf_worker* wait_worker_id(uint32_t id); void start_worker(sf_worker* w); diff --git a/srsenb/hdr/phy/phy.h b/srsenb/hdr/phy/phy.h index 5a46315bd..8048f6af0 100644 --- a/srsenb/hdr/phy/phy.h +++ b/srsenb/hdr/phy/phy.h @@ -77,11 +77,11 @@ private: srslog::basic_logger& phy_log; srslog::basic_logger& phy_lib_log; - lte::worker_pool lte_workers; - nr::worker_pool nr_workers; - phy_common workers_common; - prach_worker_pool prach; - txrx tx_rx; + lte::worker_pool lte_workers; + std::unique_ptr nr_workers; + phy_common workers_common; + prach_worker_pool prach; + txrx tx_rx; bool initialized = false; diff --git a/srsenb/hdr/stack/gnb_stack_nr.h b/srsenb/hdr/stack/gnb_stack_nr.h index a53b37fc6..90b108807 100644 --- a/srsenb/hdr/stack/gnb_stack_nr.h +++ b/srsenb/hdr/stack/gnb_stack_nr.h @@ -72,6 +72,8 @@ public: 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; private: void run_thread() final; diff --git a/srsenb/hdr/stack/mac/mac_nr.h b/srsenb/hdr/stack/mac/mac_nr.h index ae557544b..274efb74b 100644 --- a/srsenb/hdr/stack/mac/mac_nr.h +++ b/srsenb/hdr/stack/mac/mac_nr.h @@ -53,18 +53,20 @@ public: void get_metrics(srsenb::mac_metrics_t& metrics); // MAC interface for RRC - int cell_cfg(srsenb::sched_interface::cell_cfg_t* cell_cfg); + int cell_cfg(srsenb::sched_interface::cell_cfg_t* cell_cfg) override; int read_pdu_bcch_bch(uint8_t* payload); // MAC interface for RLC // TODO: - int rlc_buffer_state(uint16_t rnti, uint32_t lc_id, uint32_t tx_queue, uint32_t retx_queue) { return 0; } + int rlc_buffer_state(uint16_t rnti, uint32_t lc_id, uint32_t tx_queue, uint32_t retx_queue) override { return 0; } // Interface for PHY int sf_indication(const uint32_t tti); 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; private: void get_dl_config(const uint32_t tti, diff --git a/srsenb/src/phy/CMakeLists.txt b/srsenb/src/phy/CMakeLists.txt index 8371549b2..60061af9f 100644 --- a/srsenb/src/phy/CMakeLists.txt +++ b/srsenb/src/phy/CMakeLists.txt @@ -13,6 +13,7 @@ set(SOURCES nr/cc_worker.cc nr/sf_worker.cc nr/worker_pool.cc + nr/phy_nr_state.cc phy.cc phy_common.cc phy_ue_db.cc @@ -22,6 +23,6 @@ add_library(srsenb_phy STATIC ${SOURCES}) add_library(srsgnb_phy STATIC vnf_phy_nr.cc) -if(ENABLE_GUI AND SRSGUI_FOUND) +if (ENABLE_GUI AND SRSGUI_FOUND) target_link_libraries(srsenb_phy ${SRSGUI_LIBRARIES}) -endif() +endif () diff --git a/srsenb/src/phy/nr/cc_worker.cc b/srsenb/src/phy/nr/cc_worker.cc index 66f686800..93a8e1e5a 100644 --- a/srsenb/src/phy/nr/cc_worker.cc +++ b/srsenb/src/phy/nr/cc_worker.cc @@ -15,28 +15,32 @@ namespace srsenb { namespace nr { -cc_worker::cc_worker(uint32_t cc_idx_, srslog::basic_logger& log, phy_nr_state& phy_state_) : - cc_idx(cc_idx_), phy_state(phy_state_), logger(log) +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(phy_state.args.dl.nof_max_prb); - for (uint32_t i = 0; i < phy_state.args.dl.nof_tx_antennas; i++) { + 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(&enb_dl, buffer_c, &phy_state.args.dl)) { - ERROR("Error initiating UE DL NR"); + 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(&enb_dl); + srsran_enb_dl_nr_free(&gnb_dl); for (cf_t* p : rx_buffer) { if (p != nullptr) { free(p); @@ -49,34 +53,15 @@ cc_worker::~cc_worker() } } -bool cc_worker::set_carrier(const srsran_carrier_nr_t* carrier) -{ - if (srsran_enb_dl_nr_set_carrier(&enb_dl, carrier) < SRSRAN_SUCCESS) { - ERROR("Error setting carrier"); - return false; - } - - srsran_coreset_t coreset = {}; - coreset.freq_resources[0] = true; // Enable the bottom 6 PRB for PDCCH - coreset.duration = 2; - - srsran_dci_cfg_nr_t dci_cfg = phy_state.cfg.get_dci_cfg(); - if (srsran_enb_dl_nr_set_pdcch_config(&enb_dl, &phy_state.cfg.pdcch, &dci_cfg) < SRSRAN_SUCCESS) { - ERROR("Error setting coreset"); - return false; - } - - return true; -} - 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 >= phy_state.args.dl.nof_tx_antennas) { + if (antenna_idx >= nof_tx_antennas) { return nullptr; } @@ -85,7 +70,7 @@ cf_t* cc_worker::get_tx_buffer(uint32_t antenna_idx) cf_t* cc_worker::get_rx_buffer(uint32_t antenna_idx) { - if (antenna_idx >= phy_state.args.dl.nof_tx_antennas) { + if (antenna_idx >= nof_tx_antennas) { return nullptr; } @@ -104,7 +89,7 @@ int cc_worker::encode_pdcch_dl(stack_interface_phy_nr::dl_sched_grant_t* grants, // ... // Put actual DCI - if (srsran_enb_dl_nr_pdcch_put(&enb_dl, &dl_slot_cfg, &grants[i].dci) < SRSRAN_SUCCESS) { + if (srsran_enb_dl_nr_pdcch_put(&gnb_dl, &dl_slot_cfg, &grants[i].dci) < SRSRAN_SUCCESS) { ERROR("Error putting PDCCH"); return SRSRAN_ERROR; } @@ -127,10 +112,10 @@ int cc_worker::encode_pdsch(stack_interface_phy_nr::dl_sched_grant_t* grants, ui // Compute DL grant if (srsran_ra_dl_dci_to_grant_nr( - &enb_dl.carrier, &dl_slot_cfg, &pdsch_hl_cfg, &grants[i].dci, &pdsch_cfg, &pdsch_cfg.grant) < + &gnb_dl.carrier, &dl_slot_cfg, &pdsch_hl_cfg, &grants[i].dci, &pdsch_cfg, &pdsch_cfg.grant) < SRSRAN_SUCCESS) { ERROR("Computing DL grant"); - return false; + return SRSRAN_ERROR; } // Set soft buffer @@ -138,15 +123,15 @@ int cc_worker::encode_pdsch(stack_interface_phy_nr::dl_sched_grant_t* grants, ui pdsch_cfg.grant.tb[j].softbuffer.tx = grants[i].softbuffer_tx[j]; } - if (srsran_enb_dl_nr_pdsch_put(&enb_dl, &dl_slot_cfg, &pdsch_cfg, grants[i].data) < SRSRAN_SUCCESS) { + if (srsran_enb_dl_nr_pdsch_put(&gnb_dl, &dl_slot_cfg, &pdsch_cfg, grants[i].data) < SRSRAN_SUCCESS) { ERROR("Error putting PDSCH"); - return false; + return SRSRAN_ERROR; } // Logging if (logger.info.enabled()) { char str[512]; - srsran_enb_dl_nr_pdsch_info(&enb_dl, &pdsch_cfg, str, sizeof(str)); + srsran_enb_dl_nr_pdsch_info(&gnb_dl, &pdsch_cfg, str, sizeof(str)); logger.info("PDSCH: cc=%d, %s", cc_idx, str); } } @@ -154,10 +139,15 @@ int cc_worker::encode_pdsch(stack_interface_phy_nr::dl_sched_grant_t* grants, ui return SRSRAN_SUCCESS; } -bool cc_worker::work_dl(const srsran_slot_cfg_t& dl_sf_cfg, stack_interface_phy_nr::dl_sched_t& dl_grants) +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(&enb_dl) < SRSRAN_SUCCESS) { + if (srsran_enb_dl_nr_base_zero(&gnb_dl) < SRSRAN_SUCCESS) { ERROR("Error setting base to zero"); return SRSRAN_ERROR; } @@ -167,7 +157,7 @@ bool cc_worker::work_dl(const srsran_slot_cfg_t& dl_sf_cfg, stack_interface_phy_ encode_pdsch(dl_grants.pdsch, dl_grants.nof_grants); // Generate signal - srsran_enb_dl_nr_gen_signal(&enb_dl); + srsran_enb_dl_nr_gen_signal(&gnb_dl); return true; } diff --git a/srsenb/src/phy/nr/phy_nr_state.cc b/srsenb/src/phy/nr/phy_nr_state.cc new file mode 100644 index 000000000..9135c0885 --- /dev/null +++ b/srsenb/src/phy/nr/phy_nr_state.cc @@ -0,0 +1,79 @@ +/** + * + * \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 +{ + std::lock_guard lock(mutex); + + 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 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 lock(mutex); + + if (_assert_rnti(rnti) < SRSRAN_SUCCESS) { + return SRSRAN_ERROR; + } + + ue_db.erase(rnti); + + return SRSRAN_SUCCESS; +} + +} // namespace nr +} // namespace srsenb \ No newline at end of file diff --git a/srsenb/src/phy/nr/sf_worker.cc b/srsenb/src/phy/nr/sf_worker.cc index 6e9118c72..e165b8f0a 100644 --- a/srsenb/src/phy/nr/sf_worker.cc +++ b/srsenb/src/phy/nr/sf_worker.cc @@ -17,8 +17,15 @@ 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) { - for (uint32_t i = 0; i < phy_state.args.nof_carriers; i++) { - cc_worker* w = new cc_worker(i, logger, phy_state); + 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_worker* w = new cc_worker(cc_args, logger, phy_state); cc_workers.push_back(std::unique_ptr(w)); } @@ -37,15 +44,6 @@ sf_worker::~sf_worker() srsran_softbuffer_tx_free(&softbuffer_tx); } -bool sf_worker::set_carrier_unlocked(uint32_t cc_idx, const srsran_carrier_nr_t* carrier_) -{ - if (cc_idx >= cc_workers.size()) { - return false; - } - - return cc_workers.at(cc_idx)->set_carrier(carrier_); -} - cf_t* sf_worker::get_buffer_rx(uint32_t cc_idx, uint32_t antenna_idx) { if (cc_idx >= cc_workers.size()) { @@ -69,12 +67,15 @@ uint32_t sf_worker::get_buffer_len() return cc_workers.at(0)->get_buffer_len(); } -void sf_worker::set_tti(uint32_t tti) +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() @@ -82,38 +83,30 @@ void sf_worker::work_imp() // Get Transmission buffers srsran::rf_buffer_t tx_buffer = {}; srsran::rf_timestamp_t dummy_ts = {}; - for (uint32_t cc = 0; cc < phy_state.args.nof_carriers; cc++) { - for (uint32_t ant = 0; ant < phy_state.args.nof_ports; ant++) { - tx_buffer.set(cc, ant, phy_state.args.nof_ports, cc_workers[cc]->get_tx_buffer(ant)); - } + 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)); } - // Configure user - phy_state.cfg.pdsch.rbg_size_cfg_1 = false; - - // Fill grant (this comes from the scheduler) - srsran_slot_cfg_t dl_cfg = {}; - stack_interface_phy_nr::dl_sched_t grants = {}; - - grants.nof_grants = 1; - grants.pdsch[0].data[0] = data.data(); - grants.pdsch[0].softbuffer_tx[0] = &softbuffer_tx; - srsran_softbuffer_tx_reset(&softbuffer_tx); - - grants.pdsch[0].dci.ctx.rnti = 0x1234; - grants.pdsch[0].dci.ctx.format = srsran_dci_format_nr_1_0; - - grants.pdsch[0].dci.freq_domain_assigment = 0x1FFF; - grants.pdsch[0].dci.time_domain_assigment = 0; - grants.pdsch[0].dci.mcs = 27; + // 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, dummy_ts, true); + return; + } - grants.pdsch[0].dci.ctx.ss_type = srsran_search_space_type_ue; - grants.pdsch[0].dci.ctx.coreset_id = 1; - grants.pdsch[0].dci.ctx.location.L = 0; - grants.pdsch[0].dci.ctx.location.ncce = 0; + // 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, dummy_ts, true); + return; + } for (auto& w : cc_workers) { - w->work_dl(dl_cfg, grants); + w->work_dl(dl_sched_list[0], ul_sched_list[0]); } common.worker_end(this, true, tx_buffer, dummy_ts, true); diff --git a/srsenb/src/phy/nr/worker_pool.cc b/srsenb/src/phy/nr/worker_pool.cc index 30eddcdcb..12a0c8edf 100644 --- a/srsenb/src/phy/nr/worker_pool.cc +++ b/srsenb/src/phy/nr/worker_pool.cc @@ -14,33 +14,24 @@ namespace srsenb { namespace nr { -worker_pool::worker_pool(uint32_t max_workers) : pool(max_workers) {} - -bool worker_pool::init(const phy_cell_cfg_list_nr_t& cell_list, - const phy_args_t& args, - srsran::phy_common_interface& common, - srslog::sink& log_sink, - int prio) +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) { - // Save cell list - phy_state.cell_list = cell_list; - // Add workers to workers pool and start threads - srslog::basic_levels log_level = srslog::str_to_basic_level(args.log.phy_level); - for (uint32_t i = 0; i < args.nof_phy_threads; i++) { + srslog::basic_levels log_level = srslog::str_to_basic_level(args.log_level); + for (uint32_t i = 0; i < args.nof_workers; i++) { auto& log = srslog::fetch_basic_logger(fmt::format("PHY{}-NR", i), log_sink); log.set_level(log_level); - log.set_hex_dump_max_size(args.log.phy_hex_limit); + log.set_hex_dump_max_size(args.log_hex_limit); auto w = new sf_worker(common, phy_state, log); - pool.init_worker(i, w, prio); + pool.init_worker(i, w, args.prio); workers.push_back(std::unique_ptr(w)); - - srsran_carrier_nr_t c = phy_state.cell_list[0].carrier; - w->set_carrier_unlocked(0, &c); } - - return true; } void worker_pool::start_worker(sf_worker* w) diff --git a/srsenb/src/phy/phy.cc b/srsenb/src/phy/phy.cc index 8243b5e53..ee8dadcbe 100644 --- a/srsenb/src/phy/phy.cc +++ b/srsenb/src/phy/phy.cc @@ -66,7 +66,6 @@ phy::phy(srslog::sink& log_sink) : phy_log(srslog::fetch_basic_logger("PHY", log_sink)), phy_lib_log(srslog::fetch_basic_logger("PHY_LIB", log_sink)), lte_workers(MAX_WORKERS), - nr_workers(MAX_WORKERS), workers_common(), nof_workers(0), tx_rx(phy_log) @@ -132,7 +131,10 @@ int phy::init(const phy_args_t& args, lte_workers.init(args, &workers_common, log_sink, WORKERS_THREAD_PRIO); } if (not cfg.phy_cell_cfg_nr.empty()) { - nr_workers.init(cfg.phy_cell_cfg_nr, args, workers_common, log_sink, WORKERS_THREAD_PRIO); + // Not implemented + // nr_workers = std::unique_ptr( + // new nr::worker_pool(cfg.phy_cell_cfg_nr, workers_common, stack_, log_sink, MAX_WORKERS, + // WORKERS_THREAD_PRIO)); } // For each carrier, initialise PRACH worker @@ -144,7 +146,7 @@ int phy::init(const phy_args_t& args, prach.set_max_prach_offset_us(args.max_prach_offset_us); // Warning this must be initialized after all workers have been added to the pool - tx_rx.init(stack_, radio, <e_workers, &nr_workers, &workers_common, &prach, SF_RECV_THREAD_PRIO); + tx_rx.init(stack_, radio, <e_workers, nr_workers.get(), &workers_common, &prach, SF_RECV_THREAD_PRIO); initialized = true; @@ -157,7 +159,7 @@ void phy::stop() tx_rx.stop(); workers_common.stop(); lte_workers.stop(); - nr_workers.stop(); + nr_workers->stop(); prach.stop(); initialized = false; diff --git a/srsenb/src/phy/txrx.cc b/srsenb/src/phy/txrx.cc index d78393550..326114faa 100644 --- a/srsenb/src/phy/txrx.cc +++ b/srsenb/src/phy/txrx.cc @@ -47,13 +47,13 @@ bool txrx::init(stack_interface_phy_lte* stack_, prach_worker_pool* prach_, uint32_t prio_) { - stack = stack_; - radio_h = radio_h_; - lte_workers = lte_workers_; - nr_workers = nr_workers_; - worker_com = worker_com_; - prach = prach_; - running = true; + stack = stack_; + radio_h = radio_h_; + lte_workers = lte_workers_; + nr_workers = nr_workers_; + worker_com = worker_com_; + prach = prach_; + running = true; // Instantiate UL channel emulator if (worker_com->params.ul_channel_args.enable) { @@ -179,7 +179,7 @@ void txrx::run_thread() // Launch NR worker only if available if (nr_worker != nullptr) { - nr_worker->set_tti(tti); + nr_worker->set_time(tti, timestamp); worker_com->semaphore.push(nr_worker); nr_workers->start_worker(nr_worker); } diff --git a/srsenb/src/stack/gnb_stack_nr.cc b/srsenb/src/stack/gnb_stack_nr.cc index 9f3d93f06..cf90c2393 100644 --- a/srsenb/src/stack/gnb_stack_nr.cc +++ b/srsenb/src/stack/gnb_stack_nr.cc @@ -182,5 +182,13 @@ 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) +{ + return m_mac->get_dl_sched(tti, dl_sched_res); +} +int gnb_stack_nr::get_ul_sched(uint32_t tti, mac_interface_phy_nr::ul_sched_list_t& ul_sched_res) +{ + return m_mac->get_ul_sched(tti, ul_sched_res); +} } // namespace srsenb diff --git a/srsenb/src/stack/mac/nr/mac_nr.cc b/srsenb/src/stack/mac/nr/mac_nr.cc index eafe1e7cb..4ae51e0e3 100644 --- a/srsenb/src/stack/mac/nr/mac_nr.cc +++ b/srsenb/src/stack/mac/nr/mac_nr.cc @@ -267,5 +267,13 @@ 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) +{ + return 0; +} +int mac_nr::get_ul_sched(uint32_t tti, mac_interface_phy_nr::ul_sched_list_t& ul_sched_res) +{ + return 0; +} } // namespace srsenb diff --git a/srsue/hdr/phy/nr/sf_worker.h b/srsue/hdr/phy/nr/sf_worker.h index e2dc1637f..9c595d1ef 100644 --- a/srsue/hdr/phy/nr/sf_worker.h +++ b/srsue/hdr/phy/nr/sf_worker.h @@ -40,6 +40,7 @@ public: cf_t* get_buffer(uint32_t cc_idx, uint32_t antenna_idx); uint32_t get_buffer_len(); void set_tti(uint32_t tti); + void set_tx_time(const srsran::rf_timestamp_t& tx_time_); int read_pdsch_d(cf_t* pdsch_d); void start_plot(); @@ -54,10 +55,10 @@ private: srsran::phy_common_interface& common; state& phy_state; srslog::basic_logger& logger; - - uint32_t tti_rx = 0; - cf_t* prach_ptr = nullptr; - float prach_power = 0; + srsran::rf_timestamp_t tx_time = {}; + uint32_t tti_rx = 0; + cf_t* prach_ptr = nullptr; + float prach_power = 0; }; } // namespace nr diff --git a/srsue/src/phy/nr/sf_worker.cc b/srsue/src/phy/nr/sf_worker.cc index da303e6fe..b761c0c8a 100644 --- a/srsue/src/phy/nr/sf_worker.cc +++ b/srsue/src/phy/nr/sf_worker.cc @@ -68,10 +68,14 @@ void sf_worker::set_tti(uint32_t tti) } } +void sf_worker::set_tx_time(const srsran::rf_timestamp_t& tx_time_) +{ + tx_time.copy(tx_time_); +} + void sf_worker::work_imp() { - srsran::rf_buffer_t tx_buffer = {}; - srsran::rf_timestamp_t dummy_ts = {}; + srsran::rf_buffer_t tx_buffer = {}; // Perform DL processing for (auto& w : cc_workers) { @@ -95,7 +99,7 @@ void sf_worker::work_imp() 0); // Transmit NR PRACH - common.worker_end(this, true, tx_buffer, dummy_ts, true); + common.worker_end(this, true, tx_buffer, tx_time, true); // Reset PRACH pointer prach_ptr = nullptr; @@ -114,7 +118,7 @@ void sf_worker::work_imp() } // Always call worker_end before returning - common.worker_end(this, true, tx_buffer, dummy_ts, true); + common.worker_end(this, true, tx_buffer, tx_time, true); // Tell the plotting thread to draw the plots #ifdef ENABLE_GUI diff --git a/test/phy/CMakeLists.txt b/test/phy/CMakeLists.txt index fd5f8e3f5..959bd21bb 100644 --- a/test/phy/CMakeLists.txt +++ b/test/phy/CMakeLists.txt @@ -7,7 +7,7 @@ # if (RF_FOUND AND ENABLE_SRSUE AND ENABLE_SRSENB) - add_executable(nr_phy_test nr_phy_test.cc) + add_executable(nr_phy_test nr_dl_flood.cc) target_link_libraries(nr_phy_test srsue_phy_nr srsue_phy @@ -22,4 +22,4 @@ if (RF_FOUND AND ENABLE_SRSUE AND ENABLE_SRSENB) ${ATOMIC_LIBS}) add_nr_test(nr_phy_test nr_phy_test) -endif () \ No newline at end of file +endif () diff --git a/test/phy/dummy_phy_common.h b/test/phy/dummy_phy_common.h new file mode 100644 index 000000000..389b8022b --- /dev/null +++ b/test/phy/dummy_phy_common.h @@ -0,0 +1,233 @@ +/** + * + * \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_PHY_COMMON_H +#define SRSRAN_DUMMY_PHY_COMMON_H + +#include +#include +#include +#include +#include + +class phy_common : public srsran::phy_common_interface +{ +private: + const uint32_t RINGBUFFER_TIMEOUT_MS = 10; + bool quit = false; + srslog::basic_logger& logger; + double srate_hz; + uint64_t write_ts = 0; + uint64_t read_ts = 0; + std::vector zero_buffer; ///< Zero buffer for Tx + std::vector sink_buffer; ///< Dummy buffer for Rx + std::vector ringbuffers; + srsran::tti_semaphore semaphore; + + void write_zero_padding(uint32_t nof_zeros) + { + // Skip if no pading is required + if (nof_zeros == 0) { + return; + } + + logger.debug("Padding %d zeros", nof_zeros); + + // For each ringbuffer, padd zero + int nof_bytes = (int)(nof_zeros * sizeof(cf_t)); + for (srsran_ringbuffer_t& rb : ringbuffers) { + // If quit is flagged, return instantly + if (quit) { + return; + } + + // Actual write + int err = SRSRAN_SUCCESS; + do { + err = srsran_ringbuffer_write_timed(&rb, zero_buffer.data(), nof_bytes, RINGBUFFER_TIMEOUT_MS); + if (err < SRSRAN_SUCCESS and err != SRSRAN_ERROR_TIMEOUT) { + logger.error("Error writing zeros in ringbuffer"); + } + } while (err < SRSRAN_SUCCESS and not quit); + } + + // Increment write timestamp + write_ts += nof_zeros; + } + + void write_baseband(srsran::rf_buffer_t& buffer) + { + // skip if baseband is not available + if (buffer.get_nof_samples() == 0) { + return; + } + + // For each ringbuffer, write + int nof_bytes = (int)(buffer.get_nof_samples() * sizeof(cf_t)); + uint32_t channel_idx = 0; + for (srsran_ringbuffer_t& rb : ringbuffers) { + // If quit is flagged, return instantly + if (quit) { + return; + } + + // Extract channel buffer pointer + cf_t* channel_buffer = buffer.get(channel_idx); + + // If the pointer is not set, use the zero buffer + if (channel_buffer == nullptr) { + channel_buffer = zero_buffer.data(); + } + + // Actual write + int err = SRSRAN_SUCCESS; + do { + err = srsran_ringbuffer_write_timed(&rb, channel_buffer, nof_bytes, RINGBUFFER_TIMEOUT_MS); + if (err < SRSRAN_SUCCESS and err != SRSRAN_ERROR_TIMEOUT) { + logger.error("Error writing zeros in ringbuffer"); + } + } while (err < SRSRAN_SUCCESS and not quit); + + // Increment channel counter + channel_idx++; + } + + // Increment write timestamp + write_ts += buffer.get_nof_samples(); + } + + void read_baseband(std::vector& buffers, uint32_t nof_samples) + { + // For each ringbuffer, read + int nof_bytes = (int)(nof_samples * sizeof(cf_t)); + uint32_t channel_idx = 0; + for (srsran_ringbuffer_t& rb : ringbuffers) { + // If quit is flagged, return instantly + if (quit) { + return; + } + + // Extract channel buffer pointer + cf_t* channel_buffer = buffers[channel_idx]; + + // If the pointer is not set, use the zero buffer + if (channel_buffer == nullptr) { + channel_buffer = sink_buffer.data(); + } + + // Actual write + int err = SRSRAN_SUCCESS; + do { + err = srsran_ringbuffer_read_timed(&rb, channel_buffer, nof_bytes, RINGBUFFER_TIMEOUT_MS); + if (err < SRSRAN_SUCCESS and err != SRSRAN_ERROR_TIMEOUT) { + logger.error("Error reading zeros in ringbuffer"); + } + } while (err < SRSRAN_SUCCESS and not quit); + + // Increment channel counter + channel_idx++; + } + } + +public: + struct args_t { + double srate_hz = 11.52e6; + uint32_t buffer_sz_ms = 10; ///< Buffer size in milliseconds + 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_) + {} + }; + + phy_common(const args_t& args, srslog::basic_logger& logger_) : srate_hz(args.srate_hz), logger(logger_) + { + uint32_t buffer_sz = std::ceil((double)args.buffer_sz_ms * srate_hz * 1e-3); + uint32_t buffer_sz_bytes = sizeof(cf_t) * buffer_sz; + + // Allocate data buffer + zero_buffer.resize(buffer_sz); + sink_buffer.resize(buffer_sz); + + // Allocate ring buffers + ringbuffers.resize(args.nof_channels); + + // Initialise buffers + for (srsran_ringbuffer_t& rb : ringbuffers) { + if (srsran_ringbuffer_init(&rb, buffer_sz_bytes) < SRSRAN_SUCCESS) { + logger.error("Error ringbuffer init"); + } + } + } + + ~phy_common() + { + for (srsran_ringbuffer_t& rb : ringbuffers) { + srsran_ringbuffer_free(&rb); + } + } + + void push_semaphore(void* worker_ptr) { semaphore.push(worker_ptr); } + + void + worker_end(void* h, bool tx_enable, srsran::rf_buffer_t& buffer, srsran::rf_timestamp_t& tx_time, bool is_nr) override + { + // Synchronize worker + semaphore.wait(h); + + uint64_t tx_ts = srsran_timestamp_uint64(&tx_time.get(0), srate_hz); + + // Check transmit timestamp is not in the past + if (tx_ts < write_ts) { + logger.error("Tx time is %d samples in the past", (uint32_t)(write_ts - tx_ts)); + semaphore.release(); + return; + } + + // Write zero padding if necessary + write_zero_padding((uint32_t)(tx_ts - write_ts)); + + // Write baseband + if (tx_enable) { + write_baseband(buffer); + } else { + write_zero_padding(buffer.get_nof_samples()); + } + + // Release semaphore, so next worker can be used + semaphore.release(); + } + + void read(std::vector& buffers, uint32_t nof_samples, srsran::rf_timestamp_t& timestamp) + { + // 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); + write_zero_padding(nof_zero_pading); + } + + // Actual baseband read + read_baseband(buffers, nof_samples); + + // Write timestamp + srsran_timestamp_init_uint64(timestamp.get_ptr(0), read_ts, srate_hz); + + // Increment Rx timestamp + read_ts += nof_samples; + } + + void stop() { + quit = true; + } +}; + +#endif // SRSRAN_DUMMY_PHY_COMMON_H diff --git a/test/phy/nr_dl_flood.cc b/test/phy/nr_dl_flood.cc new file mode 100644 index 000000000..b005fd5a6 --- /dev/null +++ b/test/phy/nr_dl_flood.cc @@ -0,0 +1,563 @@ +/** + * + * \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 "srsran/common/test_common.h" +#include "test_bench.h" + +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; + + phy_cfg.carrier = cell_list[0].carrier; + 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; + phy_cfg.ssb.scs = srsran_subcarrier_spacing_30kHz; + + phy_cfg.pdcch.coreset_present[1] = true; + phy_cfg.pdcch.coreset[1].id = 1; + phy_cfg.pdcch.coreset[1].freq_resources[0] = true; + phy_cfg.pdcch.coreset[1].freq_resources[1] = true; + phy_cfg.pdcch.coreset[1].freq_resources[2] = true; + phy_cfg.pdcch.coreset[1].freq_resources[3] = true; + phy_cfg.pdcch.coreset[1].freq_resources[4] = true; + phy_cfg.pdcch.coreset[1].freq_resources[5] = true; + phy_cfg.pdcch.coreset[1].freq_resources[6] = true; + phy_cfg.pdcch.coreset[1].freq_resources[7] = true; + phy_cfg.pdcch.coreset[1].duration = 1; + phy_cfg.pdcch.coreset[1].mapping_type = srsran_coreset_mapping_type_non_interleaved; + phy_cfg.pdcch.coreset[1].precoder_granularity = srsran_coreset_precoder_granularity_reg_bundle; + phy_cfg.pdcch.coreset_present[2] = true; + phy_cfg.pdcch.coreset[2].id = 2; + phy_cfg.pdcch.coreset[2].freq_resources[0] = true; + phy_cfg.pdcch.coreset[2].freq_resources[1] = true; + phy_cfg.pdcch.coreset[2].freq_resources[2] = true; + phy_cfg.pdcch.coreset[2].freq_resources[3] = true; + phy_cfg.pdcch.coreset[2].freq_resources[4] = true; + phy_cfg.pdcch.coreset[2].freq_resources[5] = true; + phy_cfg.pdcch.coreset[2].freq_resources[6] = true; + phy_cfg.pdcch.coreset[2].freq_resources[7] = true; + phy_cfg.pdcch.coreset[2].duration = 1; + phy_cfg.pdcch.coreset[2].mapping_type = srsran_coreset_mapping_type_non_interleaved; + phy_cfg.pdcch.coreset[2].precoder_granularity = srsran_coreset_precoder_granularity_reg_bundle; + + phy_cfg.pdcch.search_space_present[1] = true; + phy_cfg.pdcch.search_space[1].id = 1; + phy_cfg.pdcch.search_space[1].coreset_id = 1; + phy_cfg.pdcch.search_space[1].duration = 1; + phy_cfg.pdcch.search_space[1].nof_candidates[0] = 1; + phy_cfg.pdcch.search_space[1].nof_candidates[1] = 1; + phy_cfg.pdcch.search_space[1].nof_candidates[2] = 1; + phy_cfg.pdcch.search_space[1].nof_candidates[3] = 0; + phy_cfg.pdcch.search_space[1].nof_candidates[4] = 0; + phy_cfg.pdcch.search_space[1].formats[0] = srsran_dci_format_nr_0_0; + phy_cfg.pdcch.search_space[1].formats[1] = srsran_dci_format_nr_1_0; + phy_cfg.pdcch.search_space[1].nof_formats = 2; + phy_cfg.pdcch.search_space[1].type = srsran_search_space_type_common_3; + + phy_cfg.pdcch.search_space_present[2] = true; + phy_cfg.pdcch.search_space[2].id = 2; + phy_cfg.pdcch.search_space[2].coreset_id = 2; + phy_cfg.pdcch.search_space[2].duration = 1; + phy_cfg.pdcch.search_space[2].nof_candidates[0] = 0; + phy_cfg.pdcch.search_space[2].nof_candidates[1] = 2; + phy_cfg.pdcch.search_space[2].nof_candidates[2] = 1; + phy_cfg.pdcch.search_space[2].nof_candidates[3] = 0; + phy_cfg.pdcch.search_space[2].nof_candidates[4] = 0; + phy_cfg.pdcch.search_space[2].formats[0] = srsran_dci_format_nr_0_0; + phy_cfg.pdcch.search_space[2].formats[1] = srsran_dci_format_nr_1_0; + phy_cfg.pdcch.search_space[2].nof_formats = 2; + phy_cfg.pdcch.search_space[2].type = srsran_search_space_type_ue; + + phy_cfg.pdcch.ra_search_space_present = true; + phy_cfg.pdcch.ra_search_space = phy_cfg.pdcch.search_space[1]; + phy_cfg.pdcch.ra_search_space.type = srsran_search_space_type_common_1; + + phy_cfg.pdsch.common_time_ra[0].mapping_type = srsran_sch_mapping_type_A; + phy_cfg.pdsch.common_time_ra[0].sliv = 40; + phy_cfg.pdsch.common_time_ra[1].mapping_type = srsran_sch_mapping_type_A; + phy_cfg.pdsch.common_time_ra[1].sliv = 57; + phy_cfg.pdsch.nof_common_time_ra = 2; + + phy_cfg.pusch.common_time_ra[0].k = 4; + phy_cfg.pusch.common_time_ra[0].mapping_type = srsran_sch_mapping_type_A; + phy_cfg.pusch.common_time_ra[0].sliv = 27; + phy_cfg.pusch.common_time_ra[1].k = 5; + phy_cfg.pusch.common_time_ra[1].mapping_type = srsran_sch_mapping_type_A; + phy_cfg.pusch.common_time_ra[1].sliv = 27; + phy_cfg.pusch.nof_common_time_ra = 2; + + phy_cfg.pdsch.typeA_pos = srsran_dmrs_sch_typeA_pos_2; + phy_cfg.pusch.typeA_pos = srsran_dmrs_sch_typeA_pos_2; + + phy_cfg.tdd.pattern1.period_ms = 10; + phy_cfg.tdd.pattern1.nof_dl_slots = 7; + phy_cfg.tdd.pattern1.nof_dl_symbols = 6; + phy_cfg.tdd.pattern1.nof_ul_slots = 4; + phy_cfg.tdd.pattern1.nof_ul_symbols = 4; + + phy_cfg.pdsch.dmrs_typeA.additional_pos = srsran_dmrs_sch_add_pos_1; + phy_cfg.pdsch.dmrs_typeA.present = true; + phy_cfg.pdsch.alloc = srsran_resource_alloc_type1; + + phy_cfg.pucch.enabled = true; + srsran_pucch_nr_resource_t& pucch0 = phy_cfg.pucch.sets[0].resources[0]; + srsran_pucch_nr_resource_t& pucch1 = phy_cfg.pucch.sets[0].resources[1]; + srsran_pucch_nr_resource_t& pucch2 = phy_cfg.pucch.sets[0].resources[2]; + srsran_pucch_nr_resource_t& pucch3 = phy_cfg.pucch.sets[0].resources[3]; + srsran_pucch_nr_resource_t& pucch4 = phy_cfg.pucch.sets[0].resources[4]; + srsran_pucch_nr_resource_t& pucch5 = phy_cfg.pucch.sets[0].resources[5]; + srsran_pucch_nr_resource_t& pucch6 = phy_cfg.pucch.sets[0].resources[6]; + srsran_pucch_nr_resource_t& pucch7 = phy_cfg.pucch.sets[0].resources[7]; + phy_cfg.pucch.sets[0].nof_resources = 8; + srsran_pucch_nr_resource_t& pucch8 = phy_cfg.pucch.sets[1].resources[0]; + srsran_pucch_nr_resource_t& pucch9 = phy_cfg.pucch.sets[1].resources[1]; + srsran_pucch_nr_resource_t& pucch10 = phy_cfg.pucch.sets[1].resources[2]; + srsran_pucch_nr_resource_t& pucch11 = phy_cfg.pucch.sets[1].resources[3]; + srsran_pucch_nr_resource_t& pucch12 = phy_cfg.pucch.sets[1].resources[4]; + srsran_pucch_nr_resource_t& pucch13 = phy_cfg.pucch.sets[1].resources[5]; + srsran_pucch_nr_resource_t& pucch14 = phy_cfg.pucch.sets[1].resources[6]; + srsran_pucch_nr_resource_t& pucch15 = phy_cfg.pucch.sets[1].resources[7]; + phy_cfg.pucch.sets[1].nof_resources = 8; + + pucch0.starting_prb = 0; + pucch0.format = SRSRAN_PUCCH_NR_FORMAT_1; + pucch0.initial_cyclic_shift = 0; + pucch0.nof_symbols = 14; + pucch0.start_symbol_idx = 0; + pucch0.time_domain_occ = 0; + pucch1 = pucch0; + pucch1.initial_cyclic_shift = 4; + pucch1.time_domain_occ = 0; + pucch2 = pucch0; + pucch2.initial_cyclic_shift = 8; + pucch2.time_domain_occ = 0; + pucch3 = pucch0; + pucch3.initial_cyclic_shift = 0; + pucch3.time_domain_occ = 1; + pucch4 = pucch0; + pucch4.initial_cyclic_shift = 0; + pucch4.time_domain_occ = 1; + pucch5 = pucch0; + pucch5.initial_cyclic_shift = 4; + pucch5.time_domain_occ = 1; + pucch6 = pucch0; + pucch6.initial_cyclic_shift = 0; + pucch6.time_domain_occ = 2; + pucch7 = pucch0; + pucch7.initial_cyclic_shift = 4; + pucch7.time_domain_occ = 2; + + pucch8.starting_prb = 51; + pucch8.format = SRSRAN_PUCCH_NR_FORMAT_2; + pucch8.nof_prb = 1; + pucch8.nof_symbols = 2; + pucch8.start_symbol_idx = 0; + + pucch9 = pucch8; + pucch9.start_symbol_idx = 2; + pucch10 = pucch8; + pucch10.start_symbol_idx = 4; + pucch11 = pucch8; + pucch11.start_symbol_idx = 6; + pucch12 = pucch8; + pucch12.start_symbol_idx = 8; + pucch13 = pucch8; + pucch13.start_symbol_idx = 10; + pucch14 = pucch8; + pucch14.start_symbol_idx = 12; + pucch15 = pucch8; + pucch15.starting_prb = 1; + pucch15.start_symbol_idx = 0; + + srsran_pucch_nr_resource_t& pucch16 = phy_cfg.pucch.sr_resources[1].resource; + pucch16.starting_prb = 0; + pucch16.format = SRSRAN_PUCCH_NR_FORMAT_1; + pucch16.initial_cyclic_shift = 8; + pucch16.nof_symbols = 14; + pucch16.start_symbol_idx = 0; + pucch16.time_domain_occ = 2; + + phy_cfg.pucch.sr_resources[1].configured = true; + phy_cfg.pucch.sr_resources[1].sr_id = 0; + phy_cfg.pucch.sr_resources[1].period = 40; + phy_cfg.pucch.sr_resources[1].offset = 8; + phy_cfg.pucch.sr_resources[1].resource = pucch16; + + phy_cfg.harq_ack.dl_data_to_ul_ack[0] = 8; + phy_cfg.harq_ack.dl_data_to_ul_ack[1] = 7; + phy_cfg.harq_ack.dl_data_to_ul_ack[2] = 6; + phy_cfg.harq_ack.dl_data_to_ul_ack[3] = 5; + 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.prach.freq_offset = 2; + + // pusch-Config: setup (1) + // setup + // dmrs-UplinkForPUSCH-MappingTypeA: setup (1) + // setup + // dmrs-AdditionalPosition: pos1 (1) + // transformPrecodingDisabled + // pusch-PowerControl + // msg3-Alpha: alpha1 (7) + // p0-NominalWithoutGrant: -90dBm + // p0-AlphaSets: 1 item + // Item 0 + // P0-PUSCH-AlphaSet + // p0-PUSCH-AlphaSetId: 0 + // p0: 0dB + // alpha: alpha1 (7) + // pathlossReferenceRSToAddModList: 1 item + // Item 0 + // PUSCH-PathlossReferenceRS + // pusch-PathlossReferenceRS-Id: 0 + // referenceSignal: ssb-Index (0) + // ssb-Index: 0 + // sri-PUSCH-MappingToAddModList: 1 item + // Item 0 + // SRI-PUSCH-PowerControl + // sri-PUSCH-PowerControlId: 0 + // sri-PUSCH-PathlossReferenceRS-Id: 0 + // sri-P0-PUSCH-AlphaSetId: 0 + // sri-PUSCH-ClosedLoopIndex: i0 (0) + // resourceAllocation: resourceAllocationType1 (1) + // uci-OnPUSCH: setup (1) + // setup + // betaOffsets: semiStatic (1) + // semiStatic + // betaOffsetACK-Index1: 9 + // betaOffsetACK-Index2: 9 + // betaOffsetACK-Index3: 9 + // betaOffsetCSI-Part1-Index1: 6 + // betaOffsetCSI-Part1-Index2: 6 + // betaOffsetCSI-Part2-Index1: 6 + // betaOffsetCSI-Part2-Index2: 6 + // scaling: f1 (3) + // srs-Config: setup (1) + // setup + // srs-ResourceSetToAddModList: 1 item + // Item 0 + // SRS-ResourceSet + // srs-ResourceSetId: 0 + // srs-ResourceIdList: 1 item + // Item 0 + // SRS-ResourceId: 0 + // resourceType: aperiodic (0) + // aperiodic + // aperiodicSRS-ResourceTrigger: 1 + // slotOffset: 7 + // usage: codebook (1) + // p0: -90dBm + // pathlossReferenceRS: ssb-Index (0) + // ssb-Index: 0 + // srs-ResourceToAddModList: 1 item + // Item 0 + // SRS-Resource + // srs-ResourceId: 0 + // nrofSRS-Ports: port1 (0) + // transmissionComb: n2 (0) + // n2 + // combOffset-n2: 0 + // cyclicShift-n2: 0 + // resourceMapping + // startPosition: 0 + // nrofSymbols: n1 (0) + // repetitionFactor: n1 (0) + // freqDomainPosition: 0 + // freqDomainShift: 6 + // freqHopping + // c-SRS: 11 + // b-SRS: 3 + // b-hop: 0 + // groupOrSequenceHopping: neither (0) + // resourceType: aperiodic (0) + // aperiodic + // sequenceId: 500 + // firstActiveUplinkBWP-Id: 0 + // pusch-ServingCellConfig: setup (1) + // setup + // pdcch-ServingCellConfig: setup (1) + // setup + // pdsch-ServingCellConfig: setup (1) + // setup + // nrofHARQ-ProcessesForPDSCH: n16 (5) + // csi-MeasConfig: setup (1) + // setup + // nzp-CSI-RS-ResourceToAddModList: 5 items + // Item 0 + // NZP-CSI-RS-Resource + // nzp-CSI-RS-ResourceId: 0 + // resourceMapping + // frequencyDomainAllocation: row2 (1) + // row2: 8000 [bit length 12, 4 LSB pad bits, 1000 0000 0000 + // .... decimal value 2048] + // nrofPorts: p1 (0) + // firstOFDMSymbolInTimeDomain: 4 + // cdm-Type: noCDM (0) + // density: one (1) + // one: NULL + // freqBand + // startingRB: 0 + // nrofRBs: 52 + // powerControlOffset: 0dB + // powerControlOffsetSS: db0 (1) + // scramblingID: 0 + // periodicityAndOffset: slots80 (9) + // slots80: 1 + // qcl-InfoPeriodicCSI-RS: 0 + // Item 1 + // NZP-CSI-RS-Resource + // nzp-CSI-RS-ResourceId: 1 + // resourceMapping + // frequencyDomainAllocation: row1 (0) + // row1: 10 [bit length 4, 4 LSB pad bits, 0001 .... decimal + // value 1] + // nrofPorts: p1 (0) + // firstOFDMSymbolInTimeDomain: 4 + // cdm-Type: noCDM (0) + // density: three (2) + // three: NULL + // freqBand + // startingRB: 0 + // nrofRBs: 52 + // powerControlOffset: 0dB + // powerControlOffsetSS: db0 (1) + // scramblingID: 0 + // periodicityAndOffset: slots40 (7) + // slots40: 11 + // qcl-InfoPeriodicCSI-RS: 0 + // Item 2 + // NZP-CSI-RS-Resource + // nzp-CSI-RS-ResourceId: 2 + // resourceMapping + // frequencyDomainAllocation: row1 (0) + // row1: 10 [bit length 4, 4 LSB pad bits, 0001 .... decimal + // value 1] + // nrofPorts: p1 (0) + // firstOFDMSymbolInTimeDomain: 8 + // cdm-Type: noCDM (0) + // density: three (2) + // three: NULL + // freqBand + // startingRB: 0 + // nrofRBs: 52 + // powerControlOffset: 0dB + // powerControlOffsetSS: db0 (1) + // scramblingID: 0 + // periodicityAndOffset: slots40 (7) + // slots40: 11 + // qcl-InfoPeriodicCSI-RS: 0 + // Item 3 + // NZP-CSI-RS-Resource + // nzp-CSI-RS-ResourceId: 3 + // resourceMapping + // frequencyDomainAllocation: row1 (0) + // row1: 10 [bit length 4, 4 LSB pad bits, 0001 .... decimal + // value 1] + // nrofPorts: p1 (0) + // firstOFDMSymbolInTimeDomain: 4 + // cdm-Type: noCDM (0) + // density: three (2) + // three: NULL + // freqBand + // startingRB: 0 + // nrofRBs: 52 + // powerControlOffset: 0dB + // powerControlOffsetSS: db0 (1) + // scramblingID: 0 + // periodicityAndOffset: slots40 (7) + // slots40: 12 + // qcl-InfoPeriodicCSI-RS: 0 + // Item 4 + // NZP-CSI-RS-Resource + // nzp-CSI-RS-ResourceId: 4 + // resourceMapping + // frequencyDomainAllocation: row1 (0) + // row1: 10 [bit length 4, 4 LSB pad bits, 0001 .... decimal + // value 1] + // nrofPorts: p1 (0) + // firstOFDMSymbolInTimeDomain: 8 + // cdm-Type: noCDM (0) + // density: three (2) + // three: NULL + // freqBand + // startingRB: 0 + // nrofRBs: 52 + // powerControlOffset: 0dB + // powerControlOffsetSS: db0 (1) + // scramblingID: 0 + // periodicityAndOffset: slots40 (7) + // slots40: 12 + // qcl-InfoPeriodicCSI-RS: 0 + // nzp-CSI-RS-ResourceSetToAddModList: 2 items + // Item 0 + // NZP-CSI-RS-ResourceSet + // nzp-CSI-ResourceSetId: 0 + // nzp-CSI-RS-Resources: 1 item + // Item 0 + // NZP-CSI-RS-ResourceId: 0 + // Item 1 + // NZP-CSI-RS-ResourceSet + // nzp-CSI-ResourceSetId: 1 + // nzp-CSI-RS-Resources: 4 items + // Item 0 + // NZP-CSI-RS-ResourceId: 1 + // Item 1 + // NZP-CSI-RS-ResourceId: 2 + // Item 2 + // NZP-CSI-RS-ResourceId: 3 + // Item 3 + // NZP-CSI-RS-ResourceId: 4 + // trs-Info: true (0) + // csi-IM-ResourceToAddModList: 1 item + // Item 0 + // CSI-IM-Resource + // csi-IM-ResourceId: 0 + // csi-IM-ResourceElementPattern: pattern1 (1) + // pattern1 + // subcarrierLocation-p1: s8 (2) + // symbolLocation-p1: 8 + // freqBand + // startingRB: 0 + // nrofRBs: 52 + // periodicityAndOffset: slots80 (9) + // slots80: 1 + // csi-IM-ResourceSetToAddModList: 1 item + // Item 0 + // CSI-IM-ResourceSet + // csi-IM-ResourceSetId: 0 + // csi-IM-Resources: 1 item + // Item 0 + // CSI-IM-ResourceId: 0 + // csi-ResourceConfigToAddModList: 3 items + // Item 0 + // CSI-ResourceConfig + // csi-ResourceConfigId: 0 + // csi-RS-ResourceSetList: nzp-CSI-RS-SSB (0) + // nzp-CSI-RS-SSB + // nzp-CSI-RS-ResourceSetList: 1 item + // Item 0 + // NZP-CSI-RS-ResourceSetId: 0 + // bwp-Id: 0 + // resourceType: periodic (2) + // Item 1 + // CSI-ResourceConfig + // csi-ResourceConfigId: 1 + // csi-RS-ResourceSetList: csi-IM-ResourceSetList (1) + // csi-IM-ResourceSetList: 1 item + // Item 0 + // CSI-IM-ResourceSetId: 0 + // bwp-Id: 0 + // resourceType: periodic (2) + // Item 2 + // CSI-ResourceConfig + // csi-ResourceConfigId: 2 + // csi-RS-ResourceSetList: nzp-CSI-RS-SSB (0) + // nzp-CSI-RS-SSB + // nzp-CSI-RS-ResourceSetList: 1 item + // Item 0 + // NZP-CSI-RS-ResourceSetId: 1 + // bwp-Id: 0 + // resourceType: periodic (2) + // csi-ReportConfigToAddModList: 1 item + // Item 0 + // CSI-ReportConfig + // reportConfigId: 0 + // resourcesForChannelMeasurement: 0 + // csi-IM-ResourcesForInterference: 1 + // reportConfigType: periodic (0) + // periodic + // reportSlotConfig: slots80 (7) + // slots80: 9 + // pucch-CSI-ResourceList: 1 item + // Item 0 + // PUCCH-CSI-Resource + // uplinkBandwidthPartId: 0 + // pucch-Resource: 17 + // reportQuantity: cri-RI-PMI-CQI (1) + // cri-RI-PMI-CQI: NULL + // reportFreqConfiguration + // cqi-FormatIndicator: widebandCQI (0) + // timeRestrictionForChannelMeasurements: notConfigured (1) + // timeRestrictionForInterferenceMeasurements: notConfigured (1) + // groupBasedBeamReporting: disabled (1) + // disabled + // cqi-Table: table2 (1) + // subbandSize: value1 (0) + // tag-Id: 0 +} + +class ue_dummy_stack : public srsue::stack_interface_phy_nr +{ +public: + void in_sync() override {} + void out_of_sync() override {} + void run_tti(const uint32_t tti) override {} + int sf_indication(const uint32_t tti) override { return 0; } + sched_rnti_t get_dl_sched_rnti_nr(const uint32_t tti) override { return sched_rnti_t(); } + sched_rnti_t get_ul_sched_rnti_nr(const uint32_t tti) override { return sched_rnti_t(); } + void new_grant_dl(const uint32_t cc_idx, const mac_nr_grant_dl_t& grant, tb_action_dl_t* action) override {} + void tb_decoded(const uint32_t cc_idx, const mac_nr_grant_dl_t& grant, tb_action_dl_result_t result) override {} + void new_grant_ul(const uint32_t cc_idx, const mac_nr_grant_ul_t& grant, tb_action_ul_t* action) override {} + void prach_sent(uint32_t tti, uint32_t s_id, uint32_t t_id, uint32_t f_id, uint32_t ul_carrier_id) override {} + bool sr_opportunity(uint32_t tti, uint32_t sr_id, bool meas_gap, bool ul_sch_tx) override { return false; } +}; + +class gnb_dummy_stack : public srsenb::stack_interface_phy_nr +{ +public: + 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 + { + dl_sched_res[0].nof_grants = 0; + 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) +{ + test_bench::args_t args(argc, argv); + + // Parse arguments + TESTASSERT(args.valid); + + ue_dummy_stack ue_stack; + gnb_dummy_stack gnb_stack; + + // Create test bench + test_bench tb(args, gnb_stack, ue_stack); + + // Assert bench is initialised correctly + TESTASSERT(tb.is_initialised()); + + for (uint32_t i = 0; i < 1000; i++) { + TESTASSERT(tb.run_tti()); + } + + // If reached here, the test is successful + return SRSRAN_SUCCESS; +} \ No newline at end of file diff --git a/test/phy/nr_phy_test.cc b/test/phy/nr_phy_test.cc deleted file mode 100644 index 7d4f7b825..000000000 --- a/test/phy/nr_phy_test.cc +++ /dev/null @@ -1,113 +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/worker_pool.h" -#include "srsran/common/test_common.h" -#include "srsue/hdr/phy/nr/worker_pool.h" - -class phy_common : public srsran::phy_common_interface -{ -public: - void - worker_end(void* h, bool tx_enable, srsran::rf_buffer_t& buffer, srsran::rf_timestamp_t& tx_time, bool is_nr) override - {} -}; - -class ue_dummy_stack : public srsue::stack_interface_phy_nr -{ -public: - void in_sync() override {} - void out_of_sync() override {} - void run_tti(const uint32_t tti) override {} - int sf_indication(const uint32_t tti) override { return 0; } - sched_rnti_t get_dl_sched_rnti_nr(const uint32_t tti) override { return sched_rnti_t(); } - sched_rnti_t get_ul_sched_rnti_nr(const uint32_t tti) override { return sched_rnti_t(); } - void new_grant_dl(const uint32_t cc_idx, const mac_nr_grant_dl_t& grant, tb_action_dl_t* action) override {} - void tb_decoded(const uint32_t cc_idx, const mac_nr_grant_dl_t& grant, tb_action_dl_result_t result) override {} - void new_grant_ul(const uint32_t cc_idx, const mac_nr_grant_ul_t& grant, tb_action_ul_t* action) override {} - void prach_sent(uint32_t tti, uint32_t s_id, uint32_t t_id, uint32_t f_id, uint32_t ul_carrier_id) override {} - bool sr_opportunity(uint32_t tti, uint32_t sr_id, bool meas_gap, bool ul_sch_tx) override { return false; } -}; - -class test_bench -{ -private: - srsenb::nr::worker_pool gnb_phy; - phy_common gnb_phy_com; - srsue::nr::worker_pool ue_phy; - phy_common ue_phy_com; - ue_dummy_stack ue_stack; - bool initialised = false; - -public: - struct args_t { - uint32_t nof_threads = 6; - uint32_t nof_prb = 52; - - bool parse(int argc, char** argv); - }; - - test_bench(const args_t& args) : ue_phy(args.nof_threads), gnb_phy(args.nof_threads) - { - // Prepare cell list - srsenb::phy_cell_cfg_list_nr_t cell_list(1); - cell_list[0].carrier.nof_prb = args.nof_prb; - - // Prepare gNb PHY arguments - srsenb::phy_args_t gnb_phy_args = {}; - - // Initialise gnb - if (not gnb_phy.init(cell_list, gnb_phy_args, gnb_phy_com, srslog::get_default_sink(), 31)) { - return; - } - - // Prepare PHY - srsue::phy_args_nr_t ue_phy_args = {}; - - // Initialise UE PHY - if (not ue_phy.init(ue_phy_args, ue_phy_com, &ue_stack, 31)) { - return; - } - - initialised = true; - } - - ~test_bench() - { - gnb_phy.stop(); - ue_phy.stop(); - } - - bool is_initialised() const { return initialised; } -}; - -bool test_bench::args_t::parse(int argc, char** argv) -{ - return true; -} - -int main(int argc, char** argv) -{ - test_bench::args_t args = {}; - - // Parse arguments - TESTASSERT(args.parse(argc, argv)); - - // Create test bench - test_bench tb(args); - - // Assert bench is initialised correctly - TESTASSERT(tb.is_initialised()); - - // If reached here, the test is successful - return SRSRAN_SUCCESS; -} \ No newline at end of file diff --git a/test/phy/test_bench.h b/test/phy/test_bench.h new file mode 100644 index 000000000..ff572d958 --- /dev/null +++ b/test/phy/test_bench.h @@ -0,0 +1,131 @@ +/** + * + * \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_TEST_BENCH_H +#define SRSRAN_TEST_BENCH_H + +#include "dummy_phy_common.h" +#include "srsenb/hdr/phy/nr/worker_pool.h" +#include "srsue/hdr/phy/nr/worker_pool.h" + +class test_bench +{ +private: + uint32_t tti = 0; + srsenb::nr::worker_pool gnb_phy; + phy_common gnb_phy_com; + srsue::nr::worker_pool ue_phy; + phy_common ue_phy_com; + bool initialised = false; + uint32_t sf_sz = 0; + +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; + srsran::phy_cfg_nr_t phy_cfg = {}; + srsenb::phy_cell_cfg_list_nr_t cell_list = {}; + srsenb::nr::worker_pool::args_t gnb_args; + uint16_t rnti = 0x1234; + + args_t(int argc, char** argv); + }; + + 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_com(phy_common::args_t(args.srate_hz, args.buffer_sz_ms, args.nof_channels), + srslog::fetch_basic_logger("UE /PHY/COM")), + gnb_phy_com(phy_common::args_t(args.srate_hz, args.buffer_sz_ms, args.nof_channels), + srslog::fetch_basic_logger("GNB/PHY/COM")) + { + // Calculate subframe length + sf_sz = (uint32_t)std::round(args.srate_hz * 1e-3); + + // Prepare PHY + srsue::phy_args_nr_t ue_phy_args = {}; + + // Initialise UE PHY + if (not ue_phy.init(ue_phy_args, ue_phy_com, &ue_stack, 31)) { + return; + } + + // Set UE configuration + if (not ue_phy.set_config(args.phy_cfg)) { + return; + } + + initialised = true; + } + + ~test_bench() + { + ue_phy_com.stop(); + gnb_phy_com.stop(); + gnb_phy.stop(); + ue_phy.stop(); + } + + bool is_initialised() const { return initialised; } + + bool run_tti() + { + // Get gNb worker + srsenb::nr::sf_worker* gnb_worker = gnb_phy.wait_worker(tti); + if (gnb_worker == nullptr) { + return false; + } + + // Feed gNb the UE transmitted signal + srsran::rf_timestamp_t gnb_time = {}; + std::vector gnb_rx_buffers(1); + gnb_rx_buffers[0] = gnb_worker->get_buffer_rx(0, 0); + ue_phy_com.read(gnb_rx_buffers, sf_sz, gnb_time); + + // Set gNb time + gnb_time.add(TX_ENB_DELAY * 1e-3); + gnb_worker->set_time(tti, gnb_time); + + // Start gNb work + gnb_phy_com.push_semaphore(gnb_worker); + gnb_phy.start_worker(gnb_worker); + + // Get UE worker + srsue::nr::sf_worker* ue_worker = ue_phy.wait_worker(tti); + if (ue_worker == nullptr) { + return false; + } + + // Feed UE the gNb transmitted signal + srsran::rf_timestamp_t ue_time = {}; + std::vector ue_rx_buffers(1); + ue_rx_buffers[0] = ue_worker->get_buffer(0, 0); + gnb_phy_com.read(ue_rx_buffers, sf_sz, ue_time); + + // Set UE time + ue_time.add(TX_ENB_DELAY * 1e-3); + ue_worker->set_tti(tti); + ue_worker->set_tx_time(ue_time); + + // Start gNb work + ue_phy_com.push_semaphore(ue_worker); + ue_phy.start_worker(ue_worker); + + tti++; + return true; + } +}; + +#endif // SRSRAN_TEST_BENCH_H