diff --git a/lib/include/srsran/interfaces/gnb_interfaces.h b/lib/include/srsran/interfaces/gnb_interfaces.h index f27b5d8f2..4dc8af583 100644 --- a/lib/include/srsran/interfaces/gnb_interfaces.h +++ b/lib/include/srsran/interfaces/gnb_interfaces.h @@ -258,9 +258,22 @@ public: srsran::bounded_vector pucch; }; - 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; + struct pucch_info_t { + srsran_uci_data_nr_t uci_data; ///< RNTI is available under cfg->pucch->rnti + // ... add signal measurements here + }; + + struct pusch_info_t { + uint16_t rnti; + srsran_pusch_res_nr_t pusch_data; + // ... add signal measurements here + }; + + 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; + virtual int pucch_info(const srsran_slot_cfg_t& slot_cfg, const pucch_info_t& pucch_info) = 0; + virtual int pusch_info(const srsran_slot_cfg_t& slot_cfg, const pusch_info_t& pusch_info) = 0; }; class stack_interface_phy_nr : public mac_interface_phy_nr, public srsran::stack_interface_phy_nr diff --git a/lib/include/srsran/phy/phch/pucch_nr.h b/lib/include/srsran/phy/phch/pucch_nr.h index a562e7b03..c652c148c 100644 --- a/lib/include/srsran/phy/phch/pucch_nr.h +++ b/lib/include/srsran/phy/phch/pucch_nr.h @@ -188,6 +188,7 @@ SRSRAN_API int srsran_pucch_nr_format1_encode(const srsran_pucch_nr_t* * @param[in] slot_symbols Resource grid of the given slot * @param[out] b Bits to decode * @param[in] nof_bits Number of bits to decode in the message + * @param[out] norm_corr Normalised correlation * @return SRSRAN_SUCCESS if successful, SRSRAN_ERROR code otherwise */ SRSRAN_API int srsran_pucch_nr_format1_decode(srsran_pucch_nr_t* q, @@ -197,7 +198,8 @@ SRSRAN_API int srsran_pucch_nr_format1_decode(srsran_pucch_nr_t* srsran_chest_ul_res_t* chest_res, cf_t* slot_symbols, uint8_t b[SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS], - uint32_t nof_bits); + uint32_t nof_bits, + float* norm_corr); /** * @brief Encoder NR-PUCCH formats 2, 3 and 4. The NR-PUCCH format is selected by resource->format. diff --git a/lib/src/common/phy_cfg_nr_default.cc b/lib/src/common/phy_cfg_nr_default.cc index becebda6a..b674ea8d8 100644 --- a/lib/src/common/phy_cfg_nr_default.cc +++ b/lib/src/common/phy_cfg_nr_default.cc @@ -228,7 +228,7 @@ phy_cfg_nr_default_t::phy_cfg_nr_default_t(const reference_cfg_t& reference_cfg) switch (reference_cfg.pucch) { case reference_cfg_t::R_PUCCH_CUSTOM_ONE: - make_pusch_default(pusch); + make_pucch_custom_one(pucch); break; } diff --git a/lib/src/phy/gnb/gnb_ul.c b/lib/src/phy/gnb/gnb_ul.c index 0072adcbe..b8961c682 100644 --- a/lib/src/phy/gnb/gnb_ul.c +++ b/lib/src/phy/gnb/gnb_ul.c @@ -194,18 +194,25 @@ static int gnb_ul_decode_pucch_format1(srsran_gnb_ul_t* q, nof_bits = 1; } + // Channel estimation if (srsran_dmrs_pucch_format1_estimate(&q->pucch, cfg, slot_cfg, resource, q->sf_symbols[0], &q->chest_pucch) < SRSRAN_SUCCESS) { ERROR("Error in PUCCH format 1 estimation"); return SRSRAN_ERROR; } + // Actual decode + float norm_corr = 0.0f; if (srsran_pucch_nr_format1_decode( - &q->pucch, cfg, slot_cfg, resource, &q->chest_pucch, q->sf_symbols[0], b, nof_bits) < SRSRAN_SUCCESS) { + &q->pucch, cfg, slot_cfg, resource, &q->chest_pucch, q->sf_symbols[0], b, nof_bits, &norm_corr) < + SRSRAN_SUCCESS) { ERROR("Error in PUCCH format 1 decoding"); return SRSRAN_ERROR; } + // Take valid decision + uci_value->valid = (norm_corr > 0.5f); + // De-multiplex ACK bits for (uint32_t i = 0; i < nof_bits; i++) { uci_value->ack[i] = b[i]; diff --git a/lib/src/phy/phch/pucch_nr.c b/lib/src/phy/phch/pucch_nr.c index f7a7d1b80..58264f449 100644 --- a/lib/src/phy/phch/pucch_nr.c +++ b/lib/src/phy/phch/pucch_nr.c @@ -452,7 +452,8 @@ int srsran_pucch_nr_format1_decode(srsran_pucch_nr_t* q, srsran_chest_ul_res_t* chest_res, cf_t* slot_symbols, uint8_t b[SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS], - uint32_t nof_bits) + uint32_t nof_bits, + float* norm_corr) { uint32_t m_cs = 0; @@ -524,8 +525,14 @@ int srsran_pucch_nr_format1_decode(srsran_pucch_nr_t* q, srsran_demod_soft_demodulate((nof_bits == 1) ? SRSRAN_MOD_BPSK : SRSRAN_MOD_QPSK, &d, llr, 1); // Hard decision + float corr = 0.0f; for (uint32_t i = 0; i < nof_bits; i++) { b[i] = llr[i] > 0.0f ? 1 : 0; + corr += fabsf(llr[i]); + } + + if (norm_corr != NULL && nof_bits > 0) { + *norm_corr = corr / nof_bits; } return SRSRAN_SUCCESS; diff --git a/lib/src/phy/phch/test/pucch_nr_test.c b/lib/src/phy/phch/test/pucch_nr_test.c index 933f3661a..067c3b8ad 100644 --- a/lib/src/phy/phch/test/pucch_nr_test.c +++ b/lib/src/phy/phch/test/pucch_nr_test.c @@ -139,7 +139,7 @@ static int test_pucch_format1(srsran_pucch_nr_t* pucch, // Decode PUCCH uint8_t b_rx[SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS]; TESTASSERT(srsran_pucch_nr_format1_decode( - pucch, cfg, &slot, &resource, chest_res, slot_symbols, b_rx, nof_bits) == + pucch, cfg, &slot, &resource, chest_res, slot_symbols, b_rx, nof_bits, NULL) == SRSRAN_SUCCESS); // Check received bits diff --git a/srsenb/hdr/stack/gnb_stack_nr.h b/srsenb/hdr/stack/gnb_stack_nr.h index 328348e4c..556e349a8 100644 --- a/srsenb/hdr/stack/gnb_stack_nr.h +++ b/srsenb/hdr/stack/gnb_stack_nr.h @@ -75,6 +75,8 @@ public: 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; + int pucch_info(const srsran_slot_cfg_t& slot_cfg, const pucch_info_t& pucch_info) override; + int pusch_info(const srsran_slot_cfg_t& slot_cfg, const pusch_info_t& pusch_info) 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 7290dfcbd..94ab96e56 100644 --- a/srsenb/hdr/stack/mac/mac_nr.h +++ b/srsenb/hdr/stack/mac/mac_nr.h @@ -68,6 +68,8 @@ public: 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; + int pucch_info(const srsran_slot_cfg_t& slot_cfg, const pucch_info_t& pucch_info) override; + int pusch_info(const srsran_slot_cfg_t& slot_cfg, const pusch_info_t& pusch_info) override; private: void get_dl_config(const uint32_t tti, diff --git a/srsenb/src/phy/nr/slot_worker.cc b/srsenb/src/phy/nr/slot_worker.cc index bd89652ba..b355f8b55 100644 --- a/srsenb/src/phy/nr/slot_worker.cc +++ b/srsenb/src/phy/nr/slot_worker.cc @@ -159,17 +159,30 @@ bool slot_worker::work_ul() // Decode PUCCH for (stack_interface_phy_nr::pucch_t& pucch : ul_sched.pucch) { - srsran_uci_value_nr_t uci_value; - if (srsran_gnb_ul_get_pucch(&gnb_ul, &ul_slot_cfg, &pucch.pucch_cfg, &pucch.resource, &pucch.uci_cfg, &uci_value) < - SRSRAN_SUCCESS) { + stack_interface_phy_nr::pucch_info_t pucch_info = {}; + pucch_info.uci_data.cfg = pucch.uci_cfg; + + // Decode PUCCH + if (srsran_gnb_ul_get_pucch(&gnb_ul, + &ul_slot_cfg, + &pucch.pucch_cfg, + &pucch.resource, + &pucch_info.uci_data.cfg, + &pucch_info.uci_data.value) < SRSRAN_SUCCESS) { logger.error("Error getting PUCCH"); return false; } + // Inform stack + if (stack.pucch_info(ul_slot_cfg, pucch_info) < SRSRAN_SUCCESS) { + logger.error("Error pushing PUCCH information to stack"); + return false; + } + + // Log PUCCH decoding if (logger.info.enabled()) { std::array str; - srsran_uci_data_nr_t uci_data = {.cfg = pucch.uci_cfg, .value = uci_value}; - srsran_gnb_ul_pucch_info(&gnb_ul, &pucch.resource, &uci_data, str.data(), (uint32_t)str.size()); + srsran_gnb_ul_pucch_info(&gnb_ul, &pucch.resource, &pucch_info.uci_data, str.data(), (uint32_t)str.size()); logger.info("PUCCH: %s", str.data()); } diff --git a/srsenb/src/stack/gnb_stack_nr.cc b/srsenb/src/stack/gnb_stack_nr.cc index 54a25b4bc..1247d9b2d 100644 --- a/srsenb/src/stack/gnb_stack_nr.cc +++ b/srsenb/src/stack/gnb_stack_nr.cc @@ -189,5 +189,13 @@ int gnb_stack_nr::get_ul_sched(const srsran_slot_cfg_t& slot_cfg, ul_sched_t& ul { return m_mac->get_ul_sched(slot_cfg, ul_sched); } +int gnb_stack_nr::pucch_info(const srsran_slot_cfg_t& slot_cfg, const mac_interface_phy_nr::pucch_info_t& pucch_info) +{ + return m_mac->pucch_info(slot_cfg, pucch_info); +} +int gnb_stack_nr::pusch_info(const srsran_slot_cfg_t& slot_cfg, const mac_interface_phy_nr::pusch_info_t& pusch_info) +{ + return m_mac->pusch_info(slot_cfg, pusch_info); +} } // namespace srsenb diff --git a/srsenb/src/stack/mac/nr/mac_nr.cc b/srsenb/src/stack/mac/nr/mac_nr.cc index f03dec542..def64c456 100644 --- a/srsenb/src/stack/mac/nr/mac_nr.cc +++ b/srsenb/src/stack/mac/nr/mac_nr.cc @@ -276,5 +276,13 @@ int mac_nr::get_ul_sched(const srsran_slot_cfg_t& slot_cfg, ul_sched_t& ul_sched { return 0; } +int mac_nr::pucch_info(const srsran_slot_cfg_t& slot_cfg, const mac_interface_phy_nr::pucch_info_t& pucch_info) +{ + return 0; +} +int mac_nr::pusch_info(const srsran_slot_cfg_t& slot_cfg, const mac_interface_phy_nr::pusch_info_t& pusch_info) +{ + return 0; +} } // namespace srsenb diff --git a/test/phy/dummy_gnb_stack.h b/test/phy/dummy_gnb_stack.h index 5705d78ee..1d1008c9a 100644 --- a/test/phy/dummy_gnb_stack.h +++ b/test/phy/dummy_gnb_stack.h @@ -14,8 +14,10 @@ #define SRSRAN_DUMMY_GNB_STACK_H #include +#include #include #include +#include #include class gnb_dummy_stack : public srsenb::stack_interface_phy_nr @@ -36,6 +38,9 @@ private: srsran::phy_cfg_nr_t phy_cfg = {}; bool valid = false; + std::mutex mac_metrics_mutex; + srsenb::mac_ue_metrics_t mac_metrics = {}; + // HARQ feedback class pending_ack_t { @@ -61,21 +66,15 @@ private: srsran_pdsch_ack_nr_t get_ack() { std::unique_lock lock(mutex); - - return ack; + srsran_pdsch_ack_nr_t ret = ack; + ack = {}; + return ret; } uint32_t get_dai() { std::unique_lock lock(mutex); return ack.cc[0].M % 4; } - - void reset() - { - std::unique_lock lock(mutex); - - ack = {}; - } }; srsran::circular_array pending_ack; @@ -264,7 +263,6 @@ public: logger.set_context(slot_cfg.idx); srsran_pdsch_ack_nr_t ack = pending_ack[slot_cfg.idx].get_ack(); - pending_ack[slot_cfg.idx].reset(); if (ack.nof_cc > 0) { mac_interface_phy_nr::pucch_t pucch = {}; @@ -286,6 +284,36 @@ public: return 0; } + + int pucch_info(const srsran_slot_cfg_t& slot_cfg, const pucch_info_t& pucch_info) override + { + std::unique_lock lock(mac_metrics_mutex); + + for (uint32_t i = 0; i < pucch_info.uci_data.cfg.ack.count; i++) { + const srsran_harq_ack_bit_t* ack_bit = &pucch_info.uci_data.cfg.ack.bits[i]; + bool is_ok = (pucch_info.uci_data.value.ack[i] == 1) and pucch_info.uci_data.value.valid; + uint32_t tb_count = (ack_bit->tb0 ? 1 : 0) + (ack_bit->tb1 ? 1 : 0); + mac_metrics.tx_pkts += tb_count; + if (not is_ok) { + mac_metrics.tx_errors += tb_count; + logger.debug("NACK received!"); + } + } + return SRSRAN_SUCCESS; + } + + int pusch_info(const srsran_slot_cfg_t& slot_cfg, const pusch_info_t& pusch_info) override + { + // ... Not implemented + return SRSRAN_ERROR; + } + + srsenb::mac_ue_metrics_t get_metrics() + { + std::unique_lock lock(mac_metrics_mutex); + + return mac_metrics; + } }; #endif // SRSRAN_DUMMY_GNB_STACK_H diff --git a/test/phy/nr_dl_flood.cc b/test/phy/nr_dl_flood.cc index 5476c93d0..270e74894 100644 --- a/test/phy/nr_dl_flood.cc +++ b/test/phy/nr_dl_flood.cc @@ -120,10 +120,38 @@ int main(int argc, char** argv) // Assert bench is initialised correctly TESTASSERT(tb.is_initialised()); - for (uint32_t i = 0; i < 20; i++) { + // Run per TTI basis + for (uint32_t i = 0; i < 1000; i++) { TESTASSERT(tb.run_tti()); } + // Stop test bench + tb.stop(); + + // Flush log + srslog::flush(); + + // Retrieve MAC metrics + srsenb::mac_ue_metrics_t mac_metrics = gnb_stack.get_metrics(); + + // Print metrics + float pdsch_bler = 0.0f; + if (mac_metrics.tx_pkts != 0) { + pdsch_bler = (float)mac_metrics.tx_errors / (float)mac_metrics.tx_pkts; + } + float pdsch_rate = 0.0f; + if (mac_metrics.tx_pkts != 0) { + pdsch_rate = (float)mac_metrics.tx_brate / (float)mac_metrics.tx_pkts / 1000.0f; + } + + srsran::console("PDSCH:\n"); + srsran::console(" Count: %d\n", mac_metrics.tx_pkts); + srsran::console(" BLER: %f\n", pdsch_bler); + srsran::console(" Rate: %f Mbps\n", pdsch_rate); + + // Assert metrics + TESTASSERT(mac_metrics.tx_errors == 0); + // If reached here, the test is successful return SRSRAN_SUCCESS; } diff --git a/test/phy/test_bench.h b/test/phy/test_bench.h index 11425de6f..91282ed4c 100644 --- a/test/phy/test_bench.h +++ b/test/phy/test_bench.h @@ -75,7 +75,7 @@ public: initialised = true; } - ~test_bench() + void stop() { ue_phy_com.stop(); gnb_phy_com.stop(); @@ -83,6 +83,8 @@ public: ue_phy.stop(); } + ~test_bench() = default; + bool is_initialised() const { return initialised; } bool run_tti()