diff --git a/lib/include/srsran/interfaces/gnb_interfaces.h b/lib/include/srsran/interfaces/gnb_interfaces.h index f8f41b677..c061c58cc 100644 --- a/lib/include/srsran/interfaces/gnb_interfaces.h +++ b/lib/include/srsran/interfaces/gnb_interfaces.h @@ -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 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; + uint32_t pdcch_dl_count = 0; + std::array pdcch_ul; + uint32_t pdcch_ul_count = 0; + std::array pdsch; + uint32_t pdsch_count = 0; }; - /** - * 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; + struct pusch_t { + srsran_sch_cfg_nr_t sch = {}; ///< PUSCH configuration + std::array data = {}; ///< Data pointer + std::array softbuffer_tx = {}; ///< Tx Softbuffer }; - /** - * 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 + struct uci_t { + srsran_uci_cfg_nr_t cfg; }; - /** - * List of UL scheduling results, one entry per cell/carrier - */ - typedef std::vector ul_sched_list_t; + struct ul_sched_t { + std::array pusch; + uint32_t pusch_count = 0; + std::array uci; + uint32_t uci_count; + }; - 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 diff --git a/lib/include/srsran/phy/enb/enb_dl_nr.h b/lib/include/srsran/phy/enb/enb_dl_nr.h index 4e5601a1e..edc7c8ac5 100644 --- a/lib/include/srsran/phy/enb/enb_dl_nr.h +++ b/lib/include/srsran/phy/enb/enb_dl_nr.h @@ -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 diff --git a/lib/src/phy/enb/enb_dl_nr.c b/lib/src/phy/enb/enb_dl_nr.c index b78928e02..f98cc411c 100644 --- a/lib/src/phy/enb/enb_dl_nr.c +++ b/lib/src/phy/enb/enb_dl_nr.c @@ -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; +} diff --git a/lib/test/phy/phy_dl_nr_test.c b/lib/test/phy/phy_dl_nr_test.c index d9fd1960f..c07bed2a9 100644 --- a/lib/test/phy/phy_dl_nr_test.c +++ b/lib/test/phy/phy_dl_nr_test.c @@ -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; } diff --git a/srsenb/hdr/phy/nr/cc_worker.h b/srsenb/hdr/phy/nr/cc_worker.h deleted file mode 100644 index e08eaf961..000000000 --- a/srsenb/hdr/phy/nr/cc_worker.h +++ /dev/null @@ -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 -#include - -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 tx_buffer = {}; - std::array 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 diff --git a/srsenb/hdr/phy/nr/phy_nr_state.h b/srsenb/hdr/phy/nr/phy_nr_state.h deleted file mode 100644 index 64468a80f..000000000 --- a/srsenb/hdr/phy/nr/phy_nr_state.h +++ /dev/null @@ -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 -#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); - - 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_ diff --git a/srsenb/hdr/phy/nr/sf_worker.h b/srsenb/hdr/phy/nr/sf_worker.h deleted file mode 100644 index 20189e8d9..000000000 --- a/srsenb/hdr/phy/nr/sf_worker.h +++ /dev/null @@ -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 > 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 data; -}; - -} // namespace nr -} // namespace srsenb - -#endif // SRSENB_NR_PHCH_WORKER_H diff --git a/srsenb/hdr/phy/nr/slot_worker.h b/srsenb/hdr/phy/nr/slot_worker.h new file mode 100644 index 000000000..7756b2116 --- /dev/null +++ b/srsenb/hdr/phy/nr/slot_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 tx_buffer; ///< Baseband transmit buffers + std::vector rx_buffer; ///< Baseband receive buffers +}; + +} // namespace nr +} // namespace srsenb + +#endif // SRSENB_NR_PHCH_WORKER_H diff --git a/srsenb/hdr/phy/nr/worker_pool.h b/srsenb/hdr/phy/nr/worker_pool.h index d909e4be1..5d648efbf 100644 --- a/srsenb/hdr/phy/nr/worker_pool.h +++ b/srsenb/hdr/phy/nr/worker_pool.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 > 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 > 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 diff --git a/srsenb/hdr/phy/phy_interfaces.h b/srsenb/hdr/phy/phy_interfaces.h index b1e8d59cf..35dee14c2 100644 --- a/srsenb/hdr/phy/phy_interfaces.h +++ b/srsenb/hdr/phy/phy_interfaces.h @@ -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 #include @@ -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_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; diff --git a/srsenb/hdr/stack/gnb_stack_nr.h b/srsenb/hdr/stack/gnb_stack_nr.h index 90b108807..549791e32 100644 --- a/srsenb/hdr/stack/gnb_stack_nr.h +++ b/srsenb/hdr/stack/gnb_stack_nr.h @@ -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; diff --git a/srsenb/hdr/stack/mac/mac_nr.h b/srsenb/hdr/stack/mac/mac_nr.h index 274efb74b..7290dfcbd 100644 --- a/srsenb/hdr/stack/mac/mac_nr.h +++ b/srsenb/hdr/stack/mac/mac_nr.h @@ -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, diff --git a/srsenb/src/phy/CMakeLists.txt b/srsenb/src/phy/CMakeLists.txt index 60061af9f..66c4db7b2 100644 --- a/srsenb/src/phy/CMakeLists.txt +++ b/srsenb/src/phy/CMakeLists.txt @@ -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 diff --git a/srsenb/src/phy/nr/cc_worker.cc b/srsenb/src/phy/nr/cc_worker.cc deleted file mode 100644 index cadb736fb..000000000 --- a/srsenb/src/phy/nr/cc_worker.cc +++ /dev/null @@ -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 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 diff --git a/srsenb/src/phy/nr/phy_nr_state.cc b/srsenb/src/phy/nr/phy_nr_state.cc deleted file mode 100644 index 80c271b28..000000000 --- a/srsenb/src/phy/nr/phy_nr_state.cc +++ /dev/null @@ -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 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; -} - -int phy_nr_state::get_config(uint16_t rnti, srsran::phy_cfg_nr_t& phy_cfg) -{ - std::lock_guard lock(mutex); - - return _get_rnti_config(rnti, phy_cfg); -} - -} // 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 deleted file mode 100644 index 662b77ca9..000000000 --- a/srsenb/src/phy/nr/sf_worker.cc +++ /dev/null @@ -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(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 \ No newline at end of file diff --git a/srsenb/src/phy/nr/slot_worker.cc b/srsenb/src/phy/nr/slot_worker.cc new file mode 100644 index 000000000..c47a4572e --- /dev/null +++ b/srsenb/src/phy/nr/slot_worker.cc @@ -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 + +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 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 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 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 \ No newline at end of file diff --git a/srsenb/src/phy/nr/worker_pool.cc b/srsenb/src/phy/nr/worker_pool.cc index dd8726334..b2a16999f 100644 --- a/srsenb/src/phy/nr/worker_pool.cc +++ b/srsenb/src/phy/nr/worker_pool.cc @@ -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(w)); + workers.push_back(std::unique_ptr(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 \ No newline at end of file diff --git a/srsenb/src/phy/txrx.cc b/srsenb/src/phy/txrx.cc index 326114faa..c05633c2f 100644 --- a/srsenb/src/phy/txrx.cc +++ b/srsenb/src/phy/txrx.cc @@ -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)); } } } diff --git a/srsenb/src/stack/gnb_stack_nr.cc b/srsenb/src/stack/gnb_stack_nr.cc index cf90c2393..cafe2e7c3 100644 --- a/srsenb/src/stack/gnb_stack_nr.cc +++ b/srsenb/src/stack/gnb_stack_nr.cc @@ -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 diff --git a/srsenb/src/stack/mac/nr/mac_nr.cc b/srsenb/src/stack/mac/nr/mac_nr.cc index 4ae51e0e3..66ba30c0f 100644 --- a/srsenb/src/stack/mac/nr/mac_nr.cc +++ b/srsenb/src/stack/mac/nr/mac_nr.cc @@ -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; } diff --git a/srsenb/test/phy/enb_phy_test.cc b/srsenb/test/phy/enb_phy_test.cc index f2014e637..016aee059 100644 --- a/srsenb/test/phy/enb_phy_test.cc +++ b/srsenb/test/phy/enb_phy_test.cc @@ -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 #include #include @@ -22,7 +22,6 @@ #include #include #include -#include static inline bool dl_ack_value(uint32_t ue_cc_idx, uint32_t tti) { diff --git a/test/phy/dummy_gnb_stack.h b/test/phy/dummy_gnb_stack.h new file mode 100644 index 000000000..4536ac999 --- /dev/null +++ b/test/phy/dummy_gnb_stack.h @@ -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 +#include +#include + +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 dci_dl_location; + srsran::circular_array dci_ul_location; + srsran::circular_array 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 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 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 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 diff --git a/test/phy/dummy_phy_common.h b/test/phy/dummy_phy_common.h index 2f898e90b..bb7d4a992 100644 --- a/test/phy/dummy_phy_common.h +++ b/test/phy/dummy_phy_common.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 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::mutex ringbuffers_mutex; std::vector ringbuffers; srsran::tti_semaphore 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 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& buffers, uint32_t nof_samples, srsran::rf_timestamp_t& timestamp) { + // Protect internal buffers and states + std::unique_lock 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); diff --git a/test/phy/nr_dl_flood.cc b/test/phy/nr_dl_flood.cc index 2407b3b18..26c5bd04e 100644 --- a/test/phy/nr_dl_flood.cc +++ b/test/phy/nr_dl_flood.cc @@ -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 pdsch_mask; - srsran::circular_array dci_dl_location; - srsran::circular_array dci_ul_location; - srsran::circular_array 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 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 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 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 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); diff --git a/test/phy/test_bench.h b/test/phy/test_bench.h index b878cb355..11425de6f 100644 --- a/test/phy/test_bench.h +++ b/test/phy/test_bench.h @@ -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 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