From dd9889e07c1073c9ff3fa103d7f2b9efeb0dceb5 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Thu, 22 Apr 2021 16:04:05 +0200 Subject: [PATCH 01/24] Add carrier index to uplink PCAP captures --- lib/include/srsran/mac/pdu_queue.h | 5 +++-- lib/src/mac/pdu_queue.cc | 7 ++++--- srsenb/hdr/stack/mac/ue.h | 2 +- srsenb/src/stack/mac/mac.cc | 4 ++-- srsenb/src/stack/mac/ue.cc | 6 +++--- srsue/hdr/stack/mac/demux.h | 2 +- srsue/src/stack/mac/demux.cc | 4 ++-- 7 files changed, 16 insertions(+), 14 deletions(-) diff --git a/lib/include/srsran/mac/pdu_queue.h b/lib/include/srsran/mac/pdu_queue.h index 424c505b0..00aa3cde7 100644 --- a/lib/include/srsran/mac/pdu_queue.h +++ b/lib/include/srsran/mac/pdu_queue.h @@ -30,7 +30,7 @@ public: class process_callback { public: - virtual void process_pdu(uint8_t* buff, uint32_t len, channel_t channel, int ul_nof_prbs = -1) = 0; + virtual void process_pdu(uint8_t* buff, uint32_t len, uint32_t ue_cc_idx, channel_t channel, int ul_nof_prbs = -1) = 0; }; pdu_queue(srslog::basic_logger& logger) : pool(DEFAULT_POOL_SIZE), callback(NULL), logger(logger) {} @@ -38,7 +38,7 @@ public: uint8_t* request(uint32_t len); void deallocate(const uint8_t* pdu); - void push(const uint8_t* ptr, uint32_t len, channel_t channel = DCH, int ul_nof_prbs = -1); + void push(const uint8_t* ptr, uint32_t len, uint32_t ue_cc_idx, channel_t channel = DCH, int ul_nof_prbs = -1); bool process_pdus(); @@ -51,6 +51,7 @@ private: typedef struct { uint8_t ptr[MAX_PDU_LEN]; uint32_t len; + uint32_t ue_cc_idx; channel_t channel; int grant_nof_prbs; #ifdef SRSRAN_BUFFER_POOL_LOG_ENABLED diff --git a/lib/src/mac/pdu_queue.cc b/lib/src/mac/pdu_queue.cc index cc4481234..e80b0b89e 100644 --- a/lib/src/mac/pdu_queue.cc +++ b/lib/src/mac/pdu_queue.cc @@ -50,15 +50,16 @@ void pdu_queue::deallocate(const uint8_t* pdu) } /* Demultiplexing of logical channels and dissassemble of MAC CE - * This function enqueues the packet and returns quicly because ACK + * This function enqueues the packet and returns quickly because ACK * deadline is important here. */ -void pdu_queue::push(const uint8_t* ptr, uint32_t len, channel_t channel, int grant_nof_prbs) +void pdu_queue::push(const uint8_t* ptr, uint32_t len, uint32_t ue_cc_idx, channel_t channel, int grant_nof_prbs) { if (ptr) { pdu_t* pdu = (pdu_t*)ptr; pdu->len = len; pdu->channel = channel; + pdu->ue_cc_idx = ue_cc_idx; pdu->grant_nof_prbs = grant_nof_prbs; if (!pdu_q.try_push(pdu)) { logger.warning("Error pushing pdu: queue is full"); @@ -75,7 +76,7 @@ bool pdu_queue::process_pdus() pdu_t* pdu; while (pdu_q.try_pop(pdu)) { if (callback) { - callback->process_pdu(pdu->ptr, pdu->len, pdu->channel, pdu->grant_nof_prbs); + callback->process_pdu(pdu->ptr, pdu->len, pdu->ue_cc_idx, pdu->channel, pdu->grant_nof_prbs); } cnt++; have_data = true; diff --git a/srsenb/hdr/stack/mac/ue.h b/srsenb/hdr/stack/mac/ue.h index 77d7354a5..cb7a21164 100644 --- a/srsenb/hdr/stack/mac/ue.h +++ b/srsenb/hdr/stack/mac/ue.h @@ -160,7 +160,7 @@ public: srsran_softbuffer_rx_t* get_rx_softbuffer(uint32_t enb_cc_idx, uint32_t tti); uint8_t* request_buffer(uint32_t tti, uint32_t enb_cc_idx, uint32_t len); - void process_pdu(srsran::unique_byte_buffer_t pdu, uint32_t grant_nof_prbs); + void process_pdu(srsran::unique_byte_buffer_t pdu, uint32_t ue_cc_idx, uint32_t grant_nof_prbs); srsran::unique_byte_buffer_t release_pdu(uint32_t tti, uint32_t enb_cc_idx); void clear_old_buffers(uint32_t tti); diff --git a/srsenb/src/stack/mac/mac.cc b/srsenb/src/stack/mac/mac.cc index 144e2dd5b..430f7e493 100644 --- a/srsenb/src/stack/mac/mac.cc +++ b/srsenb/src/stack/mac/mac.cc @@ -331,10 +331,10 @@ int mac::push_pdu(uint32_t tti_rx, tti_rx, nof_bytes, (int)pdu->size()); - auto process_pdu_task = [this, rnti, ul_nof_prbs](srsran::unique_byte_buffer_t& pdu) { + auto process_pdu_task = [this, rnti, enb_cc_idx, ul_nof_prbs](srsran::unique_byte_buffer_t& pdu) { srsran::rwlock_read_guard lock(rwlock); if (check_ue_active(rnti)) { - ue_db[rnti]->process_pdu(std::move(pdu), ul_nof_prbs); + ue_db[rnti]->process_pdu(std::move(pdu), enb_cc_idx, ul_nof_prbs); } else { logger.debug("Discarding PDU rnti=0x%x", rnti); } diff --git a/srsenb/src/stack/mac/ue.cc b/srsenb/src/stack/mac/ue.cc index 0772a1491..4a54a7294 100644 --- a/srsenb/src/stack/mac/ue.cc +++ b/srsenb/src/stack/mac/ue.cc @@ -287,7 +287,7 @@ uint32_t ue::set_ta(int ta_) return nof_cmd; } -void ue::process_pdu(srsran::unique_byte_buffer_t pdu, uint32_t grant_nof_prbs) +void ue::process_pdu(srsran::unique_byte_buffer_t pdu, uint32_t ue_cc_idx, uint32_t grant_nof_prbs) { // Unpack ULSCH MAC PDU mac_msg_ul.init_rx(pdu->size(), true); @@ -300,11 +300,11 @@ void ue::process_pdu(srsran::unique_byte_buffer_t pdu, uint32_t grant_nof_prbs) } if (pcap != nullptr) { - pcap->write_ul_crnti(pdu->data(), pdu->size(), rnti, true, last_tti, UL_CC_IDX); + pcap->write_ul_crnti(pdu->data(), pdu->size(), rnti, true, last_tti, ue_cc_idx); } if (pcap_net != nullptr) { - pcap_net->write_ul_crnti(pdu->data(), pdu->size(), rnti, true, last_tti, UL_CC_IDX); + pcap_net->write_ul_crnti(pdu->data(), pdu->size(), rnti, true, last_tti, ue_cc_idx); } uint32_t lcid_most_data = 0; diff --git a/srsue/hdr/stack/mac/demux.h b/srsue/hdr/stack/mac/demux.h index b010252c9..cf30a4c32 100644 --- a/srsue/hdr/stack/mac/demux.h +++ b/srsue/hdr/stack/mac/demux.h @@ -56,7 +56,7 @@ public: bool get_uecrid_successful(); - void process_pdu(uint8_t* pdu, uint32_t nof_bytes, srsran::pdu_queue::channel_t channel, int ul_nof_prbs); + void process_pdu(uint8_t* pdu, uint32_t nof_bytes, uint32_t cc_idx, srsran::pdu_queue::channel_t channel, int ul_nof_prbs); void mch_start_rx(uint32_t lcid); private: diff --git a/srsue/src/stack/mac/demux.cc b/srsue/src/stack/mac/demux.cc index eeff692b0..3a2d74a65 100644 --- a/srsue/src/stack/mac/demux.cc +++ b/srsue/src/stack/mac/demux.cc @@ -123,7 +123,7 @@ void demux::push_pdu(uint8_t* buff, uint32_t nof_bytes, uint32_t tti) // Process Real-Time PDUs process_sch_pdu_rt(buff, nof_bytes, tti); - return pdus.push(buff, nof_bytes, srsran::pdu_queue::DCH); + return pdus.push(buff, nof_bytes, 0, srsran::pdu_queue::DCH); } /* Demultiplexing of MAC PDU associated with SI-RNTI. The PDU passes through @@ -147,7 +147,7 @@ bool demux::process_pdus() return pdus.process_pdus(); } -void demux::process_pdu(uint8_t* mac_pdu, uint32_t nof_bytes, srsran::pdu_queue::channel_t channel, int ul_nof_prbs) +void demux::process_pdu(uint8_t* mac_pdu, uint32_t nof_bytes, uint32_t cc_idx, srsran::pdu_queue::channel_t channel, int ul_nof_prbs) { Debug("Processing MAC PDU channel %d", channel); switch (channel) { From c206d3c0fafca5e91e1079e1a14f24097e8f92de Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Mon, 17 May 2021 18:23:58 +0200 Subject: [PATCH 02/24] fix ttcn3 tests --- srsue/src/test/ttcn3/hdr/ttcn3_syssim.h | 2 +- srsue/src/test/ttcn3/src/ttcn3_syssim.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/srsue/src/test/ttcn3/hdr/ttcn3_syssim.h b/srsue/src/test/ttcn3/hdr/ttcn3_syssim.h index 7de69a831..d362092b0 100644 --- a/srsue/src/test/ttcn3/hdr/ttcn3_syssim.h +++ b/srsue/src/test/ttcn3/hdr/ttcn3_syssim.h @@ -104,7 +104,7 @@ public: uint32_t get_tti(); - void process_pdu(uint8_t* buff, uint32_t len, pdu_queue::channel_t channel, int ul_nof_prbs); + void process_pdu(uint8_t* buff, uint32_t len, uint32_t ue_cc_idx, pdu_queue::channel_t channel, int ul_nof_prbs); void set_cell_config(const ttcn3_helpers::timing_info_t timing, const cell_config_t cell); void set_cell_config_impl(const cell_config_t cell); diff --git a/srsue/src/test/ttcn3/src/ttcn3_syssim.cc b/srsue/src/test/ttcn3/src/ttcn3_syssim.cc index ab6c51fe3..ba1a82df2 100644 --- a/srsue/src/test/ttcn3/src/ttcn3_syssim.cc +++ b/srsue/src/test/ttcn3/src/ttcn3_syssim.cc @@ -759,7 +759,7 @@ uint32_t ttcn3_syssim::get_tti() return tti; } -void ttcn3_syssim::process_pdu(uint8_t* buff, uint32_t len, pdu_queue::channel_t channel, int ul_nof_prbs) {} +void ttcn3_syssim::process_pdu(uint8_t* buff, uint32_t len, uint32_t ue_cc_idx, pdu_queue::channel_t channel, int ul_nof_prbs) {} void ttcn3_syssim::set_cell_config(const ttcn3_helpers::timing_info_t timing, const cell_config_t cell) { From 02ec4dd3d01f375a90b9f1457c766e0a84aba7db Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Tue, 18 May 2021 10:35:02 +0200 Subject: [PATCH 03/24] Remove unused variable --- srsenb/hdr/stack/mac/ue.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/srsenb/hdr/stack/mac/ue.h b/srsenb/hdr/stack/mac/ue.h index cb7a21164..895466104 100644 --- a/srsenb/hdr/stack/mac/ue.h +++ b/srsenb/hdr/stack/mac/ue.h @@ -215,8 +215,6 @@ private: // Mutexes std::mutex mutex; std::mutex rx_buffers_mutex; - - static const uint8_t UL_CC_IDX = 0; ///< Passed to write CC index in PCAP }; } // namespace srsenb From aa5944da78f6064f3d076d4c5f67f573a29b19df Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Wed, 2 Jun 2021 12:53:15 +0200 Subject: [PATCH 04/24] Fix T-CRNTI push pdu --- srsue/src/stack/mac/demux.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/srsue/src/stack/mac/demux.cc b/srsue/src/stack/mac/demux.cc index 3a2d74a65..77f666f78 100644 --- a/srsue/src/stack/mac/demux.cc +++ b/srsue/src/stack/mac/demux.cc @@ -105,7 +105,7 @@ void demux::push_pdu_temp_crnti(uint8_t* buff, uint32_t nof_bytes) pending_mac_msg.reset(); if (is_uecrid_successful) { Debug("Saved MAC PDU with Temporal C-RNTI in buffer"); - pdus.push(buff, nof_bytes, srsran::pdu_queue::DCH); + pdus.push(buff, nof_bytes, 0, srsran::pdu_queue::DCH); } else { pdus.deallocate(buff); } From e35a0d72faef384acaaceb598b7cfa14b89ed6c9 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Fri, 18 Jun 2021 14:47:02 +0200 Subject: [PATCH 05/24] Revert UE changes --- lib/include/srsran/mac/pdu_queue.h | 2 +- lib/src/mac/pdu_queue.cc | 2 +- srsue/hdr/stack/mac/demux.h | 2 +- srsue/src/stack/mac/demux.cc | 2 +- srsue/src/test/ttcn3/hdr/ttcn3_syssim.h | 2 +- srsue/src/test/ttcn3/src/ttcn3_syssim.cc | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/include/srsran/mac/pdu_queue.h b/lib/include/srsran/mac/pdu_queue.h index 00aa3cde7..f93f4cfd2 100644 --- a/lib/include/srsran/mac/pdu_queue.h +++ b/lib/include/srsran/mac/pdu_queue.h @@ -30,7 +30,7 @@ public: class process_callback { public: - virtual void process_pdu(uint8_t* buff, uint32_t len, uint32_t ue_cc_idx, channel_t channel, int ul_nof_prbs = -1) = 0; + virtual void process_pdu(uint8_t* buff, uint32_t len, channel_t channel, int ul_nof_prbs = -1) = 0; }; pdu_queue(srslog::basic_logger& logger) : pool(DEFAULT_POOL_SIZE), callback(NULL), logger(logger) {} diff --git a/lib/src/mac/pdu_queue.cc b/lib/src/mac/pdu_queue.cc index e80b0b89e..16c6cde6d 100644 --- a/lib/src/mac/pdu_queue.cc +++ b/lib/src/mac/pdu_queue.cc @@ -76,7 +76,7 @@ bool pdu_queue::process_pdus() pdu_t* pdu; while (pdu_q.try_pop(pdu)) { if (callback) { - callback->process_pdu(pdu->ptr, pdu->len, pdu->ue_cc_idx, pdu->channel, pdu->grant_nof_prbs); + callback->process_pdu(pdu->ptr, pdu->len, pdu->channel, pdu->grant_nof_prbs); } cnt++; have_data = true; diff --git a/srsue/hdr/stack/mac/demux.h b/srsue/hdr/stack/mac/demux.h index cf30a4c32..b010252c9 100644 --- a/srsue/hdr/stack/mac/demux.h +++ b/srsue/hdr/stack/mac/demux.h @@ -56,7 +56,7 @@ public: bool get_uecrid_successful(); - void process_pdu(uint8_t* pdu, uint32_t nof_bytes, uint32_t cc_idx, srsran::pdu_queue::channel_t channel, int ul_nof_prbs); + void process_pdu(uint8_t* pdu, uint32_t nof_bytes, srsran::pdu_queue::channel_t channel, int ul_nof_prbs); void mch_start_rx(uint32_t lcid); private: diff --git a/srsue/src/stack/mac/demux.cc b/srsue/src/stack/mac/demux.cc index 77f666f78..7c73e60e2 100644 --- a/srsue/src/stack/mac/demux.cc +++ b/srsue/src/stack/mac/demux.cc @@ -147,7 +147,7 @@ bool demux::process_pdus() return pdus.process_pdus(); } -void demux::process_pdu(uint8_t* mac_pdu, uint32_t nof_bytes, uint32_t cc_idx, srsran::pdu_queue::channel_t channel, int ul_nof_prbs) +void demux::process_pdu(uint8_t* mac_pdu, uint32_t nof_bytes, srsran::pdu_queue::channel_t channel, int ul_nof_prbs) { Debug("Processing MAC PDU channel %d", channel); switch (channel) { diff --git a/srsue/src/test/ttcn3/hdr/ttcn3_syssim.h b/srsue/src/test/ttcn3/hdr/ttcn3_syssim.h index d362092b0..7de69a831 100644 --- a/srsue/src/test/ttcn3/hdr/ttcn3_syssim.h +++ b/srsue/src/test/ttcn3/hdr/ttcn3_syssim.h @@ -104,7 +104,7 @@ public: uint32_t get_tti(); - void process_pdu(uint8_t* buff, uint32_t len, uint32_t ue_cc_idx, pdu_queue::channel_t channel, int ul_nof_prbs); + void process_pdu(uint8_t* buff, uint32_t len, pdu_queue::channel_t channel, int ul_nof_prbs); void set_cell_config(const ttcn3_helpers::timing_info_t timing, const cell_config_t cell); void set_cell_config_impl(const cell_config_t cell); diff --git a/srsue/src/test/ttcn3/src/ttcn3_syssim.cc b/srsue/src/test/ttcn3/src/ttcn3_syssim.cc index ba1a82df2..ab6c51fe3 100644 --- a/srsue/src/test/ttcn3/src/ttcn3_syssim.cc +++ b/srsue/src/test/ttcn3/src/ttcn3_syssim.cc @@ -759,7 +759,7 @@ uint32_t ttcn3_syssim::get_tti() return tti; } -void ttcn3_syssim::process_pdu(uint8_t* buff, uint32_t len, uint32_t ue_cc_idx, pdu_queue::channel_t channel, int ul_nof_prbs) {} +void ttcn3_syssim::process_pdu(uint8_t* buff, uint32_t len, pdu_queue::channel_t channel, int ul_nof_prbs) {} void ttcn3_syssim::set_cell_config(const ttcn3_helpers::timing_info_t timing, const cell_config_t cell) { From 5aa5a8e997ce5143f2c5a8b813b1670c7f0eba0c Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Fri, 18 Jun 2021 14:50:19 +0200 Subject: [PATCH 06/24] Revert UE changes --- lib/include/srsran/mac/pdu_queue.h | 3 +-- lib/src/mac/pdu_queue.cc | 3 +-- srsue/src/stack/mac/demux.cc | 4 ++-- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/lib/include/srsran/mac/pdu_queue.h b/lib/include/srsran/mac/pdu_queue.h index f93f4cfd2..424c505b0 100644 --- a/lib/include/srsran/mac/pdu_queue.h +++ b/lib/include/srsran/mac/pdu_queue.h @@ -38,7 +38,7 @@ public: uint8_t* request(uint32_t len); void deallocate(const uint8_t* pdu); - void push(const uint8_t* ptr, uint32_t len, uint32_t ue_cc_idx, channel_t channel = DCH, int ul_nof_prbs = -1); + void push(const uint8_t* ptr, uint32_t len, channel_t channel = DCH, int ul_nof_prbs = -1); bool process_pdus(); @@ -51,7 +51,6 @@ private: typedef struct { uint8_t ptr[MAX_PDU_LEN]; uint32_t len; - uint32_t ue_cc_idx; channel_t channel; int grant_nof_prbs; #ifdef SRSRAN_BUFFER_POOL_LOG_ENABLED diff --git a/lib/src/mac/pdu_queue.cc b/lib/src/mac/pdu_queue.cc index 16c6cde6d..0bb879467 100644 --- a/lib/src/mac/pdu_queue.cc +++ b/lib/src/mac/pdu_queue.cc @@ -53,13 +53,12 @@ void pdu_queue::deallocate(const uint8_t* pdu) * This function enqueues the packet and returns quickly because ACK * deadline is important here. */ -void pdu_queue::push(const uint8_t* ptr, uint32_t len, uint32_t ue_cc_idx, channel_t channel, int grant_nof_prbs) +void pdu_queue::push(const uint8_t* ptr, uint32_t len, channel_t channel, int grant_nof_prbs) { if (ptr) { pdu_t* pdu = (pdu_t*)ptr; pdu->len = len; pdu->channel = channel; - pdu->ue_cc_idx = ue_cc_idx; pdu->grant_nof_prbs = grant_nof_prbs; if (!pdu_q.try_push(pdu)) { logger.warning("Error pushing pdu: queue is full"); diff --git a/srsue/src/stack/mac/demux.cc b/srsue/src/stack/mac/demux.cc index 7c73e60e2..eeff692b0 100644 --- a/srsue/src/stack/mac/demux.cc +++ b/srsue/src/stack/mac/demux.cc @@ -105,7 +105,7 @@ void demux::push_pdu_temp_crnti(uint8_t* buff, uint32_t nof_bytes) pending_mac_msg.reset(); if (is_uecrid_successful) { Debug("Saved MAC PDU with Temporal C-RNTI in buffer"); - pdus.push(buff, nof_bytes, 0, srsran::pdu_queue::DCH); + pdus.push(buff, nof_bytes, srsran::pdu_queue::DCH); } else { pdus.deallocate(buff); } @@ -123,7 +123,7 @@ void demux::push_pdu(uint8_t* buff, uint32_t nof_bytes, uint32_t tti) // Process Real-Time PDUs process_sch_pdu_rt(buff, nof_bytes, tti); - return pdus.push(buff, nof_bytes, 0, srsran::pdu_queue::DCH); + return pdus.push(buff, nof_bytes, srsran::pdu_queue::DCH); } /* Demultiplexing of MAC PDU associated with SI-RNTI. The PDU passes through From 181b903117ab13c74bb53a559c2b732330f05874 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Fri, 18 Jun 2021 14:13:44 +0100 Subject: [PATCH 07/24] Small log fix for RNTI in integrity failure notifications --- srsenb/src/stack/rrc/rrc.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/srsenb/src/stack/rrc/rrc.cc b/srsenb/src/stack/rrc/rrc.cc index eedc915a8..a82cde2d0 100644 --- a/srsenb/src/stack/rrc/rrc.cc +++ b/srsenb/src/stack/rrc/rrc.cc @@ -293,7 +293,7 @@ void rrc::write_pdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t p void rrc::notify_pdcp_integrity_error(uint16_t rnti, uint32_t lcid) { - logger.warning("Received integrity protection failure indication, rnti=0x%u, lcid=%u", rnti, lcid); + logger.warning("Received integrity protection failure indication, rnti=0x%x, lcid=%u", rnti, lcid); s1ap->user_release(rnti, asn1::s1ap::cause_radio_network_opts::unspecified); } From ce30b7e1cec1125c4f7d72afe328c6563803a5c2 Mon Sep 17 00:00:00 2001 From: yagoda Date: Thu, 20 May 2021 18:58:08 +0200 Subject: [PATCH 08/24] fixing eMBMS after new ue_db architecture and scheduler changes --- CMakeLists.txt | 2 +- srsenb/src/stack/mac/mac.cc | 9 ++++++--- srsenb/src/stack/mac/schedulers/sched_time_pf.cc | 6 ++++++ 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4109dd73e..a5cae6c3f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,7 +55,7 @@ option(ENABLE_SRSENB "Build srsENB application" ON) option(ENABLE_SRSEPC "Build srsEPC application" ON) option(DISABLE_SIMD "Disable SIMD instructions" OFF) option(AUTO_DETECT_ISA "Autodetect supported ISA extensions" ON) - + option(ENABLE_GUI "Enable GUI (using srsGUI)" ON) option(ENABLE_UHD "Enable UHD" ON) option(ENABLE_BLADERF "Enable BladeRF" ON) diff --git a/srsenb/src/stack/mac/mac.cc b/srsenb/src/stack/mac/mac.cc index 430f7e493..2aafc7d90 100644 --- a/srsenb/src/stack/mac/mac.cc +++ b/srsenb/src/stack/mac/mac.cc @@ -976,9 +976,12 @@ void mac::write_mcch(const srsran::sib2_mbms_t* sib2_, sib13 = *sib13_; memcpy(mcch_payload_buffer, mcch_payload, mcch_payload_length * sizeof(uint8_t)); current_mcch_length = mcch_payload_length; - ue_db[SRSRAN_MRNTI] = std::unique_ptr{ - new ue(SRSRAN_MRNTI, 0, &scheduler, rrc_h, rlc_h, phy_h, logger, cells.size(), softbuffer_pool.get())}; - + std::unique_ptr ptr = std::unique_ptr{ + new ue(SRSRAN_MRNTI, args.nof_prb, &scheduler, rrc_h, rlc_h, phy_h, logger, cells.size(), softbuffer_pool.get())}; + auto ret = ue_db.insert(SRSRAN_MRNTI, std::move(ptr)); + if (!ret) { + logger.info("Failed to allocate rnti=0x%x.for eMBMS", SRSRAN_MRNTI); + } rrc_h->add_user(SRSRAN_MRNTI, {}); } diff --git a/srsenb/src/stack/mac/schedulers/sched_time_pf.cc b/srsenb/src/stack/mac/schedulers/sched_time_pf.cc index 11a0f8aab..53de3621c 100644 --- a/srsenb/src/stack/mac/schedulers/sched_time_pf.cc +++ b/srsenb/src/stack/mac/schedulers/sched_time_pf.cc @@ -35,6 +35,12 @@ sched_time_pf::sched_time_pf(const sched_cell_params_t& cell_params_, const sche void sched_time_pf::new_tti(sched_ue_list& ue_db, sf_sched* tti_sched) { + while (not dl_queue.empty()) { + dl_queue.pop(); + } + while (not ul_queue.empty()) { + ul_queue.pop(); + } current_tti_rx = tti_point{tti_sched->get_tti_rx()}; // remove deleted users from history for (auto it = ue_history_db.begin(); it != ue_history_db.end();) { From 66eb6f20f19e03cd3c2787440668298cc50d2429 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Thu, 17 Jun 2021 16:49:24 +0200 Subject: [PATCH 09/24] Fix non-contention HO missing the T-CRNTI --- srsue/src/stack/mac/proc_ra.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/srsue/src/stack/mac/proc_ra.cc b/srsue/src/stack/mac/proc_ra.cc index ad150fd32..c38f8ac39 100644 --- a/srsue/src/stack/mac/proc_ra.cc +++ b/srsue/src/stack/mac/proc_ra.cc @@ -220,6 +220,7 @@ void ra_proc::initialization() preambleTransmissionCounter = 1; mux_unit->msg3_flush(); backoff_param_ms = 0; + transmitted_crnti = 0; resource_selection(); } @@ -405,10 +406,12 @@ void ra_proc::tb_decoded_ok(const uint8_t cc_idx, const uint32_t tti) rar_pdu_msg.get()->get_ta_cmd(), rar_pdu_msg.get()->get_temp_crnti()); + // Save Temp-CRNTI before generating the reply + rntis->temp_rnti = rar_pdu_msg.get()->get_temp_crnti(); + // Perform actions when preamble was selected by UE MAC if (preambleIndex <= 0) { mux_unit->msg3_prepare(); - rntis->temp_rnti = rar_pdu_msg.get()->get_temp_crnti(); // If this is the first successfully received RAR within this procedure, Msg3 is empty if (mux_unit->msg3_is_empty()) { From 9c60ef092cc09c8a293e060da6b46717d5f2153e Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Thu, 17 Jun 2021 16:49:37 +0200 Subject: [PATCH 10/24] Fix test for non-contention HO --- srsue/src/stack/mac/test/mac_test.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/srsue/src/stack/mac/test/mac_test.cc b/srsue/src/stack/mac/test/mac_test.cc index ba81533fe..1d8b90f88 100644 --- a/srsue/src/stack/mac/test/mac_test.cc +++ b/srsue/src/stack/mac/test/mac_test.cc @@ -2330,6 +2330,7 @@ int mac_random_access_test() my_test.rar_nof_invalid_rapid = 0; my_test.check_ra_successful = true; my_test.temp_rnti++; // Temporal C-RNTI has to change to avoid duplicate + my_test.crnti = 0; TESTASSERT(!run_mac_ra_test(my_test, &mac, &phy, &tti, &stack)); stack.run_tti(tti++); TESTASSERT(rrc.ho_finish_successful); From 83bf5dcd4917ad636f0c14aa6a628ae61099ecc6 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Tue, 15 Jun 2021 11:59:39 +0200 Subject: [PATCH 11/24] rlc_am_lte: reduce time holding Tx mutex when processing status PDUs the patch is a re-implementation of the customer-specific optimization we did in order to reduce the time the RLC holds the Tx mutex when processing an incoming status PDU. The patch makes sure to never operate on a raw mutex but instead uses the deadlock-avoiding RAII lock. --- lib/src/upper/rlc_am_lte.cc | 83 ++++++++++++++++++++----------------- 1 file changed, 46 insertions(+), 37 deletions(-) diff --git a/lib/src/upper/rlc_am_lte.cc b/lib/src/upper/rlc_am_lte.cc index 30dc53afa..026355535 100644 --- a/lib/src/upper/rlc_am_lte.cc +++ b/lib/src/upper/rlc_am_lte.cc @@ -1168,48 +1168,55 @@ void rlc_am_lte::rlc_am_lte_tx::handle_control_pdu(uint8_t* payload, uint32_t no return; } - std::unique_lock lock(mutex); + // Local variables for handling Status PDU will be updated with lock + rlc_status_pdu_t status = {}; + uint32_t i = 0; + uint32_t vt_s_local = 0; - logger.debug(payload, nof_bytes, "%s Rx control PDU", RB_NAME); + { + std::lock_guard lock(mutex); - rlc_status_pdu_t status; - rlc_am_read_status_pdu(payload, nof_bytes, &status); + logger.debug(payload, nof_bytes, "%s Rx control PDU", RB_NAME); - log_rlc_am_status_pdu_to_string(logger.info, "%s Rx Status PDU: %s", &status, RB_NAME); + rlc_am_read_status_pdu(payload, nof_bytes, &status); - // make sure ACK_SN is within our Tx window - if (((MOD + status.ack_sn - vt_a) % MOD > RLC_AM_WINDOW_SIZE) || - ((MOD + vt_s - status.ack_sn) % MOD > RLC_AM_WINDOW_SIZE)) { - logger.warning("%s Received invalid status PDU (ack_sn=%d, vt_a=%d, vt_s=%d). Dropping PDU.", - RB_NAME, - status.ack_sn, - vt_a, - vt_s); - return; + log_rlc_am_status_pdu_to_string(logger.info, "%s Rx Status PDU: %s", &status, RB_NAME); + + // make sure ACK_SN is within our Tx window + if (((MOD + status.ack_sn - vt_a) % MOD > RLC_AM_WINDOW_SIZE) || + ((MOD + vt_s - status.ack_sn) % MOD > RLC_AM_WINDOW_SIZE)) { + logger.warning("%s Received invalid status PDU (ack_sn=%d, vt_a=%d, vt_s=%d). Dropping PDU.", + RB_NAME, + status.ack_sn, + vt_a, + vt_s); + return; + } + + // Sec 5.2.2.2, stop poll reTx timer if status PDU comprises a positive _or_ negative acknowledgement + // for the RLC data PDU with sequence number poll_sn + if (poll_retx_timer.is_valid() && (TX_MOD_BASE(poll_sn) < TX_MOD_BASE(status.ack_sn))) { + logger.debug("%s Stopping pollRetx timer", RB_NAME); + poll_retx_timer.stop(); + } + + // flush retx queue to avoid unordered SNs, we expect the Rx to request lost PDUs again + if (status.N_nack > 0) { + retx_queue.clear(); + } + + i = vt_a; + vt_s_local = vt_s; } - // Sec 5.2.2.2, stop poll reTx timer if status PDU comprises a positive _or_ negative acknowledgement - // for the RLC data PDU with sequence number poll_sn - if (poll_retx_timer.is_valid() && (TX_MOD_BASE(poll_sn) < TX_MOD_BASE(status.ack_sn))) { - logger.debug("%s Stopping pollRetx timer", RB_NAME); - poll_retx_timer.stop(); - } - - // flush retx queue to avoid unordered SNs, we expect the Rx to request lost PDUs again - if (status.N_nack > 0) { - retx_queue.clear(); - } - - // Handle ACKs and NACKs - bool update_vt_a = true; - uint32_t i = vt_a; - - while (TX_MOD_BASE(i) < TX_MOD_BASE(status.ack_sn) && TX_MOD_BASE(i) < TX_MOD_BASE(vt_s)) { + bool update_vt_a = true; + while (TX_MOD_BASE(i) < TX_MOD_BASE(status.ack_sn) && TX_MOD_BASE(i) < TX_MOD_BASE(vt_s_local)) { bool nack = false; for (uint32_t j = 0; j < status.N_nack; j++) { if (status.nacks[j].nack_sn == i) { nack = true; update_vt_a = false; + std::lock_guard lock(mutex); if (tx_window.has_sn(i)) { auto& pdu = tx_window[i]; if (not retx_queue.has_sn(i)) { @@ -1259,6 +1266,7 @@ void rlc_am_lte::rlc_am_lte_tx::handle_control_pdu(uint8_t* payload, uint32_t no if (!nack) { // ACKed SNs get marked and removed from tx_window so PDCP get's only notified once + std::lock_guard lock(mutex); if (tx_window.has_sn(i)) { update_notification_ack_info(i); logger.debug("Tx PDU SN=%zd being removed from tx window", i); @@ -1273,16 +1281,17 @@ void rlc_am_lte::rlc_am_lte_tx::handle_control_pdu(uint8_t* payload, uint32_t no i = (i + 1) % MOD; } - // Make sure vt_a points to valid SN - if (not tx_window.empty() && not tx_window.has_sn(vt_a)) { - logger.error("%s vt_a=%d points to invalid position in Tx window.", RB_NAME, vt_a); - parent->rrc->protocol_failure(); + { + // Make sure vt_a points to valid SN + std::lock_guard lock(mutex); + if (not tx_window.empty() && not tx_window.has_sn(vt_a)) { + logger.error("%s vt_a=%d points to invalid position in Tx window.", RB_NAME, vt_a); + parent->rrc->protocol_failure(); + } } debug_state(); - lock.unlock(); - // Notify PDCP without holding Tx mutex if (not notify_info_vec.empty()) { parent->pdcp->notify_delivery(parent->lcid, notify_info_vec); From 027201d457b48b30b63f267c8fc62914ecac0e20 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Thu, 17 Jun 2021 18:24:02 +0200 Subject: [PATCH 12/24] SRSUE/SRSENB: Refactor NR workers to generalise lower PHY --- .../srsran/interfaces/phy_common_interface.h | 29 +++++ srsenb/hdr/phy/nr/cc_worker.h | 19 +-- srsenb/hdr/phy/nr/sf_worker.h | 16 +-- srsenb/hdr/phy/nr/worker_pool.h | 13 +- srsenb/hdr/phy/phy_common.h | 17 +-- srsenb/src/phy/nr/cc_worker.cc | 16 +-- srsenb/src/phy/nr/sf_worker.cc | 16 +-- srsenb/src/phy/nr/worker_pool.cc | 13 +- srsenb/src/phy/phy.cc | 2 +- srsue/hdr/phy/nr/cc_worker.h | 10 +- srsue/hdr/phy/nr/sf_worker.h | 10 +- srsue/hdr/phy/nr/worker_pool.h | 2 +- srsue/hdr/phy/phy_common.h | 5 +- srsue/src/phy/lte/sf_worker.cc | 10 +- srsue/src/phy/nr/cc_worker.cc | 110 ++++++++--------- srsue/src/phy/nr/sf_worker.cc | 24 ++-- srsue/src/phy/nr/worker_pool.cc | 7 +- srsue/src/phy/phy.cc | 2 +- srsue/src/phy/phy_common.cc | 8 +- test/CMakeLists.txt | 2 + test/phy/CMakeLists.txt | 23 ++++ test/phy/nr_phy_test.cc | 111 ++++++++++++++++++ 22 files changed, 323 insertions(+), 142 deletions(-) create mode 100644 lib/include/srsran/interfaces/phy_common_interface.h create mode 100644 test/phy/CMakeLists.txt create mode 100644 test/phy/nr_phy_test.cc diff --git a/lib/include/srsran/interfaces/phy_common_interface.h b/lib/include/srsran/interfaces/phy_common_interface.h new file mode 100644 index 000000000..a0df2e6e5 --- /dev/null +++ b/lib/include/srsran/interfaces/phy_common_interface.h @@ -0,0 +1,29 @@ +/** + * + * \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_PHY_COMMON_INTERFACE_H +#define SRSRAN_PHY_COMMON_INTERFACE_H + +#include "../radio/rf_buffer.h" +#include "../radio/rf_timestamp.h" + +namespace srsran { + +class phy_common_interface +{ +public: + virtual void worker_end(void* h, srsran::rf_buffer_t& buffer, srsran::rf_timestamp_t& tx_time, bool is_nr) = 0; +}; + +} // namespace srsran + +#endif // SRSRAN_PHY_COMMON_INTERFACE_H diff --git a/srsenb/hdr/phy/nr/cc_worker.h b/srsenb/hdr/phy/nr/cc_worker.h index 2226c83b8..26667f1f4 100644 --- a/srsenb/hdr/phy/nr/cc_worker.h +++ b/srsenb/hdr/phy/nr/cc_worker.h @@ -13,6 +13,7 @@ #ifndef SRSENB_NR_CC_WORKER_H #define SRSENB_NR_CC_WORKER_H +#include "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" @@ -24,16 +25,18 @@ namespace srsenb { namespace nr { -typedef struct { - uint32_t nof_carriers; - srsran_enb_dl_nr_args_t dl; -} phy_nr_args_t; +struct phy_nr_args_t { + uint32_t nof_carriers = 1; + uint32_t nof_ports = 1; + srsran_enb_dl_nr_args_t dl = {}; +}; class phy_nr_state { public: - phy_nr_args_t args = {}; - srsran::phy_cfg_nr_t cfg = {}; + phy_cell_cfg_list_nr_t cell_list = {}; + phy_nr_args_t args; + srsran::phy_cfg_nr_t cfg; phy_nr_state() { @@ -49,7 +52,7 @@ public: class cc_worker { public: - cc_worker(uint32_t cc_idx, srslog::basic_logger& logger, phy_nr_state* phy_state_); + cc_worker(uint32_t cc_idx, srslog::basic_logger& logger, phy_nr_state& phy_state_); ~cc_worker(); bool set_carrier(const srsran_carrier_nr_t* carrier); @@ -70,7 +73,7 @@ private: std::array tx_buffer = {}; std::array rx_buffer = {}; uint32_t buffer_sz = 0; - phy_nr_state* phy_state; + phy_nr_state& phy_state; srsran_enb_dl_nr_t enb_dl = {}; srslog::basic_logger& logger; }; diff --git a/srsenb/hdr/phy/nr/sf_worker.h b/srsenb/hdr/phy/nr/sf_worker.h index bf15ccc1d..2c41a6eb6 100644 --- a/srsenb/hdr/phy/nr/sf_worker.h +++ b/srsenb/hdr/phy/nr/sf_worker.h @@ -10,12 +10,12 @@ * */ -#ifndef SRSUE_NR_PHCH_WORKER_H -#define SRSUE_NR_PHCH_WORKER_H +#ifndef SRSENB_NR_PHCH_WORKER_H +#define SRSENB_NR_PHCH_WORKER_H #include "cc_worker.h" -#include "srsenb/hdr/phy/phy_common.h" #include "srsran/common/thread_pool.h" +#include "srsran/interfaces/phy_common_interface.h" #include "srsran/srslog/srslog.h" namespace srsenb { @@ -32,7 +32,7 @@ namespace nr { class sf_worker final : public srsran::thread_pool::worker { public: - sf_worker(phy_common* phy_, phy_nr_state* phy_state_, srslog::basic_logger& logger); + sf_worker(srsran::phy_common_interface& common_, phy_nr_state& phy_state_, srslog::basic_logger& logger); ~sf_worker(); bool set_carrier_unlocked(uint32_t cc_idx, const srsran_carrier_nr_t* carrier_); @@ -49,9 +49,9 @@ private: std::vector > cc_workers; - phy_common* phy = nullptr; - phy_nr_state* phy_state = nullptr; - srslog::basic_logger& logger; + srsran::phy_common_interface& common; + phy_nr_state& phy_state; + srslog::basic_logger& logger; // Temporal attributes srsran_softbuffer_tx_t softbuffer_tx = {}; @@ -61,4 +61,4 @@ private: } // namespace nr } // namespace srsenb -#endif // SRSUE_NR_PHCH_WORKER_H +#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 ebe00b378..37df6bb33 100644 --- a/srsenb/hdr/phy/nr/worker_pool.h +++ b/srsenb/hdr/phy/nr/worker_pool.h @@ -10,10 +10,11 @@ * */ -#ifndef SRSUE_NR_WORKER_POOL_H -#define SRSUE_NR_WORKER_POOL_H +#ifndef SRSENB_NR_WORKER_POOL_H +#define SRSENB_NR_WORKER_POOL_H #include "sf_worker.h" +#include "srsenb/hdr/phy/phy_interfaces.h" #include "srsran/common/thread_pool.h" namespace srsenb { @@ -29,7 +30,11 @@ 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, srslog::sink& log_sink, int prio); + bool init(const phy_cell_cfg_list_nr_t& cell_list, + const phy_args_t& args, + srsran::phy_common_interface& common, + srslog::sink& log_sink, + int prio); sf_worker* wait_worker(uint32_t tti); sf_worker* wait_worker_id(uint32_t id); void start_worker(sf_worker* w); @@ -39,4 +44,4 @@ public: } // namespace nr } // namespace srsenb -#endif // SRSUE_NR_WORKER_POOL_H +#endif // SRSENB_NR_WORKER_POOL_H diff --git a/srsenb/hdr/phy/phy_common.h b/srsenb/hdr/phy/phy_common.h index 7ff216ca1..f8fbc2546 100644 --- a/srsenb/hdr/phy/phy_common.h +++ b/srsenb/hdr/phy/phy_common.h @@ -21,6 +21,7 @@ #include "srsran/common/thread_pool.h" #include "srsran/common/threads.h" #include "srsran/interfaces/enb_metrics_interface.h" +#include "srsran/interfaces/phy_common_interface.h" #include "srsran/interfaces/radio_interfaces.h" #include "srsran/phy/channel/channel.h" #include "srsran/radio/radio.h" @@ -31,7 +32,7 @@ namespace srsenb { -class phy_common +class phy_common : public srsran::phy_common_interface { public: phy_common() = default; @@ -56,7 +57,10 @@ public: * @param tx_time timestamp to transmit samples * @param is_nr flag is true if it is called from NR */ - void worker_end(void* tx_sem_id, srsran::rf_buffer_t& buffer, srsran::rf_timestamp_t& tx_time, bool is_nr = false); + void worker_end(void* tx_sem_id, + srsran::rf_buffer_t& buffer, + srsran::rf_timestamp_t& tx_time, + bool is_nr = false) override; // Common objects phy_args_t params = {}; @@ -151,15 +155,6 @@ public: } return c; }; - srsran_carrier_nr_t get_cell_nr(uint32_t cc_idx) - { - srsran_carrier_nr_t c = {}; - if (cc_idx < cell_list_nr.size()) { - c = cell_list_nr[cc_idx].carrier; - } - - return c; - }; void set_cell_gain(uint32_t cell_id, float gain_db) { diff --git a/srsenb/src/phy/nr/cc_worker.cc b/srsenb/src/phy/nr/cc_worker.cc index d6e182be0..66f686800 100644 --- a/srsenb/src/phy/nr/cc_worker.cc +++ b/srsenb/src/phy/nr/cc_worker.cc @@ -15,20 +15,20 @@ namespace srsenb { namespace nr { -cc_worker::cc_worker(uint32_t cc_idx_, srslog::basic_logger& log, phy_nr_state* phy_state_) : +cc_worker::cc_worker(uint32_t cc_idx_, srslog::basic_logger& log, phy_nr_state& phy_state_) : cc_idx(cc_idx_), phy_state(phy_state_), logger(log) { cf_t* buffer_c[SRSRAN_MAX_PORTS] = {}; // Allocate buffers - buffer_sz = SRSRAN_SF_LEN_PRB(phy_state->args.dl.nof_max_prb); - for (uint32_t i = 0; i < phy_state_->args.dl.nof_tx_antennas; i++) { + buffer_sz = SRSRAN_SF_LEN_PRB(phy_state.args.dl.nof_max_prb); + for (uint32_t i = 0; i < phy_state.args.dl.nof_tx_antennas; i++) { tx_buffer[i] = srsran_vec_cf_malloc(buffer_sz); rx_buffer[i] = srsran_vec_cf_malloc(buffer_sz); buffer_c[i] = tx_buffer[i]; } - if (srsran_enb_dl_nr_init(&enb_dl, buffer_c, &phy_state_->args.dl)) { + if (srsran_enb_dl_nr_init(&enb_dl, buffer_c, &phy_state.args.dl)) { ERROR("Error initiating UE DL NR"); return; } @@ -60,8 +60,8 @@ bool cc_worker::set_carrier(const srsran_carrier_nr_t* carrier) coreset.freq_resources[0] = true; // Enable the bottom 6 PRB for PDCCH coreset.duration = 2; - srsran_dci_cfg_nr_t dci_cfg = phy_state->cfg.get_dci_cfg(); - if (srsran_enb_dl_nr_set_pdcch_config(&enb_dl, &phy_state->cfg.pdcch, &dci_cfg) < SRSRAN_SUCCESS) { + srsran_dci_cfg_nr_t dci_cfg = phy_state.cfg.get_dci_cfg(); + if (srsran_enb_dl_nr_set_pdcch_config(&enb_dl, &phy_state.cfg.pdcch, &dci_cfg) < SRSRAN_SUCCESS) { ERROR("Error setting coreset"); return false; } @@ -76,7 +76,7 @@ void cc_worker::set_tti(uint32_t tti) cf_t* cc_worker::get_tx_buffer(uint32_t antenna_idx) { - if (antenna_idx >= phy_state->args.dl.nof_tx_antennas) { + if (antenna_idx >= phy_state.args.dl.nof_tx_antennas) { return nullptr; } @@ -85,7 +85,7 @@ cf_t* cc_worker::get_tx_buffer(uint32_t antenna_idx) cf_t* cc_worker::get_rx_buffer(uint32_t antenna_idx) { - if (antenna_idx >= phy_state->args.dl.nof_tx_antennas) { + if (antenna_idx >= phy_state.args.dl.nof_tx_antennas) { return nullptr; } diff --git a/srsenb/src/phy/nr/sf_worker.cc b/srsenb/src/phy/nr/sf_worker.cc index fb134852a..be1b300fa 100644 --- a/srsenb/src/phy/nr/sf_worker.cc +++ b/srsenb/src/phy/nr/sf_worker.cc @@ -14,10 +14,10 @@ namespace srsenb { namespace nr { -sf_worker::sf_worker(phy_common* phy_, phy_nr_state* phy_state_, srslog::basic_logger& logger) : - phy(phy_), 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) { - for (uint32_t i = 0; i < phy_state->args.nof_carriers; i++) { + for (uint32_t i = 0; i < phy_state.args.nof_carriers; i++) { cc_worker* w = new cc_worker(i, logger, phy_state); cc_workers.push_back(std::unique_ptr(w)); } @@ -82,14 +82,14 @@ void sf_worker::work_imp() // Get Transmission buffers srsran::rf_buffer_t tx_buffer = {}; srsran::rf_timestamp_t dummy_ts = {}; - for (uint32_t cc = 0; cc < phy->get_nof_carriers_nr(); cc++) { - for (uint32_t ant = 0; ant < phy->get_nof_ports(0); ant++) { - tx_buffer.set(cc, ant, phy->get_nof_ports(0), cc_workers[cc]->get_tx_buffer(ant)); + for (uint32_t cc = 0; cc < phy_state.args.nof_carriers; cc++) { + for (uint32_t ant = 0; ant < phy_state.args.nof_ports; ant++) { + tx_buffer.set(cc, ant, phy_state.args.nof_ports, cc_workers[cc]->get_tx_buffer(ant)); } } // Configure user - phy_state->cfg.pdsch.rbg_size_cfg_1 = false; + phy_state.cfg.pdsch.rbg_size_cfg_1 = false; // Fill grant (this comes from the scheduler) srsran_slot_cfg_t dl_cfg = {}; @@ -116,7 +116,7 @@ void sf_worker::work_imp() w->work_dl(dl_cfg, grants); } - phy->worker_end(this, tx_buffer, dummy_ts, true); + common.worker_end(this, tx_buffer, dummy_ts, true); } } // namespace nr diff --git a/srsenb/src/phy/nr/worker_pool.cc b/srsenb/src/phy/nr/worker_pool.cc index eed75af45..30eddcdcb 100644 --- a/srsenb/src/phy/nr/worker_pool.cc +++ b/srsenb/src/phy/nr/worker_pool.cc @@ -16,8 +16,15 @@ 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, srslog::sink& log_sink, int prio) +bool worker_pool::init(const phy_cell_cfg_list_nr_t& cell_list, + const phy_args_t& args, + srsran::phy_common_interface& common, + srslog::sink& log_sink, + int prio) { + // Save cell list + phy_state.cell_list = cell_list; + // Add workers to workers pool and start threads srslog::basic_levels log_level = srslog::str_to_basic_level(args.log.phy_level); for (uint32_t i = 0; i < args.nof_phy_threads; i++) { @@ -25,11 +32,11 @@ bool worker_pool::init(const phy_args_t& args, phy_common* common, srslog::sink& log.set_level(log_level); log.set_hex_dump_max_size(args.log.phy_hex_limit); - auto w = new sf_worker(common, &phy_state, log); + auto w = new sf_worker(common, phy_state, log); pool.init_worker(i, w, prio); workers.push_back(std::unique_ptr(w)); - srsran_carrier_nr_t c = common->get_cell_nr(0); + srsran_carrier_nr_t c = phy_state.cell_list[0].carrier; w->set_carrier_unlocked(0, &c); } diff --git a/srsenb/src/phy/phy.cc b/srsenb/src/phy/phy.cc index 1db96641c..8243b5e53 100644 --- a/srsenb/src/phy/phy.cc +++ b/srsenb/src/phy/phy.cc @@ -132,7 +132,7 @@ int phy::init(const phy_args_t& args, lte_workers.init(args, &workers_common, log_sink, WORKERS_THREAD_PRIO); } if (not cfg.phy_cell_cfg_nr.empty()) { - nr_workers.init(args, &workers_common, log_sink, WORKERS_THREAD_PRIO); + nr_workers.init(cfg.phy_cell_cfg_nr, args, workers_common, log_sink, WORKERS_THREAD_PRIO); } // For each carrier, initialise PRACH worker diff --git a/srsue/hdr/phy/nr/cc_worker.h b/srsue/hdr/phy/nr/cc_worker.h index 1d0687435..90e1f5d7f 100644 --- a/srsue/hdr/phy/nr/cc_worker.h +++ b/srsue/hdr/phy/nr/cc_worker.h @@ -22,7 +22,7 @@ namespace nr { class cc_worker { public: - cc_worker(uint32_t cc_idx, srslog::basic_logger& log, state* phy_state_); + cc_worker(uint32_t cc_idx, srslog::basic_logger& log, state& phy_state_); ~cc_worker(); bool update_cfg(); @@ -49,10 +49,10 @@ private: std::array rx_buffer = {}; std::array tx_buffer = {}; uint32_t buffer_sz = 0; - state* phy = nullptr; - srsran_ssb_t ssb = {}; - srsran_ue_dl_nr_t ue_dl = {}; - srsran_ue_ul_nr_t ue_ul = {}; + state& phy; + srsran_ssb_t ssb = {}; + srsran_ue_dl_nr_t ue_dl = {}; + srsran_ue_ul_nr_t ue_ul = {}; srslog::basic_logger& logger; // Methods for DCI blind search diff --git a/srsue/hdr/phy/nr/sf_worker.h b/srsue/hdr/phy/nr/sf_worker.h index 61eee0535..e2dc1637f 100644 --- a/srsue/hdr/phy/nr/sf_worker.h +++ b/srsue/hdr/phy/nr/sf_worker.h @@ -13,9 +13,9 @@ #ifndef SRSUE_NR_PHCH_WORKER_H #define SRSUE_NR_PHCH_WORKER_H -#include "../phy_common.h" #include "cc_worker.h" #include "srsran/common/thread_pool.h" +#include "srsran/interfaces/phy_common_interface.h" namespace srsue { namespace nr { @@ -31,7 +31,7 @@ namespace nr { class sf_worker final : public srsran::thread_pool::worker { public: - sf_worker(phy_common* phy, state* phy_state_, srslog::basic_logger& logger); + sf_worker(srsran::phy_common_interface& common_, state& phy_state_, srslog::basic_logger& logger); ~sf_worker() = default; bool update_cfg(uint32_t cc_idx); @@ -51,9 +51,9 @@ private: std::vector > cc_workers; - phy_common* phy = nullptr; - state* phy_state = nullptr; - srslog::basic_logger& logger; + srsran::phy_common_interface& common; + state& phy_state; + srslog::basic_logger& logger; uint32_t tti_rx = 0; cf_t* prach_ptr = nullptr; diff --git a/srsue/hdr/phy/nr/worker_pool.h b/srsue/hdr/phy/nr/worker_pool.h index adc42609d..286bf8bc1 100644 --- a/srsue/hdr/phy/nr/worker_pool.h +++ b/srsue/hdr/phy/nr/worker_pool.h @@ -33,7 +33,7 @@ public: sf_worker* operator[](std::size_t pos) { return workers.at(pos).get(); } worker_pool(uint32_t max_workers); - bool init(const phy_args_nr_t& args_, phy_common* common, stack_interface_phy_nr* stack_, int prio); + bool init(const phy_args_nr_t& args_, srsran::phy_common_interface& common, stack_interface_phy_nr* stack_, int prio); sf_worker* wait_worker(uint32_t tti); void start_worker(sf_worker* w); void stop(); diff --git a/srsue/hdr/phy/phy_common.h b/srsue/hdr/phy/phy_common.h index d283ddf7d..10d26aa1e 100644 --- a/srsue/hdr/phy/phy_common.h +++ b/srsue/hdr/phy/phy_common.h @@ -17,6 +17,7 @@ #include "srsran/adt/circular_array.h" #include "srsran/common/gen_mch_tables.h" #include "srsran/common/tti_sempahore.h" +#include "srsran/interfaces/phy_common_interface.h" #include "srsran/interfaces/phy_interface_types.h" #include "srsran/interfaces/radio_interfaces.h" #include "srsran/interfaces/rrc_interface_types.h" @@ -46,7 +47,7 @@ public: }; /* Subclass that manages variables common to all workers */ -class phy_common +class phy_common : public srsran::phy_common_interface { public: /* Common variables used by all phy workers */ @@ -129,7 +130,7 @@ public: srsran_pdsch_ack_resource_t resource); bool get_dl_pending_ack(srsran_ul_sf_cfg_t* sf, uint32_t cc_idx, srsran_pdsch_ack_cc_t* ack); - void worker_end(void* h, bool tx_enable, srsran::rf_buffer_t& buffer, srsran::rf_timestamp_t& tx_time, bool is_nr); + void worker_end(void* h, srsran::rf_buffer_t& buffer, srsran::rf_timestamp_t& tx_time, bool is_nr) override; void set_cell(const srsran_cell_t& c); diff --git a/srsue/src/phy/lte/sf_worker.cc b/srsue/src/phy/lte/sf_worker.cc index 2ff948e9e..ea7b6a58c 100644 --- a/srsue/src/phy/lte/sf_worker.cc +++ b/srsue/src/phy/lte/sf_worker.cc @@ -155,7 +155,7 @@ void sf_worker::work_imp() { srsran::rf_buffer_t tx_signal_ptr = {}; if (!cell_initiated) { - phy->worker_end(this, false, tx_signal_ptr, tx_time, false); + phy->worker_end(this, tx_signal_ptr, tx_time, false); return; } @@ -216,7 +216,6 @@ void sf_worker::work_imp() } } } - tx_signal_ptr.set_nof_samples(nof_samples); // Set PRACH buffer signal pointer if (prach_ptr) { @@ -225,8 +224,13 @@ void sf_worker::work_imp() prach_ptr = nullptr; } + // Indicates worker there is a transmission by setting the number of samples + if (tx_signal_ready) { + tx_signal_ptr.set_nof_samples(nof_samples); + } + // Call worker_end to transmit the signal - phy->worker_end(this, tx_signal_ready, tx_signal_ptr, tx_time, false); + phy->worker_end(this, tx_signal_ptr, tx_time, false); if (rx_signal_ok) { update_measurements(); diff --git a/srsue/src/phy/nr/cc_worker.cc b/srsue/src/phy/nr/cc_worker.cc index ba818bdfe..1b2269a61 100644 --- a/srsue/src/phy/nr/cc_worker.cc +++ b/srsue/src/phy/nr/cc_worker.cc @@ -17,25 +17,25 @@ namespace srsue { namespace nr { -cc_worker::cc_worker(uint32_t cc_idx_, srslog::basic_logger& log, state* phy_state_) : +cc_worker::cc_worker(uint32_t cc_idx_, srslog::basic_logger& log, state& phy_state_) : cc_idx(cc_idx_), phy(phy_state_), logger(log) { cf_t* rx_buffer_c[SRSRAN_MAX_PORTS] = {}; // Allocate buffers - buffer_sz = SRSRAN_SF_LEN_PRB(phy->args.dl.nof_max_prb) * 5; - for (uint32_t i = 0; i < phy_state_->args.dl.nof_rx_antennas; i++) { + buffer_sz = SRSRAN_SF_LEN_PRB(phy.args.dl.nof_max_prb) * 5; + for (uint32_t i = 0; i < phy.args.dl.nof_rx_antennas; i++) { rx_buffer[i] = srsran_vec_cf_malloc(buffer_sz); rx_buffer_c[i] = rx_buffer[i]; tx_buffer[i] = srsran_vec_cf_malloc(buffer_sz); } - if (srsran_ue_dl_nr_init(&ue_dl, rx_buffer.data(), &phy_state_->args.dl) < SRSRAN_SUCCESS) { + if (srsran_ue_dl_nr_init(&ue_dl, rx_buffer.data(), &phy.args.dl) < SRSRAN_SUCCESS) { ERROR("Error initiating UE DL NR"); return; } - if (srsran_ue_ul_nr_init(&ue_ul, tx_buffer[0], &phy_state_->args.ul) < SRSRAN_SUCCESS) { + if (srsran_ue_ul_nr_init(&ue_ul, tx_buffer[0], &phy.args.ul) < SRSRAN_SUCCESS) { ERROR("Error initiating UE DL NR"); return; } @@ -67,38 +67,38 @@ cc_worker::~cc_worker() bool cc_worker::update_cfg() { - if (srsran_ue_dl_nr_set_carrier(&ue_dl, &phy->cfg.carrier) < SRSRAN_SUCCESS) { + if (srsran_ue_dl_nr_set_carrier(&ue_dl, &phy.cfg.carrier) < SRSRAN_SUCCESS) { ERROR("Error setting carrier"); return false; } - if (srsran_ue_ul_nr_set_carrier(&ue_ul, &phy->cfg.carrier) < SRSRAN_SUCCESS) { + if (srsran_ue_ul_nr_set_carrier(&ue_ul, &phy.cfg.carrier) < SRSRAN_SUCCESS) { ERROR("Error setting carrier"); return false; } - srsran_dci_cfg_nr_t dci_cfg = phy->cfg.get_dci_cfg(); - if (srsran_ue_dl_nr_set_pdcch_config(&ue_dl, &phy->cfg.pdcch, &dci_cfg) < SRSRAN_SUCCESS) { + srsran_dci_cfg_nr_t dci_cfg = phy.cfg.get_dci_cfg(); + if (srsran_ue_dl_nr_set_pdcch_config(&ue_dl, &phy.cfg.pdcch, &dci_cfg) < SRSRAN_SUCCESS) { logger.error("Error setting NR PDCCH configuration"); return false; } double abs_freq_point_a_freq = - srsran::srsran_band_helper().nr_arfcn_to_freq(phy->cfg.carrier.absolute_frequency_point_a); - double abs_freq_ssb_freq = srsran::srsran_band_helper().nr_arfcn_to_freq(phy->cfg.carrier.absolute_frequency_ssb); + srsran::srsran_band_helper().nr_arfcn_to_freq(phy.cfg.carrier.absolute_frequency_point_a); + double abs_freq_ssb_freq = srsran::srsran_band_helper().nr_arfcn_to_freq(phy.cfg.carrier.absolute_frequency_ssb); - double carrier_center_freq = abs_freq_point_a_freq + (phy->cfg.carrier.nof_prb / 2 * - SRSRAN_SUBC_SPACING_NR(phy->cfg.carrier.scs) * SRSRAN_NRE); - uint16_t band = srsran::srsran_band_helper().get_band_from_dl_freq_Hz(carrier_center_freq); + double carrier_center_freq = + abs_freq_point_a_freq + (phy.cfg.carrier.nof_prb / 2 * SRSRAN_SUBC_SPACING_NR(phy.cfg.carrier.scs) * SRSRAN_NRE); + uint16_t band = srsran::srsran_band_helper().get_band_from_dl_freq_Hz(carrier_center_freq); srsran_ssb_cfg_t ssb_cfg = {}; - ssb_cfg.srate_hz = srsran_min_symbol_sz_rb(phy->cfg.carrier.nof_prb) * SRSRAN_SUBC_SPACING_NR(phy->cfg.carrier.scs); + ssb_cfg.srate_hz = srsran_min_symbol_sz_rb(phy.cfg.carrier.nof_prb) * SRSRAN_SUBC_SPACING_NR(phy.cfg.carrier.scs); ssb_cfg.center_freq_hz = carrier_center_freq; ssb_cfg.ssb_freq_hz = abs_freq_ssb_freq; - ssb_cfg.scs = phy->cfg.ssb.scs; - ssb_cfg.pattern = srsran::srsran_band_helper().get_ssb_pattern(band, phy->cfg.ssb.scs); + ssb_cfg.scs = phy.cfg.ssb.scs; + ssb_cfg.pattern = srsran::srsran_band_helper().get_ssb_pattern(band, phy.cfg.ssb.scs); ssb_cfg.duplex_mode = srsran::srsran_band_helper().get_duplex_mode(band); - ssb_cfg.periodicity_ms = phy->cfg.ssb.periodicity_ms; + ssb_cfg.periodicity_ms = phy.cfg.ssb.periodicity_ms; if (srsran_ssb_set_cfg(&ssb, &ssb_cfg) < SRSRAN_SUCCESS) { logger.error("Error setting SSB configuration"); @@ -119,7 +119,7 @@ void cc_worker::set_tti(uint32_t tti) cf_t* cc_worker::get_rx_buffer(uint32_t antenna_idx) { - if (antenna_idx >= phy->args.dl.nof_rx_antennas) { + if (antenna_idx >= phy.args.dl.nof_rx_antennas) { return nullptr; } @@ -128,7 +128,7 @@ cf_t* cc_worker::get_rx_buffer(uint32_t antenna_idx) cf_t* cc_worker::get_tx_buffer(uint32_t antenna_idx) { - if (antenna_idx >= phy->args.dl.nof_rx_antennas) { + if (antenna_idx >= phy.args.dl.nof_rx_antennas) { return nullptr; } @@ -143,7 +143,7 @@ uint32_t cc_worker::get_buffer_len() void cc_worker::decode_pdcch_dl() { std::array dci_rx = {}; - srsue::mac_interface_phy_nr::sched_rnti_t rnti = phy->stack->get_dl_sched_rnti_nr(dl_slot_cfg.idx); + srsue::mac_interface_phy_nr::sched_rnti_t rnti = phy.stack->get_dl_sched_rnti_nr(dl_slot_cfg.idx); // Skip search if no valid RNTI is given if (rnti.id == SRSRAN_INVALID_RNTI) { @@ -168,7 +168,7 @@ void cc_worker::decode_pdcch_dl() } // Enqueue UL grants - phy->set_dl_pending_grant(dl_slot_cfg, dci_rx[i]); + phy.set_dl_pending_grant(dl_slot_cfg, dci_rx[i]); } if (logger.debug.enabled()) { @@ -194,7 +194,7 @@ void cc_worker::decode_pdcch_dl() void cc_worker::decode_pdcch_ul() { std::array dci_rx = {}; - srsue::mac_interface_phy_nr::sched_rnti_t rnti = phy->stack->get_ul_sched_rnti_nr(ul_slot_cfg.idx); + srsue::mac_interface_phy_nr::sched_rnti_t rnti = phy.stack->get_ul_sched_rnti_nr(ul_slot_cfg.idx); // Skip search if no valid RNTI is given if (rnti.id == SRSRAN_INVALID_RNTI) { @@ -219,7 +219,7 @@ void cc_worker::decode_pdcch_ul() } // Enqueue UL grants - phy->set_ul_pending_grant(dl_slot_cfg.idx, dci_rx[i]); + phy.set_ul_pending_grant(dl_slot_cfg.idx, dci_rx[i]); } } @@ -229,7 +229,7 @@ bool cc_worker::decode_pdsch_dl() uint32_t pid = 0; srsran_sch_cfg_nr_t pdsch_cfg = {}; srsran_pdsch_ack_resource_nr_t ack_resource = {}; - if (not phy->get_dl_pending_grant(dl_slot_cfg.idx, pdsch_cfg, ack_resource, pid)) { + if (not phy.get_dl_pending_grant(dl_slot_cfg.idx, pdsch_cfg, ack_resource, pid)) { // Early return if no grant was available return true; } @@ -242,13 +242,13 @@ bool cc_worker::decode_pdsch_dl() mac_dl_grant.ndi = pdsch_cfg.grant.tb[0].ndi; mac_dl_grant.tbs = pdsch_cfg.grant.tb[0].tbs / 8; mac_dl_grant.tti = dl_slot_cfg.idx; - phy->stack->new_grant_dl(0, mac_dl_grant, &dl_action); + phy.stack->new_grant_dl(0, mac_dl_grant, &dl_action); // Abort if MAC says it doesn't need the TB if (not dl_action.tb.enabled) { // Force positive ACK if (pdsch_cfg.grant.rnti_type == srsran_rnti_type_c) { - phy->set_pending_ack(dl_slot_cfg.idx, ack_resource, true); + phy.set_pending_ack(dl_slot_cfg.idx, ack_resource, true); } logger.info("Decoding not required. Skipping PDSCH. ack_tti_tx=%d", TTI_ADD(dl_slot_cfg.idx, ack_resource.k1)); @@ -302,17 +302,17 @@ bool cc_worker::decode_pdsch_dl() // Enqueue PDSCH ACK information only if the RNTI is type C if (pdsch_cfg.grant.rnti_type == srsran_rnti_type_c) { - phy->set_pending_ack(dl_slot_cfg.idx, ack_resource, pdsch_res.tb[0].crc); + phy.set_pending_ack(dl_slot_cfg.idx, ack_resource, pdsch_res.tb[0].crc); } // Notify MAC about PDSCH decoding result mac_interface_phy_nr::tb_action_dl_result_t mac_dl_result = {}; mac_dl_result.ack = pdsch_res.tb[0].crc; mac_dl_result.payload = mac_dl_result.ack ? std::move(data) : nullptr; // only pass data when successful - phy->stack->tb_decoded(cc_idx, mac_dl_grant, std::move(mac_dl_result)); + phy.stack->tb_decoded(cc_idx, mac_dl_grant, std::move(mac_dl_result)); if (pdsch_cfg.grant.rnti_type == srsran_rnti_type_ra) { - phy->rar_grant_tti = dl_slot_cfg.idx; + phy.rar_grant_tti = dl_slot_cfg.idx; } if (pdsch_res.tb[0].crc) { @@ -321,7 +321,7 @@ bool cc_worker::decode_pdsch_dl() dl_m.mcs = pdsch_cfg.grant.tb[0].mcs; dl_m.fec_iters = pdsch_res.tb[0].avg_iter; dl_m.evm = pdsch_res.evm[0]; - phy->set_dl_metrics(dl_m); + phy.set_dl_metrics(dl_m); } return true; @@ -334,7 +334,7 @@ bool cc_worker::measure_csi() srsran_csi_trs_measurements_t meas = {}; // Iterate all possible candidates - const std::array position_in_burst = phy->cfg.ssb.position_in_burst; + const std::array position_in_burst = phy.cfg.ssb.position_in_burst; for (uint32_t ssb_idx = 0; ssb_idx < SRSRAN_SSB_NOF_CANDIDATES; ssb_idx++) { // Skip SSB candidate if not enabled if (not position_in_burst[ssb_idx]) { @@ -342,7 +342,7 @@ bool cc_worker::measure_csi() } // Measure SSB candidate - if (srsran_ssb_csi_measure(&ssb, phy->cfg.carrier.pci, ssb_idx, rx_buffer[0], &meas) < SRSRAN_SUCCESS) { + if (srsran_ssb_csi_measure(&ssb, phy.cfg.carrier.pci, ssb_idx, rx_buffer[0], &meas) < SRSRAN_SUCCESS) { logger.error("Error measuring SSB"); return false; } @@ -360,13 +360,13 @@ bool cc_worker::measure_csi() ch_metrics.rsrq = 0.0f; // Not supported ch_metrics.rssi = 0.0f; // Not supported ch_metrics.sync_err = - meas.delay_us / (float)(ue_dl.fft->fft_plan.size * SRSRAN_SUBC_SPACING_NR(phy->cfg.carrier.scs)); - phy->set_channel_metrics(ch_metrics); + meas.delay_us / (float)(ue_dl.fft->fft_plan.size * SRSRAN_SUBC_SPACING_NR(phy.cfg.carrier.scs)); + phy.set_channel_metrics(ch_metrics); // Compute synch metrics and report it to the PHY state sync_metrics_t sync_metrics = {}; sync_metrics.cfo = meas.cfo_hz; - phy->set_sync_metrics(sync_metrics); + phy.set_sync_metrics(sync_metrics); // Report SSB candidate channel measurement to the PHY state // ... @@ -376,7 +376,7 @@ bool cc_worker::measure_csi() // Iterate all NZP-CSI-RS marked as TRS and perform channel measurements for (uint32_t resource_set_id = 0; resource_set_id < SRSRAN_PHCH_CFG_MAX_NOF_CSI_RS_SETS; resource_set_id++) { // Select NZP-CSI-RS set - const srsran_csi_rs_nzp_set_t& nzp_set = phy->cfg.pdsch.nzp_csi_rs_sets[resource_set_id]; + const srsran_csi_rs_nzp_set_t& nzp_set = phy.cfg.pdsch.nzp_csi_rs_sets[resource_set_id]; // Skip set if not set as TRS (it will be processed later) if (not nzp_set.trs_info) { @@ -409,13 +409,13 @@ bool cc_worker::measure_csi() ch_metrics.rsrq = 0.0f; // Not supported ch_metrics.rssi = 0.0f; // Not supported ch_metrics.sync_err = - trs_measurements.delay_us / (float)(ue_dl.fft->fft_plan.size * SRSRAN_SUBC_SPACING_NR(phy->cfg.carrier.scs)); - phy->set_channel_metrics(ch_metrics); + trs_measurements.delay_us / (float)(ue_dl.fft->fft_plan.size * SRSRAN_SUBC_SPACING_NR(phy.cfg.carrier.scs)); + phy.set_channel_metrics(ch_metrics); // Compute synch metrics and report it to the PHY state sync_metrics_t sync_metrics = {}; sync_metrics.cfo = trs_measurements.cfo_hz; - phy->set_sync_metrics(sync_metrics); + phy.set_sync_metrics(sync_metrics); // Convert to CSI channel measurement and report new NZP-CSI-RS measurement to the PHY state srsran_csi_channel_measurements_t measurements = {}; @@ -425,13 +425,13 @@ bool cc_worker::measure_csi() measurements.wideband_snr_db = trs_measurements.snr_dB; measurements.nof_ports = 1; // Other values are not supported measurements.K_csi_rs = (uint32_t)n; - phy->new_nzp_csi_rs_channel_measurement(measurements, resource_set_id); + phy.new_nzp_csi_rs_channel_measurement(measurements, resource_set_id); } // Iterate all NZP-CSI-RS not marked as TRS and perform channel measurements for (uint32_t resource_set_id = 0; resource_set_id < SRSRAN_PHCH_CFG_MAX_NOF_CSI_RS_SETS; resource_set_id++) { // Select NZP-CSI-RS set - const srsran_csi_rs_nzp_set_t& nzp_set = phy->cfg.pdsch.nzp_csi_rs_sets[resource_set_id]; + const srsran_csi_rs_nzp_set_t& nzp_set = phy.cfg.pdsch.nzp_csi_rs_sets[resource_set_id]; // Skip set if set as TRS (it was processed previously) if (nzp_set.trs_info) { @@ -458,7 +458,7 @@ bool cc_worker::measure_csi() measurements.wideband_snr_db); // Report new measurement to the PHY state - phy->new_nzp_csi_rs_channel_measurement(measurements, resource_set_id); + phy.new_nzp_csi_rs_channel_measurement(measurements, resource_set_id); } return true; @@ -472,7 +472,7 @@ bool cc_worker::work_dl() } // Check if it is a DL slot, if not skip - if (!srsran_tdd_nr_is_dl(&phy->cfg.tdd, 0, dl_slot_cfg.idx)) { + if (!srsran_tdd_nr_is_dl(&phy.cfg.tdd, 0, dl_slot_cfg.idx)) { return true; } @@ -503,7 +503,7 @@ bool cc_worker::work_dl() bool cc_worker::work_ul() { // Check if it is a UL slot, if not skip - if (!srsran_tdd_nr_is_ul(&phy->cfg.tdd, 0, ul_slot_cfg.idx)) { + if (!srsran_tdd_nr_is_ul(&phy.cfg.tdd, 0, ul_slot_cfg.idx)) { // No NR signal shall be transmitted srsran_vec_cf_zero(tx_buffer[0], ue_ul.ifft.sf_sz); return true; @@ -514,11 +514,11 @@ bool cc_worker::work_ul() // Gather PDSCH ACK information srsran_pdsch_ack_nr_t pdsch_ack = {}; - bool has_ul_ack = phy->get_pending_ack(ul_slot_cfg.idx, pdsch_ack); + bool has_ul_ack = phy.get_pending_ack(ul_slot_cfg.idx, pdsch_ack); // Request grant to PHY state for this transmit TTI srsran_sch_cfg_nr_t pusch_cfg = {}; - bool has_pusch_grant = phy->get_ul_pending_grant(ul_slot_cfg.idx, pusch_cfg, pid); + bool has_pusch_grant = phy.get_ul_pending_grant(ul_slot_cfg.idx, pusch_cfg, pid); // If PDSCH UL ACK is available, load into UCI if (has_ul_ack) { @@ -531,7 +531,7 @@ bool cc_worker::work_ul() } } - if (srsran_ue_dl_nr_gen_ack(&phy->cfg.harq_ack, &pdsch_ack, &uci_data) < SRSRAN_SUCCESS) { + if (srsran_ue_dl_nr_gen_ack(&phy.cfg.harq_ack, &pdsch_ack, &uci_data) < SRSRAN_SUCCESS) { ERROR("Filling UCI ACK bits"); return false; } @@ -539,11 +539,11 @@ bool cc_worker::work_ul() // Add SR to UCI data only if there is no UL grant! if (!has_ul_ack) { - phy->get_pending_sr(ul_slot_cfg.idx, uci_data); + phy.get_pending_sr(ul_slot_cfg.idx, uci_data); } // Add CSI reports to UCI data if available - phy->get_periodic_csi(ul_slot_cfg.idx, uci_data); + phy.get_periodic_csi(ul_slot_cfg.idx, uci_data); if (has_pusch_grant) { // Notify MAC about PUSCH found grant @@ -556,7 +556,7 @@ bool cc_worker::work_ul() mac_ul_grant.ndi = pusch_cfg.grant.tb[0].ndi; mac_ul_grant.rv = pusch_cfg.grant.tb[0].rv; mac_ul_grant.is_rar_grant = (pusch_cfg.grant.rnti_type == srsran_rnti_type_ra); - phy->stack->new_grant_ul(0, mac_ul_grant, &ul_action); + phy.stack->new_grant_ul(0, mac_ul_grant, &ul_action); // Don't process further if MAC can't provide PDU if (not ul_action.tb.enabled) { @@ -565,7 +565,7 @@ bool cc_worker::work_ul() } // Set UCI configuration following procedures - srsran_ra_ul_set_grant_uci_nr(&phy->cfg.carrier, &phy->cfg.pusch, &uci_data.cfg, &pusch_cfg); + srsran_ra_ul_set_grant_uci_nr(&phy.cfg.carrier, &phy.cfg.pusch, &uci_data.cfg, &pusch_cfg); // Assigning MAC provided values to PUSCH config structs pusch_cfg.grant.tb[0].softbuffer.tx = ul_action.tb.softbuffer; @@ -612,18 +612,18 @@ bool cc_worker::work_ul() ul_metrics_t ul_m = {}; ul_m.mcs = pusch_cfg.grant.tb[0].mcs; ul_m.power = srsran_convert_power_to_dB(srsran_vec_avg_power_cf(tx_buffer[0], ue_ul.ifft.sf_sz)); - phy->set_ul_metrics(ul_m); + phy.set_ul_metrics(ul_m); } else if (srsran_uci_nr_total_bits(&uci_data.cfg) > 0) { // Get PUCCH resource srsran_pucch_nr_resource_t resource = {}; - if (srsran_ra_ul_nr_pucch_resource(&phy->cfg.pucch, &uci_data.cfg, &resource) < SRSRAN_SUCCESS) { + if (srsran_ra_ul_nr_pucch_resource(&phy.cfg.pucch, &uci_data.cfg, &resource) < SRSRAN_SUCCESS) { ERROR("Selecting PUCCH resource"); return false; } // Encode PUCCH message - if (srsran_ue_ul_nr_encode_pucch(&ue_ul, &ul_slot_cfg, &phy->cfg.pucch.common, &resource, &uci_data) < + if (srsran_ue_ul_nr_encode_pucch(&ue_ul, &ul_slot_cfg, &phy.cfg.pucch.common, &resource, &uci_data) < SRSRAN_SUCCESS) { ERROR("Encoding PUCCH"); return false; diff --git a/srsue/src/phy/nr/sf_worker.cc b/srsue/src/phy/nr/sf_worker.cc index a9e004276..bb596d1c9 100644 --- a/srsue/src/phy/nr/sf_worker.cc +++ b/srsue/src/phy/nr/sf_worker.cc @@ -27,10 +27,10 @@ static int plot_worker_id = -1; namespace srsue { namespace nr { -sf_worker::sf_worker(phy_common* phy_, state* phy_state_, srslog::basic_logger& log) : - phy_state(phy_state_), phy(phy_), logger(log) +sf_worker::sf_worker(srsran::phy_common_interface& common_, state& phy_state_, srslog::basic_logger& log) : + phy_state(phy_state_), common(common_), logger(log) { - for (uint32_t i = 0; i < phy_state->args.nof_carriers; i++) { + 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)); } @@ -79,8 +79,8 @@ void sf_worker::work_imp() } // Align workers, wait for previous workers to finish DL processing before starting UL processing - phy_state->dl_ul_semaphore.wait(this); - phy_state->dl_ul_semaphore.release(); + phy_state.dl_ul_semaphore.wait(this); + phy_state.dl_ul_semaphore.release(); // Check if PRACH is available if (prach_ptr != nullptr) { @@ -88,14 +88,14 @@ void sf_worker::work_imp() tx_buffer.set(0, prach_ptr); // Notify MAC about PRACH transmission - phy_state->stack->prach_sent(TTI_TX(tti_rx), - srsran_prach_nr_start_symbol_fr1_unpaired(phy_state->cfg.prach.config_idx), - SRSRAN_SLOT_NR_MOD(phy_state->cfg.carrier.scs, TTI_TX(tti_rx)), - 0, - 0); + phy_state.stack->prach_sent(TTI_TX(tti_rx), + srsran_prach_nr_start_symbol_fr1_unpaired(phy_state.cfg.prach.config_idx), + SRSRAN_SLOT_NR_MOD(phy_state.cfg.carrier.scs, TTI_TX(tti_rx)), + 0, + 0); // Transmit NR PRACH - phy->worker_end(this, false, tx_buffer, dummy_ts, true); + common.worker_end(this, tx_buffer, dummy_ts, true); // Reset PRACH pointer prach_ptr = nullptr; @@ -114,7 +114,7 @@ void sf_worker::work_imp() } // Always call worker_end before returning - phy->worker_end(this, false, tx_buffer, dummy_ts, true); + common.worker_end(this, tx_buffer, dummy_ts, true); // Tell the plotting thread to draw the plots #ifdef ENABLE_GUI diff --git a/srsue/src/phy/nr/worker_pool.cc b/srsue/src/phy/nr/worker_pool.cc index f4d66bc9f..44a30b656 100644 --- a/srsue/src/phy/nr/worker_pool.cc +++ b/srsue/src/phy/nr/worker_pool.cc @@ -16,7 +16,10 @@ namespace nr { worker_pool::worker_pool(uint32_t max_workers) : pool(max_workers), logger(srslog::fetch_basic_logger("PHY-NR")) {} -bool worker_pool::init(const phy_args_nr_t& args, phy_common* common, stack_interface_phy_nr* stack_, int prio) +bool worker_pool::init(const phy_args_nr_t& args, + srsran::phy_common_interface& common, + stack_interface_phy_nr* stack_, + int prio) { phy_state.stack = stack_; phy_state.args = args; @@ -43,7 +46,7 @@ bool worker_pool::init(const phy_args_nr_t& args, phy_common* common, stack_inte log.set_level(srslog::str_to_basic_level(args.log.phy_level)); log.set_hex_dump_max_size(args.log.phy_hex_limit); - auto w = new sf_worker(common, &phy_state, log); + auto w = new sf_worker(common, phy_state, log); pool.init_worker(i, w, prio, args.worker_cpu_mask); workers.push_back(std::unique_ptr(w)); } diff --git a/srsue/src/phy/phy.cc b/srsue/src/phy/phy.cc index 12de63ba3..e9d84e7c6 100644 --- a/srsue/src/phy/phy.cc +++ b/srsue/src/phy/phy.cc @@ -615,7 +615,7 @@ void phy::set_mch_period_stop(uint32_t stop) int phy::init(const phy_args_nr_t& args_, stack_interface_phy_nr* stack_, srsran::radio_interface_phy* radio_) { - if (!nr_workers.init(args_, &common, stack_, WORKERS_THREAD_PRIO)) { + if (!nr_workers.init(args_, common, stack_, WORKERS_THREAD_PRIO)) { return SRSRAN_ERROR; } diff --git a/srsue/src/phy/phy_common.cc b/srsue/src/phy/phy_common.cc index 4803d5fce..4b4462052 100644 --- a/srsue/src/phy/phy_common.cc +++ b/srsue/src/phy/phy_common.cc @@ -531,12 +531,10 @@ bool phy_common::get_dl_pending_ack(srsran_ul_sf_cfg_t* sf, uint32_t cc_idx, srs * Each worker uses this function to indicate that all processing is done and data is ready for transmission or * there is no transmission at all (tx_enable). In that case, the end of burst message will be sent to the radio */ -void phy_common::worker_end(void* tx_sem_id, - bool tx_enable, - srsran::rf_buffer_t& buffer, - srsran::rf_timestamp_t& tx_time, - bool is_nr) +void phy_common::worker_end(void* tx_sem_id, srsran::rf_buffer_t& buffer, srsran::rf_timestamp_t& tx_time, bool is_nr) { + bool tx_enable = buffer.get_nof_samples() > 0; + // Wait for the green light to transmit in the current TTI semaphore.wait(tx_sem_id); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 3d08986bd..996426ab2 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -19,3 +19,5 @@ if (ZEROMQ_FOUND AND ENABLE_ZMQ_TEST) endforeach (cell_n_prb) endforeach (num_cc) endif (ZEROMQ_FOUND AND ENABLE_ZMQ_TEST) + +add_subdirectory(phy) \ No newline at end of file diff --git a/test/phy/CMakeLists.txt b/test/phy/CMakeLists.txt new file mode 100644 index 000000000..943cf44d8 --- /dev/null +++ b/test/phy/CMakeLists.txt @@ -0,0 +1,23 @@ +# +# 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. +# + +add_executable(nr_phy_test nr_phy_test.cc) +target_link_libraries(nr_phy_test + srsue_phy_nr + srsue_phy + srsran_common + srsran_phy + srsran_radio + srsenb_phy + ${CMAKE_THREAD_LIBS_INIT} + ${Boost_LIBRARIES} + ${CMAKE_THREAD_LIBS_INIT} + ${Boost_LIBRARIES} + ${ATOMIC_LIBS}) + +add_nr_test(nr_phy_test nr_phy_test) \ No newline at end of file diff --git a/test/phy/nr_phy_test.cc b/test/phy/nr_phy_test.cc new file mode 100644 index 000000000..e7ea7ec8e --- /dev/null +++ b/test/phy/nr_phy_test.cc @@ -0,0 +1,111 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2021 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include "srsenb/hdr/phy/nr/worker_pool.h" +#include "srsran/common/test_common.h" +#include "srsue/hdr/phy/nr/worker_pool.h" + +class phy_common : public srsran::phy_common_interface +{ +public: + void worker_end(void* h, srsran::rf_buffer_t& buffer, srsran::rf_timestamp_t& tx_time, bool is_nr) override {} +}; + +class ue_dummy_stack : public srsue::stack_interface_phy_nr +{ +public: + void in_sync() override {} + void out_of_sync() override {} + void run_tti(const uint32_t tti) override {} + int sf_indication(const uint32_t tti) override { return 0; } + sched_rnti_t get_dl_sched_rnti_nr(const uint32_t tti) override { return sched_rnti_t(); } + sched_rnti_t get_ul_sched_rnti_nr(const uint32_t tti) override { return sched_rnti_t(); } + void new_grant_dl(const uint32_t cc_idx, const mac_nr_grant_dl_t& grant, tb_action_dl_t* action) override {} + void tb_decoded(const uint32_t cc_idx, const mac_nr_grant_dl_t& grant, tb_action_dl_result_t result) override {} + void new_grant_ul(const uint32_t cc_idx, const mac_nr_grant_ul_t& grant, tb_action_ul_t* action) override {} + void prach_sent(uint32_t tti, uint32_t s_id, uint32_t t_id, uint32_t f_id, uint32_t ul_carrier_id) override {} + bool sr_opportunity(uint32_t tti, uint32_t sr_id, bool meas_gap, bool ul_sch_tx) override { return false; } +}; + +class test_bench +{ +private: + srsenb::nr::worker_pool gnb_phy; + phy_common gnb_phy_com; + srsue::nr::worker_pool ue_phy; + phy_common ue_phy_com; + ue_dummy_stack ue_stack; + bool initialised = false; + +public: + struct args_t { + uint32_t nof_threads = 6; + uint32_t nof_prb = 52; + + bool parse(int argc, char** argv); + }; + + test_bench(const args_t& args) : ue_phy(args.nof_threads), gnb_phy(args.nof_threads) + { + // Prepare cell list + srsenb::phy_cell_cfg_list_nr_t cell_list(1); + cell_list[0].carrier.nof_prb = args.nof_prb; + + // Prepare gNb PHY arguments + srsenb::phy_args_t gnb_phy_args = {}; + + // Initialise gnb + if (not gnb_phy.init(cell_list, gnb_phy_args, gnb_phy_com, srslog::get_default_sink(), 31)) { + return; + } + + // Prepare PHY + srsue::phy_args_nr_t ue_phy_args = {}; + + // Initialise UE PHY + if (not ue_phy.init(ue_phy_args, ue_phy_com, &ue_stack, 31)) { + return; + } + + initialised = true; + } + + ~test_bench() + { + gnb_phy.stop(); + ue_phy.stop(); + } + + bool is_initialised() const { return initialised; } +}; + +bool test_bench::args_t::parse(int argc, char** argv) +{ + return true; +} + +int main(int argc, char** argv) +{ + test_bench::args_t args = {}; + + // Parse arguments + TESTASSERT(args.parse(argc, argv)); + + // Create test bench + test_bench tb(args); + + // Assert bench is initialised correctly + TESTASSERT(tb.is_initialised()); + + // If reached here, the test is successful + return SRSRAN_SUCCESS; +} \ No newline at end of file From b1e47207219c49eaa3945d8f8d015937b8fc25c5 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Fri, 18 Jun 2021 09:11:32 +0200 Subject: [PATCH 13/24] SRSUE/SRSENB: added tx_enable flag in worker_end --- lib/include/srsran/interfaces/phy_common_interface.h | 11 ++++++++++- srsenb/hdr/phy/phy_common.h | 3 ++- srsenb/src/phy/lte/sf_worker.cc | 10 +++++----- srsenb/src/phy/nr/sf_worker.cc | 2 +- srsenb/src/phy/phy_common.cc | 6 +++++- srsue/hdr/phy/phy_common.h | 6 +++++- srsue/src/phy/lte/sf_worker.cc | 10 +++------- srsue/src/phy/nr/sf_worker.cc | 4 ++-- srsue/src/phy/phy_common.cc | 8 +++++--- test/phy/nr_phy_test.cc | 4 +++- 10 files changed, 41 insertions(+), 23 deletions(-) diff --git a/lib/include/srsran/interfaces/phy_common_interface.h b/lib/include/srsran/interfaces/phy_common_interface.h index a0df2e6e5..5dec8e06c 100644 --- a/lib/include/srsran/interfaces/phy_common_interface.h +++ b/lib/include/srsran/interfaces/phy_common_interface.h @@ -21,7 +21,16 @@ namespace srsran { class phy_common_interface { public: - virtual void worker_end(void* h, srsran::rf_buffer_t& buffer, srsran::rf_timestamp_t& tx_time, bool is_nr) = 0; + /** + * @brief Common PHY interface for workers to indicate they ended + * @param h Worker pointer used as unique identifier for synchronising Tx + * @param tx_enable Indicates whether the buffer has baseband samples to transmit + * @param buffer Baseband buffer + * @param tx_time Transmit timestamp + * @param is_nr Indicates whether the worker is NR or not + */ + virtual void + worker_end(void* h, bool tx_enable, srsran::rf_buffer_t& buffer, srsran::rf_timestamp_t& tx_time, bool is_nr) = 0; }; } // namespace srsran diff --git a/srsenb/hdr/phy/phy_common.h b/srsenb/hdr/phy/phy_common.h index f8fbc2546..234adfda9 100644 --- a/srsenb/hdr/phy/phy_common.h +++ b/srsenb/hdr/phy/phy_common.h @@ -58,9 +58,10 @@ public: * @param is_nr flag is true if it is called from NR */ void worker_end(void* tx_sem_id, + bool tx_enable, srsran::rf_buffer_t& buffer, srsran::rf_timestamp_t& tx_time, - bool is_nr = false) override; + bool is_nr) override; // Common objects phy_args_t params = {}; diff --git a/srsenb/src/phy/lte/sf_worker.cc b/srsenb/src/phy/lte/sf_worker.cc index d95c43d9d..5976f42e0 100644 --- a/srsenb/src/phy/lte/sf_worker.cc +++ b/srsenb/src/phy/lte/sf_worker.cc @@ -154,7 +154,7 @@ void sf_worker::work_imp() } if (!running) { - phy->worker_end(this, tx_buffer, tx_time); + phy->worker_end(this, true, tx_buffer, tx_time, false); return; } @@ -192,14 +192,14 @@ void sf_worker::work_imp() if (sf_type == SRSRAN_SF_NORM) { if (stack->get_dl_sched(tti_tx_dl, dl_grants) < 0) { Error("Getting DL scheduling from MAC"); - phy->worker_end(this, tx_buffer, tx_time); + phy->worker_end(this, false, tx_buffer, tx_time, false); return; } } else { dl_grants[0].cfi = mbsfn_cfg.non_mbsfn_region_length; if (stack->get_mch_sched(tti_tx_dl, mbsfn_cfg.is_mcch, dl_grants)) { Error("Getting MCH packets from MAC"); - phy->worker_end(this, tx_buffer, tx_time); + phy->worker_end(this, false, tx_buffer, tx_time, false); return; } } @@ -207,7 +207,7 @@ void sf_worker::work_imp() // Get UL scheduling for the TX TTI from MAC if (stack->get_ul_sched(tti_tx_ul, ul_grants_tx) < 0) { Error("Getting UL scheduling from MAC"); - phy->worker_end(this, tx_buffer, tx_time); + phy->worker_end(this, false, tx_buffer, tx_time, false); return; } @@ -234,7 +234,7 @@ void sf_worker::work_imp() Debug("Sending to radio"); tx_buffer.set_nof_samples(SRSRAN_SF_LEN_PRB(phy->get_nof_prb(0))); - phy->worker_end(this, tx_buffer, tx_time); + phy->worker_end(this, true, tx_buffer, tx_time, false); #ifdef DEBUG_WRITE_FILE fwrite(signal_buffer_tx, SRSRAN_SF_LEN_PRB(phy->cell.nof_prb) * sizeof(cf_t), 1, f); diff --git a/srsenb/src/phy/nr/sf_worker.cc b/srsenb/src/phy/nr/sf_worker.cc index be1b300fa..6e9118c72 100644 --- a/srsenb/src/phy/nr/sf_worker.cc +++ b/srsenb/src/phy/nr/sf_worker.cc @@ -116,7 +116,7 @@ void sf_worker::work_imp() w->work_dl(dl_cfg, grants); } - common.worker_end(this, tx_buffer, dummy_ts, true); + common.worker_end(this, true, tx_buffer, dummy_ts, true); } } // namespace nr diff --git a/srsenb/src/phy/phy_common.cc b/srsenb/src/phy/phy_common.cc index ca76d4dc8..e1fa1e6a4 100644 --- a/srsenb/src/phy/phy_common.cc +++ b/srsenb/src/phy/phy_common.cc @@ -104,7 +104,11 @@ void phy_common::set_ul_grants(uint32_t tti, const stack_interface_phy_lte::ul_s * Each worker uses this function to indicate that all processing is done and data is ready for transmission or * there is no transmission at all (tx_enable). In that case, the end of burst message will be sent to the radio */ -void phy_common::worker_end(void* tx_sem_id, srsran::rf_buffer_t& buffer, srsran::rf_timestamp_t& tx_time, bool is_nr) +void phy_common::worker_end(void* tx_sem_id, + bool tx_enable, + srsran::rf_buffer_t& buffer, + srsran::rf_timestamp_t& tx_time, + bool is_nr) { // Wait for the green light to transmit in the current TTI semaphore.wait(tx_sem_id); diff --git a/srsue/hdr/phy/phy_common.h b/srsue/hdr/phy/phy_common.h index 10d26aa1e..e850caac2 100644 --- a/srsue/hdr/phy/phy_common.h +++ b/srsue/hdr/phy/phy_common.h @@ -130,7 +130,11 @@ public: srsran_pdsch_ack_resource_t resource); bool get_dl_pending_ack(srsran_ul_sf_cfg_t* sf, uint32_t cc_idx, srsran_pdsch_ack_cc_t* ack); - void worker_end(void* h, srsran::rf_buffer_t& buffer, srsran::rf_timestamp_t& tx_time, bool is_nr) override; + void worker_end(void* h, + bool tx_enable, + srsran::rf_buffer_t& buffer, + srsran::rf_timestamp_t& tx_time, + bool is_nr) override; void set_cell(const srsran_cell_t& c); diff --git a/srsue/src/phy/lte/sf_worker.cc b/srsue/src/phy/lte/sf_worker.cc index ea7b6a58c..cb603ee92 100644 --- a/srsue/src/phy/lte/sf_worker.cc +++ b/srsue/src/phy/lte/sf_worker.cc @@ -155,7 +155,7 @@ void sf_worker::work_imp() { srsran::rf_buffer_t tx_signal_ptr = {}; if (!cell_initiated) { - phy->worker_end(this, tx_signal_ptr, tx_time, false); + phy->worker_end(this, false, tx_signal_ptr, tx_time, false); return; } @@ -182,6 +182,7 @@ void sf_worker::work_imp() } } } + tx_signal_ptr.set_nof_samples(nof_samples); /***** Uplink Generation + Transmission *******/ @@ -224,13 +225,8 @@ void sf_worker::work_imp() prach_ptr = nullptr; } - // Indicates worker there is a transmission by setting the number of samples - if (tx_signal_ready) { - tx_signal_ptr.set_nof_samples(nof_samples); - } - // Call worker_end to transmit the signal - phy->worker_end(this, tx_signal_ptr, tx_time, false); + phy->worker_end(this, tx_signal_ready, tx_signal_ptr, tx_time, false); if (rx_signal_ok) { update_measurements(); diff --git a/srsue/src/phy/nr/sf_worker.cc b/srsue/src/phy/nr/sf_worker.cc index bb596d1c9..da303e6fe 100644 --- a/srsue/src/phy/nr/sf_worker.cc +++ b/srsue/src/phy/nr/sf_worker.cc @@ -95,7 +95,7 @@ void sf_worker::work_imp() 0); // Transmit NR PRACH - common.worker_end(this, tx_buffer, dummy_ts, true); + common.worker_end(this, true, tx_buffer, dummy_ts, true); // Reset PRACH pointer prach_ptr = nullptr; @@ -114,7 +114,7 @@ void sf_worker::work_imp() } // Always call worker_end before returning - common.worker_end(this, tx_buffer, dummy_ts, true); + common.worker_end(this, true, tx_buffer, dummy_ts, true); // Tell the plotting thread to draw the plots #ifdef ENABLE_GUI diff --git a/srsue/src/phy/phy_common.cc b/srsue/src/phy/phy_common.cc index 4b4462052..4803d5fce 100644 --- a/srsue/src/phy/phy_common.cc +++ b/srsue/src/phy/phy_common.cc @@ -531,10 +531,12 @@ bool phy_common::get_dl_pending_ack(srsran_ul_sf_cfg_t* sf, uint32_t cc_idx, srs * Each worker uses this function to indicate that all processing is done and data is ready for transmission or * there is no transmission at all (tx_enable). In that case, the end of burst message will be sent to the radio */ -void phy_common::worker_end(void* tx_sem_id, srsran::rf_buffer_t& buffer, srsran::rf_timestamp_t& tx_time, bool is_nr) +void phy_common::worker_end(void* tx_sem_id, + bool tx_enable, + srsran::rf_buffer_t& buffer, + srsran::rf_timestamp_t& tx_time, + bool is_nr) { - bool tx_enable = buffer.get_nof_samples() > 0; - // Wait for the green light to transmit in the current TTI semaphore.wait(tx_sem_id); diff --git a/test/phy/nr_phy_test.cc b/test/phy/nr_phy_test.cc index e7ea7ec8e..7d4f7b825 100644 --- a/test/phy/nr_phy_test.cc +++ b/test/phy/nr_phy_test.cc @@ -17,7 +17,9 @@ class phy_common : public srsran::phy_common_interface { public: - void worker_end(void* h, srsran::rf_buffer_t& buffer, srsran::rf_timestamp_t& tx_time, bool is_nr) override {} + void + worker_end(void* h, bool tx_enable, srsran::rf_buffer_t& buffer, srsran::rf_timestamp_t& tx_time, bool is_nr) override + {} }; class ue_dummy_stack : public srsue::stack_interface_phy_nr From 78acf81cf034b1ee05211ba5b22d148835f7296b Mon Sep 17 00:00:00 2001 From: Francisco Date: Thu, 17 Jun 2021 13:33:29 +0100 Subject: [PATCH 14/24] bugfix,sched: avoid instability in TPCs around PHR~0 --- lib/include/srsran/adt/accumulators.h | 5 ++ srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h | 66 +++++++++++---------- srsenb/test/mac/sched_tpc_test.cc | 75 ++++++++++++++++++++---- 3 files changed, 105 insertions(+), 41 deletions(-) diff --git a/lib/include/srsran/adt/accumulators.h b/lib/include/srsran/adt/accumulators.h index e6b8d639b..4e2413982 100644 --- a/lib/include/srsran/adt/accumulators.h +++ b/lib/include/srsran/adt/accumulators.h @@ -30,6 +30,11 @@ struct rolling_average { } T value() const { return count_ == 0 ? 0 : avg_; } uint32_t count() const { return count_; } + void reset() + { + avg_ = 0; + count_ = 0; + } private: T avg_ = 0; diff --git a/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h b/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h index de37dd6a6..ddfbd5ab2 100644 --- a/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h +++ b/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h @@ -77,7 +77,7 @@ public: { last_phr = phr_; for (auto& ch_snr : snr_estim_list) { - ch_snr.phr_flag = false; + ch_snr.acc_tpc_phr_values = 0; } // compute and cache the max nof UL PRBs that avoids overflowing PHR @@ -109,6 +109,7 @@ public: if (ch_snr.pending_snr == null_snr) { ch_snr.last_snr_sample_count++; ch_snr.acc_tpc_values += ch_snr.win_tpc_values.oldest(); + ch_snr.acc_tpc_phr_values += ch_snr.win_tpc_values.oldest(); } else { ch_snr.acc_tpc_values = 0; ch_snr.snr_avg.push(ch_snr.pending_snr, ch_snr.last_snr_sample_count); @@ -170,40 +171,43 @@ private: // undefined target SINR case return encode_tpc_delta(0); } - if ((tti_count - ch_snr.last_tpc_tti_count) < min_tpc_tti_interval) { - // more time required before sending next TPC - return encode_tpc_delta(0); - } - if (cc == PUSCH_CODE and last_phr < 0 and not ch_snr.phr_flag) { - // if negative PHR and PUSCH - logger.info("TPC: rnti=0x%x, PUSCH command=0 due to PHR=%d<0", rnti, last_phr); - ch_snr.phr_flag = true; - ch_snr.pending_delta = -1; - return encode_tpc_delta(ch_snr.pending_delta); + + // limitation of TPC based on PHR + int max_delta = 3; + int eff_phr = last_phr; + if (cc == PUSCH_CODE and last_phr != undefined_phr) { + eff_phr -= ch_snr.win_tpc_values.value() + ch_snr.acc_tpc_phr_values; + max_delta = std::min(max_delta, eff_phr); } - // target SINR is finite and there is power headroom - float diff = target_snr_dB - ch_snr.last_snr_sample; - diff -= ch_snr.win_tpc_values.value() + ch_snr.acc_tpc_values; - if (diff >= 1) { - ch_snr.pending_delta = diff > 3 ? 3 : 1; - if (cc == PUSCH_CODE and static_cast(ch_snr.pending_delta) > last_phr) { - // cap PUSCH TPC when PHR is low - ch_snr.pending_delta = last_phr > 1 ? 1 : 0; + float snr = ch_snr.last_snr_sample; + // In case of periodicity of TPCs is > 1 tti, use average SNR to compute SNR diff + if (min_tpc_tti_interval > 1) { + ch_snr.tpc_snr_avg.push(snr); + if ((tti_count - ch_snr.last_tpc_tti_count) < min_tpc_tti_interval) { + // more time required before sending next TPC + return encode_tpc_delta(0); } - ch_snr.last_tpc_tti_count = tti_count; - } else if (diff <= -1) { - ch_snr.pending_delta = -1; - ch_snr.last_tpc_tti_count = tti_count; + snr = ch_snr.tpc_snr_avg.value(); } + + float diff = target_snr_dB - snr; + diff -= ch_snr.win_tpc_values.value() + ch_snr.acc_tpc_values; + ch_snr.pending_delta = std::max(std::min((int)floorf(diff), max_delta), -1); + ch_snr.pending_delta = (ch_snr.pending_delta == 2) ? 1 : ch_snr.pending_delta; if (ch_snr.pending_delta != 0) { - logger.debug("TPC: rnti=0x%x, %s command=%d, last SNR=%d, SNR average=%f, diff_acc=%f", + if (min_tpc_tti_interval > 1) { + ch_snr.last_tpc_tti_count = tti_count; + ch_snr.tpc_snr_avg.reset(); + } + logger.debug("TPC: rnti=0x%x, %s command=%d, last SNR=%d, SNR average=%f, diff_acc=%f, eff_phr=%d", rnti, cc == PUSCH_CODE ? "PUSCH" : "PUCCH", encode_tpc_delta(ch_snr.pending_delta), ch_snr.last_snr_sample, ch_snr.snr_avg.value(), - diff); + diff, + eff_phr); } return encode_tpc_delta(ch_snr.pending_delta); } @@ -225,8 +229,6 @@ private: // SNR estimation struct ul_ch_snr_estim { - // flag used in undefined target SINR case - bool phr_flag = false; // pending new snr sample float pending_snr = srsran::null_sliding_average::null_value(); // SNR average estimation with irregular sample spacing @@ -234,10 +236,12 @@ private: srsran::exp_average_irreg_sampling snr_avg; int last_snr_sample; // Accumulation of past TPC commands - srsran::sliding_sum win_tpc_values; - int8_t pending_delta = 0; - int acc_tpc_values = 0; - uint32_t last_tpc_tti_count = 0; + srsran::sliding_sum win_tpc_values; + int acc_tpc_values = 0; + int acc_tpc_phr_values = 0; + int8_t pending_delta = 0; + uint32_t last_tpc_tti_count = 0; + srsran::rolling_average tpc_snr_avg; // average of SNRs since last TPC != 1 explicit ul_ch_snr_estim(float exp_avg_alpha, int initial_snr) : snr_avg(exp_avg_alpha, initial_snr), diff --git a/srsenb/test/mac/sched_tpc_test.cc b/srsenb/test/mac/sched_tpc_test.cc index 914cd36e3..f0019fae8 100644 --- a/srsenb/test/mac/sched_tpc_test.cc +++ b/srsenb/test/mac/sched_tpc_test.cc @@ -72,23 +72,40 @@ int test_finite_target_snr() } // TEST: PHR is negative. Checks: - // - one TPC should be sent to decrease power. No more TPCs != 0 should be sent until the next PHR - snr_diff = -10; + // - TPCs sent should be negative or zero + // - The accumulation of TPCs should lead to next PHR being zero. + snr_diff = -10; + int next_phr = -2; tpcfsm.set_snr(target_snr + snr_diff, tpc::PUSCH_CODE); tpcfsm.set_snr(target_snr + snr_diff, tpc::PUCCH_CODE); + sum_pucch = 0; for (uint32_t i = 0; i < 3; ++i) { - tpcfsm.set_phr(-2, 1); - tpcfsm.new_tti(); - TESTASSERT(decode_tpc(tpcfsm.encode_pusch_tpc()) == -1); - TESTASSERT(decode_tpc(tpcfsm.encode_pucch_tpc()) == 3); // PUCCH doesnt get affected by neg PHR + tpcfsm.set_phr(next_phr, 1); for (uint32_t j = 0; j < 100; ++j) { tpcfsm.new_tti(); - TESTASSERT(decode_tpc(tpcfsm.encode_pusch_tpc()) == 0); + int tpc_pusch = decode_tpc(tpcfsm.encode_pusch_tpc()); + TESTASSERT(tpc_pusch <= 0); + next_phr -= tpc_pusch; + sum_pucch += decode_tpc(tpcfsm.encode_pucch_tpc()); } + TESTASSERT(next_phr == 0); } - tpcfsm.set_phr(20, 1); - tpcfsm.new_tti(); - TESTASSERT(decode_tpc(tpcfsm.encode_pusch_tpc()) == 3); + TESTASSERT(sum_pucch == -snr_diff); // PUCCH doesnt get affected by neg PHR + + // TEST: PHR is positive and SINR < target SINR. Checks: + // - accumulation of TPCs should not make next PHR negative + // - TPCs should be positive or zero + next_phr = 5; + snr_diff = -10; + tpcfsm.set_phr(next_phr, 1); + tpcfsm.set_snr(target_snr + snr_diff, tpc::PUSCH_CODE); + for (uint32_t j = 0; j < 100; ++j) { + tpcfsm.new_tti(); + int tpc_pusch = decode_tpc(tpcfsm.encode_pusch_tpc()); + next_phr -= tpc_pusch; + TESTASSERT(tpc_pusch >= 0); + } + TESTASSERT(next_phr == 0); return SRSRAN_SUCCESS; } @@ -164,11 +181,49 @@ int test_undefined_target_snr() return SRSRAN_SUCCESS; } +void test_finite_target_snr_tpc_period_above_1() +{ + const uint32_t nof_prbs = 50; + const int target_snr = 15; + + tpc tpcfsm(0x46, nof_prbs, 15, 15, true, 0, 5); + + // TEST: While UL SNR ~ target, no TPC commands are sent + for (uint32_t i = 0; i < 100 and tpcfsm.get_ul_snr_estim(0) < 14; ++i) { + tpcfsm.set_snr(15, 0); + tpcfsm.set_snr(15, 1); + tpcfsm.new_tti(); + } + for (uint32_t i = 0; i < 100; ++i) { + tpcfsm.new_tti(); + TESTASSERT(decode_tpc(tpcfsm.encode_pucch_tpc()) == 0); + TESTASSERT(decode_tpc(tpcfsm.encode_pusch_tpc()) == 0); + } + + // TEST: current SNR above target SNR. Checks: + // - TPC commands should be sent to decrease power + // - The sum power of TPC commands should not exceed the difference between current and target SNRs + int snr_diff = 10; + tpcfsm.set_snr(target_snr + snr_diff, tpc::PUSCH_CODE); + tpcfsm.set_snr(target_snr + snr_diff, tpc::PUCCH_CODE); + int sum_pusch = 0, sum_pucch = 0; + for (uint32_t i = 0; i < 100; ++i) { + tpcfsm.new_tti(); + int tpc = decode_tpc(tpcfsm.encode_pusch_tpc()); + TESTASSERT(tpc <= 0); + sum_pusch += tpc; + sum_pucch += decode_tpc(tpcfsm.encode_pucch_tpc()); + TESTASSERT(sum_pucch < 0 and sum_pucch >= -snr_diff); + } + TESTASSERT(sum_pusch == -snr_diff); +} + } // namespace srsenb int main() { TESTASSERT(srsenb::test_finite_target_snr() == 0); TESTASSERT(srsenb::test_undefined_target_snr() == 0); + srsenb::test_finite_target_snr_tpc_period_above_1(); printf("Success\n"); } From 85d7a851fb70589a76eecdf1f256ebf7c99b1729 Mon Sep 17 00:00:00 2001 From: David Rupprecht Date: Tue, 8 Jun 2021 09:54:57 +0200 Subject: [PATCH 15/24] Added 5G NAS PCAP support --- lib/examples/npdsch_ue.c | 4 ++-- lib/examples/pssch_ue.c | 4 ++-- lib/include/srsran/common/nas_pcap.h | 3 ++- lib/include/srsran/common/pcap.h | 5 +++-- lib/src/common/mac_pcap.cc | 4 ++-- lib/src/common/nas_pcap.cc | 12 ++++++++---- lib/src/common/pcap.c | 4 ++-- lib/src/common/rlc_pcap.cc | 4 ++-- lib/src/common/s1ap_pcap.cc | 4 ++-- 9 files changed, 25 insertions(+), 19 deletions(-) diff --git a/lib/examples/npdsch_ue.c b/lib/examples/npdsch_ue.c index e301f2071..fb1c17a94 100644 --- a/lib/examples/npdsch_ue.c +++ b/lib/examples/npdsch_ue.c @@ -330,7 +330,7 @@ int main(int argc, char** argv) parse_args(&prog_args, argc, argv); #if HAVE_PCAP - FILE* pcap_file = LTE_PCAP_Open(MAC_LTE_DLT, "/tmp/npdsch.pcap"); + FILE* pcap_file = DLT_PCAP_Open(MAC_LTE_DLT, "/tmp/npdsch.pcap"); #endif sigset_t sigset; @@ -856,7 +856,7 @@ int main(int argc, char** argv) #if HAVE_PCAP printf("Saving PCAP file\n"); - LTE_PCAP_Close(pcap_file); + DLT_PCAP_Close(pcap_file); #endif #ifndef DISABLE_RF diff --git a/lib/examples/pssch_ue.c b/lib/examples/pssch_ue.c index a7524bba4..f96ddc182 100644 --- a/lib/examples/pssch_ue.c +++ b/lib/examples/pssch_ue.c @@ -223,7 +223,7 @@ int main(int argc, char** argv) parse_args(&prog_args, argc, argv); - FILE* pcap_file = LTE_PCAP_Open(MAC_LTE_DLT, PCAP_FILENAME); + FILE* pcap_file = DLT_PCAP_Open(MAC_LTE_DLT, PCAP_FILENAME); srsran_use_standard_symbol_size(prog_args.use_standard_lte_rates); @@ -537,7 +537,7 @@ clean_exit: if (pcap_file != NULL) { printf("Saving PCAP file to %s\n", PCAP_FILENAME); - LTE_PCAP_Close(pcap_file); + DLT_PCAP_Close(pcap_file); } #ifdef ENABLE_GUI diff --git a/lib/include/srsran/common/nas_pcap.h b/lib/include/srsran/common/nas_pcap.h index 30b85adbe..c1bc5fd76 100644 --- a/lib/include/srsran/common/nas_pcap.h +++ b/lib/include/srsran/common/nas_pcap.h @@ -13,6 +13,7 @@ #ifndef SRSRAN_NAS_PCAP_H #define SRSRAN_NAS_PCAP_H +#include "srsran/common/common.h" #include "srsran/common/pcap.h" #include @@ -28,7 +29,7 @@ public: pcap_file = NULL; } void enable(); - uint32_t open(std::string filename_, uint32_t ue_id = 0); + uint32_t open(std::string filename_, uint32_t ue_id = 0, srsran_rat_t rat_type = srsran_rat_t::lte); void close(); void write_nas(uint8_t* pdu, uint32_t pdu_len_bytes); diff --git a/lib/include/srsran/common/pcap.h b/lib/include/srsran/common/pcap.h index d3c709d04..10bcef01d 100644 --- a/lib/include/srsran/common/pcap.h +++ b/lib/include/srsran/common/pcap.h @@ -23,6 +23,7 @@ #define NAS_LTE_DLT 148 #define UDP_DLT 149 // UDP needs to be selected as protocol #define S1AP_LTE_DLT 150 +#define NAS_5G_DLT 151 /* This structure gets written to the start of the file */ typedef struct pcap_hdr_s { @@ -184,10 +185,10 @@ extern "C" { #endif /* Open the file and write file header */ -FILE* LTE_PCAP_Open(uint32_t DLT, const char* fileName); +FILE* DLT_PCAP_Open(uint32_t DLT, const char* fileName); /* Close the PCAP file */ -void LTE_PCAP_Close(FILE* fd); +void DLT_PCAP_Close(FILE* fd); /* Write an individual MAC PDU (PCAP packet header + mac-context + mac-pdu) */ int LTE_PCAP_MAC_WritePDU(FILE* fd, MAC_Context_Info_t* context, const unsigned char* PDU, unsigned int length); diff --git a/lib/src/common/mac_pcap.cc b/lib/src/common/mac_pcap.cc index a258f1059..3a909d397 100644 --- a/lib/src/common/mac_pcap.cc +++ b/lib/src/common/mac_pcap.cc @@ -32,7 +32,7 @@ uint32_t mac_pcap::open(std::string filename_, uint32_t ue_id_) // set DLT for selected RAT dlt = UDP_DLT; - pcap_file = LTE_PCAP_Open(dlt, filename_.c_str()); + pcap_file = DLT_PCAP_Open(dlt, filename_.c_str()); if (pcap_file == nullptr) { logger.error("Couldn't open %s to write PCAP", filename_.c_str()); return SRSRAN_ERROR; @@ -68,7 +68,7 @@ uint32_t mac_pcap::close() { std::lock_guard lock(mutex); srsran::console("Saving MAC PCAP (DLT=%d) to %s\n", dlt, filename.c_str()); - LTE_PCAP_Close(pcap_file); + DLT_PCAP_Close(pcap_file); pcap_file = nullptr; } diff --git a/lib/src/common/nas_pcap.cc b/lib/src/common/nas_pcap.cc index 05ff76ca5..6d45d2a09 100644 --- a/lib/src/common/nas_pcap.cc +++ b/lib/src/common/nas_pcap.cc @@ -22,10 +22,14 @@ void nas_pcap::enable() enable_write = true; } -uint32_t nas_pcap::open(std::string filename_, uint32_t ue_id_) +uint32_t nas_pcap::open(std::string filename_, uint32_t ue_id_, srsran_rat_t rat_type) { - filename = filename_; - pcap_file = LTE_PCAP_Open(NAS_LTE_DLT, filename.c_str()); + filename = filename_; + if (rat_type == srsran_rat_t::nr) { + pcap_file = DLT_PCAP_Open(NAS_5G_DLT, filename.c_str()); + } else { + pcap_file = DLT_PCAP_Open(NAS_LTE_DLT, filename.c_str()); + } if (pcap_file == nullptr) { return SRSRAN_ERROR; } @@ -37,7 +41,7 @@ uint32_t nas_pcap::open(std::string filename_, uint32_t ue_id_) void nas_pcap::close() { fprintf(stdout, "Saving NAS PCAP file (DLT=%d) to %s \n", NAS_LTE_DLT, filename.c_str()); - LTE_PCAP_Close(pcap_file); + DLT_PCAP_Close(pcap_file); } void nas_pcap::write_nas(uint8_t* pdu, uint32_t pdu_len_bytes) diff --git a/lib/src/common/pcap.c b/lib/src/common/pcap.c index d51727551..fcb44f0bf 100644 --- a/lib/src/common/pcap.c +++ b/lib/src/common/pcap.c @@ -18,7 +18,7 @@ #include /* Open the file and write file header */ -FILE* LTE_PCAP_Open(uint32_t DLT, const char* fileName) +FILE* DLT_PCAP_Open(uint32_t DLT, const char* fileName) { pcap_hdr_t file_header = { 0xa1b2c3d4, /* magic number */ @@ -43,7 +43,7 @@ FILE* LTE_PCAP_Open(uint32_t DLT, const char* fileName) } /* Close the PCAP file */ -void LTE_PCAP_Close(FILE* fd) +void DLT_PCAP_Close(FILE* fd) { if (fd) { fclose(fd); diff --git a/lib/src/common/rlc_pcap.cc b/lib/src/common/rlc_pcap.cc index a0878bb76..9a5aa8230 100644 --- a/lib/src/common/rlc_pcap.cc +++ b/lib/src/common/rlc_pcap.cc @@ -25,7 +25,7 @@ void rlc_pcap::enable(bool en) void rlc_pcap::open(const char* filename, rlc_config_t config) { fprintf(stdout, "Opening RLC PCAP with DLT=%d\n", UDP_DLT); - pcap_file = LTE_PCAP_Open(UDP_DLT, filename); + pcap_file = DLT_PCAP_Open(UDP_DLT, filename); enable_write = true; if (config.rlc_mode == rlc_mode_t::am) { @@ -45,7 +45,7 @@ void rlc_pcap::open(const char* filename, rlc_config_t config) void rlc_pcap::close() { fprintf(stdout, "Saving RLC PCAP file\n"); - LTE_PCAP_Close(pcap_file); + DLT_PCAP_Close(pcap_file); } void rlc_pcap::set_ue_id(uint16_t ue_id_) diff --git a/lib/src/common/s1ap_pcap.cc b/lib/src/common/s1ap_pcap.cc index fd192344b..b6a91c1e3 100644 --- a/lib/src/common/s1ap_pcap.cc +++ b/lib/src/common/s1ap_pcap.cc @@ -23,13 +23,13 @@ void s1ap_pcap::enable() } void s1ap_pcap::open(const char* filename) { - pcap_file = LTE_PCAP_Open(S1AP_LTE_DLT, filename); + pcap_file = DLT_PCAP_Open(S1AP_LTE_DLT, filename); enable_write = true; } void s1ap_pcap::close() { fprintf(stdout, "Saving S1AP PCAP file\n"); - LTE_PCAP_Close(pcap_file); + DLT_PCAP_Close(pcap_file); } void s1ap_pcap::write_s1ap(uint8_t* pdu, uint32_t pdu_len_bytes) From aae266e848467b85f5b1c49da1b55a5b24b7f484 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Fri, 11 Jun 2021 14:41:19 +0100 Subject: [PATCH 16/24] Added configuration option for S1AP SCTP bind port --- lib/include/srsran/common/network_utils.h | 2 +- lib/include/srsran/interfaces/enb_s1ap_interfaces.h | 1 + lib/src/common/network_utils.cc | 4 ++-- lib/test/common/network_utils_test.cc | 4 ++-- srsenb/enb.conf.example | 2 ++ srsenb/src/main.cc | 1 + srsenb/src/stack/ngap/ngap.cc | 2 +- srsenb/src/stack/s1ap/s1ap.cc | 2 +- 8 files changed, 11 insertions(+), 7 deletions(-) diff --git a/lib/include/srsran/common/network_utils.h b/lib/include/srsran/common/network_utils.h index d897dc9fb..8f19dd5d2 100644 --- a/lib/include/srsran/common/network_utils.h +++ b/lib/include/srsran/common/network_utils.h @@ -86,7 +86,7 @@ protected: namespace net_utils { -bool sctp_init_client(unique_socket* socket, net_utils::socket_type socktype, const char* bind_addr_str); +bool sctp_init_client(unique_socket* socket, net_utils::socket_type socktype, const char* bind_addr_str, int bind_port); bool sctp_init_server(unique_socket* socket, net_utils::socket_type socktype, const char* bind_addr_str, int port); } // namespace net_utils diff --git a/lib/include/srsran/interfaces/enb_s1ap_interfaces.h b/lib/include/srsran/interfaces/enb_s1ap_interfaces.h index 6bb07f353..233857470 100644 --- a/lib/include/srsran/interfaces/enb_s1ap_interfaces.h +++ b/lib/include/srsran/interfaces/enb_s1ap_interfaces.h @@ -28,6 +28,7 @@ struct s1ap_args_t { std::string gtp_bind_addr; std::string gtp_advertise_addr; std::string s1c_bind_addr; + uint16_t s1c_bind_port; std::string enb_name; }; diff --git a/lib/src/common/network_utils.cc b/lib/src/common/network_utils.cc index 0ff7f26ad..bd21546c4 100644 --- a/lib/src/common/network_utils.cc +++ b/lib/src/common/network_utils.cc @@ -309,9 +309,9 @@ bool sctp_init_socket(unique_socket* socket, net_utils::socket_type socktype, co return true; } -bool sctp_init_client(unique_socket* socket, net_utils::socket_type socktype, const char* bind_addr_str) +bool sctp_init_client(unique_socket* socket, net_utils::socket_type socktype, const char* bind_addr_str, int bind_port) { - return sctp_init_socket(socket, socktype, bind_addr_str, 0); + return sctp_init_socket(socket, socktype, bind_addr_str, bind_port); } bool sctp_init_server(unique_socket* socket, net_utils::socket_type socktype, const char* bind_addr_str, int port) diff --git a/lib/test/common/network_utils_test.cc b/lib/test/common/network_utils_test.cc index 5701e1d89..3e36508fa 100644 --- a/lib/test/common/network_utils_test.cc +++ b/lib/test/common/network_utils_test.cc @@ -55,8 +55,8 @@ int test_socket_handler() TESTASSERT(sctp_init_server(&server_socket, socket_type::seqpacket, server_addr, server_port)); logger.info("Listening from fd=%d", server_socket.fd()); - TESTASSERT(sctp_init_client(&client_socket, socket_type::seqpacket, "127.0.0.1")); - TESTASSERT(sctp_init_client(&client_socket2, socket_type::seqpacket, "127.0.0.2")); + TESTASSERT(sctp_init_client(&client_socket, socket_type::seqpacket, "127.0.0.1", 0)); + TESTASSERT(sctp_init_client(&client_socket2, socket_type::seqpacket, "127.0.0.2", 0)); TESTASSERT(client_socket.connect_to(server_addr, server_port)); TESTASSERT(client_socket2.connect_to(server_addr, server_port)); diff --git a/srsenb/enb.conf.example b/srsenb/enb.conf.example index 36b3ee83e..4eacc23e1 100644 --- a/srsenb/enb.conf.example +++ b/srsenb/enb.conf.example @@ -12,6 +12,7 @@ # gtp_bind_addr: Local IP address to bind for GTP connection # gtp_advertise_addr: IP address of eNB to advertise for DL GTP-U Traffic # s1c_bind_addr: Local IP address to bind for S1AP connection +# s1c_bind_port: Source port for S1AP connection (0 means any) # n_prb: Number of Physical Resource Blocks (6,15,25,50,75,100) # tm: Transmission mode 1-4 (TM1 default) # nof_ports: Number of Tx ports (1 port default, set to 2 for TM2/3/4) @@ -24,6 +25,7 @@ mnc = 01 mme_addr = 127.0.1.100 gtp_bind_addr = 127.0.1.1 s1c_bind_addr = 127.0.1.1 +s1c_bind_port = 0 n_prb = 50 #tm = 4 #nof_ports = 2 diff --git a/srsenb/src/main.cc b/srsenb/src/main.cc index 1d9119457..3b264fe74 100644 --- a/srsenb/src/main.cc +++ b/srsenb/src/main.cc @@ -74,6 +74,7 @@ void parse_args(all_args_t* args, int argc, char* argv[]) ("enb.gtp_bind_addr", bpo::value(&args->stack.s1ap.gtp_bind_addr)->default_value("192.168.3.1"), "Local IP address to bind for GTP connection") ("enb.gtp_advertise_addr", bpo::value(&args->stack.s1ap.gtp_advertise_addr)->default_value(""), "IP address of eNB to advertise for DL GTP-U Traffic") ("enb.s1c_bind_addr", bpo::value(&args->stack.s1ap.s1c_bind_addr)->default_value("192.168.3.1"), "Local IP address to bind for S1AP connection") + ("enb.s1c_bind_port", bpo::value(&args->stack.s1ap.s1c_bind_port)->default_value(0), "Source port for S1AP connection (0 means any)") ("enb.n_prb", bpo::value(&args->enb.n_prb)->default_value(25), "Number of PRB") ("enb.nof_ports", bpo::value(&args->enb.nof_ports)->default_value(1), "Number of ports") ("enb.tm", bpo::value(&args->enb.transmission_mode)->default_value(1), "Transmission mode (1-8)") diff --git a/srsenb/src/stack/ngap/ngap.cc b/srsenb/src/stack/ngap/ngap.cc index 75fec27c6..8cbca6fee 100644 --- a/srsenb/src/stack/ngap/ngap.cc +++ b/srsenb/src/stack/ngap/ngap.cc @@ -505,7 +505,7 @@ bool ngap::connect_amf() logger.info("Connecting to AMF %s:%d", args.amf_addr.c_str(), int(AMF_PORT)); // Init SCTP socket and bind it - if (not sctp_init_client(&amf_socket, socket_type::seqpacket, args.ngc_bind_addr.c_str())) { + if (not sctp_init_client(&amf_socket, socket_type::seqpacket, args.ngc_bind_addr.c_str(), 0)) { return false; } logger.info("SCTP socket opened. fd=%d", amf_socket.fd()); diff --git a/srsenb/src/stack/s1ap/s1ap.cc b/srsenb/src/stack/s1ap/s1ap.cc index 82cd36707..9ad267ea4 100644 --- a/srsenb/src/stack/s1ap/s1ap.cc +++ b/srsenb/src/stack/s1ap/s1ap.cc @@ -476,7 +476,7 @@ bool s1ap::connect_mme() logger.info("Connecting to MME %s:%d", args.mme_addr.c_str(), int(MME_PORT)); // Init SCTP socket and bind it - if (not sctp_init_client(&mme_socket, socket_type::seqpacket, args.s1c_bind_addr.c_str())) { + if (not sctp_init_client(&mme_socket, socket_type::seqpacket, args.s1c_bind_addr.c_str(), args.s1c_bind_port)) { return false; } logger.info("SCTP socket opened. fd=%d", mme_socket.fd()); From cc3ac83c144487434a568db65272ab6e6c7d2810 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Tue, 22 Jun 2021 10:15:26 +0200 Subject: [PATCH 17/24] Skip nr_phy_test compilation without RF --- test/phy/CMakeLists.txt | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/test/phy/CMakeLists.txt b/test/phy/CMakeLists.txt index 943cf44d8..fd5f8e3f5 100644 --- a/test/phy/CMakeLists.txt +++ b/test/phy/CMakeLists.txt @@ -6,18 +6,20 @@ # the distribution. # -add_executable(nr_phy_test nr_phy_test.cc) -target_link_libraries(nr_phy_test - srsue_phy_nr - srsue_phy - srsran_common - srsran_phy - srsran_radio - srsenb_phy - ${CMAKE_THREAD_LIBS_INIT} - ${Boost_LIBRARIES} - ${CMAKE_THREAD_LIBS_INIT} - ${Boost_LIBRARIES} - ${ATOMIC_LIBS}) +if (RF_FOUND AND ENABLE_SRSUE AND ENABLE_SRSENB) + add_executable(nr_phy_test nr_phy_test.cc) + target_link_libraries(nr_phy_test + srsue_phy_nr + srsue_phy + srsran_common + srsran_phy + srsran_radio + srsenb_phy + ${CMAKE_THREAD_LIBS_INIT} + ${Boost_LIBRARIES} + ${CMAKE_THREAD_LIBS_INIT} + ${Boost_LIBRARIES} + ${ATOMIC_LIBS}) -add_nr_test(nr_phy_test nr_phy_test) \ No newline at end of file + add_nr_test(nr_phy_test nr_phy_test) +endif () \ No newline at end of file From e1fb58d76ed90d766bf9e143e584efe42eba1b06 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Mon, 21 Jun 2021 13:02:12 +0200 Subject: [PATCH 18/24] rlc_um: reduce log level for message handling lost PDUs when a lost PDU is detected a warning will be logged. In theory this could be info as well but a warning may help to detect issues in tests. The same event causes multiple other warnings to be logged, which is very spammy. The patch reduces the log level for those messages to info. --- lib/src/upper/rlc_um_lte.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/src/upper/rlc_um_lte.cc b/lib/src/upper/rlc_um_lte.cc index cbfe56e4c..57d309daa 100644 --- a/lib/src/upper/rlc_um_lte.cc +++ b/lib/src/upper/rlc_um_lte.cc @@ -478,8 +478,7 @@ void rlc_um_lte::rlc_um_lte_rx::reassemble_rx_sdus() logger.debug("Reassemble loop for vr_ur=%d", vr_ur); if (not pdu_belongs_to_rx_sdu()) { - logger.warning( - "PDU SN=%d lost, stop reassambling SDU (vr_ur_in_rx_sdu=%d)", vr_ur_in_rx_sdu + 1, vr_ur_in_rx_sdu); + logger.info("PDU SN=%d lost, stop reassambling SDU (vr_ur_in_rx_sdu=%d)", vr_ur_in_rx_sdu + 1, vr_ur_in_rx_sdu); pdu_lost = false; // Reset flag to not prevent reassembling of further segments rx_sdu->clear(); } @@ -495,7 +494,7 @@ void rlc_um_lte::rlc_um_lte_rx::reassemble_rx_sdus() rlc_fi_field_text[rx_window[vr_ur].header.fi]); // Check if the first part of the PDU is a middle or end segment if (rx_sdu->N_bytes == 0 && i == 0 && !rlc_um_start_aligned(rx_window[vr_ur].header.fi)) { - logger.warning( + logger.info( rx_window[vr_ur].buf->msg, len, "Dropping first %d B of SN=%d due to lost start segment", len, vr_ur); if (rx_window[vr_ur].buf->N_bytes < len) { From 4d139067606789ccf3369aec3b489facab57dca7 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Tue, 15 Jun 2021 16:56:38 +0100 Subject: [PATCH 19/24] Increase logging level of MAC mismatches to warning in PDCP --- lib/src/upper/pdcp_entity_base.cc | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/lib/src/upper/pdcp_entity_base.cc b/lib/src/upper/pdcp_entity_base.cc index 22e3966ad..729d1c3d9 100644 --- a/lib/src/upper/pdcp_entity_base.cc +++ b/lib/src/upper/pdcp_entity_base.cc @@ -105,13 +105,6 @@ bool pdcp_entity_base::integrity_verify(uint8_t* msg, uint32_t msg_len, uint32_t break; } - logger.debug("Integrity check input: COUNT %" PRIu32 ", Bearer ID %d, Direction %s", - count, - cfg.bearer_id, - cfg.rx_direction == SECURITY_DIRECTION_DOWNLINK ? "Downlink" : "Uplink"); - logger.debug(k_int, 32, "Integrity check key:"); - logger.debug(msg, msg_len, "Integrity check input msg:"); - if (sec_cfg.integ_algo != INTEGRITY_ALGORITHM_ID_EIA0) { for (uint8_t i = 0; i < 4; i++) { if (mac[i] != mac_exp[i]) { @@ -121,9 +114,13 @@ bool pdcp_entity_base::integrity_verify(uint8_t* msg, uint32_t msg_len, uint32_t break; } } - if (is_valid) { - logger.info(mac_exp, 4, "MAC match"); - } + srslog::log_channel& channel = is_valid ? logger.debug : logger.warning; + channel("Integrity check input: COUNT %" PRIu32 ", Bearer ID %d, Direction %s", + count, + cfg.bearer_id, + cfg.rx_direction == SECURITY_DIRECTION_DOWNLINK ? "Downlink" : "Uplink"); + channel(k_int, 32, "Integrity check key:"); + channel(msg, msg_len, "Integrity check input msg (Bytes=%" PRIu32 "):", msg_len); } return is_valid; From eb7980f2b3c3b5b0d29f7513bbcb94bb2186853b Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Wed, 16 Jun 2021 18:10:34 +0200 Subject: [PATCH 20/24] Initial UE synchronization for NR --- lib/include/srsran/phy/common/phy_common_nr.h | 8 + lib/include/srsran/phy/sync/ssb.h | 68 +++- lib/include/srsran/phy/ue/ue_sync_nr.h | 144 ++++++++ lib/src/phy/common/phy_common_nr.c | 30 ++ lib/src/phy/sync/ssb.c | 226 +++++++++++++ lib/src/phy/ue/test/CMakeLists.txt | 4 + lib/src/phy/ue/test/ue_sync_nr_test.c | 304 +++++++++++++++++ lib/src/phy/ue/ue_sync_nr.c | 314 ++++++++++++++++++ 8 files changed, 1092 insertions(+), 6 deletions(-) create mode 100644 lib/include/srsran/phy/ue/ue_sync_nr.h create mode 100644 lib/src/phy/ue/test/ue_sync_nr_test.c create mode 100644 lib/src/phy/ue/ue_sync_nr.c diff --git a/lib/include/srsran/phy/common/phy_common_nr.h b/lib/include/srsran/phy/common/phy_common_nr.h index 1fb15d410..4f7c1776d 100644 --- a/lib/include/srsran/phy/common/phy_common_nr.h +++ b/lib/include/srsran/phy/common/phy_common_nr.h @@ -601,6 +601,14 @@ SRSRAN_API uint32_t srsran_csi_meas_info(const srsran_csi_trs_measurements_t* me */ SRSRAN_API srsran_subcarrier_spacing_t srsran_subcarrier_spacing_from_str(const char* str); +/** + * @brief Combine Channel State Information from Tracking Reference Signals (CSI-TRS) + * @param[in] a CSI-RS measurement + * @param[in] b CSI-RS measurement + * @param[out] dst Destination of the combined + */ +SRSRAN_API void srsran_combine_csi_trs_measurements(const srsran_csi_trs_measurements_t *a, const srsran_csi_trs_measurements_t *b, srsran_csi_trs_measurements_t *dst); + #ifdef __cplusplus } #endif diff --git a/lib/include/srsran/phy/sync/ssb.h b/lib/include/srsran/phy/sync/ssb.h index 26f2f9c1c..c3aa8d4ff 100644 --- a/lib/include/srsran/phy/sync/ssb.h +++ b/lib/include/srsran/phy/sync/ssb.h @@ -64,10 +64,10 @@ typedef struct SRSRAN_API { srsran_ssb_patern_t pattern; ///< SSB pattern as defined in TS 38.313 section 4.1 Cell search srsran_duplex_mode_t duplex_mode; ///< Set to true if the spectrum is paired (FDD) uint32_t periodicity_ms; ///< SSB periodicity in ms - float beta_pss; ////< PSS power allocation - float beta_sss; ////< SSS power allocation - float beta_pbch; ////< PBCH power allocation - float beta_pbch_dmrs; ////< PBCH DMRS power allocation + float beta_pss; ///< PSS power allocation + float beta_sss; ///< SSS power allocation + float beta_pbch; ///< PBCH power allocation + float beta_pbch_dmrs; ///< PBCH DMRS power allocation } srsran_ssb_cfg_t; /** @@ -79,11 +79,15 @@ typedef struct SRSRAN_API { /// Sampling rate dependent parameters float scs_hz; ///< Subcarrier spacing in Hz + uint32_t max_sf_sz; ///< Maximum subframe size at the specified sampling rate uint32_t max_symbol_sz; ///< Maximum symbol size given the minimum supported SCS and sampling rate uint32_t max_corr_sz; ///< Maximum correlation size + uint32_t max_ssb_sz; ///< Maximum SSB size in samples at the configured sampling rate + uint32_t sf_sz; ///< Current subframe size at the specified sampling rate uint32_t symbol_sz; ///< Current SSB symbol size (for the given base-band sampling rate) uint32_t corr_sz; ///< Correlation size uint32_t corr_window; ///< Correlation window length + uint32_t ssb_sz; ///< SSB size in samples at the configured sampling rate int32_t f_offset; ///< Current SSB integer frequency offset (multiple of SCS) uint32_t cp_sz; ///< CP length for the given symbol size @@ -102,6 +106,7 @@ typedef struct SRSRAN_API { cf_t* tmp_freq; ///< Temporal frequency domain buffer cf_t* tmp_time; ///< Temporal time domain buffer cf_t* tmp_corr; ///< Temporal correlation frequency domain buffer + cf_t* sf_buffer; ///< subframe buffer cf_t* pss_seq[SRSRAN_NOF_NID_2_NR]; ///< Possible frequency domain PSS for find } srsran_ssb_t; @@ -184,7 +189,7 @@ srsran_ssb_add(srsran_ssb_t* q, uint32_t N_id, const srsran_pbch_msg_nr_t* msg, /** * @brief Perform cell search and measurement * @note This function assumes the SSB transmission is aligned with the input base-band signal - * @param q NR PSS object + * @param q SSB object * @param in Base-band signal buffer * @param N_id Physical Cell Identifier of the most suitable cell identifier * @param meas SSB-based CSI measurement of the most suitable cell identifier @@ -198,7 +203,7 @@ SRSRAN_API int srsran_ssb_csi_search(srsran_ssb_t* q, /** * @brief Perform Channel State Information (CSI) measurement from the SSB - * @param q NR PSS object + * @param q SSB object * @param N_id Physical Cell Identifier * @param ssb_idx SSB candidate index * @param in Base-band signal @@ -211,4 +216,55 @@ SRSRAN_API int srsran_ssb_csi_measure(srsran_ssb_t* q, const cf_t* in, srsran_csi_trs_measurements_t* meas); +/** + * @brief Find SSB signal in a given time domain subframe buffer + * @param q SSB object + * @param sf_buffer subframe buffer with 1ms worth of samples + * @param N_id Physical cell identifier to find + * @param meas Measurements performed on the found peak + * @param pbch_msg PBCH decoded message + * @return SRSRAN_SUCCESS if the parameters are valid, SRSRAN_ERROR code otherwise + */ +SRSRAN_API int srsran_ssb_find(srsran_ssb_t* q, + const cf_t* sf_buffer, + uint32_t N_id, + srsran_csi_trs_measurements_t* meas, + srsran_pbch_msg_nr_t* pbch_msg); + +/** + * @brief Track SSB by performing measurements and decoding PBCH + * @param q SSB object + * @param sf_buffer subframe buffer with 1ms worth of samples + * @param N_id Physical cell identifier to find + * @param ssb_idx SSB candidate index + * @param n_hf Number of half frame + * @param meas Measurements perform + * @param pbch_msg PBCH decoded message + * @return SRSRAN_SUCCESS if the parameters are valid, SRSRAN_ERROR code otherwise + */ +SRSRAN_API int srsran_ssb_track(srsran_ssb_t* q, + const cf_t* sf_buffer, + uint32_t N_id, + uint32_t ssb_idx, + uint32_t n_hf, + srsran_csi_trs_measurements_t* meas, + srsran_pbch_msg_nr_t* pbch_msg); + +/** + * @brief Calculates the subframe index within the radio frame of a given SSB candidate for the SSB object + * @param q SSB object + * @param ssb_idx SSB candidate index + * @param half_frame Indicates whether it is half frame + * @return The subframe index + */ +SRSRAN_API uint32_t srsran_ssb_candidate_sf_idx(const srsran_ssb_t* q, uint32_t ssb_idx, bool half_frame); + +/** + * @brief Calculates the SSB offset within the subframe of a given SSB candidate for the SSB object + * @param q SSB object + * @param ssb_idx SSB candidate index + * @return The sample offset within the subframe + */ +SRSRAN_API uint32_t srsran_ssb_candidate_sf_offset(const srsran_ssb_t* q, uint32_t ssb_idx); + #endif // SRSRAN_SSB_H diff --git a/lib/include/srsran/phy/ue/ue_sync_nr.h b/lib/include/srsran/phy/ue/ue_sync_nr.h new file mode 100644 index 000000000..da4fcb381 --- /dev/null +++ b/lib/include/srsran/phy/ue/ue_sync_nr.h @@ -0,0 +1,144 @@ +/** + * + * \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_UE_SYNC_NR_H +#define SRSRAN_UE_SYNC_NR_H + +#include "srsran/phy/common/timestamp.h" +#include "srsran/phy/sync/ssb.h" + +#define SRSRAN_RECV_CALLBACK_TEMPLATE(NAME) int (*NAME)(void*, cf_t**, uint32_t, srsran_timestamp_t*) + +/** + * @brief Describes NR UE synchronization object internal states + */ +typedef enum SRSRAN_API { + SRSRAN_UE_SYNC_NR_STATE_IDLE = 0, ///< Initial state, the object has no configuration + SRSRAN_UE_SYNC_NR_STATE_FIND, ///< State just after configuring, baseband is not aligned + SRSRAN_UE_SYNC_NR_STATE_TRACK ///< Baseband is aligned with subframes +} srsran_ue_sync_nr_state_t; + +/** + * @brief Describes a UE sync NR object arguments + */ +typedef struct SRSRAN_API { + // Memory allocation constraints + double max_srate_hz; ///< Maximum sampling rate in Hz, set to zero to use default + srsran_subcarrier_spacing_t min_scs; ///< Minimum subcarrier spacing + uint32_t nof_rx_channels; ///< Number of receive channels, set to 0 for 1 + + // Enable/Disable features + bool disable_cfo; ///< Set to true for disabling the CFO compensation close loop + + // Signal detection thresholds and averaging coefficients + float pbch_dmrs_thr; ///< NR-PBCH DMRS threshold for blind decoding, set to 0 for default + float cfo_alpha; ///< Exponential Moving Average (EMA) alpha coefficient for CFO + + // Receive callback + void* recv_obj; ///< Receive object + SRSRAN_RECV_CALLBACK_TEMPLATE(recv_callback); ///< Receive callback +} srsran_ue_sync_nr_args_t; + +/** + * @brief Describes a UE sync NR object configuration + */ +typedef struct SRSRAN_API { + srsran_ssb_cfg_t ssb; ///< SSB configuration + uint32_t N_id; ///< Physicall cell identifier +} srsran_ue_sync_nr_cfg_t; + +/** + * @brief Describes a UE sync NR object + */ +typedef struct SRSRAN_API { + // State + srsran_ue_sync_nr_state_t state; ///< Internal state + int32_t next_rf_sample_offset; ///< Next RF sample offset + uint32_t ssb_idx; ///< Tracking SSB candidate index + uint32_t sf_idx; ///< Current subframe index (0-9) + uint32_t sfn; ///< Current system frame number (0-1023) + srsran_csi_trs_measurements_t feedback; ///< Feedback measurements + + // Components + srsran_ssb_t ssb; ///< SSB internal object + cf_t** tmp_buffer; ///< Temporal buffer pointers + + // Initialised arguments + uint32_t nof_rx_channels; ///< Number of receive channels + bool disable_cfo; ///< Set to true for disabling the CFO compensation close loop + float cfo_alpha; ///< Exponential Moving Average (EMA) alpha coefficient for CFO + void* recv_obj; ///< Receive object + SRSRAN_RECV_CALLBACK_TEMPLATE(recv_callback); ///< Receive callback + + // Current configuration + uint32_t N_id; ///< Current physical cell identifier + double srate_hz; ///< Current sampling rate in Hz + uint32_t sf_sz; ///< Current subframe size + + // Metrics + float cfo_hz; ///< Current CFO in Hz + float avg_delay_us; ///< Current average delay +} srsran_ue_sync_nr_t; + +/** + * @brief Describes a UE sync NR zerocopy outcome + */ +typedef struct SRSRAN_API { + bool in_sync; ///< Indicates whether the received baseband is synchronized + uint32_t sf_idx; ///< Subframe index + uint32_t sfn; ///< System Frame Number + srsran_timestamp_t timestamp; ///< Last received timestamp + float cfo_hz; ///< Current CFO in Hz + float delay_us; ///< Current average delay in microseconds +} srsran_ue_sync_nr_outcome_t; + +/** + * @brief Initialises a UE sync NR object + * @param q NR UE synchronization object + * @param[in] args NR UE synchronization initialization arguments + * @return SRSRAN_SUCCESS if no error occurs, SRSRAN_ERROR code otherwise + */ +SRSRAN_API int srsran_ue_sync_nr_init(srsran_ue_sync_nr_t* q, const srsran_ue_sync_nr_args_t* args); + +/** + * @brief Deallocate an NR UE synchronization object + * @param q NR UE synchronization object + */ +SRSRAN_API void srsran_ue_sync_nr_free(srsran_ue_sync_nr_t* q); + +/** + * @brief Configures a UE sync NR object + * @param q NR UE synchronization object + * @param[in] cfg NR UE synchronization configuration + * @return SRSRAN_SUCCESS if no error occurs, SRSRAN_ERROR code otherwise + */ +SRSRAN_API int srsran_ue_sync_nr_set_cfg(srsran_ue_sync_nr_t* q, const srsran_ue_sync_nr_cfg_t* cfg); + +/** + * @brief Runs the NR UE synchronization object, tries to find and track the configured SSB leaving in buffer the + * received baseband subframe + * @param q NR UE synchronization object + * @param buffer 2D complex buffer + * @param outcome zerocopy outcome + * @return SRSRAN_SUCCESS if no error occurs, SRSRAN_ERROR code otherwise + */ +SRSRAN_API int srsran_ue_sync_nr_zerocopy(srsran_ue_sync_nr_t* q, cf_t** buffer, srsran_ue_sync_nr_outcome_t* outcome); + +/** + * @brief Feedback Channel State Information from Tracking Reference Signals into a UE synchronization object + * @param q NR UE synchronization object + * @param measurements CSI-TRS feedback measurement + * @return SRSRAN_SUCCESS if no error occurs, SRSRAN_ERROR code otherwise + */ +SRSRAN_API int srsran_ue_sync_nr_feedback(srsran_ue_sync_nr_t* q, const srsran_csi_trs_measurements_t* measurements); + +#endif // SRSRAN_UE_SYNC_NR_H diff --git a/lib/src/phy/common/phy_common_nr.c b/lib/src/phy/common/phy_common_nr.c index 2f206ef62..21f0151fb 100644 --- a/lib/src/phy/common/phy_common_nr.c +++ b/lib/src/phy/common/phy_common_nr.c @@ -351,3 +351,33 @@ srsran_subcarrier_spacing_t srsran_subcarrier_spacing_from_str(const char* str) return srsran_subcarrier_spacing_invalid; } + +void srsran_combine_csi_trs_measurements(const srsran_csi_trs_measurements_t* a, + const srsran_csi_trs_measurements_t* b, + srsran_csi_trs_measurements_t* dst) +{ + // Verify inputs + if (a == NULL || b == NULL || dst == NULL) { + return; + } + + // Protect from zero division + uint32_t nof_re_sum = a->nof_re + b->nof_re; + if (nof_re_sum == 0) { + SRSRAN_MEM_ZERO(dst, srsran_csi_trs_measurements_t, 1); + return; + } + + // Perform proportional average + dst->rsrp = SRSRAN_VEC_PMA(a->rsrp, a->nof_re, b->rsrp, b->nof_re); + dst->rsrp_dB = SRSRAN_VEC_PMA(a->rsrp_dB, a->nof_re, b->rsrp_dB, b->nof_re); + dst->epre = SRSRAN_VEC_PMA(a->epre, a->nof_re, b->epre, b->nof_re); + dst->epre_dB = SRSRAN_VEC_PMA(a->epre_dB, a->nof_re, b->epre_dB, b->nof_re); + dst->n0 = SRSRAN_VEC_PMA(a->n0, a->nof_re, b->n0, b->nof_re); + dst->n0_dB = SRSRAN_VEC_PMA(a->n0_dB, a->nof_re, b->n0_dB, b->nof_re); + dst->snr_dB = SRSRAN_VEC_PMA(a->snr_dB, a->nof_re, b->snr_dB, b->nof_re); + dst->cfo_hz = SRSRAN_VEC_PMA(a->cfo_hz, a->nof_re, b->cfo_hz, b->nof_re); + dst->cfo_hz_max = SRSRAN_MAX(a->cfo_hz_max, b->cfo_hz_max); + dst->delay_us = SRSRAN_VEC_PMA(a->delay_us, a->nof_re, b->delay_us, b->nof_re); + dst->nof_re = nof_re_sum; +} diff --git a/lib/src/phy/sync/ssb.c b/lib/src/phy/sync/ssb.c index 28fa42666..e79826d13 100644 --- a/lib/src/phy/sync/ssb.c +++ b/lib/src/phy/sync/ssb.c @@ -56,6 +56,13 @@ static int ssb_init_corr(srsran_ssb_t* q) } } + q->sf_buffer = srsran_vec_cf_malloc(q->max_ssb_sz + q->max_sf_sz); + if (q->sf_buffer == NULL) { + ERROR("Malloc"); + return SRSRAN_ERROR; + } + srsran_vec_cf_zero(q->sf_buffer, q->max_ssb_sz + q->max_sf_sz); + return SRSRAN_SUCCESS; } @@ -93,8 +100,10 @@ int srsran_ssb_init(srsran_ssb_t* q, const srsran_ssb_args_t* args) q->args.pbch_dmrs_thr = (!isnormal(q->args.pbch_dmrs_thr)) ? SSB_PBCH_DMRS_DEFAULT_CORR_THR : q->args.pbch_dmrs_thr; q->scs_hz = (float)SRSRAN_SUBC_SPACING_NR(q->args.min_scs); + q->max_sf_sz = (uint32_t)round(1e-3 * q->args.max_srate_hz); q->max_symbol_sz = (uint32_t)round(q->args.max_srate_hz / q->scs_hz); q->max_corr_sz = SSB_CORR_SZ(q->max_symbol_sz); + q->max_ssb_sz = SRSRAN_SSB_DURATION_NSYMB * (q->max_symbol_sz + (144 * q->max_symbol_sz) / 2048); // Allocate temporal data q->tmp_time = srsran_vec_cf_malloc(q->max_corr_sz); @@ -143,6 +152,10 @@ void srsran_ssb_free(srsran_ssb_t* q) } } + if (q->sf_buffer != NULL) { + free(q->sf_buffer); + } + srsran_dft_plan_free(&q->ifft); srsran_dft_plan_free(&q->fft); srsran_dft_plan_free(&q->fft_corr); @@ -437,6 +450,7 @@ int srsran_ssb_set_cfg(srsran_ssb_t* q, const srsran_ssb_cfg_t* cfg) // Verify symbol size if (q->max_symbol_sz < symbol_sz) { ERROR("New symbol size (%d) exceeds maximum symbol size (%d)", symbol_sz, q->max_symbol_sz); + return SRSRAN_ERROR; } // Replan iFFT @@ -468,6 +482,8 @@ int srsran_ssb_set_cfg(srsran_ssb_t* q, const srsran_ssb_cfg_t* cfg) // Finally, copy configuration q->cfg = *cfg; q->symbol_sz = symbol_sz; + q->sf_sz = (uint32_t)round(1e-3 * cfg->srate_hz); + q->ssb_sz = SRSRAN_SSB_DURATION_NSYMB * (q->symbol_sz + q->cp_sz); // Initialise correlation if (ssb_setup_corr(q) < SRSRAN_SUCCESS) { @@ -1093,3 +1109,213 @@ int srsran_ssb_search(srsran_ssb_t* q, const cf_t* in, uint32_t nof_samples, srs return SRSRAN_SUCCESS; } + +static int ssb_pss_find(srsran_ssb_t* q, const cf_t* in, uint32_t nof_samples, uint32_t N_id_2, uint32_t* found_delay) +{ + // verify it is initialised + if (q->corr_sz == 0) { + return SRSRAN_ERROR; + } + + // Correlation best sequence + float best_corr = 0; + uint32_t best_delay = 0; + + // Delay in correlation window + uint32_t t_offset = 0; + while ((t_offset + q->symbol_sz) < nof_samples) { + // Number of samples taken in this iteration + uint32_t n = q->corr_sz; + + // Detect if the correlation input exceeds the input length, take the maximum amount of samples + if (t_offset + q->corr_sz > nof_samples) { + n = nof_samples - t_offset; + } + + // Copy the amount of samples + srsran_vec_cf_copy(q->tmp_time, &in[t_offset], n); + + // Append zeros if there is space left + if (n < q->corr_sz) { + srsran_vec_cf_zero(&q->tmp_time[n], q->corr_sz - n); + } + + // Convert to frequency domain + srsran_dft_run_guru_c(&q->fft_corr); + + // Actual correlation in frequency domain + srsran_vec_prod_conj_ccc(q->tmp_freq, q->pss_seq[N_id_2], q->tmp_corr, q->corr_sz); + + // Convert to time domain + srsran_dft_run_guru_c(&q->ifft_corr); + + // Find maximum + uint32_t peak_idx = srsran_vec_max_abs_ci(q->tmp_time, q->corr_window); + + // Average power, skip window if value is invalid (0.0, nan or inf) + float avg_pwr_corr = srsran_vec_avg_power_cf(&q->tmp_time[peak_idx], q->symbol_sz); + if (!isnormal(avg_pwr_corr)) { + continue; + } + + // Normalise correlation + float corr = SRSRAN_CSQABS(q->tmp_time[peak_idx]) / avg_pwr_corr / sqrtf(SRSRAN_PSS_NR_LEN); + + // Update if the correlation is better than the current best + if (best_corr < corr) { + best_corr = corr; + best_delay = peak_idx + t_offset; + } + + // Advance time + t_offset += q->corr_window; + } + + // Save findings + *found_delay = best_delay; + + return SRSRAN_SUCCESS; +} + +int srsran_ssb_find(srsran_ssb_t* q, + const cf_t* sf_buffer, + uint32_t N_id, + srsran_csi_trs_measurements_t* meas, + srsran_pbch_msg_nr_t* pbch_msg) +{ + // Verify inputs + if (q == NULL || sf_buffer == NULL || meas == NULL || !isnormal(q->scs_hz)) { + return SRSRAN_ERROR_INVALID_INPUTS; + } + + if (!q->args.enable_search) { + ERROR("SSB is not configured for search"); + return SRSRAN_ERROR; + } + + // Copy tail from previous execution into the start of this + srsran_vec_cf_copy(q->sf_buffer, &q->sf_buffer[q->sf_sz], q->ssb_sz); + + // Append new samples + srsran_vec_cf_copy(&q->sf_buffer[q->ssb_sz], sf_buffer, q->sf_sz); + + // Search for PSS in time domain + uint32_t t_offset = 0; + if (ssb_pss_find(q, q->sf_buffer, q->sf_sz + q->ssb_sz, SRSRAN_NID_2_NR(N_id), &t_offset) < SRSRAN_SUCCESS) { + ERROR("Error searching for N_id_2"); + return SRSRAN_ERROR; + } + + // Remove CP offset prior demodulation + if (t_offset >= q->cp_sz) { + t_offset -= q->cp_sz; + } else { + t_offset = 0; + } + + // Demodulate + cf_t ssb_grid[SRSRAN_SSB_NOF_RE] = {}; + if (ssb_demodulate(q, q->sf_buffer, t_offset, ssb_grid) < SRSRAN_SUCCESS) { + ERROR("Error demodulating"); + return SRSRAN_ERROR; + } + + // Measure selected N_id + if (ssb_measure(q, ssb_grid, N_id, meas)) { + ERROR("Error measuring"); + return SRSRAN_ERROR; + } + + // Select the most suitable SSB candidate + uint32_t n_hf = 0; + uint32_t ssb_idx = 0; // SSB candidate index + if (ssb_select_pbch(q, N_id, ssb_grid, &n_hf, &ssb_idx) < SRSRAN_SUCCESS) { + ERROR("Error selecting PBCH"); + return SRSRAN_ERROR; + } + + // Calculate the SSB offset in the subframe + uint32_t ssb_offset = srsran_ssb_candidate_sf_offset(q, ssb_idx); + + // Compute PBCH channel estimates + if (ssb_decode_pbch(q, N_id, n_hf, ssb_idx, ssb_grid, pbch_msg) < SRSRAN_SUCCESS) { + ERROR("Error decoding PBCH"); + return SRSRAN_ERROR; + } + + // SSB delay in SF + float ssb_delay_us = (float)(1e6 * (((double)t_offset - (double)q->ssb_sz - (double)ssb_offset) / q->cfg.srate_hz)); + + // Add delay to measure + meas->delay_us += ssb_delay_us; + + return SRSRAN_SUCCESS; +} + +int srsran_ssb_track(srsran_ssb_t* q, + const cf_t* sf_buffer, + uint32_t N_id, + uint32_t ssb_idx, + uint32_t n_hf, + srsran_csi_trs_measurements_t* meas, + srsran_pbch_msg_nr_t* pbch_msg) +{ + // Verify inputs + if (q == NULL || sf_buffer == NULL || meas == NULL || !isnormal(q->scs_hz)) { + return SRSRAN_ERROR_INVALID_INPUTS; + } + + if (!q->args.enable_search) { + ERROR("SSB is not configured for search"); + return SRSRAN_ERROR; + } + + // Calculate SSB offset + uint32_t t_offset = srsran_ssb_candidate_sf_offset(q, ssb_idx); + + // Demodulate + cf_t ssb_grid[SRSRAN_SSB_NOF_RE] = {}; + if (ssb_demodulate(q, sf_buffer, t_offset, ssb_grid) < SRSRAN_SUCCESS) { + ERROR("Error demodulating"); + return SRSRAN_ERROR; + } + + // Measure selected N_id + if (ssb_measure(q, ssb_grid, N_id, meas)) { + ERROR("Error measuring"); + return SRSRAN_ERROR; + } + + // Compute PBCH channel estimates + if (ssb_decode_pbch(q, N_id, n_hf, ssb_idx, ssb_grid, pbch_msg) < SRSRAN_SUCCESS) { + ERROR("Error decoding PBCH"); + return SRSRAN_ERROR; + } + + return SRSRAN_SUCCESS; +} + +uint32_t srsran_ssb_candidate_sf_idx(const srsran_ssb_t* q, uint32_t ssb_idx, bool half_frame) +{ + if (q == NULL) { + return 0; + } + + uint32_t nof_symbols_subframe = SRSRAN_NSYMB_PER_SLOT_NR * SRSRAN_NSLOTS_PER_SF_NR(q->cfg.scs); + + return q->l_first[ssb_idx] / nof_symbols_subframe + (half_frame ? (SRSRAN_NOF_SF_X_FRAME / 2) : 0); +} + +uint32_t srsran_ssb_candidate_sf_offset(const srsran_ssb_t* q, uint32_t ssb_idx) +{ + if (q == NULL) { + return 0; + } + + uint32_t nof_symbols_subframe = SRSRAN_NSYMB_PER_SLOT_NR * SRSRAN_NSLOTS_PER_SF_NR(q->cfg.scs); + uint32_t l = q->l_first[ssb_idx] % nof_symbols_subframe; + + uint32_t cp_sz_0 = (16U * q->symbol_sz) / 2048U; + + return cp_sz_0 + l * (q->symbol_sz + q->cp_sz); +} diff --git a/lib/src/phy/ue/test/CMakeLists.txt b/lib/src/phy/ue/test/CMakeLists.txt index 9bf31d112..7c512f9ab 100644 --- a/lib/src/phy/ue/test/CMakeLists.txt +++ b/lib/src/phy/ue/test/CMakeLists.txt @@ -26,6 +26,10 @@ add_executable(ue_dl_nbiot_test ue_dl_nbiot_test.c) target_link_libraries(ue_dl_nbiot_test srsran_phy pthread) add_test(ue_dl_nbiot_test ue_dl_nbiot_test) +add_executable(ue_sync_nr_test ue_sync_nr_test.c) +target_link_libraries(ue_sync_nr_test srsran_phy pthread) +add_test(ue_sync_nr_test ue_sync_nr_test) + if(RF_FOUND) add_executable(ue_mib_sync_test_nbiot_usrp ue_mib_sync_test_nbiot_usrp.c) target_link_libraries(ue_mib_sync_test_nbiot_usrp srsran_phy srsran_rf pthread) diff --git a/lib/src/phy/ue/test/ue_sync_nr_test.c b/lib/src/phy/ue/test/ue_sync_nr_test.c new file mode 100644 index 000000000..eff7480ce --- /dev/null +++ b/lib/src/phy/ue/test/ue_sync_nr_test.c @@ -0,0 +1,304 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2021 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include "srsran/common/test_common.h" +#include "srsran/phy/channel/ch_awgn.h" +#include "srsran/phy/channel/delay.h" +#include "srsran/phy/ue/ue_sync_nr.h" +#include "srsran/phy/utils/debug.h" +#include "srsran/phy/utils/ringbuffer.h" +#include "srsran/phy/utils/vector.h" +#include +#include + +// NR parameters +static uint32_t pci = 1; // Physical Cell Identifier +static uint32_t carrier_nof_prb = 52; // Carrier bandwidth +static srsran_subcarrier_spacing_t carrier_scs = srsran_subcarrier_spacing_15kHz; +static srsran_subcarrier_spacing_t ssb_scs = srsran_subcarrier_spacing_30kHz; + +// Test and channel parameters +static uint32_t nof_sf = 1000; // Number of subframes to test +static float cfo_hz = 100.0f; // CFO in Hz +static float n0_dB = -10.0f; // Noise floor in dB relative to full-scale +static float delay_min_us = 10.0f; // Minimum dynamic delay in microseconds +static float delay_max_us = 1000.0f; // Maximum dynamic delay in microseconds +static float delay_period_s = 60.0f; // Delay period in seconds + +// Test context +static double srate_hz = 0.0f; // Base-band sampling rate +static uint32_t sf_len = 0; // Subframe length +static cf_t* buffer = NULL; // Base-band buffer +static cf_t* buffer2 = NULL; // Base-band buffer + +static void usage(char* prog) +{ + printf("Usage: %s [v]\n", prog); + printf("\t-v [set srsran_verbose to debug, default none]\n"); +} + +static void parse_args(int argc, char** argv) +{ + int opt; + while ((opt = getopt(argc, argv, "v")) != -1) { + switch (opt) { + case 'v': + srsran_verbose++; + break; + default: + usage(argv[0]); + exit(-1); + } + } +} + +typedef struct { + uint32_t sf_idx; + uint32_t sfn; + srsran_ringbuffer_t ringbuffer; + srsran_ssb_t ssb; + srsran_timestamp_t timestamp; + srsran_channel_awgn_t awgn; + srsran_channel_delay_t delay; +} test_context_t; + +static void run_channel(test_context_t* ctx) +{ + // Delay + srsran_channel_delay_execute(&ctx->delay, buffer, buffer2, sf_len, &ctx->timestamp); + + // CFO + srsran_vec_apply_cfo(buffer2, -cfo_hz / srate_hz, buffer, sf_len); + + // AWGN + srsran_channel_awgn_run_c(&ctx->awgn, buffer, buffer, sf_len); +} + +static int test_context_init(test_context_t* ctx) +{ + SRSRAN_MEM_ZERO(ctx, test_context_t, 1); + + if (ctx == NULL) { + return SRSRAN_ERROR_INVALID_INPUTS; + } + + ctx->sfn = 1; + + if (srsran_ringbuffer_init(&ctx->ringbuffer, (int)(10 * sf_len * sizeof(cf_t))) < SRSRAN_SUCCESS) { + return SRSRAN_ERROR; + } + + srsran_ssb_args_t ssb_args = {}; + ssb_args.max_srate_hz = srate_hz; + ssb_args.min_scs = carrier_scs; + ssb_args.enable_encode = true; + if (srsran_ssb_init(&ctx->ssb, &ssb_args) < SRSRAN_SUCCESS) { + return SRSRAN_ERROR; + } + + srsran_ssb_cfg_t ssb_cfg = {}; + ssb_cfg.srate_hz = srate_hz; + ssb_cfg.srate_hz = srate_hz; + ssb_cfg.center_freq_hz = 3.5e9; + ssb_cfg.ssb_freq_hz = 3.5e9 - 960e3; + ssb_cfg.scs = ssb_scs; + ssb_cfg.pattern = SRSRAN_SSB_PATTERN_C; + if (srsran_ssb_set_cfg(&ctx->ssb, &ssb_cfg) < SRSRAN_SUCCESS) { + return SRSRAN_ERROR; + } + + if (srsran_channel_delay_init(&ctx->delay, delay_min_us, delay_max_us, delay_period_s, 0, (uint32_t)srate_hz) < + SRSRAN_SUCCESS) { + ERROR("Init"); + return SRSRAN_ERROR; + } + + if (srsran_channel_awgn_init(&ctx->awgn, 0x0) < SRSRAN_SUCCESS) { + ERROR("Init"); + return SRSRAN_ERROR; + } + + if (srsran_channel_awgn_set_n0(&ctx->awgn, n0_dB) < SRSRAN_SUCCESS) { + ERROR("Init"); + return SRSRAN_ERROR; + } + + return SRSRAN_SUCCESS; +} + +static void test_context_free(test_context_t* ctx) +{ + if (ctx == NULL) { + return; + } + + srsran_ringbuffer_free(&ctx->ringbuffer); + srsran_ssb_free(&ctx->ssb); + srsran_channel_delay_free(&ctx->delay); + srsran_channel_awgn_free(&ctx->awgn); +} + +static int recv_callback(void* ptr, cf_t** rx_buffer, uint32_t nof_samples, srsran_timestamp_t* timestamp) +{ + test_context_t* ctx = (test_context_t*)ptr; + + // Check inputs + if (ctx == NULL || rx_buffer == NULL || rx_buffer[0] == NULL) { + return SRSRAN_ERROR; + } + + // Calculate the number of required bytes + int required_nbytes = (int)sizeof(cf_t) * nof_samples; + + // Execute subframe until the ringbuffer has data + while (srsran_ringbuffer_status(&ctx->ringbuffer) < required_nbytes) { + // Reset buffer + srsran_vec_cf_zero(buffer, sf_len); + + if (ctx->sf_idx % (SRSRAN_NOF_SF_X_FRAME / 2) == 0) { + // Prepare PBCH message + srsran_pbch_msg_nr_t pbch_msg = {}; + pbch_msg.ssb_idx = 0; + pbch_msg.hrf = ctx->sf_idx >= (SRSRAN_NOF_SF_X_FRAME / 2); + pbch_msg.sfn_4lsb = ctx->sfn & 0b1111U; + + // Encode SSB + if (srsran_ssb_add(&ctx->ssb, pci, &pbch_msg, buffer, buffer) < SRSRAN_SUCCESS) { + return SRSRAN_ERROR; + } + } + + // Run channel + run_channel(ctx); + + // Write in the ring buffer + if (srsran_ringbuffer_write(&ctx->ringbuffer, buffer, (int)sf_len * sizeof(cf_t)) < SRSRAN_SUCCESS) { + return SRSRAN_ERROR; + } + + // Increment subframe index + ctx->sf_idx++; + + // Increment SFN if required + if (ctx->sf_idx >= SRSRAN_NOF_SF_X_FRAME) { + ctx->sfn = (ctx->sfn + 1) % 1024U; + ctx->sf_idx = 0; + } + } + + srsran_vec_cf_zero(buffer, sf_len); + + // Read ringbuffer + if (srsran_ringbuffer_read(&ctx->ringbuffer, rx_buffer[0], required_nbytes) < SRSRAN_SUCCESS) { + return SRSRAN_ERROR; + } + + // Setup timestamp + *timestamp = ctx->timestamp; + + // Advance timestamp + srsran_timestamp_add(&ctx->timestamp, 0, (float)(nof_samples / srate_hz)); + + return SRSRAN_SUCCESS; +} + +static int test_case_1(srsran_ue_sync_nr_t* ue_sync) +{ + for (uint32_t sf_idx = 0; sf_idx < nof_sf; sf_idx++) { + srsran_ue_sync_nr_outcome_t outcome = {}; + TESTASSERT(srsran_ue_sync_nr_zerocopy(ue_sync, &buffer, &outcome) == SRSRAN_SUCCESS); + + // Print outcome + INFO("measure - zerocpy in-sync=%s sf_idx=%d sfn=%d timestamp=%f cfo_hz=%+.1f delay_us=%+.3f", + outcome.in_sync ? "y" : "n", + outcome.sf_idx, + outcome.sfn, + srsran_timestamp_real(&outcome.timestamp), + outcome.cfo_hz, + outcome.delay_us); + } + + return SRSRAN_SUCCESS; +} + +int main(int argc, char** argv) +{ + int ret = SRSRAN_ERROR; + parse_args(argc, argv); + + srate_hz = (double)SRSRAN_SUBC_SPACING_NR(carrier_scs) * srsran_min_symbol_sz_rb(carrier_nof_prb); + sf_len = (uint32_t)ceil(srate_hz / 1000.0); + buffer = srsran_vec_cf_malloc(sf_len); + buffer2 = srsran_vec_cf_malloc(sf_len); + + test_context_t ctx = {}; + srsran_ue_sync_nr_t ue_sync = {}; + + if (buffer == NULL) { + ERROR("Malloc"); + goto clean_exit; + } + + if (buffer2 == NULL) { + ERROR("Malloc"); + goto clean_exit; + } + + srsran_ue_sync_nr_args_t ue_sync_args = {}; + ue_sync_args.max_srate_hz = srate_hz; + ue_sync_args.min_scs = carrier_scs; + ue_sync_args.recv_obj = &ctx; + ue_sync_args.recv_callback = &recv_callback; + ue_sync_args.disable_cfo = false; + if (srsran_ue_sync_nr_init(&ue_sync, &ue_sync_args) < SRSRAN_SUCCESS) { + ERROR("Init"); + goto clean_exit; + } + + srsran_ue_sync_nr_cfg_t ue_sync_cfg = {}; + ue_sync_cfg.ssb.srate_hz = srate_hz; + ue_sync_cfg.ssb.center_freq_hz = 3.5e9; + ue_sync_cfg.ssb.ssb_freq_hz = 3.5e9 - 960e3; + ue_sync_cfg.ssb.scs = ssb_scs; + ue_sync_cfg.ssb.pattern = SRSRAN_SSB_PATTERN_C; + ue_sync_cfg.N_id = pci; + if (srsran_ue_sync_nr_set_cfg(&ue_sync, &ue_sync_cfg) < SRSRAN_SUCCESS) { + ERROR("Init"); + goto clean_exit; + } + + if (test_context_init(&ctx) < SRSRAN_SUCCESS) { + ERROR("Init"); + goto clean_exit; + } + + if (test_case_1(&ue_sync) != SRSRAN_SUCCESS) { + ERROR("test case failed"); + } + + ret = SRSRAN_SUCCESS; + +clean_exit: + srsran_ue_sync_nr_free(&ue_sync); + + if (buffer) { + free(buffer); + } + + if (buffer2) { + free(buffer2); + } + + test_context_free(&ctx); + + return ret; +} \ No newline at end of file diff --git a/lib/src/phy/ue/ue_sync_nr.c b/lib/src/phy/ue/ue_sync_nr.c new file mode 100644 index 000000000..97ae3df10 --- /dev/null +++ b/lib/src/phy/ue/ue_sync_nr.c @@ -0,0 +1,314 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2021 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include "srsran/phy/ue/ue_sync_nr.h" +#include "srsran/phy/utils/vector.h" + +#define UE_SYNC_NR_DEFAULT_CFO_ALPHA 0.1 + +int srsran_ue_sync_nr_init(srsran_ue_sync_nr_t* q, const srsran_ue_sync_nr_args_t* args) +{ + // Check inputs + if (q == NULL || args == NULL) { + return SRSRAN_ERROR_INVALID_INPUTS; + } + + // Copy arguments + q->recv_obj = args->recv_obj; + q->recv_callback = args->recv_callback; + q->nof_rx_channels = args->nof_rx_channels == 0 ? 1 : args->nof_rx_channels; + q->disable_cfo = args->disable_cfo; + q->cfo_alpha = isnormal(args->cfo_alpha) ? args->cfo_alpha : UE_SYNC_NR_DEFAULT_CFO_ALPHA; + + // Initialise SSB + srsran_ssb_args_t ssb_args = {}; + ssb_args.max_srate_hz = args->max_srate_hz; + ssb_args.min_scs = args->min_scs; + ssb_args.enable_search = true; + ssb_args.enable_decode = true; + ssb_args.pbch_dmrs_thr = args->pbch_dmrs_thr; + if (srsran_ssb_init(&q->ssb, &ssb_args) < SRSRAN_SUCCESS) { + ERROR("Error SSB init"); + return SRSRAN_ERROR; + } + + // Allocate temporal buffer pointers + q->tmp_buffer = SRSRAN_MEM_ALLOC(cf_t*, q->nof_rx_channels); + if (q->tmp_buffer == NULL) { + ERROR("Error alloc"); + return SRSRAN_ERROR; + } + + return SRSRAN_SUCCESS; +} + +void srsran_ue_sync_nr_free(srsran_ue_sync_nr_t* q) +{ + // Check inputs + if (q == NULL) { + return; + } + + srsran_ssb_free(&q->ssb); + + if (q->tmp_buffer) { + free(q->tmp_buffer); + } + + SRSRAN_MEM_ZERO(q, srsran_ue_sync_nr_t, 1); +} + +int srsran_ue_sync_nr_set_cfg(srsran_ue_sync_nr_t* q, const srsran_ue_sync_nr_cfg_t* cfg) +{ + // Check inputs + if (q == NULL || cfg == NULL) { + return SRSRAN_ERROR_INVALID_INPUTS; + } + + // Copy parameters + q->N_id = cfg->N_id; + q->srate_hz = cfg->ssb.srate_hz; + + // Calculate new subframe size + q->sf_sz = (uint32_t)round(1e-3 * q->srate_hz); + + // Configure SSB + if (srsran_ssb_set_cfg(&q->ssb, &cfg->ssb) < SRSRAN_SUCCESS) { + ERROR("Error configuring SSB"); + return SRSRAN_ERROR; + } + + // Transition to find + q->state = SRSRAN_UE_SYNC_NR_STATE_FIND; + + return SRSRAN_SUCCESS; +} + +static void ue_sync_nr_reset_feedback(srsran_ue_sync_nr_t* q) +{ + SRSRAN_MEM_ZERO(&q->feedback, srsran_csi_trs_measurements_t, 1); +} + +static void ue_sync_nr_apply_feedback(srsran_ue_sync_nr_t* q) +{ + // Skip any update if there is no feedback available + if (q->feedback.nof_re == 0) { + return; + } + + // Update number of samples + q->avg_delay_us = q->feedback.delay_us; + q->next_rf_sample_offset = (uint32_t)round((double)q->avg_delay_us * (q->srate_hz * 1e-6)); + + // Integrate CFO + if (q->disable_cfo) { + q->cfo_hz = SRSRAN_VEC_SAFE_EMA(q->feedback.cfo_hz, q->cfo_hz, q->cfo_alpha); + } else { + q->cfo_hz += q->feedback.cfo_hz * q->cfo_alpha; + } + + // Reset feedback + ue_sync_nr_reset_feedback(q); +} + +static int ue_sync_nr_run_find(srsran_ue_sync_nr_t* q, cf_t* buffer) +{ + srsran_csi_trs_measurements_t measurements = {}; + srsran_pbch_msg_nr_t pbch_msg = {}; + + // Find SSB, measure PSS/SSS and decode PBCH + if (srsran_ssb_find(&q->ssb, buffer, q->N_id, &measurements, &pbch_msg) < SRSRAN_SUCCESS) { + ERROR("Error finding SSB"); + return SRSRAN_ERROR; + } + + // If the PBCH message was NOT decoded, early return + if (!pbch_msg.crc) { + return SRSRAN_SUCCESS; + } + + // Reset feedback to prevent any previous erroneous measurement + ue_sync_nr_reset_feedback(q); + + // Set feedback measurement + srsran_combine_csi_trs_measurements(&q->feedback, &measurements, &q->feedback); + + // Apply feedback + ue_sync_nr_apply_feedback(q); + + // Setup context + q->ssb_idx = pbch_msg.ssb_idx; + q->sf_idx = srsran_ssb_candidate_sf_idx(&q->ssb, pbch_msg.ssb_idx, pbch_msg.hrf); + q->sfn = pbch_msg.sfn_4lsb; + + // Transition to track only if the measured delay is below 2.4 microseconds + if (measurements.delay_us < 2.4f) { + q->state = SRSRAN_UE_SYNC_NR_STATE_TRACK; + } + + return SRSRAN_SUCCESS; +} + +static int ue_sync_nr_run_track(srsran_ue_sync_nr_t* q, cf_t* buffer) +{ + srsran_csi_trs_measurements_t measurements = {}; + srsran_pbch_msg_nr_t pbch_msg = {}; + uint32_t half_frame = q->sf_idx / (SRSRAN_NOF_SF_X_FRAME / 2); + + // Check if the SSB selected candidate index shall be received in this subframe + bool is_ssb_opportunity = (q->sf_idx == srsran_ssb_candidate_sf_idx(&q->ssb, q->ssb_idx, half_frame > 0)); + + // If + if (is_ssb_opportunity) { + // Measure PSS/SSS and decode PBCH + if (srsran_ssb_track(&q->ssb, buffer, q->N_id, q->ssb_idx, half_frame, &measurements, &pbch_msg) < SRSRAN_SUCCESS) { + ERROR("Error finding SSB"); + return SRSRAN_ERROR; + } + + // If the PBCH message was NOT decoded, transition to track + if (!pbch_msg.crc) { + q->state = SRSRAN_UE_SYNC_NR_STATE_FIND; + return SRSRAN_SUCCESS; + } + + // Otherwise feedback measurements and apply + srsran_combine_csi_trs_measurements(&q->feedback, &measurements, &q->feedback); + } + + // Apply accumulated feedback + ue_sync_nr_apply_feedback(q); + + return SRSRAN_SUCCESS; +} + +static int ue_sync_nr_recv(srsran_ue_sync_nr_t* q, cf_t** buffer, srsran_timestamp_t* timestamp) +{ + // Verify callback and srate are valid + if (q->recv_callback == NULL && !isnormal(q->srate_hz)) { + return SRSRAN_ERROR; + } + + uint32_t buffer_offset = 0; + uint32_t nof_samples = q->sf_sz; + + if (q->next_rf_sample_offset > 0) { + // Discard a number of samples from RF + if (q->recv_callback(q->recv_obj, buffer, (uint32_t)q->next_rf_sample_offset, timestamp) < SRSRAN_SUCCESS) { + return SRSRAN_ERROR; + } + } else { + // Adjust receive buffer + buffer_offset = (uint32_t)(-q->next_rf_sample_offset); + nof_samples = (uint32_t)(q->sf_sz + q->next_rf_sample_offset); + } + q->next_rf_sample_offset = 0; + + // Select buffer offsets + for (uint32_t chan = 0; chan < q->nof_rx_channels; chan++) { + // Set buffer to NULL if not present + if (buffer[chan] == NULL) { + q->tmp_buffer[chan] = NULL; + continue; + } + + // Initialise first offset samples to zero + if (buffer_offset > 0) { + srsran_vec_cf_zero(buffer[chan], buffer_offset); + } + + // Set to sample index + q->tmp_buffer[chan] = &buffer[chan][buffer_offset]; + } + + // Receive + if (q->recv_callback(q->recv_obj, q->tmp_buffer, nof_samples, timestamp) < SRSRAN_SUCCESS) { + return SRSRAN_ERROR; + } + + // Compensate CFO + for (uint32_t chan = 0; chan < q->nof_rx_channels; chan++) { + if (buffer[chan] != 0 && !q->disable_cfo) { + srsran_vec_apply_cfo(buffer[chan], q->cfo_hz / q->srate_hz, buffer[chan], (int)q->sf_sz); + } + } + + return SRSRAN_SUCCESS; +} + +int srsran_ue_sync_nr_zerocopy(srsran_ue_sync_nr_t* q, cf_t** buffer, srsran_ue_sync_nr_outcome_t* outcome) +{ + // Check inputs + if (q == NULL || buffer == NULL || outcome == NULL) { + return SRSRAN_ERROR_INVALID_INPUTS; + } + + // Verify callback is valid + if (q->recv_callback == NULL) { + return SRSRAN_ERROR; + } + + // Receive + if (ue_sync_nr_recv(q, buffer, &outcome->timestamp) < SRSRAN_SUCCESS) { + ERROR("Error receiving baseband"); + return SRSRAN_ERROR; + } + + // Run FSM + switch (q->state) { + case SRSRAN_UE_SYNC_NR_STATE_IDLE: + // Do nothing + break; + case SRSRAN_UE_SYNC_NR_STATE_FIND: + if (ue_sync_nr_run_find(q, buffer[0]) < SRSRAN_SUCCESS) { + ERROR("Error running find"); + return SRSRAN_ERROR; + } + break; + case SRSRAN_UE_SYNC_NR_STATE_TRACK: + if (ue_sync_nr_run_track(q, buffer[0]) < SRSRAN_SUCCESS) { + ERROR("Error running track"); + return SRSRAN_ERROR; + } + break; + } + + // Increment subframe counter + q->sf_idx++; + + // Increment SFN + if (q->sf_idx >= SRSRAN_NOF_SF_X_FRAME) { + q->sfn = (q->sfn + 1) % 1024; + q->sf_idx = 0; + } + + // Fill outcome + outcome->in_sync = (q->state == SRSRAN_UE_SYNC_NR_STATE_TRACK); + outcome->sf_idx = q->sf_idx; + outcome->sfn = q->sfn; + outcome->cfo_hz = q->cfo_hz; + outcome->delay_us = q->avg_delay_us; + + return SRSRAN_SUCCESS; +} + +int srsran_ue_sync_nr_feedback(srsran_ue_sync_nr_t* q, const srsran_csi_trs_measurements_t* measurements) +{ + if (q == NULL || measurements == NULL) { + return SRSRAN_ERROR_INVALID_INPUTS; + } + + // Accumulate feedback proportional to the number of elements provided by the measurement + srsran_combine_csi_trs_measurements(&q->feedback, measurements, &q->feedback); + + return SRSRAN_SUCCESS; +} From ec1991924679f4543df3a0a3ae5bfb9eda9a5729 Mon Sep 17 00:00:00 2001 From: David Rupprecht Date: Tue, 22 Jun 2021 16:48:44 +0200 Subject: [PATCH 21/24] Fix NGAP valgrind test --- .../srsran/interfaces/gnb_ngap_interfaces.h | 20 +++++++++---------- srsenb/hdr/stack/ngap/ngap.h | 2 +- srsenb/test/ngap/ngap_test.cc | 4 ++-- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/include/srsran/interfaces/gnb_ngap_interfaces.h b/lib/include/srsran/interfaces/gnb_ngap_interfaces.h index eed86ca4d..5d3fd92a8 100644 --- a/lib/include/srsran/interfaces/gnb_ngap_interfaces.h +++ b/lib/include/srsran/interfaces/gnb_ngap_interfaces.h @@ -18,16 +18,16 @@ namespace srsenb { struct ngap_args_t { - uint32_t gnb_id; // 20-bit id (lsb bits) - uint8_t cell_id; // 8-bit cell id - uint16_t tac; // 16-bit tac - uint16_t mcc; // BCD-coded with 0xF filler - uint16_t mnc; // BCD-coded with 0xF filler - std::string amf_addr; - std::string gtp_bind_addr; - std::string gtp_advertise_addr; - std::string ngc_bind_addr; - std::string gnb_name; + uint32_t gnb_id = 0; // 20-bit id (lsb bits) + uint8_t cell_id = 0; // 8-bit cell id + uint16_t tac = 0; // 16-bit tac + uint16_t mcc = 0; // BCD-coded with 0xF filler + uint16_t mnc = 0; // BCD-coded with 0xF filler + std::string amf_addr = ""; + std::string gtp_bind_addr = ""; + std::string gtp_advertise_addr = ""; + std::string ngc_bind_addr = ""; + std::string gnb_name = ""; }; // NGAP interface for RRC diff --git a/srsenb/hdr/stack/ngap/ngap.h b/srsenb/hdr/stack/ngap/ngap.h index 737d6022d..9ee160629 100644 --- a/srsenb/hdr/stack/ngap/ngap.h +++ b/srsenb/hdr/stack/ngap/ngap.h @@ -77,7 +77,7 @@ private: // args rrc_interface_ngap_nr* rrc = nullptr; - ngap_args_t args; + ngap_args_t args = {}; srslog::basic_logger& logger; srsran::task_sched_handle task_sched; srsran::task_queue_handle amf_task_queue; diff --git a/srsenb/test/ngap/ngap_test.cc b/srsenb/test/ngap/ngap_test.cc index d21bf7223..24a556b31 100644 --- a/srsenb/test/ngap/ngap_test.cc +++ b/srsenb/test/ngap/ngap_test.cc @@ -86,7 +86,7 @@ struct dummy_socket_manager : public srsran::socket_manager_itf { return true; } - int s1u_fd; + int s1u_fd = 0; recv_callback_t callback; }; @@ -141,7 +141,7 @@ int main(int argc, char** argv) args.ngc_bind_addr = "127.0.0.100"; args.tac = 7; args.gtp_bind_addr = "127.0.0.100"; - args.amf_addr = amf_addr_str; + args.amf_addr = "127.0.0.1"; args.gnb_name = "srsgnb01"; rrc_interface_ngap_nr rrc; ngap_obj.init(args, &rrc); From 3e9678d496c425e782ee460ac92ff272be52c036 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Fri, 13 Mar 2020 14:46:32 +0100 Subject: [PATCH 22/24] srsepc: send detach accept when receiving detach request for non-switchoff --- srsepc/src/mme/nas.cc | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/srsepc/src/mme/nas.cc b/srsepc/src/mme/nas.cc index 0f7e6b001..e7fe1f304 100644 --- a/srsepc/src/mme/nas.cc +++ b/srsepc/src/mme/nas.cc @@ -765,6 +765,31 @@ bool nas::handle_detach_request(uint32_t m_tmsi, ecm_ctx_t* ecm_ctx = &nas_ctx->m_ecm_ctx; sec_ctx_t* sec_ctx = &nas_ctx->m_sec_ctx; + // TS 24.301, Sec 5.5.2.2.1, UE initiated detach request + if (detach_req.detach_type.switch_off == 0) { + // UE expects detach accept + srsran::unique_byte_buffer_t nas_tx = srsran::make_byte_buffer(); + if (nas_tx == nullptr) { + nas_logger.error("Couldn't allocate PDU in %s().", __FUNCTION__); + return false; + } + + LIBLTE_MME_DETACH_ACCEPT_MSG_STRUCT detach_accept = {}; + err = liblte_mme_pack_detach_accept_msg(&detach_accept, + LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS, + sec_ctx->dl_nas_count, + (LIBLTE_BYTE_MSG_STRUCT*)nas_tx.get()); + if (err != LIBLTE_SUCCESS) { + nas_logger.error("Error packing Detach Accept\n"); + } + + nas_logger.info("Sending detach accept.\n"); + sec_ctx->dl_nas_count++; + s1ap->send_downlink_nas_transport(enb_ue_s1ap_id, s1ap->get_next_mme_ue_s1ap_id(), nas_tx.get(), *enb_sri); + } else { + nas_logger.info("UE is switched off\n"); + } + gtpc->send_delete_session_request(emm_ctx->imsi); emm_ctx->state = EMM_STATE_DEREGISTERED; sec_ctx->ul_nas_count++; From ff72c78745c3665dadde29aa13b247a3538ecc7e Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Tue, 15 Jun 2021 12:53:51 +0200 Subject: [PATCH 23/24] enb,mac: fix indention --- srsenb/src/stack/mac/mac.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/srsenb/src/stack/mac/mac.cc b/srsenb/src/stack/mac/mac.cc index 2aafc7d90..3f865d396 100644 --- a/srsenb/src/stack/mac/mac.cc +++ b/srsenb/src/stack/mac/mac.cc @@ -821,9 +821,9 @@ int mac::get_mch_sched(uint32_t tti, bool is_mcch, dl_sched_list_t& dl_sched_res int requested_bytes = (mcs_data.tbs / 8 > (int)mch.mtch_sched[mtch_index].lcid_buffer_size) ? (mch.mtch_sched[mtch_index].lcid_buffer_size) : ((mcs_data.tbs / 8) - 2); - int bytes_received = ue_db[SRSRAN_MRNTI]->read_pdu(current_lcid, mtch_payload_buffer, requested_bytes); - mch.pdu[0].lcid = current_lcid; - mch.pdu[0].nbytes = bytes_received; + int bytes_received = ue_db[SRSRAN_MRNTI]->read_pdu(current_lcid, mtch_payload_buffer, requested_bytes); + mch.pdu[0].lcid = current_lcid; + mch.pdu[0].nbytes = bytes_received; mch.mtch_sched[0].mtch_payload = mtch_payload_buffer; dl_sched_res->pdsch[0].dci.rnti = SRSRAN_MRNTI; if (bytes_received) { From 4b069d9b869446de1c2d66860b1acc1bd08b989a Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Tue, 15 Jun 2021 12:54:10 +0200 Subject: [PATCH 24/24] enb,mac: fix concurrent access to cell structs this patch moves the rwlock that protects the UE database outside to also protect the cell struct. It also adds a missing write guard when setting the cell --- srsenb/src/stack/mac/mac.cc | 110 +++++++++++++++++------------------- 1 file changed, 52 insertions(+), 58 deletions(-) diff --git a/srsenb/src/stack/mac/mac.cc b/srsenb/src/stack/mac/mac.cc index 3f865d396..21cfad988 100644 --- a/srsenb/src/stack/mac/mac.cc +++ b/srsenb/src/stack/mac/mac.cc @@ -228,6 +228,7 @@ int mac::ue_set_crnti(uint16_t temp_crnti, uint16_t crnti, const sched_interface int mac::cell_cfg(const std::vector& cell_cfg_) { + srsran::rwlock_write_guard lock(rwlock); cell_config = cell_cfg_; return scheduler.cell_cfg(cell_config); } @@ -576,6 +577,8 @@ int mac::get_dl_sched(uint32_t tti_tx_dl, dl_sched_list_t& dl_sched_res_list) add_padding(); } + srsran::rwlock_read_guard lock(rwlock); + for (uint32_t enb_cc_idx = 0; enb_cc_idx < cell_config.size(); enb_cc_idx++) { // Run scheduler with current info sched_interface::dl_sched_res_t sched_result = {}; @@ -587,68 +590,62 @@ int mac::get_dl_sched(uint32_t tti_tx_dl, dl_sched_list_t& dl_sched_res_list) int n = 0; dl_sched_t* dl_sched_res = &dl_sched_res_list[enb_cc_idx]; - { - srsran::rwlock_read_guard lock(rwlock); + // Copy data grants + for (uint32_t i = 0; i < sched_result.data.size(); i++) { + uint32_t tb_count = 0; - // Copy data grants - for (uint32_t i = 0; i < sched_result.data.size(); i++) { - uint32_t tb_count = 0; + // Get UE + uint16_t rnti = sched_result.data[i].dci.rnti; - // Get UE - uint16_t rnti = sched_result.data[i].dci.rnti; + if (ue_db.contains(rnti)) { + // Copy dci info + dl_sched_res->pdsch[n].dci = sched_result.data[i].dci; - if (ue_db.contains(rnti)) { - // Copy dci info - dl_sched_res->pdsch[n].dci = sched_result.data[i].dci; + for (uint32_t tb = 0; tb < SRSRAN_MAX_TB; tb++) { + dl_sched_res->pdsch[n].softbuffer_tx[tb] = + ue_db[rnti]->get_tx_softbuffer(enb_cc_idx, sched_result.data[i].dci.pid, tb); - for (uint32_t tb = 0; tb < SRSRAN_MAX_TB; tb++) { - dl_sched_res->pdsch[n].softbuffer_tx[tb] = - ue_db[rnti]->get_tx_softbuffer(enb_cc_idx, sched_result.data[i].dci.pid, tb); - - // If the Rx soft-buffer is not given, abort transmission - if (dl_sched_res->pdsch[n].softbuffer_tx[tb] == nullptr) { - continue; - } - - if (sched_result.data[i].nof_pdu_elems[tb] > 0) { - /* Get PDU if it's a new transmission */ - dl_sched_res->pdsch[n].data[tb] = ue_db[rnti]->generate_pdu(enb_cc_idx, - sched_result.data[i].dci.pid, - tb, - sched_result.data[i].pdu[tb], - sched_result.data[i].nof_pdu_elems[tb], - sched_result.data[i].tbs[tb]); - - if (!dl_sched_res->pdsch[n].data[tb]) { - logger.error("Error! PDU was not generated (rnti=0x%04x, tb=%d)", rnti, tb); - } - - if (pcap) { - pcap->write_dl_crnti( - dl_sched_res->pdsch[n].data[tb], sched_result.data[i].tbs[tb], rnti, true, tti_tx_dl, enb_cc_idx); - } - if (pcap_net) { - pcap_net->write_dl_crnti( - dl_sched_res->pdsch[n].data[tb], sched_result.data[i].tbs[tb], rnti, true, tti_tx_dl, enb_cc_idx); - } - } else { - /* TB not enabled OR no data to send: set pointers to NULL */ - dl_sched_res->pdsch[n].data[tb] = nullptr; - } - - tb_count++; + // If the Rx soft-buffer is not given, abort transmission + if (dl_sched_res->pdsch[n].softbuffer_tx[tb] == nullptr) { + continue; } - // Count transmission if at least one TB has succesfully added - if (tb_count > 0) { - n++; + if (sched_result.data[i].nof_pdu_elems[tb] > 0) { + /* Get PDU if it's a new transmission */ + dl_sched_res->pdsch[n].data[tb] = ue_db[rnti]->generate_pdu(enb_cc_idx, + sched_result.data[i].dci.pid, + tb, + sched_result.data[i].pdu[tb], + sched_result.data[i].nof_pdu_elems[tb], + sched_result.data[i].tbs[tb]); + + if (!dl_sched_res->pdsch[n].data[tb]) { + logger.error("Error! PDU was not generated (rnti=0x%04x, tb=%d)", rnti, tb); + } + + if (pcap) { + pcap->write_dl_crnti( + dl_sched_res->pdsch[n].data[tb], sched_result.data[i].tbs[tb], rnti, true, tti_tx_dl, enb_cc_idx); + } + if (pcap_net) { + pcap_net->write_dl_crnti( + dl_sched_res->pdsch[n].data[tb], sched_result.data[i].tbs[tb], rnti, true, tti_tx_dl, enb_cc_idx); + } + } else { + /* TB not enabled OR no data to send: set pointers to NULL */ + dl_sched_res->pdsch[n].data[tb] = nullptr; } - } else { - logger.warning("Invalid DL scheduling result. User 0x%x does not exist", rnti); + + tb_count++; } - } - // No more uses of shared ue_db beyond here + // Count transmission if at least one TB has succesfully added + if (tb_count > 0) { + n++; + } + } else { + logger.warning("Invalid DL scheduling result. User 0x%x does not exist", rnti); + } } // Copy RAR grants @@ -728,11 +725,8 @@ int mac::get_dl_sched(uint32_t tti_tx_dl, dl_sched_list_t& dl_sched_res_list) } // Count number of TTIs for all active users - { - srsran::rwlock_read_guard lock(rwlock); - for (auto& u : ue_db) { - u.second->metrics_cnt(); - } + for (auto& u : ue_db) { + u.second->metrics_cnt(); } return SRSRAN_SUCCESS;