From a908fb6c5bd6c306a25b1c06cbcc5e713967d6fc Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Wed, 18 Nov 2020 14:48:43 +0100 Subject: [PATCH] Fix NR srsue/srsenb. Initial PHY NR in SRSENB. --- lib/include/srslte/phy/enb/enb_dl_nr.h | 8 ++ lib/include/srslte/phy/fec/softbuffer.h | 8 ++ lib/include/srslte/phy/phch/pdsch_cfg_nr.h | 8 ++ lib/include/srslte/phy/phch/ra_nr.h | 9 ++ lib/include/srslte/phy/ue/ue_dl_nr_data.h | 8 ++ srsenb/hdr/phy/nr/cc_worker.h | 90 +++++++++++++ srsenb/hdr/phy/nr/sf_worker.h | 68 ++++++++++ srsenb/hdr/phy/nr/worker_pool.h | 55 ++++++++ srsenb/hdr/phy/phy_common.h | 105 ++++++++++++---- srsenb/hdr/phy/phy_interfaces.h | 18 ++- srsenb/hdr/phy/txrx.h | 16 +-- srsenb/src/phy/CMakeLists.txt | 13 +- srsenb/src/phy/lte/worker_pool.cc | 21 ---- srsenb/src/phy/nr/cc_worker.cc | 140 +++++++++++++++++++++ srsenb/src/phy/nr/sf_worker.cc | 82 ++++++++++++ srsenb/src/phy/nr/worker_pool.cc | 73 +++++++++++ srsenb/src/phy/phy.cc | 2 +- srsenb/src/phy/phy_common.cc | 18 +-- srsenb/src/phy/txrx.cc | 96 ++++++++------ srsue/hdr/phy/nr/cc_worker.h | 1 + srsue/src/phy/nr/cc_worker.cc | 2 + 21 files changed, 739 insertions(+), 102 deletions(-) create mode 100644 srsenb/hdr/phy/nr/cc_worker.h create mode 100644 srsenb/hdr/phy/nr/sf_worker.h create mode 100644 srsenb/hdr/phy/nr/worker_pool.h create mode 100644 srsenb/src/phy/nr/cc_worker.cc create mode 100644 srsenb/src/phy/nr/sf_worker.cc create mode 100644 srsenb/src/phy/nr/worker_pool.cc diff --git a/lib/include/srslte/phy/enb/enb_dl_nr.h b/lib/include/srslte/phy/enb/enb_dl_nr.h index 0f822164b..a203ca075 100644 --- a/lib/include/srslte/phy/enb/enb_dl_nr.h +++ b/lib/include/srslte/phy/enb/enb_dl_nr.h @@ -17,6 +17,10 @@ #include "srslte/phy/dft/ofdm.h" #include "srslte/phy/phch/pdsch_nr.h" +#ifdef __cplusplus +extern "C" { +#endif + typedef struct SRSLTE_API { srslte_pdsch_args_t pdsch; uint32_t nof_tx_antennas; @@ -49,4 +53,8 @@ SRSLTE_API int srslte_enb_dl_nr_pdsch_put(srslte_enb_dl_nr_t* q, const srslte_pdsch_grant_nr_t* grant, uint8_t* data[SRSLTE_MAX_TB]); +#ifdef __cplusplus +} +#endif + #endif // SRSLTE_ENB_DL_NR_H diff --git a/lib/include/srslte/phy/fec/softbuffer.h b/lib/include/srslte/phy/fec/softbuffer.h index 10a2593b3..a16a55962 100644 --- a/lib/include/srslte/phy/fec/softbuffer.h +++ b/lib/include/srslte/phy/fec/softbuffer.h @@ -24,6 +24,10 @@ #include "srslte/config.h" +#ifdef __cplusplus +extern "C" { +#endif + typedef struct SRSLTE_API { uint32_t max_cb; uint32_t max_cb_size; @@ -79,4 +83,8 @@ SRSLTE_API void srslte_softbuffer_tx_reset_cb(srslte_softbuffer_tx_t* q, uint32_ SRSLTE_API void srslte_softbuffer_tx_free(srslte_softbuffer_tx_t* p); +#ifdef __cplusplus +} +#endif + #endif // SRSLTE_SOFTBUFFER_H diff --git a/lib/include/srslte/phy/phch/pdsch_cfg_nr.h b/lib/include/srslte/phy/phch/pdsch_cfg_nr.h index 3942039a6..37398400a 100644 --- a/lib/include/srslte/phy/phch/pdsch_cfg_nr.h +++ b/lib/include/srslte/phy/phch/pdsch_cfg_nr.h @@ -24,6 +24,10 @@ #include "srslte/phy/common/phy_common_nr.h" #include "srslte/phy/phch/sch_cfg_nr.h" +#ifdef __cplusplus +extern "C" { +#endif + /** * @brief PDSCH DMRS type */ @@ -146,4 +150,8 @@ typedef struct SRSLTE_API { srslte_sch_cfg_t sch_cfg; ///< Common shared channel parameters } srslte_pdsch_cfg_nr_t; +#ifdef __cplusplus +} +#endif + #endif // SRSLTE_PDSCH_CFG_NR_H diff --git a/lib/include/srslte/phy/phch/ra_nr.h b/lib/include/srslte/phy/phch/ra_nr.h index 67d294b14..00e44fe7e 100644 --- a/lib/include/srslte/phy/phch/ra_nr.h +++ b/lib/include/srslte/phy/phch/ra_nr.h @@ -28,6 +28,10 @@ #include "srslte/phy/common/phy_common_nr.h" #include "srslte/phy/phch/pdsch_cfg_nr.h" +#ifdef __cplusplus +extern "C" { +#endif + /** * @brief Determines the number of resource elements available for a given PDSCH transmission * @param pdsch_cfg PDSCH configuration provided by higher layers @@ -52,4 +56,9 @@ SRSLTE_API int srslte_ra_nr_fill_tb(const srslte_pdsch_cfg_nr_t* pdsch_cfg, const srslte_pdsch_grant_nr_t* grant, uint32_t mcs_idx, srslte_sch_tb_t* tb); + +#ifdef __cplusplus +} +#endif + #endif // SRSLTE_RA_NR_H diff --git a/lib/include/srslte/phy/ue/ue_dl_nr_data.h b/lib/include/srslte/phy/ue/ue_dl_nr_data.h index c67a0b3d5..f5cd0ca6c 100644 --- a/lib/include/srslte/phy/ue/ue_dl_nr_data.h +++ b/lib/include/srslte/phy/ue/ue_dl_nr_data.h @@ -26,6 +26,10 @@ #include "srslte/phy/common/phy_common_nr.h" #include "srslte/phy/phch/pdsch_cfg_nr.h" +#ifdef __cplusplus +extern "C" { +#endif + /** * @brief Calculates the PDSCH time resource provided by higher layers and stores it in the provided PDSCH NR grant. * @@ -55,4 +59,8 @@ SRSLTE_API int srslte_ue_dl_nr_pdsch_time_resource_default_A(uint32_t srslte_dmrs_pdsch_typeA_pos_t dmrs_typeA_pos, srslte_pdsch_grant_nr_t* grant); +#ifdef __cplusplus +} +#endif + #endif // SRSLTE_UE_DL_NR_DATA_H diff --git a/srsenb/hdr/phy/nr/cc_worker.h b/srsenb/hdr/phy/nr/cc_worker.h new file mode 100644 index 000000000..b70168229 --- /dev/null +++ b/srsenb/hdr/phy/nr/cc_worker.h @@ -0,0 +1,90 @@ +/* + * Copyright 2013-2020 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * srsLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#ifndef SRSENB_NR_CC_WORKER_H +#define SRSENB_NR_CC_WORKER_H + +#include "srslte/common/log.h" +#include "srslte/phy/enb/enb_dl_nr.h" +#include +#include + +namespace srsenb { +namespace nr { + +typedef struct { + uint32_t nof_carriers; + uint32_t max_prb; + srslte_enb_dl_nr_args_t dl; +} phy_nr_args_t; + +typedef struct { + srslte_pdsch_cfg_nr_t pdsch; +} phy_nr_cfg_t; + +class phy_nr_state +{ +public: + phy_nr_args_t args = {}; + phy_nr_cfg_t cfg = {}; + + phy_nr_state() + { + args.nof_carriers = 1; + args.max_prb = SRSLTE_MAX_PRB; + args.dl.nof_tx_antennas = 1; + args.dl.pdsch.measure_evm = true; + args.dl.pdsch.sch.disable_simd = true; + } +}; + +class cc_worker +{ +public: + cc_worker(uint32_t cc_idx, srslte::log* log, phy_nr_state* phy_state_); + ~cc_worker(); + + bool set_carrier(const srslte_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(); + +private: + srslte_dl_slot_cfg_t dl_slot_cfg = {}; + uint32_t cc_idx = 0; + std::array, SRSLTE_MAX_PORTS> tx_buffer = {}; + std::array, SRSLTE_MAX_PORTS> rx_buffer = {}; + phy_nr_state* phy_state; + srslte_enb_dl_nr_t enb_dl = {}; + + // Temporal attributes + srslte_softbuffer_tx_t softbuffer_tx = {}; + std::vector data; +}; + +} // namespace nr +} // namespace srsenb + +#endif // SRSENB_NR_CC_WORKER_H diff --git a/srsenb/hdr/phy/nr/sf_worker.h b/srsenb/hdr/phy/nr/sf_worker.h new file mode 100644 index 000000000..809531467 --- /dev/null +++ b/srsenb/hdr/phy/nr/sf_worker.h @@ -0,0 +1,68 @@ +/* + * Copyright 2013-2020 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * srsLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#ifndef SRSUE_NR_PHCH_WORKER_H +#define SRSUE_NR_PHCH_WORKER_H + +#include "cc_worker.h" +#include "srsenb/hdr/phy/phy_common.h" +#include "srslte/common/thread_pool.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 srslte::thread_pool::worker +{ +public: + sf_worker(phy_common* phy_, phy_nr_state* phy_state_, srslte::log* log); + ~sf_worker() = default; + + bool set_carrier_unlocked(uint32_t cc_idx, const srslte_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); + +private: + /* Inherited from thread_pool::worker. Function called every subframe to run the DL/UL processing */ + void work_imp() override; + + std::vector > cc_workers; + + phy_common* phy = nullptr; + phy_nr_state* phy_state = nullptr; + srslte::log* log_h = nullptr; +}; + +} // namespace nr +} // namespace srsenb + +#endif // SRSUE_NR_PHCH_WORKER_H diff --git a/srsenb/hdr/phy/nr/worker_pool.h b/srsenb/hdr/phy/nr/worker_pool.h new file mode 100644 index 000000000..77306ba29 --- /dev/null +++ b/srsenb/hdr/phy/nr/worker_pool.h @@ -0,0 +1,55 @@ +/* + * Copyright 2013-2020 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * srsLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#ifndef SRSUE_NR_WORKER_POOL_H +#define SRSUE_NR_WORKER_POOL_H + +#include "sf_worker.h" +#include "srslte/common/thread_pool.h" + +namespace srsenb { +namespace nr { + +class worker_pool +{ + +private: + std::vector > log_vec; + + srslte::thread_pool pool; + std::vector > workers; + phy_nr_state phy_state; + +public: + sf_worker* operator[](std::size_t pos) { return workers.at(pos).get(); } + + worker_pool(uint32_t max_workers); + bool init(const phy_args_t& args, phy_common* common, srslte::logger* logger, int prio); + sf_worker* wait_worker(uint32_t tti); + sf_worker* wait_worker_id(uint32_t id); + void start_worker(sf_worker* w); + void stop(); +}; + +} // namespace nr +} // namespace srsenb + +#endif // SRSUE_NR_WORKER_POOL_H diff --git a/srsenb/hdr/phy/phy_common.h b/srsenb/hdr/phy/phy_common.h index 756d398bc..bfb4225ed 100644 --- a/srsenb/hdr/phy/phy_common.h +++ b/srsenb/hdr/phy/phy_common.h @@ -36,8 +36,10 @@ class phy_common public: phy_common() = default; - bool - init(const phy_cell_cfg_list_t& cell_list_, srslte::radio_interface_phy* radio_handler, stack_interface_phy_lte* mac); + bool init(const phy_cell_cfg_list_t& cell_list_, + const phy_cell_cfg_list_nr_t& cell_list_nr_, + srslte::radio_interface_phy* radio_handler, + stack_interface_phy_lte* mac); void reset(); void stop(); @@ -58,13 +60,15 @@ public: // Common objects phy_args_t params = {}; - uint32_t get_nof_carriers() { return static_cast(cell_list.size()); }; + uint32_t get_nof_carriers_lte() { return static_cast(cell_list_lte.size()); }; + uint32_t get_nof_carriers_nr() { return static_cast(cell_list_nr.size()); }; + uint32_t get_nof_carriers() { return static_cast(cell_list_lte.size() + cell_list_nr.size()); }; uint32_t get_nof_prb(uint32_t cc_idx) { uint32_t ret = 0; - if (cc_idx < cell_list.size()) { - ret = cell_list[cc_idx].cell.nof_prb; + if (cc_idx < cell_list_lte.size()) { + ret = cell_list_lte[cc_idx].cell.nof_prb; } return ret; @@ -73,8 +77,8 @@ public: { uint32_t ret = 0; - if (cc_idx < cell_list.size()) { - ret = cell_list[cc_idx].cell.nof_ports; + if (cc_idx < cell_list_lte.size()) { + ret = cell_list_lte[cc_idx].cell.nof_ports; } return ret; @@ -83,18 +87,27 @@ public: { uint32_t count = 0; - for (auto& cell : cell_list) { + for (auto& cell : cell_list_lte) { count += cell.cell.nof_ports; } + for (auto& cell : cell_list_nr) { + count += cell.cell.max_mimo_layers; + } + return count; } double get_ul_freq_hz(uint32_t cc_idx) { double ret = 0.0; - if (cc_idx < cell_list.size()) { - ret = cell_list[cc_idx].ul_freq_hz; + if (cc_idx < cell_list_lte.size()) { + ret = cell_list_lte[cc_idx].ul_freq_hz; + } + + cc_idx -= cell_list_lte.size(); + if (cc_idx < cell_list_nr.size()) { + ret = cell_list_nr[cc_idx].ul_freq_hz; } return ret; @@ -103,8 +116,13 @@ public: { double ret = 0.0; - if (cc_idx < cell_list.size()) { - ret = cell_list[cc_idx].dl_freq_hz; + if (cc_idx < cell_list_lte.size()) { + ret = cell_list_lte[cc_idx].dl_freq_hz; + } + + cc_idx -= cell_list_lte.size(); + if (cc_idx < cell_list_nr.size()) { + ret = cell_list_nr[cc_idx].dl_freq_hz; } return ret; @@ -113,8 +131,13 @@ public: { uint32_t ret = 0; - if (cc_idx < cell_list.size()) { - ret = cell_list[cc_idx].rf_port; + if (cc_idx < cell_list_lte.size()) { + ret = cell_list_lte[cc_idx].rf_port; + } + + cc_idx -= cell_list_lte.size(); + if (cc_idx < cell_list_nr.size()) { + ret = cell_list_nr[cc_idx].rf_port; } return ret; @@ -122,31 +145,62 @@ public: srslte_cell_t get_cell(uint32_t cc_idx) { srslte_cell_t c = {}; - if (cc_idx < cell_list.size()) { - c = cell_list[cc_idx].cell; + if (cc_idx < cell_list_lte.size()) { + c = cell_list_lte[cc_idx].cell; + } + return c; + }; + srslte_carrier_nr_t get_cell_nr(uint32_t cc_idx) + { + srslte_carrier_nr_t c = {}; + if (cc_idx < cell_list_lte.size()) { + return c; + } + + cc_idx -= cell_list_lte.size(); + if (cc_idx < cell_list_nr.size()) { + c = cell_list_nr[cc_idx].cell; } + return c; }; void set_cell_gain(uint32_t cell_id, float gain_db) { - auto it = - std::find_if(cell_list.begin(), cell_list.end(), [cell_id](phy_cell_cfg_t& x) { return x.cell_id == cell_id; }); + // Find LTE cell + auto it_lte = std::find_if( + cell_list_lte.begin(), cell_list_lte.end(), [cell_id](phy_cell_cfg_t& x) { return x.cell_id == cell_id; }); - // Check if the cell was found; - if (it == cell_list.end()) { - srslte::console("cell ID %d not found\n", cell_id); + // Check if the lte cell was found; + if (it_lte != cell_list_lte.end()) { + it_lte->gain_db = gain_db; return; } - it->gain_db = gain_db; + // Find NR cell + auto it_nr = std::find_if( + cell_list_nr.begin(), cell_list_nr.end(), [cell_id](phy_cell_cfg_nr_t& x) { return x.cell_id == cell_id; }); + + // Check if the nr cell was found; + if (it_nr != cell_list_nr.end()) { + it_nr->gain_db = gain_db; + return; + } + + srslte::console("cell ID %d not found\n", cell_id); } float get_cell_gain(uint32_t cc_idx) { - if (cc_idx < cell_list.size()) { - return cell_list.at(cc_idx).gain_db; + if (cc_idx < cell_list_lte.size()) { + return cell_list_lte.at(cc_idx).gain_db; } + + cc_idx -= cell_list_lte.size(); + if (cc_idx < cell_list_nr.size()) { + return cell_list_nr.at(cc_idx).gain_db; + } + return 0.0f; } @@ -178,7 +232,8 @@ private: srslte::circular_array ul_grants = {}; std::mutex grant_mutex = {}; - phy_cell_cfg_list_t cell_list; + phy_cell_cfg_list_t cell_list_lte; + phy_cell_cfg_list_nr_t cell_list_nr; bool have_mtch_stop = false; pthread_mutex_t mtch_mutex = {}; diff --git a/srsenb/hdr/phy/phy_interfaces.h b/srsenb/hdr/phy/phy_interfaces.h index 4cbf73b26..5049f2831 100644 --- a/srsenb/hdr/phy/phy_interfaces.h +++ b/srsenb/hdr/phy/phy_interfaces.h @@ -14,9 +14,10 @@ #define SRSENB_PHY_INTERFACES_H_ #include "srslte/asn1/rrc/rr_common.h" +#include "srslte/common/interfaces_common.h" +#include "srslte/phy/channel/channel.h" +#include "srslte/phy/common/phy_common_nr.h" #include -#include -#include #include namespace srsenb { @@ -32,7 +33,19 @@ struct phy_cell_cfg_t { float gain_db; }; +struct phy_cell_cfg_nr_t { + srslte_carrier_nr_t cell; + 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; +}; + typedef std::vector phy_cell_cfg_list_t; +typedef std::vector phy_cell_cfg_list_nr_t; struct phy_args_t { std::string type; @@ -59,6 +72,7 @@ struct phy_args_t { struct phy_cfg_t { // Individual cell/sector configuration list phy_cell_cfg_list_t phy_cell_cfg; + phy_cell_cfg_list_nr_t phy_cell_cfg_nr; // Common configuration for all cells asn1::rrc::prach_cfg_sib_s prach_cnfg; diff --git a/srsenb/hdr/phy/txrx.h b/srsenb/hdr/phy/txrx.h index 7db303509..76ea7eab9 100644 --- a/srsenb/hdr/phy/txrx.h +++ b/srsenb/hdr/phy/txrx.h @@ -16,6 +16,7 @@ #include "phy_common.h" #include "prach_worker.h" #include "srsenb/hdr/phy/lte/worker_pool.h" +#include "srsenb/hdr/phy/nr/worker_pool.h" #include "srslte/common/log.h" #include "srslte/config.h" #include "srslte/phy/channel/channel.h" @@ -39,13 +40,14 @@ public: private: void run_thread() override; - stack_interface_phy_lte* stack = nullptr; - srslte::radio_interface_phy* radio_h = nullptr; - srslte::log* log_h = nullptr; - lte::worker_pool* workers_pool = nullptr; - prach_worker_pool* prach = nullptr; - phy_common* worker_com = nullptr; - srslte::channel_ptr ul_channel = nullptr; + stack_interface_phy_lte* stack = nullptr; + srslte::radio_interface_phy* radio_h = nullptr; + srslte::log* log_h = nullptr; + lte::worker_pool* lte_workers = nullptr; + nr::worker_pool* nr_workers = nullptr; + prach_worker_pool* prach = nullptr; + phy_common* worker_com = nullptr; + srslte::channel_ptr ul_channel = nullptr; // Main system TTI counter uint32_t tti = 0; diff --git a/srsenb/src/phy/CMakeLists.txt b/srsenb/src/phy/CMakeLists.txt index 719ad11ed..b7d400e3b 100644 --- a/srsenb/src/phy/CMakeLists.txt +++ b/srsenb/src/phy/CMakeLists.txt @@ -6,7 +6,18 @@ # the distribution. # -set(SOURCES lte/cc_worker.cc lte/sf_worker.cc lte/worker_pool.cc phy.cc phy_common.cc phy_ue_db.cc prach_worker.cc txrx.cc) +set(SOURCES + lte/cc_worker.cc + lte/sf_worker.cc + lte/worker_pool.cc + nr/cc_worker.cc + nr/sf_worker.cc + nr/worker_pool.cc + phy.cc + phy_common.cc + phy_ue_db.cc + prach_worker.cc + txrx.cc) add_library(srsenb_phy STATIC ${SOURCES}) if(ENABLE_GUI AND SRSGUI_FOUND) diff --git a/srsenb/src/phy/lte/worker_pool.cc b/srsenb/src/phy/lte/worker_pool.cc index 99eaa7989..54fb0a4b5 100644 --- a/srsenb/src/phy/lte/worker_pool.cc +++ b/srsenb/src/phy/lte/worker_pool.cc @@ -1,24 +1,3 @@ -/* - * Copyright 2013-2020 Software Radio Systems Limited - * - * This file is part of srsLTE. - * - * srsLTE is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * srsLTE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * A copy of the GNU Affero General Public License can be found in - * the LICENSE file in the top-level directory of this distribution - * and at http://www.gnu.org/licenses/. - * - */ - /* * Copyright 2013-2020 Software Radio Systems Limited * diff --git a/srsenb/src/phy/nr/cc_worker.cc b/srsenb/src/phy/nr/cc_worker.cc new file mode 100644 index 000000000..c2b33c5eb --- /dev/null +++ b/srsenb/src/phy/nr/cc_worker.cc @@ -0,0 +1,140 @@ +/* + * Copyright 2013-2020 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * srsLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include "srsenb/hdr/phy/nr/cc_worker.h" +#include "srslte/phy/enb/enb_dl_nr.h" +#include "srslte/phy/phch/ra_nr.h" +#include "srslte/phy/ue/ue_dl_nr_data.h" + +namespace srsenb { +namespace nr { +cc_worker::cc_worker(uint32_t cc_idx_, srslte::log* log, phy_nr_state* phy_state_) : + cc_idx(cc_idx_), phy_state(phy_state_) +{ + cf_t* buffer_c[SRSLTE_MAX_PORTS] = {}; + + // Allocate buffers + for (uint32_t i = 0; phy_state_->args.dl.nof_tx_antennas; i++) { + tx_buffer[i].resize(SRSLTE_SF_LEN_PRB(phy_state->args.max_prb)); + rx_buffer[i].resize(SRSLTE_SF_LEN_PRB(phy_state->args.max_prb)); + buffer_c[i] = tx_buffer[i].data(); + } + + if (srslte_enb_dl_nr_init(&enb_dl, buffer_c, &phy_state_->args.dl)) { + ERROR("Error initiating UE DL NR\n"); + return; + } + + if (srslte_softbuffer_tx_init_guru(&softbuffer_tx, SRSLTE_SCH_NR_MAX_NOF_CB_LDPC, SRSLTE_LDPC_MAX_LEN_ENCODED_CB) < + SRSLTE_SUCCESS) { + ERROR("Error init soft-buffer\n"); + return; + } + data.resize(SRSLTE_SCH_NR_MAX_NOF_CB_LDPC * SRSLTE_LDPC_MAX_LEN_ENCODED_CB); + srslte_random_t r = srslte_random_init(1234); + for (uint32_t i = 0; i < SRSLTE_SCH_NR_MAX_NOF_CB_LDPC * SRSLTE_LDPC_MAX_LEN_ENCODED_CB; i++) { + data[i] = srslte_random_uniform_int_dist(r, 0, UINT8_MAX); + } + srslte_random_free(r); +} + +cc_worker::~cc_worker() +{ + srslte_enb_dl_nr_free(&enb_dl); + srslte_softbuffer_tx_free(&softbuffer_tx); +} + +bool cc_worker::set_carrier(const srslte_carrier_nr_t* carrier) +{ + if (srslte_enb_dl_nr_set_carrier(&enb_dl, carrier) < SRSLTE_SUCCESS) { + return false; + } + + return true; +} + +void cc_worker::set_tti(uint32_t tti) +{ + dl_slot_cfg.idx = tti; +} + +cf_t* cc_worker::get_tx_buffer(uint32_t antenna_idx) +{ + if (antenna_idx >= phy_state->args.dl.nof_tx_antennas) { + return nullptr; + } + + return tx_buffer.at(antenna_idx).data(); +} + +cf_t* cc_worker::get_rx_buffer(uint32_t antenna_idx) +{ + if (antenna_idx >= phy_state->args.dl.nof_tx_antennas) { + return nullptr; + } + + return rx_buffer.at(antenna_idx).data(); +} + +uint32_t cc_worker::get_buffer_len() +{ + return tx_buffer.size(); +} + +bool cc_worker::work_dl() +{ + srslte_pdsch_grant_nr_t pdsch_grant = {}; + srslte_pdsch_cfg_nr_t pdsch_cfg = phy_state->cfg.pdsch; + + // Use grant default A time resources with m=0 + if (srslte_ue_dl_nr_pdsch_time_resource_default_A(0, pdsch_cfg.dmrs_cfg_typeA.typeA_pos, &pdsch_grant) < + SRSLTE_SUCCESS) { + ERROR("Error loading default grant\n"); + return false; + } + pdsch_grant.nof_layers = enb_dl.carrier.max_mimo_layers; + pdsch_grant.dci_format = srslte_dci_format_nr_1_0; + + for (uint32_t i = 0; i < enb_dl.carrier.nof_prb; i++) { + pdsch_grant.prb_idx[i] = true; + } + + if (srslte_ra_nr_fill_tb(&pdsch_cfg, &pdsch_grant, 20, &pdsch_grant.tb[0]) < SRSLTE_SUCCESS) { + ERROR("Error filing tb\n"); + return false; + } + + uint8_t* data2[SRSLTE_MAX_TB] = {data.data(), data.data()}; + pdsch_grant.tb[0].softbuffer.tx = &softbuffer_tx; + srslte_softbuffer_tx_reset(pdsch_grant.tb[0].softbuffer.tx); + + if (srslte_enb_dl_nr_pdsch_put(&enb_dl, &dl_slot_cfg, &pdsch_cfg, &pdsch_grant, data2) < SRSLTE_SUCCESS) { + ERROR("Error decoding PDSCH\n"); + return false; + } + + srslte_enb_dl_nr_gen_signal(&enb_dl); + + return true; +} + +} // 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 new file mode 100644 index 000000000..98ee740b3 --- /dev/null +++ b/srsenb/src/phy/nr/sf_worker.cc @@ -0,0 +1,82 @@ +/* + * Copyright 2013-2020 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * srsLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include "srsenb/hdr/phy/nr/sf_worker.h" + +namespace srsenb { +namespace nr { +sf_worker::sf_worker(phy_common* phy_, phy_nr_state* phy_state_, srslte::log* log) : + phy(phy_), phy_state(phy_state_), log_h(log) +{ + for (uint32_t i = 0; i < phy_state->args.nof_carriers; i++) { + cc_worker* w = new cc_worker(i, log, phy_state); + cc_workers.push_back(std::unique_ptr(w)); + } +} + +bool sf_worker::set_carrier_unlocked(uint32_t cc_idx, const srslte_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()) { + 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_tti(uint32_t tti) +{ + for (auto& w : cc_workers) { + w->set_tti(tti); + } +} + +void sf_worker::work_imp() +{ + for (auto& w : cc_workers) { + w->work_dl(); + } +} + +}; // 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 new file mode 100644 index 000000000..484324436 --- /dev/null +++ b/srsenb/src/phy/nr/worker_pool.cc @@ -0,0 +1,73 @@ +/* + * Copyright 2013-2020 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * srsLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ +#include "srsenb/hdr/phy/nr/worker_pool.h" + +namespace srsenb { +namespace nr { + +worker_pool::worker_pool(uint32_t max_workers) : pool(max_workers) {} + +bool worker_pool::init(const phy_args_t& args, phy_common* common, srslte::logger* logger, int prio) +{ + // Create logs + // Create array of pointers to phy_logs + for (uint32_t i = 0; i < args.nof_phy_threads; i++) { + auto* mylog = new srslte::log_filter; + char tmp[16]; + sprintf(tmp, "PHY%d", i); + mylog->init(tmp, logger, true); + mylog->set_level(args.log.phy_level); + mylog->set_hex_limit(args.log.phy_hex_limit); + log_vec.push_back(std::unique_ptr(mylog)); + } + + // Add workers to workers pool and start threads + for (uint32_t i = 0; i < args.nof_phy_threads; i++) { + auto w = std::unique_ptr(new sf_worker(common, &phy_state, (srslte::log*)log_vec[i].get())); + pool.init_worker(i, w.get(), prio); + workers.push_back(std::move(w)); + } + + return true; +} + +void worker_pool::start_worker(sf_worker* w) +{ + pool.start_worker(w); +} + +sf_worker* worker_pool::wait_worker(uint32_t tti) +{ + return (sf_worker*)pool.wait_worker(tti); +} + +sf_worker* worker_pool::wait_worker_id(uint32_t id) +{ + return (sf_worker*)pool.wait_worker_id(id); +} + +void worker_pool::stop() +{ + pool.stop(); +} + +}; // namespace nr +}; // namespace srsenb \ No newline at end of file diff --git a/srsenb/src/phy/phy.cc b/srsenb/src/phy/phy.cc index e1179f16f..e65b70737 100644 --- a/srsenb/src/phy/phy.cc +++ b/srsenb/src/phy/phy.cc @@ -119,7 +119,7 @@ int phy::init(const phy_args_t& args, workers_common.params = args; - workers_common.init(cfg.phy_cell_cfg, radio, stack_); + workers_common.init(cfg.phy_cell_cfg, cfg.phy_cell_cfg_nr, radio, stack_); parse_common_config(cfg); diff --git a/srsenb/src/phy/phy_common.cc b/srsenb/src/phy/phy_common.cc index f42d4b598..f533d62b3 100644 --- a/srsenb/src/phy/phy_common.cc +++ b/srsenb/src/phy/phy_common.cc @@ -44,13 +44,15 @@ void phy_common::reset() } } -bool phy_common::init(const phy_cell_cfg_list_t& cell_list_, - srslte::radio_interface_phy* radio_h_, - stack_interface_phy_lte* stack_) +bool phy_common::init(const phy_cell_cfg_list_t& cell_list_, + const phy_cell_cfg_list_nr_t& cell_list_nr_, + srslte::radio_interface_phy* radio_h_, + stack_interface_phy_lte* stack_) { radio = radio_h_; stack = stack_; - cell_list = cell_list_; + cell_list_lte = cell_list_; + cell_list_nr = cell_list_nr_; pthread_mutex_init(&mtch_mutex, nullptr); pthread_cond_init(&mtch_cvar, nullptr); @@ -58,17 +60,17 @@ bool phy_common::init(const phy_cell_cfg_list_t& cell_list_, // Instantiate DL channel emulator if (params.dl_channel_args.enable) { dl_channel = srslte::channel_ptr(new srslte::channel(params.dl_channel_args, get_nof_rf_channels())); - dl_channel->set_srate((uint32_t)srslte_sampling_freq_hz(cell_list[0].cell.nof_prb)); - dl_channel->set_signal_power_dBfs(srslte_enb_dl_get_maximum_signal_power_dBfs(cell_list[0].cell.nof_prb)); + dl_channel->set_srate((uint32_t)srslte_sampling_freq_hz(cell_list_lte[0].cell.nof_prb)); + dl_channel->set_signal_power_dBfs(srslte_enb_dl_get_maximum_signal_power_dBfs(cell_list_lte[0].cell.nof_prb)); } // Create grants for (auto& q : ul_grants) { - q.resize(cell_list.size()); + q.resize(cell_list_lte.size()); } // Set UE PHY data-base stack and configuration - ue_db.init(stack, params, cell_list); + ue_db.init(stack, params, cell_list_lte); reset(); return true; diff --git a/srsenb/src/phy/txrx.cc b/srsenb/src/phy/txrx.cc index 0c2e883fb..1c3f64511 100644 --- a/srsenb/src/phy/txrx.cc +++ b/srsenb/src/phy/txrx.cc @@ -16,7 +16,6 @@ #include "srslte/common/threads.h" #include "srslte/srslte.h" -#include "srsenb/hdr/phy/lte/sf_worker.h" #include "srsenb/hdr/phy/txrx.h" #define Error(fmt, ...) \ @@ -52,13 +51,13 @@ bool txrx::init(stack_interface_phy_lte* stack_, stack = stack_; radio_h = radio_h_; log_h = log_h_; - workers_pool = workers_pool_; + lte_workers = workers_pool_; worker_com = worker_com_; prach = prach_; tx_worker_cnt = 0; running = true; - nof_workers = workers_pool->get_nof_workers(); + nof_workers = lte_workers->get_nof_workers(); // Instantiate UL channel emulator if (worker_com->params.ul_channel_args.enable) { @@ -80,7 +79,6 @@ void txrx::stop() void txrx::run_thread() { - lte::sf_worker* worker = nullptr; srslte::rf_buffer_t buffer = {}; srslte::rf_timestamp_t timestamp = {}; uint32_t sf_len = SRSLTE_SF_LEN_PRB(worker_com->get_nof_prb(0)); @@ -117,59 +115,83 @@ void txrx::run_thread() // Main loop while (running) { - tti = TTI_ADD(tti, 1); + tti = TTI_ADD(tti, 1); if (log_h) { log_h->step(tti); } - worker = workers_pool->wait_worker(tti); - if (worker) { - // Multiple cell buffer mapping - for (uint32_t cc = 0; cc < worker_com->get_nof_carriers(); cc++) { + lte::sf_worker* lte_worker = nullptr; + if (worker_com->get_nof_carriers_lte() > 0) { + lte_worker = lte_workers->wait_worker(tti); + if (lte_worker == nullptr) { + // wait_worker() only returns NULL if it's being closed. Quit now to avoid unnecessary loops here + running = false; + continue; + } + } + + nr::sf_worker* nr_worker = nullptr; + if (worker_com->get_nof_carriers_nr() > 0) { + nr_worker = nr_workers->wait_worker(tti); + if (nr_worker == nullptr) { + running = false; + continue; + } + } + + // Multiple cell buffer mapping + { + uint32_t cc = 0; + for (uint32_t cc_lte = 0; cc_lte < worker_com->get_nof_carriers_lte(); cc_lte++, 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), worker->get_buffer_rx(cc, p)); + 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++) { + uint32_t rf_port = worker_com->get_rf_port(cc); - buffer.set_nof_samples(sf_len); - radio_h->rx_now(buffer, timestamp); - - if (ul_channel) { - ul_channel->run(buffer.to_cf_t(), buffer.to_cf_t(), sf_len, timestamp.get(0)); + 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)); + } } + } - // Compute TX time: Any transmission happens in TTI+4 thus advance 4 ms the reception time - timestamp.add(FDD_HARQ_DELAY_UL_MS * 1e-3); + buffer.set_nof_samples(sf_len); + radio_h->rx_now(buffer, timestamp); - Debug("Setting TTI=%d, tx_mutex=%d, tx_time=%ld:%f to worker %d\n", - tti, - tx_worker_cnt, - timestamp.get(0).full_secs, - timestamp.get(0).frac_secs, - worker->get_id()); + if (ul_channel) { + ul_channel->run(buffer.to_cf_t(), buffer.to_cf_t(), sf_len, timestamp.get(0)); + } - worker->set_time(tti, tx_worker_cnt, timestamp); - tx_worker_cnt = (tx_worker_cnt + 1) % nof_workers; + // Compute TX time: Any transmission happens in TTI+4 thus advance 4 ms the reception time + timestamp.add(FDD_HARQ_DELAY_UL_MS * 1e-3); - // Trigger phy worker execution - worker_com->semaphore.push(worker); - workers_pool->start_worker(worker); + Debug("Setting TTI=%d, tx_mutex=%d, tx_time=%ld:%f to worker %d\n", + tti, + tx_worker_cnt, + timestamp.get(0).full_secs, + timestamp.get(0).frac_secs, + lte_worker->get_id()); - // Trigger prach worker execution - for (uint32_t cc = 0; cc < worker_com->get_nof_carriers(); cc++) { - prach->new_tti(cc, tti, buffer.get(worker_com->get_rf_port(cc), 0, worker_com->get_nof_ports(0))); - } + lte_worker->set_time(tti, tx_worker_cnt, timestamp); + tx_worker_cnt = (tx_worker_cnt + 1) % nof_workers; - // Advance stack in time - stack->tti_clock(); + // Trigger phy worker execution + worker_com->semaphore.push(lte_worker); + lte_workers->start_worker(lte_worker); - } else { - // wait_worker() only returns NULL if it's being closed. Quit now to avoid unnecessary loops here - running = false; + // Trigger prach worker execution + for (uint32_t cc = 0; cc < worker_com->get_nof_carriers_lte(); cc++) { + prach->new_tti(cc, tti, buffer.get(worker_com->get_rf_port(cc), 0, worker_com->get_nof_ports(0))); } + + // Advance stack in time + stack->tti_clock(); } } diff --git a/srsue/hdr/phy/nr/cc_worker.h b/srsue/hdr/phy/nr/cc_worker.h index 099733059..29a863a0f 100644 --- a/srsue/hdr/phy/nr/cc_worker.h +++ b/srsue/hdr/phy/nr/cc_worker.h @@ -75,6 +75,7 @@ private: srslte_dl_slot_cfg_t dl_slot_cfg = {}; uint32_t cc_idx = 0; std::array, SRSLTE_MAX_PORTS> rx_buffer = {}; + std::array, SRSLTE_MAX_PORTS> tx_buffer = {}; phy_nr_state* phy_state; srslte_ue_dl_nr_t ue_dl = {}; diff --git a/srsue/src/phy/nr/cc_worker.cc b/srsue/src/phy/nr/cc_worker.cc index befd98514..e01a9769e 100644 --- a/srsue/src/phy/nr/cc_worker.cc +++ b/srsue/src/phy/nr/cc_worker.cc @@ -111,6 +111,8 @@ bool cc_worker::work_dl() pdsch_grant.tb[0].softbuffer.rx = &softbuffer_rx; srslte_softbuffer_rx_reset(pdsch_grant.tb[0].softbuffer.rx); + srslte_ue_dl_nr_estimate_fft(&ue_dl); + if (srslte_ue_dl_nr_pdsch_get(&ue_dl, &dl_slot_cfg, &pdsch_cfg, &pdsch_grant, &pdsch_res) < SRSLTE_SUCCESS) { ERROR("Error decoding PDSCH\n"); return false;