From aef3e5a40acd996130aa4d85ac0bc2140b23c8f0 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 21 Jun 2021 18:10:41 +0200 Subject: [PATCH] More NR PHY test and GNB PHY development --- lib/include/srsran/common/interfaces_common.h | 1 + .../interfaces/rrc_nr_interface_types.h | 6 +- srsenb/hdr/phy/nr/phy_nr_state.h | 2 + srsenb/hdr/phy/nr/sf_worker.h | 1 + srsenb/hdr/phy/nr/worker_pool.h | 10 +- srsenb/src/phy/nr/cc_worker.cc | 38 +- srsenb/src/phy/nr/phy_nr_state.cc | 12 +- srsenb/src/phy/nr/sf_worker.cc | 37 +- srsenb/src/phy/nr/worker_pool.cc | 12 +- srsue/src/phy/nr/cc_worker.cc | 4 +- srsue/src/phy/nr/worker_pool.cc | 2 +- test/phy/dummy_phy_common.h | 12 +- test/phy/nr_dl_flood.cc | 578 +++++++++--------- test/phy/test_bench.h | 25 +- 14 files changed, 385 insertions(+), 355 deletions(-) diff --git a/lib/include/srsran/common/interfaces_common.h b/lib/include/srsran/common/interfaces_common.h index ce7996205..d2372a58d 100644 --- a/lib/include/srsran/common/interfaces_common.h +++ b/lib/include/srsran/common/interfaces_common.h @@ -23,6 +23,7 @@ namespace srsran { typedef struct { std::string phy_level = "none"; std::string phy_lib_level = "none"; + std::string id_preamble = ""; int phy_hex_limit = -1; } phy_log_args_t; diff --git a/lib/include/srsran/interfaces/rrc_nr_interface_types.h b/lib/include/srsran/interfaces/rrc_nr_interface_types.h index a1725e734..436cbb3da 100644 --- a/lib/include/srsran/interfaces/rrc_nr_interface_types.h +++ b/lib/include/srsran/interfaces/rrc_nr_interface_types.h @@ -29,9 +29,9 @@ struct phy_cfg_nr_t { * SSB configuration */ struct ssb_cfg_t { - uint32_t periodicity_ms; - std::array position_in_burst; - srsran_subcarrier_spacing_t scs; + uint32_t periodicity_ms = 0; + std::array position_in_burst = {}; + srsran_subcarrier_spacing_t scs = srsran_subcarrier_spacing_30kHz; }; srsran_tdd_config_nr_t tdd = {}; diff --git a/srsenb/hdr/phy/nr/phy_nr_state.h b/srsenb/hdr/phy/nr/phy_nr_state.h index ac1783374..64468a80f 100644 --- a/srsenb/hdr/phy/nr/phy_nr_state.h +++ b/srsenb/hdr/phy/nr/phy_nr_state.h @@ -90,6 +90,8 @@ public: */ 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; } diff --git a/srsenb/hdr/phy/nr/sf_worker.h b/srsenb/hdr/phy/nr/sf_worker.h index 0d4b16501..20189e8d9 100644 --- a/srsenb/hdr/phy/nr/sf_worker.h +++ b/srsenb/hdr/phy/nr/sf_worker.h @@ -53,6 +53,7 @@ private: 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 = {}; diff --git a/srsenb/hdr/phy/nr/worker_pool.h b/srsenb/hdr/phy/nr/worker_pool.h index 9c99d2e38..d909e4be1 100644 --- a/srsenb/hdr/phy/nr/worker_pool.h +++ b/srsenb/hdr/phy/nr/worker_pool.h @@ -29,10 +29,11 @@ class worker_pool public: struct args_t { - uint32_t nof_workers = 3; - uint32_t prio = 52; - std::string log_level = "info"; - uint32_t log_hex_limit = 64; + 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 = ""; }; sf_worker* operator[](std::size_t pos) { return workers.at(pos).get(); } @@ -45,6 +46,7 @@ public: 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); }; } // namespace nr diff --git a/srsenb/src/phy/nr/cc_worker.cc b/srsenb/src/phy/nr/cc_worker.cc index 93a8e1e5a..cadb736fb 100644 --- a/srsenb/src/phy/nr/cc_worker.cc +++ b/srsenb/src/phy/nr/cc_worker.cc @@ -16,7 +16,10 @@ 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) + 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] = {}; @@ -85,8 +88,20 @@ uint32_t cc_worker::get_buffer_len() 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) { @@ -95,7 +110,11 @@ int cc_worker::encode_pdcch_dl(stack_interface_phy_nr::dl_sched_grant_t* grants, } if (logger.info.enabled()) { - logger.info("PDCCH: cc=%d, ...", cc_idx); + 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); + } } } @@ -106,14 +125,15 @@ int cc_worker::encode_pdsch(stack_interface_phy_nr::dl_sched_grant_t* grants, ui { for (uint32_t i = 0; i < nof_grants; i++) { // Get PHY config for UE - // ... - srsran_sch_hl_cfg_nr_t pdsch_hl_cfg = {}; - srsran_sch_cfg_nr_t pdsch_cfg = {}; + 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, &pdsch_hl_cfg, &grants[i].dci, &pdsch_cfg, &pdsch_cfg.grant) < - SRSRAN_SUCCESS) { + &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; } @@ -132,7 +152,7 @@ int cc_worker::encode_pdsch(stack_interface_phy_nr::dl_sched_grant_t* grants, ui 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", cc_idx, str); + logger.info("PDSCH: cc=%d, %s tti_tx=%d", cc_idx, str, dl_slot_cfg.idx); } } diff --git a/srsenb/src/phy/nr/phy_nr_state.cc b/srsenb/src/phy/nr/phy_nr_state.cc index 9135c0885..80c271b28 100644 --- a/srsenb/src/phy/nr/phy_nr_state.cc +++ b/srsenb/src/phy/nr/phy_nr_state.cc @@ -35,8 +35,6 @@ int phy_nr_state::_assert_rnti(uint16_t rnti) const int phy_nr_state::_get_rnti_config(uint16_t rnti, srsran::phy_cfg_nr_t& phy_cfg) const { - std::lock_guard lock(mutex); - if (_assert_rnti(rnti) < SRSRAN_SUCCESS) { return SRSRAN_ERROR; } @@ -47,7 +45,8 @@ int phy_nr_state::_get_rnti_config(uint16_t rnti, srsran::phy_cfg_nr_t& phy_cfg) } 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_) + 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) @@ -75,5 +74,12 @@ int phy_nr_state::rem_rnti(uint16_t 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 index e165b8f0a..662b77ca9 100644 --- a/srsenb/src/phy/nr/sf_worker.cc +++ b/srsenb/src/phy/nr/sf_worker.cc @@ -14,18 +14,25 @@ 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) +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_worker* w = new cc_worker(cc_args, logger, phy_state); + 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)); } @@ -81,18 +88,20 @@ void sf_worker::set_time(const uint32_t& tti, const srsran::rf_timestamp_t& time void sf_worker::work_imp() { // Get Transmission buffers - srsran::rf_buffer_t tx_buffer = {}; - srsran::rf_timestamp_t dummy_ts = {}; + 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, dummy_ts, true); + common.worker_end(this, true, tx_buffer, tx_time, true); return; } @@ -101,7 +110,7 @@ void sf_worker::work_imp() dl_sched_list.resize(1); if (phy_state.get_stack().get_dl_sched(ul_slot_cfg.idx, dl_sched_list) < SRSRAN_SUCCESS) { logger.error("DL Scheduling error"); - common.worker_end(this, true, tx_buffer, dummy_ts, true); + common.worker_end(this, true, tx_buffer, tx_time, true); return; } @@ -109,7 +118,7 @@ void sf_worker::work_imp() w->work_dl(dl_sched_list[0], ul_sched_list[0]); } - common.worker_end(this, true, tx_buffer, dummy_ts, true); + common.worker_end(this, true, tx_buffer, tx_time, true); } } // namespace nr diff --git a/srsenb/src/phy/nr/worker_pool.cc b/srsenb/src/phy/nr/worker_pool.cc index 12a0c8edf..dd8726334 100644 --- a/srsenb/src/phy/nr/worker_pool.cc +++ b/srsenb/src/phy/nr/worker_pool.cc @@ -19,12 +19,13 @@ worker_pool::worker_pool(const phy_cell_cfg_list_nr_t& cell_list, srsran::phy_common_interface& common, stack_interface_phy_nr& stack, srslog::sink& log_sink) : - pool(args.nof_workers), phy_state(cell_list, stack) + pool(args.nof_workers), + phy_state(cell_list, stack) { // 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++) { - auto& log = srslog::fetch_basic_logger(fmt::format("PHY{}-NR", i), log_sink); + 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); @@ -54,5 +55,12 @@ 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/srsue/src/phy/nr/cc_worker.cc b/srsue/src/phy/nr/cc_worker.cc index 1b2269a61..0fa3c1bbf 100644 --- a/srsue/src/phy/nr/cc_worker.cc +++ b/srsue/src/phy/nr/cc_worker.cc @@ -18,7 +18,9 @@ namespace srsue { namespace nr { cc_worker::cc_worker(uint32_t cc_idx_, srslog::basic_logger& log, state& phy_state_) : - cc_idx(cc_idx_), phy(phy_state_), logger(log) + cc_idx(cc_idx_), + phy(phy_state_), + logger(log) { cf_t* rx_buffer_c[SRSRAN_MAX_PORTS] = {}; diff --git a/srsue/src/phy/nr/worker_pool.cc b/srsue/src/phy/nr/worker_pool.cc index 44a30b656..9ac4daede 100644 --- a/srsue/src/phy/nr/worker_pool.cc +++ b/srsue/src/phy/nr/worker_pool.cc @@ -42,7 +42,7 @@ bool worker_pool::init(const phy_args_nr_t& args, // Add workers to workers pool and start threads for (uint32_t i = 0; i < args.nof_phy_threads; i++) { - auto& log = srslog::fetch_basic_logger(fmt::format("PHY{}-NR", i)); + auto& log = srslog::fetch_basic_logger(fmt::format("{}PHY{}-NR", args.log.id_preamble, i)); log.set_level(srslog::str_to_basic_level(args.log.phy_level)); log.set_hex_dump_max_size(args.log.phy_hex_limit); diff --git a/test/phy/dummy_phy_common.h b/test/phy/dummy_phy_common.h index 389b8022b..2f898e90b 100644 --- a/test/phy/dummy_phy_common.h +++ b/test/phy/dummy_phy_common.h @@ -145,7 +145,9 @@ 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_) {} }; @@ -188,7 +190,9 @@ public: // Check transmit timestamp is not in the past if (tx_ts < write_ts) { - logger.error("Tx time is %d samples in the past", (uint32_t)(write_ts - tx_ts)); + logger.error("Tx time (%f) is %d samples in the past", + srsran_timestamp_real(tx_time.get_ptr(0)), + (uint32_t)(write_ts - tx_ts)); semaphore.release(); return; } @@ -225,9 +229,7 @@ public: read_ts += nof_samples; } - void stop() { - quit = true; - } + void stop() { quit = true; } }; #endif // SRSRAN_DUMMY_PHY_COMMON_H diff --git a/test/phy/nr_dl_flood.cc b/test/phy/nr_dl_flood.cc index b005fd5a6..2407b3b18 100644 --- a/test/phy/nr_dl_flood.cc +++ b/test/phy/nr_dl_flood.cc @@ -19,10 +19,11 @@ test_bench::args_t::args_t(int argc, char** argv) valid = true; cell_list.resize(1); - cell_list[0].carrier.nof_prb = 52; + 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.pci = 500; + phy_cfg.carrier = cell_list[0].carrier; phy_cfg.carrier.absolute_frequency_point_a = 633928; phy_cfg.carrier.absolute_frequency_ssb = 634176; @@ -213,340 +214,307 @@ test_bench::args_t::args_t(int argc, char** argv) phy_cfg.harq_ack.dl_data_to_ul_ack[6] = 11; phy_cfg.prach.freq_offset = 2; - - // pusch-Config: setup (1) - // setup - // dmrs-UplinkForPUSCH-MappingTypeA: setup (1) - // setup - // dmrs-AdditionalPosition: pos1 (1) - // transformPrecodingDisabled - // pusch-PowerControl - // msg3-Alpha: alpha1 (7) - // p0-NominalWithoutGrant: -90dBm - // p0-AlphaSets: 1 item - // Item 0 - // P0-PUSCH-AlphaSet - // p0-PUSCH-AlphaSetId: 0 - // p0: 0dB - // alpha: alpha1 (7) - // pathlossReferenceRSToAddModList: 1 item - // Item 0 - // PUSCH-PathlossReferenceRS - // pusch-PathlossReferenceRS-Id: 0 - // referenceSignal: ssb-Index (0) - // ssb-Index: 0 - // sri-PUSCH-MappingToAddModList: 1 item - // Item 0 - // SRI-PUSCH-PowerControl - // sri-PUSCH-PowerControlId: 0 - // sri-PUSCH-PathlossReferenceRS-Id: 0 - // sri-P0-PUSCH-AlphaSetId: 0 - // sri-PUSCH-ClosedLoopIndex: i0 (0) - // resourceAllocation: resourceAllocationType1 (1) - // uci-OnPUSCH: setup (1) - // setup - // betaOffsets: semiStatic (1) - // semiStatic - // betaOffsetACK-Index1: 9 - // betaOffsetACK-Index2: 9 - // betaOffsetACK-Index3: 9 - // betaOffsetCSI-Part1-Index1: 6 - // betaOffsetCSI-Part1-Index2: 6 - // betaOffsetCSI-Part2-Index1: 6 - // betaOffsetCSI-Part2-Index2: 6 - // scaling: f1 (3) - // srs-Config: setup (1) - // setup - // srs-ResourceSetToAddModList: 1 item - // Item 0 - // SRS-ResourceSet - // srs-ResourceSetId: 0 - // srs-ResourceIdList: 1 item - // Item 0 - // SRS-ResourceId: 0 - // resourceType: aperiodic (0) - // aperiodic - // aperiodicSRS-ResourceTrigger: 1 - // slotOffset: 7 - // usage: codebook (1) - // p0: -90dBm - // pathlossReferenceRS: ssb-Index (0) - // ssb-Index: 0 - // srs-ResourceToAddModList: 1 item - // Item 0 - // SRS-Resource - // srs-ResourceId: 0 - // nrofSRS-Ports: port1 (0) - // transmissionComb: n2 (0) - // n2 - // combOffset-n2: 0 - // cyclicShift-n2: 0 - // resourceMapping - // startPosition: 0 - // nrofSymbols: n1 (0) - // repetitionFactor: n1 (0) - // freqDomainPosition: 0 - // freqDomainShift: 6 - // freqHopping - // c-SRS: 11 - // b-SRS: 3 - // b-hop: 0 - // groupOrSequenceHopping: neither (0) - // resourceType: aperiodic (0) - // aperiodic - // sequenceId: 500 - // firstActiveUplinkBWP-Id: 0 - // pusch-ServingCellConfig: setup (1) - // setup - // pdcch-ServingCellConfig: setup (1) - // setup - // pdsch-ServingCellConfig: setup (1) - // setup - // nrofHARQ-ProcessesForPDSCH: n16 (5) - // csi-MeasConfig: setup (1) - // setup - // nzp-CSI-RS-ResourceToAddModList: 5 items - // Item 0 - // NZP-CSI-RS-Resource - // nzp-CSI-RS-ResourceId: 0 - // resourceMapping - // frequencyDomainAllocation: row2 (1) - // row2: 8000 [bit length 12, 4 LSB pad bits, 1000 0000 0000 - // .... decimal value 2048] - // nrofPorts: p1 (0) - // firstOFDMSymbolInTimeDomain: 4 - // cdm-Type: noCDM (0) - // density: one (1) - // one: NULL - // freqBand - // startingRB: 0 - // nrofRBs: 52 - // powerControlOffset: 0dB - // powerControlOffsetSS: db0 (1) - // scramblingID: 0 - // periodicityAndOffset: slots80 (9) - // slots80: 1 - // qcl-InfoPeriodicCSI-RS: 0 - // Item 1 - // NZP-CSI-RS-Resource - // nzp-CSI-RS-ResourceId: 1 - // resourceMapping - // frequencyDomainAllocation: row1 (0) - // row1: 10 [bit length 4, 4 LSB pad bits, 0001 .... decimal - // value 1] - // nrofPorts: p1 (0) - // firstOFDMSymbolInTimeDomain: 4 - // cdm-Type: noCDM (0) - // density: three (2) - // three: NULL - // freqBand - // startingRB: 0 - // nrofRBs: 52 - // powerControlOffset: 0dB - // powerControlOffsetSS: db0 (1) - // scramblingID: 0 - // periodicityAndOffset: slots40 (7) - // slots40: 11 - // qcl-InfoPeriodicCSI-RS: 0 - // Item 2 - // NZP-CSI-RS-Resource - // nzp-CSI-RS-ResourceId: 2 - // resourceMapping - // frequencyDomainAllocation: row1 (0) - // row1: 10 [bit length 4, 4 LSB pad bits, 0001 .... decimal - // value 1] - // nrofPorts: p1 (0) - // firstOFDMSymbolInTimeDomain: 8 - // cdm-Type: noCDM (0) - // density: three (2) - // three: NULL - // freqBand - // startingRB: 0 - // nrofRBs: 52 - // powerControlOffset: 0dB - // powerControlOffsetSS: db0 (1) - // scramblingID: 0 - // periodicityAndOffset: slots40 (7) - // slots40: 11 - // qcl-InfoPeriodicCSI-RS: 0 - // Item 3 - // NZP-CSI-RS-Resource - // nzp-CSI-RS-ResourceId: 3 - // resourceMapping - // frequencyDomainAllocation: row1 (0) - // row1: 10 [bit length 4, 4 LSB pad bits, 0001 .... decimal - // value 1] - // nrofPorts: p1 (0) - // firstOFDMSymbolInTimeDomain: 4 - // cdm-Type: noCDM (0) - // density: three (2) - // three: NULL - // freqBand - // startingRB: 0 - // nrofRBs: 52 - // powerControlOffset: 0dB - // powerControlOffsetSS: db0 (1) - // scramblingID: 0 - // periodicityAndOffset: slots40 (7) - // slots40: 12 - // qcl-InfoPeriodicCSI-RS: 0 - // Item 4 - // NZP-CSI-RS-Resource - // nzp-CSI-RS-ResourceId: 4 - // resourceMapping - // frequencyDomainAllocation: row1 (0) - // row1: 10 [bit length 4, 4 LSB pad bits, 0001 .... decimal - // value 1] - // nrofPorts: p1 (0) - // firstOFDMSymbolInTimeDomain: 8 - // cdm-Type: noCDM (0) - // density: three (2) - // three: NULL - // freqBand - // startingRB: 0 - // nrofRBs: 52 - // powerControlOffset: 0dB - // powerControlOffsetSS: db0 (1) - // scramblingID: 0 - // periodicityAndOffset: slots40 (7) - // slots40: 12 - // qcl-InfoPeriodicCSI-RS: 0 - // nzp-CSI-RS-ResourceSetToAddModList: 2 items - // Item 0 - // NZP-CSI-RS-ResourceSet - // nzp-CSI-ResourceSetId: 0 - // nzp-CSI-RS-Resources: 1 item - // Item 0 - // NZP-CSI-RS-ResourceId: 0 - // Item 1 - // NZP-CSI-RS-ResourceSet - // nzp-CSI-ResourceSetId: 1 - // nzp-CSI-RS-Resources: 4 items - // Item 0 - // NZP-CSI-RS-ResourceId: 1 - // Item 1 - // NZP-CSI-RS-ResourceId: 2 - // Item 2 - // NZP-CSI-RS-ResourceId: 3 - // Item 3 - // NZP-CSI-RS-ResourceId: 4 - // trs-Info: true (0) - // csi-IM-ResourceToAddModList: 1 item - // Item 0 - // CSI-IM-Resource - // csi-IM-ResourceId: 0 - // csi-IM-ResourceElementPattern: pattern1 (1) - // pattern1 - // subcarrierLocation-p1: s8 (2) - // symbolLocation-p1: 8 - // freqBand - // startingRB: 0 - // nrofRBs: 52 - // periodicityAndOffset: slots80 (9) - // slots80: 1 - // csi-IM-ResourceSetToAddModList: 1 item - // Item 0 - // CSI-IM-ResourceSet - // csi-IM-ResourceSetId: 0 - // csi-IM-Resources: 1 item - // Item 0 - // CSI-IM-ResourceId: 0 - // csi-ResourceConfigToAddModList: 3 items - // Item 0 - // CSI-ResourceConfig - // csi-ResourceConfigId: 0 - // csi-RS-ResourceSetList: nzp-CSI-RS-SSB (0) - // nzp-CSI-RS-SSB - // nzp-CSI-RS-ResourceSetList: 1 item - // Item 0 - // NZP-CSI-RS-ResourceSetId: 0 - // bwp-Id: 0 - // resourceType: periodic (2) - // Item 1 - // CSI-ResourceConfig - // csi-ResourceConfigId: 1 - // csi-RS-ResourceSetList: csi-IM-ResourceSetList (1) - // csi-IM-ResourceSetList: 1 item - // Item 0 - // CSI-IM-ResourceSetId: 0 - // bwp-Id: 0 - // resourceType: periodic (2) - // Item 2 - // CSI-ResourceConfig - // csi-ResourceConfigId: 2 - // csi-RS-ResourceSetList: nzp-CSI-RS-SSB (0) - // nzp-CSI-RS-SSB - // nzp-CSI-RS-ResourceSetList: 1 item - // Item 0 - // NZP-CSI-RS-ResourceSetId: 1 - // bwp-Id: 0 - // resourceType: periodic (2) - // csi-ReportConfigToAddModList: 1 item - // Item 0 - // CSI-ReportConfig - // reportConfigId: 0 - // resourcesForChannelMeasurement: 0 - // csi-IM-ResourcesForInterference: 1 - // reportConfigType: periodic (0) - // periodic - // reportSlotConfig: slots80 (7) - // slots80: 9 - // pucch-CSI-ResourceList: 1 item - // Item 0 - // PUCCH-CSI-Resource - // uplinkBandwidthPartId: 0 - // pucch-Resource: 17 - // reportQuantity: cri-RI-PMI-CQI (1) - // cri-RI-PMI-CQI: NULL - // reportFreqConfiguration - // cqi-FormatIndicator: widebandCQI (0) - // timeRestrictionForChannelMeasurements: notConfigured (1) - // timeRestrictionForInterferenceMeasurements: notConfigured (1) - // groupBasedBeamReporting: disabled (1) - // disabled - // cqi-Table: table2 (1) - // subbandSize: value1 (0) - // tag-Id: 0 } class ue_dummy_stack : public srsue::stack_interface_phy_nr { +private: + uint16_t rnti = 0; + 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; + srsran_softbuffer_rx_t softbuffer = {}; + + dummy_harq_proc() + { + // Initialise softbuffer + if (srsran_softbuffer_rx_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_rx_free(&softbuffer); } + }; + srsran::circular_array rx_harq_proc; + public: + struct args_t { + uint16_t rnti = 0x1234; + }; + ue_dummy_stack(const args_t& args) : rnti(args.rnti) { valid = true; } void in_sync() override {} void out_of_sync() override {} void run_tti(const uint32_t tti) override {} int sf_indication(const uint32_t tti) override { return 0; } - sched_rnti_t get_dl_sched_rnti_nr(const uint32_t tti) override { return sched_rnti_t(); } - sched_rnti_t get_ul_sched_rnti_nr(const uint32_t tti) override { return sched_rnti_t(); } - void new_grant_dl(const uint32_t cc_idx, const mac_nr_grant_dl_t& grant, tb_action_dl_t* action) override {} + sched_rnti_t get_dl_sched_rnti_nr(const uint32_t tti) override { return {rnti, srsran_rnti_type_c}; } + sched_rnti_t get_ul_sched_rnti_nr(const uint32_t tti) override { return {rnti, srsran_rnti_type_c}; } + void new_grant_dl(const uint32_t cc_idx, const mac_nr_grant_dl_t& grant, tb_action_dl_t* action) override + { + action->tb.enabled = true; + action->tb.softbuffer = &rx_harq_proc[grant.pid].softbuffer; + } void tb_decoded(const uint32_t cc_idx, const mac_nr_grant_dl_t& grant, tb_action_dl_result_t result) override {} void new_grant_ul(const uint32_t cc_idx, const mac_nr_grant_ul_t& grant, tb_action_ul_t* action) override {} void prach_sent(uint32_t tti, uint32_t s_id, uint32_t t_id, uint32_t f_id, uint32_t ul_carrier_id) override {} bool sr_opportunity(uint32_t tti, uint32_t sr_id, bool meas_gap, bool ul_sch_tx) override { return false; } + 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 { - dl_sched_res[0].nof_grants = 0; + // 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(); + + // Parse test bench arguments 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.ue_args.log.id_preamble = " UE/"; + args.ue_args.log.phy_level = "warning"; + args.ue_args.log.phy_hex_limit = 0; + args.ue_args.nof_phy_threads = 1; // Parse arguments TESTASSERT(args.valid); - ue_dummy_stack ue_stack; - gnb_dummy_stack gnb_stack; + // Create UE stack arguments + ue_dummy_stack::args_t ue_stack_args = {}; + ue_stack_args.rnti = 0x1234; + + // Create UE stack + ue_dummy_stack ue_stack(ue_stack_args); + TESTASSERT(ue_stack.is_valid()); + + // Create GNB stack arguments + 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; + + // Create GNB stack + gnb_dummy_stack gnb_stack(gnb_stack_args); + TESTASSERT(gnb_stack.is_valid()); // Create test bench test_bench tb(args, gnb_stack, ue_stack); @@ -554,10 +522,10 @@ int main(int argc, char** argv) // Assert bench is initialised correctly TESTASSERT(tb.is_initialised()); - for (uint32_t i = 0; i < 1000; i++) { + for (uint32_t i = 0; i < 20; i++) { TESTASSERT(tb.run_tti()); } // If reached here, the test is successful return SRSRAN_SUCCESS; -} \ No newline at end of file +} diff --git a/test/phy/test_bench.h b/test/phy/test_bench.h index ff572d958..b878cb355 100644 --- a/test/phy/test_bench.h +++ b/test/phy/test_bench.h @@ -20,7 +20,9 @@ class test_bench { private: - uint32_t tti = 0; + const std::string UE_PHY_COM_LOG_NAME = "UE /PHY/COM"; + const std::string GNB_PHY_COM_LOG_NAME = "GNB/PHY/COM"; + uint32_t tti = 0; srsenb::nr::worker_pool gnb_phy; phy_common gnb_phy_com; srsue::nr::worker_pool ue_phy; @@ -38,7 +40,9 @@ public: srsran::phy_cfg_nr_t phy_cfg = {}; srsenb::phy_cell_cfg_list_nr_t cell_list = {}; srsenb::nr::worker_pool::args_t gnb_args; - uint16_t rnti = 0x1234; + srsue::phy_args_nr_t ue_args; + uint16_t rnti = 0x1234; + std::string phy_com_log_level = "info"; args_t(int argc, char** argv); }; @@ -47,18 +51,18 @@ public: ue_phy(args.nof_threads), gnb_phy(args.cell_list, args.gnb_args, gnb_phy_com, gnb_stack, srslog::get_default_sink()), ue_phy_com(phy_common::args_t(args.srate_hz, args.buffer_sz_ms, args.nof_channels), - srslog::fetch_basic_logger("UE /PHY/COM")), + 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")) + srslog::fetch_basic_logger(GNB_PHY_COM_LOG_NAME, srslog::get_default_sink(), false)) { + 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); - // Prepare PHY - srsue::phy_args_nr_t ue_phy_args = {}; - // Initialise UE PHY - if (not ue_phy.init(ue_phy_args, ue_phy_com, &ue_stack, 31)) { + if (not ue_phy.init(args.ue_args, ue_phy_com, &ue_stack, 31)) { return; } @@ -67,6 +71,11 @@ public: return; } + // Set UE configuration in gNb + if (not gnb_phy.addmod_rnti(args.rnti, args.phy_cfg)) { + return; + } + initialised = true; }