From 5a2a435710f4661fcfc275e821821d71e2c3659c Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Mon, 17 May 2021 23:03:43 +0200 Subject: [PATCH 001/156] Improve srsENB output metrics --- srsenb/src/metrics_stdout.cc | 38 ++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/srsenb/src/metrics_stdout.cc b/srsenb/src/metrics_stdout.cc index 2291a79fe..ebbd5c6b7 100644 --- a/srsenb/src/metrics_stdout.cc +++ b/srsenb/src/metrics_stdout.cc @@ -85,7 +85,7 @@ void metrics_stdout::set_metrics(const enb_metrics_t& metrics, const uint32_t pe n_reports = 0; cout << endl; cout << "------DL-------------------------------UL--------------------------------------------" << endl; - cout << "rnti cqi ri mcs brate ok nok (%) pusch pucch phr mcs brate ok nok (%) bsr" << endl; + cout << "rnti cqi ri mcs brate ok nok (%) pusch pucch phr mcs brate ok nok (%) bsr" << endl; } for (size_t i = 0; i < metrics.stack.rrc.ues.size(); i++) { @@ -101,52 +101,53 @@ void metrics_stdout::set_metrics(const enb_metrics_t& metrics, const uint32_t pe } cout << int_to_hex_string(metrics.stack.mac.ues[i].rnti, 4) << " "; - cout << float_to_string(SRSRAN_MAX(0.1, metrics.stack.mac.ues[i].dl_cqi), 1, 3); + if (not iszero(metrics.stack.mac.ues[i].dl_cqi)) { + cout << float_to_string(metrics.stack.mac.ues[i].dl_cqi, 1, 3); + } else { + cout << "n/a"; + } cout << float_to_string(metrics.stack.mac.ues[i].dl_ri, 1, 4); if (not isnan(metrics.phy[i].dl.mcs)) { - cout << float_to_string(SRSRAN_MAX(0.1, metrics.phy[i].dl.mcs), 1, 4); + cout << float_to_string(metrics.phy[i].dl.mcs, 1, 4); } else { cout << float_to_string(0, 2, 4); } if (metrics.stack.mac.ues[i].tx_brate > 0) { - cout << float_to_eng_string( - SRSRAN_MAX(0.1, (float)metrics.stack.mac.ues[i].tx_brate / (metrics.stack.mac.ues[i].nof_tti * 1e-3)), 1); + cout << float_to_eng_string((float)metrics.stack.mac.ues[i].tx_brate / (metrics.stack.mac.ues[i].nof_tti * 1e-3), 1); } else { cout << float_to_string(0, 1, 6) << ""; } cout << std::setw(5) << metrics.stack.mac.ues[i].tx_pkts - metrics.stack.mac.ues[i].tx_errors; cout << std::setw(5) << metrics.stack.mac.ues[i].tx_errors; if (metrics.stack.mac.ues[i].tx_pkts > 0 && metrics.stack.mac.ues[i].tx_errors) { - cout << float_to_string( - SRSRAN_MAX(0.1, (float)100 * metrics.stack.mac.ues[i].tx_errors / metrics.stack.mac.ues[i].tx_pkts), 1, 4) + cout << float_to_string((float)100 * metrics.stack.mac.ues[i].tx_errors / metrics.stack.mac.ues[i].tx_pkts, 1, 4) << "%"; } else { cout << float_to_string(0, 1, 4) << "%"; } cout << " "; - if (not isnan(metrics.phy[i].ul.pusch_sinr)) { - cout << float_to_string(SRSRAN_MAX(0.1, metrics.phy[i].ul.pusch_sinr), 2, 5); + if (not isnan(metrics.phy[i].ul.pusch_sinr) and not iszero(metrics.phy[i].ul.pusch_sinr)) { + cout << float_to_string(metrics.phy[i].ul.pusch_sinr, 2, 5); } else { - cout << float_to_string(0, 2, 5); + cout << " n/a"; } - if (not isnan(metrics.phy[i].ul.pucch_sinr)) { - cout << float_to_string(SRSRAN_MAX(0.1, metrics.phy[i].ul.pucch_sinr), 2, 5); + if (not isnan(metrics.phy[i].ul.pucch_sinr) and not iszero(metrics.phy[i].ul.pucch_sinr)) { + cout << float_to_string(metrics.phy[i].ul.pucch_sinr, 2, 6); } else { - cout << float_to_string(0, 2, 5); + cout << " n/a"; } cout << " "; cout << float_to_string(metrics.stack.mac.ues[i].phr, 2, 5); if (not isnan(metrics.phy[i].ul.mcs)) { - cout << float_to_string(SRSRAN_MAX(0.1, metrics.phy[i].ul.mcs), 1, 4); + cout << float_to_string(metrics.phy[i].ul.mcs, 1, 4); } else { cout << float_to_string(0, 1, 4); } if (metrics.stack.mac.ues[i].rx_brate > 0) { - cout << float_to_eng_string( - SRSRAN_MAX(0.1, (float)metrics.stack.mac.ues[i].rx_brate / (metrics.stack.mac.ues[i].nof_tti * 1e-3)), 1); + cout << float_to_eng_string((float)metrics.stack.mac.ues[i].rx_brate / (metrics.stack.mac.ues[i].nof_tti * 1e-3), 1); } else { cout << float_to_string(0, 1) << ""; } @@ -154,8 +155,7 @@ void metrics_stdout::set_metrics(const enb_metrics_t& metrics, const uint32_t pe cout << std::setw(5) << metrics.stack.mac.ues[i].rx_errors; if (metrics.stack.mac.ues[i].rx_pkts > 0 && metrics.stack.mac.ues[i].rx_errors > 0) { - cout << float_to_string( - SRSRAN_MAX(0.1, (float)100 * metrics.stack.mac.ues[i].rx_errors / metrics.stack.mac.ues[i].rx_pkts), 1, 4) + cout << float_to_string((float)100 * metrics.stack.mac.ues[i].rx_errors / metrics.stack.mac.ues[i].rx_pkts, 1, 4) << "%"; } else { cout << float_to_string(0, 1, 4) << "%"; @@ -175,7 +175,7 @@ std::string metrics_stdout::float_to_string(float f, int digits, int field_width f = 0.0; precision = digits - 1; } else { - precision = digits - (int)(log10f(fabs(f)) - 2 * DBL_EPSILON); + precision = digits - (int)(log10f(fabs(f + 0.0001)) - 2 * DBL_EPSILON); } if (precision == -1) { precision = 0; From 8414b2c2c95ed5cee47c84f07d3717869def14e1 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Tue, 18 May 2021 10:30:06 +0200 Subject: [PATCH 002/156] Define iszero in csv_stdout --- srsenb/src/metrics_stdout.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/srsenb/src/metrics_stdout.cc b/srsenb/src/metrics_stdout.cc index ebbd5c6b7..1eca8ec7e 100644 --- a/srsenb/src/metrics_stdout.cc +++ b/srsenb/src/metrics_stdout.cc @@ -65,6 +65,12 @@ void metrics_stdout::toggle_print(bool b) do_print = b; } +// Define iszero() here since it's not defined in some platforms +static bool iszero(float x) +{ + return fabsf(x) < 2 * DBL_EPSILON; +} + void metrics_stdout::set_metrics(const enb_metrics_t& metrics, const uint32_t period_usec) { if (!do_print || enb == nullptr) { From f705735093a5f38ca83e5d609a5df517b216dcf8 Mon Sep 17 00:00:00 2001 From: Francisco Date: Mon, 17 May 2021 12:57:03 +0100 Subject: [PATCH 003/156] optimization - only allow some multiqueue queues to notify the multiqueue consumer of the arrival of tasks --- lib/include/srsran/common/multiqueue.h | 9 ++++++++- srsenb/hdr/stack/enb_stack_lte.h | 2 +- srsenb/src/stack/enb_stack_lte.cc | 7 +++++-- srsenb/src/stack/gnb_stack_nr.cc | 8 +++++--- srsue/src/stack/ue_stack_lte.cc | 4 +++- srsue/src/stack/ue_stack_nr.cc | 6 ++++-- 6 files changed, 26 insertions(+), 10 deletions(-) diff --git a/lib/include/srsran/common/multiqueue.h b/lib/include/srsran/common/multiqueue.h index b69c91c76..e1830deae 100644 --- a/lib/include/srsran/common/multiqueue.h +++ b/lib/include/srsran/common/multiqueue.h @@ -66,6 +66,11 @@ class multiqueue_handler return active_; } + void set_notify_mode() + { + std::unique_lock lock(q_mutex); + notify_mode = true; + } void set_active(bool val) { std::unique_lock lock(q_mutex); @@ -152,7 +157,7 @@ class multiqueue_handler } } buffer.push(std::forward(*o)); - if (consumer_notify_needed) { + if (consumer_notify_needed and notify_mode) { // Note: The consumer thread only needs to be notified and awaken when queues transition from empty to non-empty // To ensure that the consumer noticed that the queue was empty before a push, we store the last // try_pop() return in a member variable. @@ -170,6 +175,7 @@ class multiqueue_handler std::condition_variable cv_full, cv_exit; bool active_ = true; bool consumer_notify_needed = true; + bool notify_mode = false; int nof_waiting = 0; }; @@ -192,6 +198,7 @@ public: impl = nullptr; } } + void set_notify_mode() { impl->set_notify_mode(); } size_t size() { return impl->size(); } size_t capacity() { return impl->capacity(); } diff --git a/srsenb/hdr/stack/enb_stack_lte.h b/srsenb/hdr/stack/enb_stack_lte.h index 41f5419f3..14d99279b 100644 --- a/srsenb/hdr/stack/enb_stack_lte.h +++ b/srsenb/hdr/stack/enb_stack_lte.h @@ -122,7 +122,7 @@ private: // task handling srsran::task_scheduler task_sched; - srsran::task_queue_handle enb_task_queue, sync_task_queue; + srsran::task_queue_handle enb_task_queue, sync_task_queue, metrics_task_queue; srsenb::mac mac; srsenb::rlc rlc; diff --git a/srsenb/src/stack/enb_stack_lte.cc b/srsenb/src/stack/enb_stack_lte.cc index 50bbee745..91a3a0bf3 100644 --- a/srsenb/src/stack/enb_stack_lte.cc +++ b/srsenb/src/stack/enb_stack_lte.cc @@ -42,6 +42,8 @@ enb_stack_lte::enb_stack_lte(srslog::sink& log_sink) : { get_background_workers().set_nof_workers(2); enb_task_queue = task_sched.make_task_queue(); + enb_task_queue.set_notify_mode(); + metrics_task_queue = task_sched.make_task_queue(); // sync_queue is added in init() } @@ -96,7 +98,7 @@ int enb_stack_lte::init(const stack_args_t& args_, const rrc_cfg_t& rrc_cfg_) // Set up pcap and trace if (args.mac_pcap.enable) { - mac_pcap.open(args.mac_pcap.filename.c_str()); + mac_pcap.open(args.mac_pcap.filename); mac.start_pcap(&mac_pcap); } @@ -115,6 +117,7 @@ int enb_stack_lte::init(const stack_args_t& args_, const rrc_cfg_t& rrc_cfg_) // add sync queue sync_task_queue = task_sched.make_task_queue(args.sync_queue_size); + sync_task_queue.set_notify_mode(); // Init all layers if (!mac.init(args.mac, rrc_cfg.cell_list, phy, &rlc, &rrc)) { @@ -202,7 +205,7 @@ void enb_stack_lte::stop_impl() bool enb_stack_lte::get_metrics(stack_metrics_t* metrics) { // use stack thread to query metrics - auto ret = enb_task_queue.try_push([this]() { + auto ret = metrics_task_queue.try_push([this]() { stack_metrics_t metrics{}; mac.get_metrics(metrics.mac); if (not metrics.mac.ues.empty()) { diff --git a/srsenb/src/stack/gnb_stack_nr.cc b/srsenb/src/stack/gnb_stack_nr.cc index 223798334..dec7e9d0a 100644 --- a/srsenb/src/stack/gnb_stack_nr.cc +++ b/srsenb/src/stack/gnb_stack_nr.cc @@ -26,10 +26,12 @@ gnb_stack_nr::gnb_stack_nr() : task_sched{512, 128}, thread("gNB"), rlc_logger(s m_gw.reset(new srsue::gw()); // m_gtpu.reset(new srsenb::gtpu()); - ue_task_queue = task_sched.make_task_queue(); + ue_task_queue = task_sched.make_task_queue(); + ue_task_queue.set_notify_mode(); sync_task_queue = task_sched.make_task_queue(); - gw_task_queue = task_sched.make_task_queue(); - mac_task_queue = task_sched.make_task_queue(); + sync_task_queue.set_notify_mode(); + gw_task_queue = task_sched.make_task_queue(); + mac_task_queue = task_sched.make_task_queue(); } gnb_stack_nr::~gnb_stack_nr() diff --git a/srsue/src/stack/ue_stack_lte.cc b/srsue/src/stack/ue_stack_lte.cc index e903a4a27..b3d330d8e 100644 --- a/srsue/src/stack/ue_stack_lte.cc +++ b/srsue/src/stack/ue_stack_lte.cc @@ -52,7 +52,8 @@ ue_stack_lte::ue_stack_lte() : tti_tprof("tti_tprof", "STCK", TTI_STAT_PERIOD) { get_background_workers().set_nof_workers(2); - ue_task_queue = task_sched.make_task_queue(); + ue_task_queue = task_sched.make_task_queue(); + ue_task_queue.set_notify_mode(); gw_queue_id = task_sched.make_task_queue(); cfg_task_queue = task_sched.make_task_queue(); // sync_queue is added in init() @@ -199,6 +200,7 @@ int ue_stack_lte::init(const stack_args_t& args_) // add sync queue sync_task_queue = task_sched.make_task_queue(args.sync_queue_size); + sync_task_queue.set_notify_mode(); mac.init(phy, &rlc, &rrc); rlc.init(&pdcp, &rrc, &rrc_nr, task_sched.get_timer_handler(), 0 /* RB_ID_SRB0 */); diff --git a/srsue/src/stack/ue_stack_nr.cc b/srsue/src/stack/ue_stack_nr.cc index 33ed31c5f..59a54d3fc 100644 --- a/srsue/src/stack/ue_stack_nr.cc +++ b/srsue/src/stack/ue_stack_nr.cc @@ -33,9 +33,11 @@ ue_stack_nr::ue_stack_nr() : // setup logging for pool, RLC and PDCP byte_buffer_pool::get_instance()->enable_logger(true); - ue_task_queue = task_sched.make_task_queue(); + ue_task_queue = task_sched.make_task_queue(); + ue_task_queue.set_notify_mode(); sync_task_queue = task_sched.make_task_queue(); - gw_task_queue = task_sched.make_task_queue(); + sync_task_queue.set_notify_mode(); + gw_task_queue = task_sched.make_task_queue(); } ue_stack_nr::~ue_stack_nr() From 2d6a8788263534c66ff4f275e646c80169b5ae1c Mon Sep 17 00:00:00 2001 From: Francisco Date: Mon, 17 May 2021 17:43:00 +0100 Subject: [PATCH 004/156] change interface to create multiqueue queues --- lib/include/srsran/common/multiqueue.h | 34 ++++++++++------------ lib/include/srsran/common/task_scheduler.h | 13 +++++---- lib/test/common/multiqueue_test.cc | 26 ++++++++--------- lib/test/common/network_utils_test.cc | 2 +- srsenb/src/stack/enb_stack_lte.cc | 8 ++--- srsenb/src/stack/gnb_stack_nr.cc | 10 +++---- srsue/src/stack/ue_stack_lte.cc | 10 +++---- srsue/src/stack/ue_stack_nr.cc | 8 ++--- 8 files changed, 52 insertions(+), 59 deletions(-) diff --git a/lib/include/srsran/common/multiqueue.h b/lib/include/srsran/common/multiqueue.h index e1830deae..6883fbdc7 100644 --- a/lib/include/srsran/common/multiqueue.h +++ b/lib/include/srsran/common/multiqueue.h @@ -47,7 +47,9 @@ class multiqueue_handler class input_port_impl { public: - input_port_impl(uint32_t cap, multiqueue_handler* parent_) : buffer(cap), parent(parent_) {} + input_port_impl(uint32_t cap, bool notify_flag_, multiqueue_handler* parent_) : + buffer(cap), notify_flag(notify_flag_), consumer_notify_needed(notify_flag_), parent(parent_) + {} input_port_impl(const input_port_impl&) = delete; input_port_impl(input_port_impl&&) = delete; input_port_impl& operator=(const input_port_impl&) = delete; @@ -55,6 +57,7 @@ class multiqueue_handler ~input_port_impl() { deactivate_blocking(); } size_t capacity() const { return buffer.max_size(); } + bool get_notify_mode() const { return notify_flag; } size_t size() const { std::lock_guard lock(q_mutex); @@ -65,12 +68,6 @@ class multiqueue_handler std::lock_guard lock(q_mutex); return active_; } - - void set_notify_mode() - { - std::unique_lock lock(q_mutex); - notify_mode = true; - } void set_active(bool val) { std::unique_lock lock(q_mutex); @@ -79,7 +76,7 @@ class multiqueue_handler return; } active_ = val; - consumer_notify_needed = true; + consumer_notify_needed = notify_flag; if (not active_) { buffer.clear(); @@ -120,7 +117,7 @@ class multiqueue_handler { std::unique_lock lock(q_mutex); if (buffer.empty()) { - consumer_notify_needed = true; + consumer_notify_needed = notify_flag; return false; } obj = std::move(buffer.top()); @@ -157,7 +154,7 @@ class multiqueue_handler } } buffer.push(std::forward(*o)); - if (consumer_notify_needed and notify_mode) { + if (consumer_notify_needed) { // Note: The consumer thread only needs to be notified and awaken when queues transition from empty to non-empty // To ensure that the consumer noticed that the queue was empty before a push, we store the last // try_pop() return in a member variable. @@ -174,8 +171,8 @@ class multiqueue_handler srsran::dyn_circular_buffer buffer; std::condition_variable cv_full, cv_exit; bool active_ = true; - bool consumer_notify_needed = true; - bool notify_mode = false; + bool consumer_notify_needed = false; + bool notify_flag = false; int nof_waiting = 0; }; @@ -198,7 +195,6 @@ public: impl = nullptr; } } - void set_notify_mode() { impl->set_notify_mode(); } size_t size() { return impl->size(); } size_t capacity() { return impl->capacity(); } @@ -249,20 +245,22 @@ public: * @param capacity_ The capacity of the queue. * @return The index of the newly created (or reused) queue within the vector of queues. */ - queue_handle add_queue(uint32_t capacity_) + queue_handle add_queue(uint32_t capacity_, bool notify_flag = false) { uint32_t qidx = 0; std::lock_guard lock(mutex); if (not running) { return queue_handle(); } - for (; qidx < queues.size() and (queues[qidx].active() or (queues[qidx].capacity() != capacity_)); ++qidx) - ; + while (qidx < queues.size() and (queues[qidx].active() or (queues[qidx].capacity() != capacity_) or + (queues[qidx].get_notify_mode() == notify_flag))) { + ++qidx; + } // check if there is a free queue of the required size if (qidx == queues.size()) { // create new queue - queues.emplace_back(capacity_, this); + queues.emplace_back(capacity_, notify_flag, this); qidx = queues.size() - 1; // update qidx to the last element } else { queues[qidx].set_active(true); @@ -274,7 +272,7 @@ public: * Add queue using the default capacity of the underlying multiqueue * @return The queue index */ - queue_handle add_queue() { return add_queue(default_capacity); } + queue_handle add_queue(bool notify_flag) { return add_queue(default_capacity, notify_flag); } uint32_t nof_queues() const { diff --git a/lib/include/srsran/common/task_scheduler.h b/lib/include/srsran/common/task_scheduler.h index fc0b5d3c5..8a73cc7c5 100644 --- a/lib/include/srsran/common/task_scheduler.h +++ b/lib/include/srsran/common/task_scheduler.h @@ -26,7 +26,7 @@ public: explicit task_scheduler(uint32_t default_extern_tasks_size = 512, uint32_t nof_timers_prealloc = 100) : external_tasks{default_extern_tasks_size}, timers{nof_timers_prealloc} { - background_queue = external_tasks.add_queue(); + background_queue = external_tasks.add_queue(false); } task_scheduler(const task_scheduler&) = delete; task_scheduler(task_scheduler&&) = delete; @@ -38,8 +38,11 @@ public: srsran::unique_timer get_unique_timer() { return timers.get_unique_timer(); } //! Creates new queue for tasks coming from external thread - srsran::task_queue_handle make_task_queue() { return external_tasks.add_queue(); } - srsran::task_queue_handle make_task_queue(uint32_t qsize) { return external_tasks.add_queue(qsize); } + srsran::task_queue_handle make_task_queue(bool notify_mode) { return external_tasks.add_queue(notify_mode); } + srsran::task_queue_handle make_task_queue(uint32_t qsize, bool notify_mode) + { + return external_tasks.add_queue(qsize, notify_mode); + } //! Delays a task processing by duration_ms template @@ -124,7 +127,7 @@ public: sched->defer_callback(duration_ms, std::forward(func)); } void defer_task(srsran::move_task_t func) { sched->defer_task(std::move(func)); } - srsran::task_queue_handle make_task_queue() { return sched->make_task_queue(); } + srsran::task_queue_handle make_task_queue() { return sched->make_task_queue(false); } private: task_scheduler* sched; @@ -141,7 +144,7 @@ public: { sched->notify_background_task_result(std::move(task)); } - srsran::task_queue_handle make_task_queue() { return sched->make_task_queue(); } + srsran::task_queue_handle make_task_queue() { return sched->make_task_queue(false); } template void defer_callback(uint32_t duration_ms, F&& func) { diff --git a/lib/test/common/multiqueue_test.cc b/lib/test/common/multiqueue_test.cc index bb44f461d..d906b5571 100644 --- a/lib/test/common/multiqueue_test.cc +++ b/lib/test/common/multiqueue_test.cc @@ -32,7 +32,7 @@ int test_multiqueue() TESTASSERT(multiqueue.nof_queues() == 0); // test push/pop and size for one queue - queue_handle qid1 = multiqueue.add_queue(); + queue_handle qid1 = multiqueue.add_queue(true); TESTASSERT(qid1.active()); TESTASSERT(qid1.size() == 0 and qid1.empty()); TESTASSERT(multiqueue.nof_queues() == 1); @@ -45,7 +45,7 @@ int test_multiqueue() TESTASSERT(number == 2 and qid1.empty()); // test push/pop and size for two queues - queue_handle qid2 = multiqueue.add_queue(); + queue_handle qid2 = multiqueue.add_queue(true); TESTASSERT(qid2.active()); TESTASSERT(multiqueue.nof_queues() == 2 and qid1.active()); TESTASSERT(qid2.try_push(3).has_value()); @@ -55,7 +55,7 @@ int test_multiqueue() // check if erasing a queue breaks anything qid1.reset(); TESTASSERT(multiqueue.nof_queues() == 1 and not qid1.active()); - qid1 = multiqueue.add_queue(); + qid1 = multiqueue.add_queue(true); TESTASSERT(qid1.empty() and qid1.active()); TESTASSERT(qid2.size() == 1 and not qid2.empty()); multiqueue.wait_pop(&number); @@ -89,15 +89,15 @@ int test_multiqueue() // check that adding a queue of different capacity works { - qid1 = multiqueue.add_queue(); - qid2 = multiqueue.add_queue(); + qid1 = multiqueue.add_queue(true); + qid2 = multiqueue.add_queue(true); // remove first queue again qid1.reset(); TESTASSERT(multiqueue.nof_queues() == 1); // add queue with non-default capacity - auto qid3 = multiqueue.add_queue(10); + auto qid3 = multiqueue.add_queue(10, true); TESTASSERT(qid3.capacity() == 10); // make sure neither a new queue index is returned @@ -117,7 +117,7 @@ int test_multiqueue_threading() int capacity = 4, number = 0, start_number = 2, nof_pushes = capacity + 1; multiqueue_handler multiqueue(capacity); - auto qid1 = multiqueue.add_queue(); + auto qid1 = multiqueue.add_queue(true); auto push_blocking_func = [](queue_handle* qid, int start_value, int nof_pushes, bool* is_running) { for (int i = 0; i < nof_pushes; ++i) { qid->push(start_value + i); @@ -165,7 +165,7 @@ int test_multiqueue_threading2() int capacity = 4, start_number = 2, nof_pushes = capacity + 1; multiqueue_handler multiqueue(capacity); - auto qid1 = multiqueue.add_queue(); + auto qid1 = multiqueue.add_queue(true); auto push_blocking_func = [](queue_handle* qid, int start_value, int nof_pushes, bool* is_running) { for (int i = 0; i < nof_pushes; ++i) { qid->push(start_value + i); @@ -199,7 +199,7 @@ int test_multiqueue_threading3() int capacity = 4; multiqueue_handler multiqueue(capacity); - auto qid1 = multiqueue.add_queue(); + auto qid1 = multiqueue.add_queue(true); auto pop_blocking_func = [&multiqueue](bool* success) { int number = 0; bool ret = multiqueue.wait_pop(&number); @@ -235,10 +235,10 @@ int test_multiqueue_threading4() int capacity = 4; multiqueue_handler multiqueue(capacity); - auto qid1 = multiqueue.add_queue(); - auto qid2 = multiqueue.add_queue(); - auto qid3 = multiqueue.add_queue(); - auto qid4 = multiqueue.add_queue(); + auto qid1 = multiqueue.add_queue(true); + auto qid2 = multiqueue.add_queue(true); + auto qid3 = multiqueue.add_queue(true); + auto qid4 = multiqueue.add_queue(true); std::mutex mutex; int last_number = -1; auto pop_blocking_func = [&multiqueue, &last_number, &mutex](bool* success) { diff --git a/lib/test/common/network_utils_test.cc b/lib/test/common/network_utils_test.cc index 2a9290777..fcaf6dd12 100644 --- a/lib/test/common/network_utils_test.cc +++ b/lib/test/common/network_utils_test.cc @@ -23,7 +23,7 @@ struct rx_thread_tester { std::thread t; rx_thread_tester() : - task_queue(task_sched.make_task_queue()), + task_queue(task_sched.make_task_queue(true)), t([this]() { stop_token.store(false); while (not stop_token.load(std::memory_order_relaxed)) { diff --git a/srsenb/src/stack/enb_stack_lte.cc b/srsenb/src/stack/enb_stack_lte.cc index 91a3a0bf3..ac299ddcc 100644 --- a/srsenb/src/stack/enb_stack_lte.cc +++ b/srsenb/src/stack/enb_stack_lte.cc @@ -41,9 +41,8 @@ enb_stack_lte::enb_stack_lte(srslog::sink& log_sink) : pending_stack_metrics(64) { get_background_workers().set_nof_workers(2); - enb_task_queue = task_sched.make_task_queue(); - enb_task_queue.set_notify_mode(); - metrics_task_queue = task_sched.make_task_queue(); + enb_task_queue = task_sched.make_task_queue(true); + metrics_task_queue = task_sched.make_task_queue(false); // sync_queue is added in init() } @@ -116,8 +115,7 @@ int enb_stack_lte::init(const stack_args_t& args_, const rrc_cfg_t& rrc_cfg_) } // add sync queue - sync_task_queue = task_sched.make_task_queue(args.sync_queue_size); - sync_task_queue.set_notify_mode(); + sync_task_queue = task_sched.make_task_queue(args.sync_queue_size, true); // Init all layers if (!mac.init(args.mac, rrc_cfg.cell_list, phy, &rlc, &rrc)) { diff --git a/srsenb/src/stack/gnb_stack_nr.cc b/srsenb/src/stack/gnb_stack_nr.cc index dec7e9d0a..a8ba3b3e4 100644 --- a/srsenb/src/stack/gnb_stack_nr.cc +++ b/srsenb/src/stack/gnb_stack_nr.cc @@ -26,12 +26,10 @@ gnb_stack_nr::gnb_stack_nr() : task_sched{512, 128}, thread("gNB"), rlc_logger(s m_gw.reset(new srsue::gw()); // m_gtpu.reset(new srsenb::gtpu()); - ue_task_queue = task_sched.make_task_queue(); - ue_task_queue.set_notify_mode(); - sync_task_queue = task_sched.make_task_queue(); - sync_task_queue.set_notify_mode(); - gw_task_queue = task_sched.make_task_queue(); - mac_task_queue = task_sched.make_task_queue(); + ue_task_queue = task_sched.make_task_queue(true); + sync_task_queue = task_sched.make_task_queue(true); + gw_task_queue = task_sched.make_task_queue(false); + mac_task_queue = task_sched.make_task_queue(false); } gnb_stack_nr::~gnb_stack_nr() diff --git a/srsue/src/stack/ue_stack_lte.cc b/srsue/src/stack/ue_stack_lte.cc index b3d330d8e..867b7b9b0 100644 --- a/srsue/src/stack/ue_stack_lte.cc +++ b/srsue/src/stack/ue_stack_lte.cc @@ -52,10 +52,9 @@ ue_stack_lte::ue_stack_lte() : tti_tprof("tti_tprof", "STCK", TTI_STAT_PERIOD) { get_background_workers().set_nof_workers(2); - ue_task_queue = task_sched.make_task_queue(); - ue_task_queue.set_notify_mode(); - gw_queue_id = task_sched.make_task_queue(); - cfg_task_queue = task_sched.make_task_queue(); + ue_task_queue = task_sched.make_task_queue(true); + gw_queue_id = task_sched.make_task_queue(false); + cfg_task_queue = task_sched.make_task_queue(false); // sync_queue is added in init() } @@ -199,8 +198,7 @@ int ue_stack_lte::init(const stack_args_t& args_) } // add sync queue - sync_task_queue = task_sched.make_task_queue(args.sync_queue_size); - sync_task_queue.set_notify_mode(); + sync_task_queue = task_sched.make_task_queue(args.sync_queue_size, true); mac.init(phy, &rlc, &rrc); rlc.init(&pdcp, &rrc, &rrc_nr, task_sched.get_timer_handler(), 0 /* RB_ID_SRB0 */); diff --git a/srsue/src/stack/ue_stack_nr.cc b/srsue/src/stack/ue_stack_nr.cc index 59a54d3fc..ffbf784b8 100644 --- a/srsue/src/stack/ue_stack_nr.cc +++ b/srsue/src/stack/ue_stack_nr.cc @@ -33,11 +33,9 @@ ue_stack_nr::ue_stack_nr() : // setup logging for pool, RLC and PDCP byte_buffer_pool::get_instance()->enable_logger(true); - ue_task_queue = task_sched.make_task_queue(); - ue_task_queue.set_notify_mode(); - sync_task_queue = task_sched.make_task_queue(); - sync_task_queue.set_notify_mode(); - gw_task_queue = task_sched.make_task_queue(); + ue_task_queue = task_sched.make_task_queue(true); + sync_task_queue = task_sched.make_task_queue(true); + gw_task_queue = task_sched.make_task_queue(false); } ue_stack_nr::~ue_stack_nr() From b41aba2a0370f3cafff581be1a89c5ea1c4f78e5 Mon Sep 17 00:00:00 2001 From: Francisco Date: Mon, 17 May 2021 19:02:35 +0100 Subject: [PATCH 005/156] fix task scheduler test --- lib/test/common/task_scheduler_test.cc | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/test/common/task_scheduler_test.cc b/lib/test/common/task_scheduler_test.cc index c986c20a8..640c43d2a 100644 --- a/lib/test/common/task_scheduler_test.cc +++ b/lib/test/common/task_scheduler_test.cc @@ -43,7 +43,10 @@ int test_task_scheduler_no_pool() task_sched.notify_background_task_result([&state]() { state = task_result::external; }); }); TESTASSERT(state == task_result::null); - task_sched.run_next_task(); // runs notification + while (state != task_result::external) { + task_sched.run_pending_tasks(); // runs notification + std::this_thread::sleep_for(std::chrono::microseconds(100)); + } TESTASSERT(state == task_result::external); return SRSRAN_SUCCESS; @@ -58,8 +61,10 @@ int test_task_scheduler_with_pool() task_sched.notify_background_task_result([&state]() { state = task_result::external; }); }); TESTASSERT(state == task_result::null); - task_sched.run_next_task(); // waits and runs notification - TESTASSERT(state == task_result::external); + while (state != task_result::external) { + task_sched.run_pending_tasks(); // runs notification + std::this_thread::sleep_for(std::chrono::microseconds(100)); + } return SRSRAN_SUCCESS; } From 60a8ee0af96452d555787f662bfb2145461c162e Mon Sep 17 00:00:00 2001 From: Francisco Date: Wed, 19 May 2021 18:49:06 +0100 Subject: [PATCH 006/156] multiqueue optimization - use condition_var wait_for() method, use queue try_lock in the consumer side --- lib/include/srsran/common/multiqueue.h | 79 ++++++++++++++------------ 1 file changed, 42 insertions(+), 37 deletions(-) diff --git a/lib/include/srsran/common/multiqueue.h b/lib/include/srsran/common/multiqueue.h index 6883fbdc7..0947179b7 100644 --- a/lib/include/srsran/common/multiqueue.h +++ b/lib/include/srsran/common/multiqueue.h @@ -116,18 +116,14 @@ class multiqueue_handler bool try_pop(myobj& obj) { std::unique_lock lock(q_mutex); - if (buffer.empty()) { - consumer_notify_needed = notify_flag; - return false; - } - obj = std::move(buffer.top()); - buffer.pop(); - consumer_notify_needed = false; - if (nof_waiting > 0) { - lock.unlock(); - cv_full.notify_one(); - } - return true; + return pop_(lock, obj); + } + + bool try_pop(myobj& obj, bool& try_lock_success) + { + std::unique_lock lock(q_mutex, std::try_to_lock); + try_lock_success = lock.owns_lock(); + return try_lock_success ? pop_(lock, obj) : false; } private: @@ -165,6 +161,22 @@ class multiqueue_handler return true; } + bool pop_(std::unique_lock& lock, myobj& obj) + { + if (buffer.empty()) { + consumer_notify_needed = notify_flag; + return false; + } + obj = std::move(buffer.top()); + buffer.pop(); + consumer_notify_needed = false; + if (nof_waiting > 0) { + lock.unlock(); + cv_full.notify_one(); + } + return true; + } + multiqueue_handler* parent = nullptr; mutable std::mutex q_mutex; @@ -229,8 +241,7 @@ public: // signal deactivation to pushing threads in a non-blocking way q.set_active(false); } - while (wait_state) { - pushed_data = true; + while (consumer_state) { cv_empty.notify_one(); cv_exit.wait(lock); } @@ -287,17 +298,16 @@ public: bool wait_pop(myobj* value) { std::unique_lock lock(mutex); + consumer_state = true; while (running) { if (round_robin_pop_(value)) { + consumer_state = false; return true; } - pushed_data = false; - wait_state = true; - while (not pushed_data) { - cv_empty.wait(lock); - } - wait_state = false; + cv_empty.wait_for(lock, std::chrono::microseconds(100)); } + consumer_state = false; + lock.unlock(); cv_exit.notify_one(); return false; } @@ -312,36 +322,31 @@ private: bool round_robin_pop_(myobj* value) { // Round-robin for all queues - auto it = queues.begin() + spin_idx; + auto q_it = queues.begin() + spin_idx; uint32_t count = 0; - for (; count < queues.size(); ++count, ++it) { - if (it == queues.end()) { - it = queues.begin(); // wrap-around + for (; count < queues.size(); ++count, ++q_it) { + if (q_it == queues.end()) { + q_it = queues.begin(); // wrap-around } - if (it->try_pop(*value)) { + bool try_lock_success = true; + if (q_it->try_pop(*value, try_lock_success)) { spin_idx = (spin_idx + count + 1) % queues.size(); return true; } + if (not try_lock_success) { + // restart RR search, as there was a collision with a producer + count = 0; + } } return false; } /// Called by the producer threads to signal the consumer to unlock in wait_pop - void signal_pushed_data() - { - { - std::lock_guard lock(mutex); - if (pushed_data) { - return; - } - pushed_data = true; - } - cv_empty.notify_one(); - } + void signal_pushed_data() { cv_empty.notify_one(); } mutable std::mutex mutex; std::condition_variable cv_empty, cv_exit; uint32_t spin_idx = 0; - bool running = true, pushed_data = false, wait_state = false; + bool running = true, consumer_state = false; std::deque queues; uint32_t default_capacity = 0; }; From f2a56c91390ac9c80d6c6f4bdee789b92478b1ec Mon Sep 17 00:00:00 2001 From: Francisco Date: Wed, 19 May 2021 19:18:43 +0100 Subject: [PATCH 007/156] simplification of multiqueue design. - the consumer does multi-staged waiting: 1. spins first across all queues in a RR fashion 2. each queue access is done with a try_lock. 3. if the try_lock fails, it increases the number of spins needed 2. if no queue had data, the consumer sleeps for 100 usec. - no differentiation between queues, in terms of notification features --- lib/include/srsran/common/multiqueue.h | 42 +++++++--------------- lib/include/srsran/common/task_scheduler.h | 13 +++---- lib/test/common/multiqueue_test.cc | 35 +++++++++--------- lib/test/common/network_utils_test.cc | 2 +- srsenb/src/stack/enb_stack_lte.cc | 6 ++-- srsenb/src/stack/gnb_stack_nr.cc | 8 ++--- srsue/src/stack/ue_stack_lte.cc | 8 ++--- srsue/src/stack/ue_stack_nr.cc | 6 ++-- 8 files changed, 50 insertions(+), 70 deletions(-) diff --git a/lib/include/srsran/common/multiqueue.h b/lib/include/srsran/common/multiqueue.h index 0947179b7..7ddcdfb1e 100644 --- a/lib/include/srsran/common/multiqueue.h +++ b/lib/include/srsran/common/multiqueue.h @@ -47,9 +47,7 @@ class multiqueue_handler class input_port_impl { public: - input_port_impl(uint32_t cap, bool notify_flag_, multiqueue_handler* parent_) : - buffer(cap), notify_flag(notify_flag_), consumer_notify_needed(notify_flag_), parent(parent_) - {} + input_port_impl(uint32_t cap, multiqueue_handler* parent_) : buffer(cap), parent(parent_) {} input_port_impl(const input_port_impl&) = delete; input_port_impl(input_port_impl&&) = delete; input_port_impl& operator=(const input_port_impl&) = delete; @@ -57,7 +55,6 @@ class multiqueue_handler ~input_port_impl() { deactivate_blocking(); } size_t capacity() const { return buffer.max_size(); } - bool get_notify_mode() const { return notify_flag; } size_t size() const { std::lock_guard lock(q_mutex); @@ -75,8 +72,7 @@ class multiqueue_handler // no-op return; } - active_ = val; - consumer_notify_needed = notify_flag; + active_ = val; if (not active_) { buffer.clear(); @@ -150,26 +146,16 @@ class multiqueue_handler } } buffer.push(std::forward(*o)); - if (consumer_notify_needed) { - // Note: The consumer thread only needs to be notified and awaken when queues transition from empty to non-empty - // To ensure that the consumer noticed that the queue was empty before a push, we store the last - // try_pop() return in a member variable. - // Doing this reduces the contention of multiple producers for the same condition variable - lock.unlock(); - parent->signal_pushed_data(); - } return true; } bool pop_(std::unique_lock& lock, myobj& obj) { if (buffer.empty()) { - consumer_notify_needed = notify_flag; return false; } obj = std::move(buffer.top()); buffer.pop(); - consumer_notify_needed = false; if (nof_waiting > 0) { lock.unlock(); cv_full.notify_one(); @@ -182,10 +168,8 @@ class multiqueue_handler mutable std::mutex q_mutex; srsran::dyn_circular_buffer buffer; std::condition_variable cv_full, cv_exit; - bool active_ = true; - bool consumer_notify_needed = false; - bool notify_flag = false; - int nof_waiting = 0; + bool active_ = true; + int nof_waiting = 0; }; public: @@ -242,7 +226,6 @@ public: q.set_active(false); } while (consumer_state) { - cv_empty.notify_one(); cv_exit.wait(lock); } for (auto& q : queues) { @@ -256,22 +239,21 @@ public: * @param capacity_ The capacity of the queue. * @return The index of the newly created (or reused) queue within the vector of queues. */ - queue_handle add_queue(uint32_t capacity_, bool notify_flag = false) + queue_handle add_queue(uint32_t capacity_) { uint32_t qidx = 0; std::lock_guard lock(mutex); if (not running) { return queue_handle(); } - while (qidx < queues.size() and (queues[qidx].active() or (queues[qidx].capacity() != capacity_) or - (queues[qidx].get_notify_mode() == notify_flag))) { + while (qidx < queues.size() and (queues[qidx].active() or (queues[qidx].capacity() != capacity_))) { ++qidx; } // check if there is a free queue of the required size if (qidx == queues.size()) { // create new queue - queues.emplace_back(capacity_, notify_flag, this); + queues.emplace_back(capacity_, this); qidx = queues.size() - 1; // update qidx to the last element } else { queues[qidx].set_active(true); @@ -283,7 +265,7 @@ public: * Add queue using the default capacity of the underlying multiqueue * @return The queue index */ - queue_handle add_queue(bool notify_flag) { return add_queue(default_capacity, notify_flag); } + queue_handle add_queue() { return add_queue(default_capacity); } uint32_t nof_queues() const { @@ -304,7 +286,9 @@ public: consumer_state = false; return true; } - cv_empty.wait_for(lock, std::chrono::microseconds(100)); + lock.unlock(); + std::this_thread::sleep_for(std::chrono::microseconds(100)); + lock.lock(); } consumer_state = false; lock.unlock(); @@ -340,11 +324,9 @@ private: } return false; } - /// Called by the producer threads to signal the consumer to unlock in wait_pop - void signal_pushed_data() { cv_empty.notify_one(); } mutable std::mutex mutex; - std::condition_variable cv_empty, cv_exit; + std::condition_variable cv_exit; uint32_t spin_idx = 0; bool running = true, consumer_state = false; std::deque queues; diff --git a/lib/include/srsran/common/task_scheduler.h b/lib/include/srsran/common/task_scheduler.h index 8a73cc7c5..fc0b5d3c5 100644 --- a/lib/include/srsran/common/task_scheduler.h +++ b/lib/include/srsran/common/task_scheduler.h @@ -26,7 +26,7 @@ public: explicit task_scheduler(uint32_t default_extern_tasks_size = 512, uint32_t nof_timers_prealloc = 100) : external_tasks{default_extern_tasks_size}, timers{nof_timers_prealloc} { - background_queue = external_tasks.add_queue(false); + background_queue = external_tasks.add_queue(); } task_scheduler(const task_scheduler&) = delete; task_scheduler(task_scheduler&&) = delete; @@ -38,11 +38,8 @@ public: srsran::unique_timer get_unique_timer() { return timers.get_unique_timer(); } //! Creates new queue for tasks coming from external thread - srsran::task_queue_handle make_task_queue(bool notify_mode) { return external_tasks.add_queue(notify_mode); } - srsran::task_queue_handle make_task_queue(uint32_t qsize, bool notify_mode) - { - return external_tasks.add_queue(qsize, notify_mode); - } + srsran::task_queue_handle make_task_queue() { return external_tasks.add_queue(); } + srsran::task_queue_handle make_task_queue(uint32_t qsize) { return external_tasks.add_queue(qsize); } //! Delays a task processing by duration_ms template @@ -127,7 +124,7 @@ public: sched->defer_callback(duration_ms, std::forward(func)); } void defer_task(srsran::move_task_t func) { sched->defer_task(std::move(func)); } - srsran::task_queue_handle make_task_queue() { return sched->make_task_queue(false); } + srsran::task_queue_handle make_task_queue() { return sched->make_task_queue(); } private: task_scheduler* sched; @@ -144,7 +141,7 @@ public: { sched->notify_background_task_result(std::move(task)); } - srsran::task_queue_handle make_task_queue() { return sched->make_task_queue(false); } + srsran::task_queue_handle make_task_queue() { return sched->make_task_queue(); } template void defer_callback(uint32_t duration_ms, F&& func) { diff --git a/lib/test/common/multiqueue_test.cc b/lib/test/common/multiqueue_test.cc index d906b5571..a82c6b45c 100644 --- a/lib/test/common/multiqueue_test.cc +++ b/lib/test/common/multiqueue_test.cc @@ -32,7 +32,7 @@ int test_multiqueue() TESTASSERT(multiqueue.nof_queues() == 0); // test push/pop and size for one queue - queue_handle qid1 = multiqueue.add_queue(true); + queue_handle qid1 = multiqueue.add_queue(); TESTASSERT(qid1.active()); TESTASSERT(qid1.size() == 0 and qid1.empty()); TESTASSERT(multiqueue.nof_queues() == 1); @@ -45,7 +45,7 @@ int test_multiqueue() TESTASSERT(number == 2 and qid1.empty()); // test push/pop and size for two queues - queue_handle qid2 = multiqueue.add_queue(true); + queue_handle qid2 = multiqueue.add_queue(); TESTASSERT(qid2.active()); TESTASSERT(multiqueue.nof_queues() == 2 and qid1.active()); TESTASSERT(qid2.try_push(3).has_value()); @@ -55,7 +55,7 @@ int test_multiqueue() // check if erasing a queue breaks anything qid1.reset(); TESTASSERT(multiqueue.nof_queues() == 1 and not qid1.active()); - qid1 = multiqueue.add_queue(true); + qid1 = multiqueue.add_queue(); TESTASSERT(qid1.empty() and qid1.active()); TESTASSERT(qid2.size() == 1 and not qid2.empty()); multiqueue.wait_pop(&number); @@ -89,15 +89,15 @@ int test_multiqueue() // check that adding a queue of different capacity works { - qid1 = multiqueue.add_queue(true); - qid2 = multiqueue.add_queue(true); + qid1 = multiqueue.add_queue(); + qid2 = multiqueue.add_queue(); // remove first queue again qid1.reset(); TESTASSERT(multiqueue.nof_queues() == 1); // add queue with non-default capacity - auto qid3 = multiqueue.add_queue(10, true); + auto qid3 = multiqueue.add_queue(10); TESTASSERT(qid3.capacity() == 10); // make sure neither a new queue index is returned @@ -117,7 +117,7 @@ int test_multiqueue_threading() int capacity = 4, number = 0, start_number = 2, nof_pushes = capacity + 1; multiqueue_handler multiqueue(capacity); - auto qid1 = multiqueue.add_queue(true); + auto qid1 = multiqueue.add_queue(); auto push_blocking_func = [](queue_handle* qid, int start_value, int nof_pushes, bool* is_running) { for (int i = 0; i < nof_pushes; ++i) { qid->push(start_value + i); @@ -165,7 +165,7 @@ int test_multiqueue_threading2() int capacity = 4, start_number = 2, nof_pushes = capacity + 1; multiqueue_handler multiqueue(capacity); - auto qid1 = multiqueue.add_queue(true); + auto qid1 = multiqueue.add_queue(); auto push_blocking_func = [](queue_handle* qid, int start_value, int nof_pushes, bool* is_running) { for (int i = 0; i < nof_pushes; ++i) { qid->push(start_value + i); @@ -199,7 +199,7 @@ int test_multiqueue_threading3() int capacity = 4; multiqueue_handler multiqueue(capacity); - auto qid1 = multiqueue.add_queue(true); + auto qid1 = multiqueue.add_queue(); auto pop_blocking_func = [&multiqueue](bool* success) { int number = 0; bool ret = multiqueue.wait_pop(&number); @@ -235,10 +235,10 @@ int test_multiqueue_threading4() int capacity = 4; multiqueue_handler multiqueue(capacity); - auto qid1 = multiqueue.add_queue(true); - auto qid2 = multiqueue.add_queue(true); - auto qid3 = multiqueue.add_queue(true); - auto qid4 = multiqueue.add_queue(true); + auto qid1 = multiqueue.add_queue(); + auto qid2 = multiqueue.add_queue(); + auto qid3 = multiqueue.add_queue(); + auto qid4 = multiqueue.add_queue(); std::mutex mutex; int last_number = -1; auto pop_blocking_func = [&multiqueue, &last_number, &mutex](bool* success) { @@ -348,9 +348,10 @@ int test_task_thread_pool2() // Description: push a very long task to all workers, and call thread_pool.stop() to check if it waits for the tasks // to be completed, and does not get stuck. - uint32_t nof_workers = 4; - uint8_t workers_started = 0, workers_finished = 0; - std::mutex mut; + uint32_t nof_workers = 4; + std::atomic workers_started{0}; + uint8_t workers_finished = 0; + std::mutex mut; task_thread_pool thread_pool(nof_workers); thread_pool.start(); @@ -360,7 +361,7 @@ int test_task_thread_pool2() std::lock_guard lock(mut); workers_started++; } - sleep(1); + std::this_thread::sleep_for(std::chrono::seconds{1}); std::lock_guard lock(mut); std::cout << "worker has finished\n"; workers_finished++; diff --git a/lib/test/common/network_utils_test.cc b/lib/test/common/network_utils_test.cc index fcaf6dd12..2a9290777 100644 --- a/lib/test/common/network_utils_test.cc +++ b/lib/test/common/network_utils_test.cc @@ -23,7 +23,7 @@ struct rx_thread_tester { std::thread t; rx_thread_tester() : - task_queue(task_sched.make_task_queue(true)), + task_queue(task_sched.make_task_queue()), t([this]() { stop_token.store(false); while (not stop_token.load(std::memory_order_relaxed)) { diff --git a/srsenb/src/stack/enb_stack_lte.cc b/srsenb/src/stack/enb_stack_lte.cc index ac299ddcc..4f27efe0c 100644 --- a/srsenb/src/stack/enb_stack_lte.cc +++ b/srsenb/src/stack/enb_stack_lte.cc @@ -41,8 +41,8 @@ enb_stack_lte::enb_stack_lte(srslog::sink& log_sink) : pending_stack_metrics(64) { get_background_workers().set_nof_workers(2); - enb_task_queue = task_sched.make_task_queue(true); - metrics_task_queue = task_sched.make_task_queue(false); + enb_task_queue = task_sched.make_task_queue(); + metrics_task_queue = task_sched.make_task_queue(); // sync_queue is added in init() } @@ -115,7 +115,7 @@ int enb_stack_lte::init(const stack_args_t& args_, const rrc_cfg_t& rrc_cfg_) } // add sync queue - sync_task_queue = task_sched.make_task_queue(args.sync_queue_size, true); + sync_task_queue = task_sched.make_task_queue(args.sync_queue_size); // Init all layers if (!mac.init(args.mac, rrc_cfg.cell_list, phy, &rlc, &rrc)) { diff --git a/srsenb/src/stack/gnb_stack_nr.cc b/srsenb/src/stack/gnb_stack_nr.cc index a8ba3b3e4..223798334 100644 --- a/srsenb/src/stack/gnb_stack_nr.cc +++ b/srsenb/src/stack/gnb_stack_nr.cc @@ -26,10 +26,10 @@ gnb_stack_nr::gnb_stack_nr() : task_sched{512, 128}, thread("gNB"), rlc_logger(s m_gw.reset(new srsue::gw()); // m_gtpu.reset(new srsenb::gtpu()); - ue_task_queue = task_sched.make_task_queue(true); - sync_task_queue = task_sched.make_task_queue(true); - gw_task_queue = task_sched.make_task_queue(false); - mac_task_queue = task_sched.make_task_queue(false); + ue_task_queue = task_sched.make_task_queue(); + sync_task_queue = task_sched.make_task_queue(); + gw_task_queue = task_sched.make_task_queue(); + mac_task_queue = task_sched.make_task_queue(); } gnb_stack_nr::~gnb_stack_nr() diff --git a/srsue/src/stack/ue_stack_lte.cc b/srsue/src/stack/ue_stack_lte.cc index 867b7b9b0..e903a4a27 100644 --- a/srsue/src/stack/ue_stack_lte.cc +++ b/srsue/src/stack/ue_stack_lte.cc @@ -52,9 +52,9 @@ ue_stack_lte::ue_stack_lte() : tti_tprof("tti_tprof", "STCK", TTI_STAT_PERIOD) { get_background_workers().set_nof_workers(2); - ue_task_queue = task_sched.make_task_queue(true); - gw_queue_id = task_sched.make_task_queue(false); - cfg_task_queue = task_sched.make_task_queue(false); + ue_task_queue = task_sched.make_task_queue(); + gw_queue_id = task_sched.make_task_queue(); + cfg_task_queue = task_sched.make_task_queue(); // sync_queue is added in init() } @@ -198,7 +198,7 @@ int ue_stack_lte::init(const stack_args_t& args_) } // add sync queue - sync_task_queue = task_sched.make_task_queue(args.sync_queue_size, true); + sync_task_queue = task_sched.make_task_queue(args.sync_queue_size); mac.init(phy, &rlc, &rrc); rlc.init(&pdcp, &rrc, &rrc_nr, task_sched.get_timer_handler(), 0 /* RB_ID_SRB0 */); diff --git a/srsue/src/stack/ue_stack_nr.cc b/srsue/src/stack/ue_stack_nr.cc index ffbf784b8..33ed31c5f 100644 --- a/srsue/src/stack/ue_stack_nr.cc +++ b/srsue/src/stack/ue_stack_nr.cc @@ -33,9 +33,9 @@ ue_stack_nr::ue_stack_nr() : // setup logging for pool, RLC and PDCP byte_buffer_pool::get_instance()->enable_logger(true); - ue_task_queue = task_sched.make_task_queue(true); - sync_task_queue = task_sched.make_task_queue(true); - gw_task_queue = task_sched.make_task_queue(false); + ue_task_queue = task_sched.make_task_queue(); + sync_task_queue = task_sched.make_task_queue(); + gw_task_queue = task_sched.make_task_queue(); } ue_stack_nr::~ue_stack_nr() From b0935766340b4841a8a8c20e0761469b848f90dc Mon Sep 17 00:00:00 2001 From: Francisco Date: Wed, 19 May 2021 19:56:07 +0100 Subject: [PATCH 008/156] avoid sending UEContextReleaseRequest from Source eNB during S1 Handover. --- lib/include/srsran/adt/scope_exit.h | 2 +- srsenb/src/stack/rrc/rrc_ue.cc | 26 +++++++++++--------------- srsenb/src/stack/s1ap/s1ap.cc | 21 ++++++++++++++------- 3 files changed, 26 insertions(+), 23 deletions(-) diff --git a/lib/include/srsran/adt/scope_exit.h b/lib/include/srsran/adt/scope_exit.h index 37af5148c..54f60e899 100644 --- a/lib/include/srsran/adt/scope_exit.h +++ b/lib/include/srsran/adt/scope_exit.h @@ -60,7 +60,7 @@ detail::scope_exit::type> make_scope_exit(Callable return detail::scope_exit::type>{std::forward(callable)}; } -#define DEFER(FUNC) auto on_exit_call = make_scope_exit([&]() { FUNC }) +#define DEFER(FUNC) auto on_exit_call##__LINE__ = srsran::make_scope_exit([&]() { FUNC }) } // namespace srsran diff --git a/srsenb/src/stack/rrc/rrc_ue.cc b/srsenb/src/stack/rrc/rrc_ue.cc index 10bb55d72..7c164a0d7 100644 --- a/srsenb/src/stack/rrc/rrc_ue.cc +++ b/srsenb/src/stack/rrc/rrc_ue.cc @@ -206,29 +206,25 @@ void rrc::ue::rlf_timer_expired(uint32_t timeout_id) parent->logger.info("RLC RLF timer for rnti=0x%x expired after %d ms", rnti, rlc_rlf_timer.time_elapsed()); } + phy_ul_rlf_timer.stop(); + phy_dl_rlf_timer.stop(); + rlc_rlf_timer.stop(); + state = RRC_STATE_RELEASE_REQUEST; + if (parent->s1ap->user_release(rnti, asn1::s1ap::cause_radio_network_opts::radio_conn_with_ue_lost)) { con_release_result = procedure_result_code::radio_conn_with_ue_lost; - phy_ul_rlf_timer.stop(); - phy_dl_rlf_timer.stop(); - rlc_rlf_timer.stop(); - } else { - if (rnti != SRSRAN_MRNTI) { - parent->rem_user(rnti); - } + } else if (rnti != SRSRAN_MRNTI) { + parent->rem_user(rnti); } - - state = RRC_STATE_RELEASE_REQUEST; } void rrc::ue::max_rlc_retx_reached() { - if (parent) { - parent->logger.info("Max RLC retx reached for rnti=0x%x", rnti); + parent->logger.info("Max RLC retx reached for rnti=0x%x", rnti); - // Turn off DRB scheduling but give UE chance to start re-establishment - rlc_rlf_timer.run(); - mac_ctrl.handle_max_retx(); - } + // Turn off DRB scheduling but give UE chance to start re-establishment + rlc_rlf_timer.run(); + mac_ctrl.handle_max_retx(); } void rrc::ue::set_activity_timeout(const activity_timeout_type_t type) diff --git a/srsenb/src/stack/s1ap/s1ap.cc b/srsenb/src/stack/s1ap/s1ap.cc index 551a3ec41..16edf76bd 100644 --- a/srsenb/src/stack/s1ap/s1ap.cc +++ b/srsenb/src/stack/s1ap/s1ap.cc @@ -420,11 +420,7 @@ bool s1ap::user_release(uint16_t rnti, asn1::s1ap::cause_radio_network_e cause_r cause_c cause; cause.set_radio_network().value = cause_radio.value; - if (not u->send_uectxtreleaserequest(cause)) { - users.erase(u); - return false; - } - return true; + return u->send_uectxtreleaserequest(cause); } bool s1ap::user_exists(uint16_t rnti) @@ -1400,14 +1396,21 @@ bool s1ap::ue::send_uectxtreleaserequest(const cause_c& cause) { if (was_uectxtrelease_requested()) { logger.warning("UE context for RNTI:0x%x is in zombie state. Releasing...", ctxt.rnti); + s1ap_ptr->users.erase(this); return false; } if (not ctxt.mme_ue_s1ap_id.has_value()) { logger.error("Cannot send UE context release request without a MME-UE-S1AP-Id allocated."); + s1ap_ptr->users.erase(this); + return false; + } + + if (ts1_reloc_overall.is_running()) { + logger.info("Not sending UEContextReleaseRequest for UE rnti=0x%x performing S1 Handover.", ctxt.rnti); + s1ap_ptr->users.erase(this); return false; } - release_requested = true; s1ap_pdu_c tx_pdu; tx_pdu.set_init_msg().load_info_obj(ASN1_S1AP_ID_UE_CONTEXT_RELEASE_REQUEST); ue_context_release_request_ies_container& container = @@ -1418,7 +1421,11 @@ bool s1ap::ue::send_uectxtreleaserequest(const cause_c& cause) // Cause container.cause.value = cause; - return s1ap_ptr->sctp_send_s1ap_pdu(tx_pdu, ctxt.rnti, "UEContextReleaseRequest"); + release_requested = s1ap_ptr->sctp_send_s1ap_pdu(tx_pdu, ctxt.rnti, "UEContextReleaseRequest"); + if (not release_requested) { + s1ap_ptr->users.erase(this); + } + return release_requested; } bool s1ap::ue::send_uectxtreleasecomplete() From e07ef0aa189f96ccb6cae6fbaba656425b189271 Mon Sep 17 00:00:00 2001 From: Francisco Date: Thu, 20 May 2021 11:13:13 +0100 Subject: [PATCH 009/156] avoid releasing ues doing s1 handover before TS1relocoverall expiry --- srsenb/src/stack/rrc/rrc_ue.cc | 78 +++++++++++++++++----------------- srsenb/src/stack/s1ap/s1ap.cc | 9 +++- 2 files changed, 45 insertions(+), 42 deletions(-) diff --git a/srsenb/src/stack/rrc/rrc_ue.cc b/srsenb/src/stack/rrc/rrc_ue.cc index 7c164a0d7..0fe8546c8 100644 --- a/srsenb/src/stack/rrc/rrc_ue.cc +++ b/srsenb/src/stack/rrc/rrc_ue.cc @@ -62,12 +62,20 @@ int rrc::ue::init() set_activity_timeout(MSG3_RX_TIMEOUT); // next UE response is Msg3 // Set timeout to release UE context after RLF detection - uint32_t deadline_ms = parent->cfg.rlf_release_timer_ms; - auto timer_expire_func = [this](uint32_t tid) { rlf_timer_expired(tid); }; - phy_dl_rlf_timer.set(deadline_ms, timer_expire_func); - phy_ul_rlf_timer.set(deadline_ms, timer_expire_func); - rlc_rlf_timer.set(deadline_ms, timer_expire_func); - parent->logger.info("Setting RLF timer for rnti=0x%x to %dms", rnti, deadline_ms); + uint32_t deadline_ms = parent->cfg.rlf_release_timer_ms; + if (rnti != SRSRAN_MRNTI) { + auto timer_expire_func = [this](uint32_t tid) { rlf_timer_expired(tid); }; + phy_dl_rlf_timer.set(deadline_ms, timer_expire_func); + phy_ul_rlf_timer.set(deadline_ms, timer_expire_func); + rlc_rlf_timer.set(deadline_ms, timer_expire_func); + parent->logger.info("Setting RLF timer for rnti=0x%x to %dms", rnti, deadline_ms); + } else { + // in case of M-RNTI do not handle rlf timer expiration + auto timer_expire_func = [](uint32_t tid) {}; + phy_dl_rlf_timer.set(deadline_ms, timer_expire_func); + phy_ul_rlf_timer.set(deadline_ms, timer_expire_func); + rlc_rlf_timer.set(deadline_ms, timer_expire_func); + } mobility_handler = make_rnti_obj(rnti, this); return SRSRAN_SUCCESS; @@ -94,11 +102,12 @@ void rrc::ue::get_metrics(rrc_ue_metrics_t& ue_metrics) const void rrc::ue::set_activity() { + if (rnti == SRSRAN_MRNTI) { + return; + } // re-start activity timer with current timeout value activity_timer.run(); - if (parent) { - parent->logger.debug("Activity registered for rnti=0x%x (timeout_value=%dms)", rnti, activity_timer.duration()); - } + parent->logger.debug("Activity registered for rnti=0x%x (timeout_value=%dms)", rnti, activity_timer.duration()); } void rrc::ue::set_radiolink_dl_state(bool crc_res) @@ -165,31 +174,25 @@ void rrc::ue::set_radiolink_ul_state(bool crc_res) void rrc::ue::activity_timer_expired(const activity_timeout_type_t type) { - if (parent) { - parent->logger.info("Activity timer for rnti=0x%x expired after %d ms", rnti, activity_timer.time_elapsed()); - - if (parent->s1ap->user_exists(rnti)) { - if (type == UE_INACTIVITY_TIMEOUT) { - if (not parent->s1ap->user_release(rnti, asn1::s1ap::cause_radio_network_opts::user_inactivity)) { - parent->rem_user_thread(rnti); - } - con_release_result = procedure_result_code::activity_timeout; - } else if (type == MSG3_RX_TIMEOUT) { - // MSG3 timeout, no need to notify S1AP, just remove UE - parent->rem_user_thread(rnti); - con_release_result = procedure_result_code::msg3_timeout; - } else { - // Unhandled activity timeout, just remove UE and log an error - parent->rem_user_thread(rnti); - con_release_result = procedure_result_code::activity_timeout; - parent->logger.error( - "Unhandled reason for activity timer expiration. rnti=0x%x, cause %d", rnti, static_cast(type)); - } + parent->logger.info("Activity timer for rnti=0x%x expired after %d ms", rnti, activity_timer.time_elapsed()); + + if (parent->s1ap->user_exists(rnti)) { + if (type == UE_INACTIVITY_TIMEOUT) { + parent->s1ap->user_release(rnti, asn1::s1ap::cause_radio_network_opts::user_inactivity); + con_release_result = procedure_result_code::activity_timeout; + } else if (type == MSG3_RX_TIMEOUT) { + // MSG3 timeout, no need to notify S1AP, just remove UE + parent->rem_user_thread(rnti); + con_release_result = procedure_result_code::msg3_timeout; } else { - if (rnti != SRSRAN_MRNTI) { - parent->rem_user_thread(rnti); - } + // Unhandled activity timeout, just remove UE and log an error + parent->rem_user_thread(rnti); + con_release_result = procedure_result_code::activity_timeout; + parent->logger.error( + "Unhandled reason for activity timer expiration. rnti=0x%x, cause %d", rnti, static_cast(type)); } + } else { + parent->rem_user_thread(rnti); } state = RRC_STATE_RELEASE_REQUEST; @@ -211,11 +214,8 @@ void rrc::ue::rlf_timer_expired(uint32_t timeout_id) rlc_rlf_timer.stop(); state = RRC_STATE_RELEASE_REQUEST; - if (parent->s1ap->user_release(rnti, asn1::s1ap::cause_radio_network_opts::radio_conn_with_ue_lost)) { - con_release_result = procedure_result_code::radio_conn_with_ue_lost; - } else if (rnti != SRSRAN_MRNTI) { - parent->rem_user(rnti); - } + parent->s1ap->user_release(rnti, asn1::s1ap::cause_radio_network_opts::radio_conn_with_ue_lost); + con_release_result = procedure_result_code::radio_conn_with_ue_lost; } void rrc::ue::max_rlc_retx_reached() @@ -390,9 +390,7 @@ void rrc::ue::handle_rrc_con_req(rrc_conn_request_s* msg) if (user.first != rnti && user.second->has_tmsi && user.second->mmec == mmec && user.second->m_tmsi == m_tmsi) { parent->logger.info("RRC connection request: UE context already exists. M-TMSI=%d", m_tmsi); user.second->state = RRC_STATE_IDLE; // Set old rnti to IDLE so that enb doesn't send RRC Connection Release - if (not parent->s1ap->user_release(user.first, asn1::s1ap::cause_radio_network_opts::radio_conn_with_ue_lost)) { - parent->rem_user_thread(user.first); - } + parent->s1ap->user_release(user.first, asn1::s1ap::cause_radio_network_opts::radio_conn_with_ue_lost); break; } } diff --git a/srsenb/src/stack/s1ap/s1ap.cc b/srsenb/src/stack/s1ap/s1ap.cc index 16edf76bd..42890435a 100644 --- a/srsenb/src/stack/s1ap/s1ap.cc +++ b/srsenb/src/stack/s1ap/s1ap.cc @@ -414,6 +414,7 @@ bool s1ap::user_release(uint16_t rnti, asn1::s1ap::cause_radio_network_e cause_r ue* u = users.find_ue_rnti(rnti); if (u == nullptr) { logger.warning("Released UE with rnti=0x%x not found", rnti); + rrc->release_ue(rnti); return false; } @@ -1396,18 +1397,21 @@ bool s1ap::ue::send_uectxtreleaserequest(const cause_c& cause) { if (was_uectxtrelease_requested()) { logger.warning("UE context for RNTI:0x%x is in zombie state. Releasing...", ctxt.rnti); + s1ap_ptr->rrc->release_ue(ctxt.rnti); s1ap_ptr->users.erase(this); return false; } if (not ctxt.mme_ue_s1ap_id.has_value()) { logger.error("Cannot send UE context release request without a MME-UE-S1AP-Id allocated."); + s1ap_ptr->rrc->release_ue(ctxt.rnti); s1ap_ptr->users.erase(this); return false; } if (ts1_reloc_overall.is_running()) { - logger.info("Not sending UEContextReleaseRequest for UE rnti=0x%x performing S1 Handover.", ctxt.rnti); - s1ap_ptr->users.erase(this); + logger.info("Ignoring UE context release request from lower layers for UE rnti=0x%x performing S1 Handover.", + ctxt.rnti); + // leave the UE context alive until ts1_reloc_overall expiry return false; } @@ -1423,6 +1427,7 @@ bool s1ap::ue::send_uectxtreleaserequest(const cause_c& cause) release_requested = s1ap_ptr->sctp_send_s1ap_pdu(tx_pdu, ctxt.rnti, "UEContextReleaseRequest"); if (not release_requested) { + s1ap_ptr->rrc->release_ue(ctxt.rnti); s1ap_ptr->users.erase(this); } return release_requested; From 41bc7e48109a362e5259cb05d13a7c872b4509d7 Mon Sep 17 00:00:00 2001 From: Francisco Date: Fri, 21 May 2021 21:02:47 +0100 Subject: [PATCH 010/156] avoid letting repeated s1ap::user_release calls to deem the user as in zombie state. Use timer instead to auto-remove user from s1ap if no response from mme arrives --- srsenb/hdr/stack/s1ap/s1ap.h | 1 + srsenb/src/stack/s1ap/s1ap.cc | 22 ++++++++++++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/srsenb/hdr/stack/s1ap/s1ap.h b/srsenb/hdr/stack/s1ap/s1ap.h index 5615a105a..73e214b93 100644 --- a/srsenb/hdr/stack/s1ap/s1ap.h +++ b/srsenb/hdr/stack/s1ap/s1ap.h @@ -277,6 +277,7 @@ private: bool release_requested = false; srsran::unique_timer ts1_reloc_prep; ///< TS1_{RELOCprep} - max time for HO preparation srsran::unique_timer ts1_reloc_overall; ///< TS1_{RELOCOverall} + srsran::unique_timer overall_procedure_timeout; // Procedure state s1ap_proc_id_t current_state = s1ap_proc_id_t::nulltype; diff --git a/srsenb/src/stack/s1ap/s1ap.cc b/srsenb/src/stack/s1ap/s1ap.cc index 42890435a..2f722be92 100644 --- a/srsenb/src/stack/s1ap/s1ap.cc +++ b/srsenb/src/stack/s1ap/s1ap.cc @@ -1395,12 +1395,6 @@ bool s1ap::ue::send_ulnastransport(srsran::unique_byte_buffer_t pdu) bool s1ap::ue::send_uectxtreleaserequest(const cause_c& cause) { - if (was_uectxtrelease_requested()) { - logger.warning("UE context for RNTI:0x%x is in zombie state. Releasing...", ctxt.rnti); - s1ap_ptr->rrc->release_ue(ctxt.rnti); - s1ap_ptr->users.erase(this); - return false; - } if (not ctxt.mme_ue_s1ap_id.has_value()) { logger.error("Cannot send UE context release request without a MME-UE-S1AP-Id allocated."); s1ap_ptr->rrc->release_ue(ctxt.rnti); @@ -1415,6 +1409,11 @@ bool s1ap::ue::send_uectxtreleaserequest(const cause_c& cause) return false; } + if (was_uectxtrelease_requested()) { + // let timeout auto-remove user. + return false; + } + s1ap_pdu_c tx_pdu; tx_pdu.set_init_msg().load_info_obj(ASN1_S1AP_ID_UE_CONTEXT_RELEASE_REQUEST); ue_context_release_request_ies_container& container = @@ -1429,12 +1428,21 @@ bool s1ap::ue::send_uectxtreleaserequest(const cause_c& cause) if (not release_requested) { s1ap_ptr->rrc->release_ue(ctxt.rnti); s1ap_ptr->users.erase(this); + } else { + overall_procedure_timeout.set(10000, [this](uint32_t tid) { + logger.warning("UE context for RNTI:0x%x is in zombie state. Releasing...", ctxt.rnti); + s1ap_ptr->rrc->release_ue(ctxt.rnti); + s1ap_ptr->users.erase(this); + }); + overall_procedure_timeout.run(); } return release_requested; } bool s1ap::ue::send_uectxtreleasecomplete() { + overall_procedure_timeout.stop(); + s1ap_pdu_c tx_pdu; tx_pdu.set_successful_outcome().load_info_obj(ASN1_S1AP_ID_UE_CONTEXT_RELEASE); auto& container = tx_pdu.successful_outcome().value.ue_context_release_complete().protocol_ies; @@ -1964,6 +1972,8 @@ s1ap::ue::ue(s1ap* s1ap_ptr_) : s1ap_ptr(s1ap_ptr_), ho_prep_proc(this), logger( // TS1RELOCOverall, the eNB shall request the MME to release the UE context. s1ap_ptr->user_release(ctxt.rnti, asn1::s1ap::cause_radio_network_opts::ts1relocoverall_expiry); }); + overall_procedure_timeout = s1ap_ptr->task_sched.get_unique_timer(); + overall_procedure_timeout.set(10000); } bool s1ap::ue::send_ho_required(uint32_t target_eci, From 31936c9754f75ea1f5830fdfb15fedb98cfb1509 Mon Sep 17 00:00:00 2001 From: Francisco Date: Fri, 21 May 2021 10:40:59 +0100 Subject: [PATCH 011/156] bugfix - printf formatting incorrect in bounded_bitset method --- lib/include/srsran/adt/bounded_bitset.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/include/srsran/adt/bounded_bitset.h b/lib/include/srsran/adt/bounded_bitset.h index d16966c39..552d98319 100644 --- a/lib/include/srsran/adt/bounded_bitset.h +++ b/lib/include/srsran/adt/bounded_bitset.h @@ -366,7 +366,8 @@ public: void from_uint64(uint64_t v) { srsran_assert(nof_words_() == 1, "ERROR: cannot convert bitset of size=%zd to uint64_t", size()); - srsran_assert(v < (1U << size()), "ERROR: Provided uint64=%ld does not fit in bitset of size=%zd", v, size()); + srsran_assert( + v < (1U << size()), "ERROR: Provided mask=0x%" PRIx64 " does not fit in bitset of size=%zd", v, size()); buffer[0] = v; } From 8df6ed07c665254104e2a63577a044caea9a0572 Mon Sep 17 00:00:00 2001 From: Francisco Date: Thu, 20 May 2021 18:24:16 +0100 Subject: [PATCH 012/156] sched small fixes - use 0.930 instead of 0.932 for max coderate. Allow computing mcs/tbs based on max coderate directly. Other small fixes --- lib/include/srsran/adt/accumulators.h | 13 ++++++---- srsenb/hdr/stack/mac/sched_phy_ch/sched_dci.h | 13 ++++++++++ .../src/stack/mac/sched_phy_ch/sched_dci.cc | 24 +++++++++++++------ srsenb/src/stack/mac/sched_ue.cc | 8 +------ .../stack/mac/sched_ue_ctrl/sched_ue_cell.cc | 6 +++++ srsenb/test/mac/sched_benchmark.cc | 2 +- 6 files changed, 46 insertions(+), 20 deletions(-) diff --git a/lib/include/srsran/adt/accumulators.h b/lib/include/srsran/adt/accumulators.h index 29b4ece6b..e6b8d639b 100644 --- a/lib/include/srsran/adt/accumulators.h +++ b/lib/include/srsran/adt/accumulators.h @@ -38,8 +38,10 @@ private: template struct exp_average_fast_start { - exp_average_fast_start(T alpha_, uint32_t start_size = 100) : alpha(alpha_), start_count_size(start_size) + exp_average_fast_start(T alpha_val) : exp_average_fast_start(alpha_val, 1.0 / alpha_val) {} + exp_average_fast_start(T alpha_val, uint32_t start_size) : alpha_(alpha_val), start_count_size(start_size) { + assert(alpha_ < 1); assert(start_size > 0); } void push(T sample) @@ -48,16 +50,18 @@ struct exp_average_fast_start { avg_ += (sample - avg_) / (count + 1); count++; } else { - avg_ = (1 - alpha) * avg_ + alpha * sample; + avg_ = (1 - alpha_) * avg_ + alpha_ * sample; } } - T value() const { return count == 0 ? 0 : avg_; } + T value() const { return count == 0 ? 0 : avg_; } + T alpha() const { return alpha_; } + bool is_exp_average_mode() const { return count >= start_count_size; } private: T avg_ = 0; uint32_t count = 0; uint32_t start_count_size; - T alpha; + T alpha_; }; namespace detail { @@ -112,7 +116,6 @@ private: template struct null_sliding_average { - null_sliding_average(uint32_t N) : window(N, null_value()) {} void push(T sample) { window.push(sample); } void push_hole() { window.push(null_value()); } diff --git a/srsenb/hdr/stack/mac/sched_phy_ch/sched_dci.h b/srsenb/hdr/stack/mac/sched_phy_ch/sched_dci.h index 07a5c6e00..97eb9b44b 100644 --- a/srsenb/hdr/stack/mac/sched_phy_ch/sched_dci.h +++ b/srsenb/hdr/stack/mac/sched_phy_ch/sched_dci.h @@ -47,6 +47,19 @@ tbs_info compute_mcs_and_tbs(uint32_t nof_prb, bool ulqam64_enabled, bool use_tbs_index_alt); +/** + * Compute MCS, TBS based on maximum coderate, N_prb + * \remark See TS 36.213 - Table 7.1.7.1-1/1A + * @return resulting TBS (in bytes) and mcs. TBS=-1 if no valid solution was found. + */ +tbs_info compute_mcs_and_tbs(uint32_t nof_prb, + uint32_t nof_re, + float max_coderate, + uint32_t max_mcs, + bool is_ul, + bool ulqam64_enabled, + bool use_tbs_index_alt); + /** * Compute lowest MCS, TBS based on CQI, N_prb that satisfies TBS >= req_bytes (best effort) * \remark See TS 36.213 - Table 7.1.7.1-1/1A diff --git a/srsenb/src/stack/mac/sched_phy_ch/sched_dci.cc b/srsenb/src/stack/mac/sched_phy_ch/sched_dci.cc index ed0c044ac..2df511b97 100644 --- a/srsenb/src/stack/mac/sched_phy_ch/sched_dci.cc +++ b/srsenb/src/stack/mac/sched_phy_ch/sched_dci.cc @@ -77,16 +77,26 @@ tbs_info compute_mcs_and_tbs(uint32_t nof_prb, bool is_ul, bool ulqam64_enabled, bool use_tbs_index_alt) +{ + float max_coderate = srsran_cqi_to_coderate(std::min(cqi + 1U, 15U), use_tbs_index_alt); + return compute_mcs_and_tbs(nof_prb, nof_re, max_coderate, max_mcs, is_ul, ulqam64_enabled, use_tbs_index_alt); +} + +tbs_info compute_mcs_and_tbs(uint32_t nof_prb, + uint32_t nof_re, + float max_coderate, + uint32_t max_mcs, + bool is_ul, + bool ulqam64_enabled, + bool use_tbs_index_alt) { assert((not is_ul or not use_tbs_index_alt) && "UL cannot use Alt CQI Table"); assert((is_ul or not ulqam64_enabled) && "DL cannot use UL-QAM64 enable flag"); - float max_coderate = srsran_cqi_to_coderate(std::min(cqi + 1U, 15U), use_tbs_index_alt); - uint32_t max_Qm = (is_ul) ? (ulqam64_enabled ? 6 : 4) : (use_tbs_index_alt ? 8 : 6); - max_coderate = std::min(max_coderate, 0.932F * max_Qm); + uint32_t max_Qm = (is_ul) ? (ulqam64_enabled ? 6 : 4) : (use_tbs_index_alt ? 8 : 6); + max_coderate = std::min(max_coderate, 0.930F * max_Qm); - int mcs = 0; - float prev_max_coderate = 0; + int mcs = 0; do { // update max TBS based on max coderate int max_tbs = coderate_to_tbs(max_coderate, nof_re); @@ -113,7 +123,7 @@ tbs_info compute_mcs_and_tbs(uint32_t nof_prb, // update max coderate based on mcs srsran_mod_t mod = (is_ul) ? srsran_ra_ul_mod_from_mcs(mcs) : srsran_ra_dl_mod_from_mcs(mcs, use_tbs_index_alt); uint32_t Qm = srsran_mod_bits_x_symbol(mod); - max_coderate = std::min(0.932F * Qm, max_coderate); + max_coderate = std::min(0.930F * Qm, max_coderate); if (coderate <= max_coderate) { // solution was found @@ -125,7 +135,7 @@ tbs_info compute_mcs_and_tbs(uint32_t nof_prb, // start with smaller max mcs in next iteration max_mcs = mcs - 1; - } while (mcs > 0 and max_coderate != prev_max_coderate); + } while (mcs > 0); return tbs_info{}; } diff --git a/srsenb/src/stack/mac/sched_ue.cc b/srsenb/src/stack/mac/sched_ue.cc index 5acba07ea..67a8badf7 100644 --- a/srsenb/src/stack/mac/sched_ue.cc +++ b/srsenb/src/stack/mac/sched_ue.cc @@ -93,15 +93,9 @@ void sched_ue::new_subframe(tti_point tti_rx, uint32_t enb_cc_idx) current_tti = tti_rx; lch_handler.new_tti(); for (auto& cc : cells) { - if (cc.configured()) { - cc.harq_ent.new_tti(tti_rx); - } + cc.new_tti(tti_rx); } } - - if (cells[enb_cc_idx].configured()) { - cells[enb_cc_idx].tpc_fsm.new_tti(); - } } /******************************************************* diff --git a/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc b/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc index 416b11981..9b8d84396 100644 --- a/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc +++ b/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc @@ -114,8 +114,14 @@ void sched_ue_cell::set_ue_cfg(const sched_interface::ue_cfg_t& ue_cfg_) void sched_ue_cell::new_tti(tti_point tti_rx) { + if (not configured()) { + return; + } current_tti = tti_rx; + harq_ent.new_tti(tti_rx); + tpc_fsm.new_tti(); + // Check if cell state needs to be updated if (ue_cc_idx > 0 and cc_state_ == cc_st::deactivating) { // wait for all ACKs to be received before completely deactivating SCell diff --git a/srsenb/test/mac/sched_benchmark.cc b/srsenb/test/mac/sched_benchmark.cc index c26980a87..8af5e24ad 100644 --- a/srsenb/test/mac/sched_benchmark.cc +++ b/srsenb/test/mac/sched_benchmark.cc @@ -246,7 +246,7 @@ run_data expected_run_result(run_params params) break; default: ret.avg_dl_throughput *= 0.96; - ret.avg_ul_throughput *= 0.85; + ret.avg_ul_throughput *= 0.84; break; } return ret; From a17e3b71e73d9cfc8ee4027a888e5347833a2dda Mon Sep 17 00:00:00 2001 From: Francisco Date: Thu, 20 May 2021 20:34:04 +0100 Subject: [PATCH 013/156] set minimum snr under which the UL SNR estimate is not updated --- .../stack/mac/sched_ue_ctrl/sched_ue_cell.h | 3 ++ srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h | 5 +++ srsenb/src/stack/mac/sched_ue.cc | 19 ++---------- .../stack/mac/sched_ue_ctrl/sched_ue_cell.cc | 31 +++++++++++++++++++ 4 files changed, 41 insertions(+), 17 deletions(-) diff --git a/srsenb/hdr/stack/mac/sched_ue_ctrl/sched_ue_cell.h b/srsenb/hdr/stack/mac/sched_ue_ctrl/sched_ue_cell.h index 09b8bfa80..3e72f4de1 100644 --- a/srsenb/hdr/stack/mac/sched_ue_ctrl/sched_ue_cell.h +++ b/srsenb/hdr/stack/mac/sched_ue_ctrl/sched_ue_cell.h @@ -43,6 +43,9 @@ struct sched_ue_cell { const sched_interface::ue_cfg_t* get_ue_cfg() const { return configured() ? ue_cfg : nullptr; } cc_st cc_state() const { return cc_state_; } + int set_ul_crc(tti_point tti_rx, bool crc_res); + int set_ul_snr(tti_point tti_rx, float ul_snr, uint32_t ul_ch_code); + const uint16_t rnti; /// Cell const configuration diff --git a/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h b/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h index 99dc58270..6de07c7dc 100644 --- a/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h +++ b/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h @@ -55,6 +55,11 @@ public: void set_snr(float snr, uint32_t ul_ch_code) { + static const float MIN_UL_SNR = -4.0f; + if (snr < MIN_UL_SNR) { + // Assume signal was not sent + return; + } if (ul_ch_code < nof_ul_ch_code) { snr_estim_list[ul_ch_code].pending_snr = snr; } diff --git a/srsenb/src/stack/mac/sched_ue.cc b/srsenb/src/stack/mac/sched_ue.cc index 67a8badf7..5d48a322f 100644 --- a/srsenb/src/stack/mac/sched_ue.cc +++ b/srsenb/src/stack/mac/sched_ue.cc @@ -245,14 +245,7 @@ int sched_ue::set_ack_info(tti_point tti_rx, uint32_t enb_cc_idx, uint32_t tb_id void sched_ue::set_ul_crc(tti_point tti_rx, uint32_t enb_cc_idx, bool crc_res) { - if (cells[enb_cc_idx].cc_state() != cc_st::idle) { - int ret = cells[enb_cc_idx].harq_ent.set_ul_crc(tti_rx, 0, crc_res); - if (ret < 0) { - logger.warning("Received UL CRC for invalid tti_rx=%d", (int)tti_rx.to_uint()); - } - } else { - logger.warning("Received UL CRC for invalid cell index %d", enb_cc_idx); - } + cells[enb_cc_idx].set_ul_crc(tti_rx, crc_res); } void sched_ue::set_dl_ri(tti_point tti_rx, uint32_t enb_cc_idx, uint32_t ri) @@ -286,15 +279,7 @@ void sched_ue::set_dl_cqi(tti_point tti_rx, uint32_t enb_cc_idx, uint32_t cqi) void sched_ue::set_ul_snr(tti_point tti_rx, uint32_t enb_cc_idx, float snr, uint32_t ul_ch_code) { - if (cells[enb_cc_idx].cc_state() != cc_st::idle) { - cells[enb_cc_idx].tpc_fsm.set_snr(snr, ul_ch_code); - if (ul_ch_code == tpc::PUSCH_CODE) { - cells[enb_cc_idx].ul_cqi = srsran_cqi_from_snr(snr); - cells[enb_cc_idx].ul_cqi_tti_rx = tti_rx; - } - } else { - logger.warning("Received SNR info for invalid cell index %d", enb_cc_idx); - } + cells[enb_cc_idx].set_ul_snr(tti_rx, snr, ul_ch_code); } /******************************************************* diff --git a/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc b/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc index 9b8d84396..22cacb397 100644 --- a/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc +++ b/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc @@ -16,6 +16,14 @@ #include "srsenb/hdr/stack/mac/schedulers/sched_base.h" #include +#define CHECK_INVALID_FEEDBACK(feedback_type) \ + do { \ + if (cc_state() == cc_st::idle) { \ + logger.warning("SCHED: rnti=0x%x received " feedback_type " for idle cc=%d", cell_cfg->enb_cc_idx); \ + return SRSRAN_ERROR; \ + } \ + } while (0) + namespace srsenb { /******************************************************* @@ -160,6 +168,29 @@ void sched_ue_cell::set_dl_wb_cqi(tti_point tti_rx, uint32_t dl_cqi_) } } +int sched_ue_cell::set_ul_crc(tti_point tti_rx, bool crc_res) +{ + CHECK_INVALID_FEEDBACK("UL CRC"); + // Update HARQ process + int pid = harq_ent.set_ul_crc(tti_rx, 0, crc_res); + if (pid < 0) { + logger.warning("SCHED: rnti=0x%x received UL CRC for invalid tti_rx=%d", (int)tti_rx.to_uint()); + return SRSRAN_ERROR; + } + return pid; +} + +int sched_ue_cell::set_ul_snr(tti_point tti_rx, float ul_snr, uint32_t ul_ch_code) +{ + CHECK_INVALID_FEEDBACK("UL SNR estimate"); + tpc_fsm.set_snr(ul_snr, ul_ch_code); + if (ul_ch_code == tpc::PUSCH_CODE) { + ul_cqi = srsran_cqi_from_snr(ul_snr); + ul_cqi_tti_rx = tti_rx; + } + return SRSRAN_SUCCESS; +} + /************************************************************* * TBS/MCS derivation ************************************************************/ From 59db527481c73fb932401f0c3d975c3d3408c93f Mon Sep 17 00:00:00 2001 From: Francisco Date: Fri, 21 May 2021 18:38:45 +0100 Subject: [PATCH 014/156] fix reestablishment reject logging level --- srsenb/src/stack/rrc/rrc_ue.cc | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/srsenb/src/stack/rrc/rrc_ue.cc b/srsenb/src/stack/rrc/rrc_ue.cc index 0fe8546c8..580058065 100644 --- a/srsenb/src/stack/rrc/rrc_ue.cc +++ b/srsenb/src/stack/rrc/rrc_ue.cc @@ -519,9 +519,9 @@ void rrc::ue::handle_rrc_con_reest_req(rrc_conn_reest_request_s* msg) uint16_t old_rnti = req_r8.ue_id.c_rnti.to_number(); if (not parent->s1ap->is_mme_connected()) { - parent->logger.error("MME isn't connected. Sending Connection Reject"); + parent->logger.error("RRCReestablishmentReject for rnti=0x%x. Cause: MME not connected", rnti); send_connection_reest_rej(procedure_result_code::error_mme_not_connected); - srsran::console("User 0x%x RRC Reestablishment Request rejected\n", rnti); + srsran::console("RRCReestablishmentReject for rnti=0x%x. Cause: MME not connected.\n", rnti); return; } parent->logger.debug("rnti=0x%x, phyid=0x%x, smac=0x%x, cause=%s", @@ -532,9 +532,10 @@ void rrc::ue::handle_rrc_con_reest_req(rrc_conn_reest_request_s* msg) if (not is_idle()) { // The created RNTI has to receive ReestablishmentRequest as first message - parent->logger.error("Received ReestablishmentRequest from an rnti=0x%x not in IDLE", rnti); + parent->logger.error( + "RRCReestablishmentReject for rnti=0x%x. Cause: old rnti=0x%x is not in RRC_IDLE", rnti, old_rnti); send_connection_reest_rej(procedure_result_code::error_unknown_rnti); - srsran::console("ERROR: User 0x%x requesting Reestablishment is not in RRC_IDLE\n", rnti); + srsran::console("ERROR: RRCReestablishmentReject for rnti=0x%x not in RRC_IDLE\n", rnti); return; } @@ -545,10 +546,10 @@ void rrc::ue::handle_rrc_con_reest_req(rrc_conn_reest_request_s* msg) // Reject unrecognized rntis, and PCIs that do not belong to eNB if (old_ue_it == parent->users.end() or old_cell == nullptr or old_ue_it->second->ue_cell_list.get_enb_cc_idx(old_cell->enb_cc_idx) == nullptr) { - parent->logger.error("Received ConnectionReestablishment for rnti=0x%x without context", old_rnti); send_connection_reest_rej(procedure_result_code::error_unknown_rnti); - srsran::console( - "User 0x%x RRC Reestablishment Request rejected. Cause: no rnti=0x%x context available\n", rnti, old_rnti); + parent->logger.info( + "RRCReestablishmentReject for rnti=0x%x. Cause: no rnti=0x%x context available", rnti, old_rnti); + srsran::console("RRCReestablishmentReject for rnti=0x%x. Cause: no context available\n", rnti); return; } ue* old_ue = old_ue_it->second.get(); From fbb151af2d5585e7e8ccdb3925551b6c85d9c606 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Thu, 20 May 2021 15:47:30 +0200 Subject: [PATCH 015/156] enb,rrc: fix bearer re-activation after max KO this patch makes sure that if RBs have been deactivated after max KO on either the DL or the UL, they are reactivated if either of them is working again. UL/DL are always activated together, even if just one of them recovers. The KO counter (or timer), however, is not stopped implicitly. --- srsenb/hdr/stack/rrc/mac_controller.h | 2 +- srsenb/src/stack/rrc/mac_controller.cc | 4 ++-- srsenb/src/stack/rrc/rrc_ue.cc | 10 ++++++---- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/srsenb/hdr/stack/rrc/mac_controller.h b/srsenb/hdr/stack/rrc/mac_controller.h index 5c9042bc7..ff9a62b60 100644 --- a/srsenb/hdr/stack/rrc/mac_controller.h +++ b/srsenb/hdr/stack/rrc/mac_controller.h @@ -55,7 +55,7 @@ public: const srsran::rrc_ue_capabilities_t& uecaps); void handle_ho_prep(const asn1::rrc::ho_prep_info_r8_ies_s& ho_prep); - void handle_max_retx(); + void set_radio_bearer_state(sched_interface::ue_bearer_cfg_t::direction_t dir); const ue_cfg_t& get_ue_sched_cfg() const { return current_sched_ue_cfg; } bool is_crnti_set() const { return crnti_set; } diff --git a/srsenb/src/stack/rrc/mac_controller.cc b/srsenb/src/stack/rrc/mac_controller.cc index 7322efd3e..56f3a8136 100644 --- a/srsenb/src/stack/rrc/mac_controller.cc +++ b/srsenb/src/stack/rrc/mac_controller.cc @@ -297,10 +297,10 @@ void mac_controller::handle_ho_prep(const asn1::rrc::ho_prep_info_r8_ies_s& ho_p } } -void mac_controller::handle_max_retx() +void mac_controller::set_radio_bearer_state(sched_interface::ue_bearer_cfg_t::direction_t dir) { for (auto& ue_bearer : current_sched_ue_cfg.ue_bearers) { - ue_bearer.direction = sched_interface::ue_bearer_cfg_t::IDLE; + ue_bearer.direction = dir; } update_mac(config_tx); } diff --git a/srsenb/src/stack/rrc/rrc_ue.cc b/srsenb/src/stack/rrc/rrc_ue.cc index 580058065..ef7fab433 100644 --- a/srsenb/src/stack/rrc/rrc_ue.cc +++ b/srsenb/src/stack/rrc/rrc_ue.cc @@ -122,6 +122,7 @@ void rrc::ue::set_radiolink_dl_state(bool crc_res) parent->logger.info( "DL RLF timer stopped for rnti=0x%x (time elapsed=%dms)", rnti, phy_dl_rlf_timer.time_elapsed()); phy_dl_rlf_timer.stop(); + mac_ctrl.set_radio_bearer_state(sched_interface::ue_bearer_cfg_t::BOTH); } return; } @@ -136,7 +137,7 @@ void rrc::ue::set_radiolink_dl_state(bool crc_res) consecutive_kos_dl++; if (consecutive_kos_dl > parent->cfg.max_mac_dl_kos) { parent->logger.info("Max KOs in DL reached, starting RLF timer rnti=0x%x", rnti); - mac_ctrl.handle_max_retx(); + mac_ctrl.set_radio_bearer_state(sched_interface::ue_bearer_cfg_t::IDLE); phy_dl_rlf_timer.run(); } } @@ -153,6 +154,7 @@ void rrc::ue::set_radiolink_ul_state(bool crc_res) parent->logger.info( "UL RLF timer stopped for rnti=0x%x (time elapsed=%dms)", rnti, phy_ul_rlf_timer.time_elapsed()); phy_ul_rlf_timer.stop(); + mac_ctrl.set_radio_bearer_state(sched_interface::ue_bearer_cfg_t::BOTH); } return; } @@ -167,7 +169,7 @@ void rrc::ue::set_radiolink_ul_state(bool crc_res) consecutive_kos_ul++; if (consecutive_kos_ul > parent->cfg.max_mac_ul_kos) { parent->logger.info("Max KOs in UL reached, starting RLF timer rnti=0x%x", rnti); - mac_ctrl.handle_max_retx(); + mac_ctrl.set_radio_bearer_state(sched_interface::ue_bearer_cfg_t::IDLE); phy_ul_rlf_timer.run(); } } @@ -222,9 +224,9 @@ void rrc::ue::max_rlc_retx_reached() { parent->logger.info("Max RLC retx reached for rnti=0x%x", rnti); - // Turn off DRB scheduling but give UE chance to start re-establishment + // Turn off scheduling but give UE chance to start re-establishment + mac_ctrl.set_radio_bearer_state(sched_interface::ue_bearer_cfg_t::IDLE); rlc_rlf_timer.run(); - mac_ctrl.handle_max_retx(); } void rrc::ue::set_activity_timeout(const activity_timeout_type_t type) From 59513c0eed93a453ad38288898dba8c857d438fe Mon Sep 17 00:00:00 2001 From: Francisco Date: Fri, 21 May 2021 13:58:52 +0100 Subject: [PATCH 016/156] fix bearer reactivation in case the RRC session is recovered after max KO --- srsenb/src/stack/rrc/mac_controller.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/srsenb/src/stack/rrc/mac_controller.cc b/srsenb/src/stack/rrc/mac_controller.cc index 56f3a8136..247d8052f 100644 --- a/srsenb/src/stack/rrc/mac_controller.cc +++ b/srsenb/src/stack/rrc/mac_controller.cc @@ -299,8 +299,11 @@ void mac_controller::handle_ho_prep(const asn1::rrc::ho_prep_info_r8_ies_s& ho_p void mac_controller::set_radio_bearer_state(sched_interface::ue_bearer_cfg_t::direction_t dir) { - for (auto& ue_bearer : current_sched_ue_cfg.ue_bearers) { - ue_bearer.direction = dir; + for (uint32_t i = srb_to_lcid(lte_srb::srb0); i <= srb_to_lcid(lte_srb::srb2); ++i) { + current_sched_ue_cfg.ue_bearers[i].direction = dir; + } + for (auto& drb : bearer_list.get_established_drbs()) { + current_sched_ue_cfg.ue_bearers[drb.lc_ch_id].direction = dir; } update_mac(config_tx); } From 8811b7c9a7430e9ecc0c6096c83251c4bab89a46 Mon Sep 17 00:00:00 2001 From: Francisco Date: Fri, 21 May 2021 15:14:23 +0100 Subject: [PATCH 017/156] fix handling of CRNTI CE in the RRC. The scheduler should not allocate more grants for the new rnti after this point. --- srsenb/hdr/stack/rrc/rrc_ue.h | 1 + srsenb/src/stack/rrc/rrc.cc | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/srsenb/hdr/stack/rrc/rrc_ue.h b/srsenb/hdr/stack/rrc/rrc_ue.h index a776ca62b..236dc0cb7 100644 --- a/srsenb/hdr/stack/rrc/rrc_ue.h +++ b/srsenb/hdr/stack/rrc/rrc_ue.h @@ -46,6 +46,7 @@ public: void activity_timer_expired(const activity_timeout_type_t type); void rlf_timer_expired(uint32_t timeout_id); void max_rlc_retx_reached(); + void deactivate_bearers() { mac_ctrl.set_radio_bearer_state(sched_interface::ue_bearer_cfg_t::IDLE); } rrc_state_t get_state(); void get_metrics(rrc_ue_metrics_t& ue_metrics) const; diff --git a/srsenb/src/stack/rrc/rrc.cc b/srsenb/src/stack/rrc/rrc.cc index c9144c88b..164a747d5 100644 --- a/srsenb/src/stack/rrc/rrc.cc +++ b/srsenb/src/stack/rrc/rrc.cc @@ -222,12 +222,16 @@ int rrc::add_user(uint16_t rnti, const sched_interface::ue_cfg_t& sched_ue_cfg) void rrc::upd_user(uint16_t new_rnti, uint16_t old_rnti) { // Remove new_rnti - rem_user_thread(new_rnti); + auto new_ue_it = users.find(new_rnti); + if (new_ue_it != users.end()) { + new_ue_it->second->deactivate_bearers(); + rem_user_thread(new_rnti); + } // Send Reconfiguration to old_rnti if is RRC_CONNECT or RRC Release if already released here auto old_it = users.find(old_rnti); if (old_it == users.end()) { - send_rrc_connection_reject(old_rnti); + logger.info("rnti=0x%x received MAC CRNTI CE: 0x%x, but old context is unavailable", new_rnti, old_rnti); return; } ue* ue_ptr = old_it->second.get(); From c5029fc266593526595a97ed377ab8f2b41c99f3 Mon Sep 17 00:00:00 2001 From: Francisco Date: Fri, 21 May 2021 09:52:52 +0100 Subject: [PATCH 018/156] feature - implement adaptive link adaptation in DL and UL --- .../srsran/interfaces/sched_interface.h | 24 ++++--- srsenb/enb.conf.example | 8 +++ .../stack/mac/sched_ue_ctrl/sched_ue_cell.h | 13 +++- srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h | 10 +-- srsenb/src/main.cc | 4 ++ srsenb/src/stack/mac/sched_ue.cc | 23 ++----- .../stack/mac/sched_ue_ctrl/sched_ue_cell.cc | 67 ++++++++++++++++--- srsenb/test/mac/sched_ue_cell_test.cc | 5 +- 8 files changed, 107 insertions(+), 47 deletions(-) diff --git a/lib/include/srsran/interfaces/sched_interface.h b/lib/include/srsran/interfaces/sched_interface.h index bbb8e9956..7464592e4 100644 --- a/lib/include/srsran/interfaces/sched_interface.h +++ b/lib/include/srsran/interfaces/sched_interface.h @@ -45,16 +45,20 @@ public: } cell_cfg_sib_t; struct sched_args_t { - std::string sched_policy = "time_pf"; - std::string sched_policy_args = "2"; - int pdsch_mcs = -1; - int pdsch_max_mcs = 28; - int pusch_mcs = -1; - int pusch_max_mcs = 28; - uint32_t min_nof_ctrl_symbols = 1; - uint32_t max_nof_ctrl_symbols = 3; - int max_aggr_level = 3; - bool pucch_mux_enabled = false; + std::string sched_policy = "time_pf"; + std::string sched_policy_args = "2"; + int pdsch_mcs = -1; + int pdsch_max_mcs = 28; + int pusch_mcs = -1; + int pusch_max_mcs = 28; + uint32_t min_nof_ctrl_symbols = 1; + uint32_t max_nof_ctrl_symbols = 3; + int max_aggr_level = 3; + bool pucch_mux_enabled = false; + float target_bler = 0.05; + float max_delta_dl_cqi = 5; + float max_delta_ul_snr = 5; + float adaptive_link_step_size = 0.001; }; struct cell_cfg_t { diff --git a/srsenb/enb.conf.example b/srsenb/enb.conf.example index 937192caa..fc84d6df2 100644 --- a/srsenb/enb.conf.example +++ b/srsenb/enb.conf.example @@ -167,6 +167,10 @@ enable = false # pusch_max_mcs: Optional PUSCH MCS limit # min_nof_ctrl_symbols: Minimum number of control symbols # max_nof_ctrl_symbols: Maximum number of control symbols +# target_bler: Target BLER (in decimal) to achieve via adaptive link +# max_delta_dl_cqi: Maximum shift in CQI for adaptive DL link +# max_delta_ul_cqi: Maximum shift in UL SNR for adaptive UL link +# target_bler: Step size or learning rate used in adaptive link # ##################################################################### [scheduler] @@ -180,6 +184,10 @@ enable = false #min_nof_ctrl_symbols = 1 #max_nof_ctrl_symbols = 3 #pucch_multiplex_enable = false +#target_bler = 0.05 +#max_delta_dl_cqi = 5 +#max_delta_ul_snr = 5 +#adaptive_link_step_size = 0.001 ##################################################################### # eMBMS configuration options diff --git a/srsenb/hdr/stack/mac/sched_ue_ctrl/sched_ue_cell.h b/srsenb/hdr/stack/mac/sched_ue_ctrl/sched_ue_cell.h index 3e72f4de1..6f07424dc 100644 --- a/srsenb/hdr/stack/mac/sched_ue_ctrl/sched_ue_cell.h +++ b/srsenb/hdr/stack/mac/sched_ue_ctrl/sched_ue_cell.h @@ -33,7 +33,7 @@ struct sched_ue_cell { void clear_feedback(); void finish_tti(tti_point tti_rx); - void set_dl_wb_cqi(tti_point tti_rx, uint32_t dl_cqi_); + int set_dl_wb_cqi(tti_point tti_rx, uint32_t dl_cqi_); bool configured() const { return ue_cc_idx >= 0; } int get_ue_cc_idx() const { return ue_cc_idx; } @@ -43,6 +43,11 @@ struct sched_ue_cell { const sched_interface::ue_cfg_t* get_ue_cfg() const { return configured() ? ue_cfg : nullptr; } cc_st cc_state() const { return cc_state_; } + int get_dl_cqi() const; + int get_dl_cqi(const rbgmask_t& rbgs) const; + int get_ul_cqi() const; + + int set_ack_info(tti_point tti_rx, uint32_t tb_idx, bool ack); int set_ul_crc(tti_point tti_rx, bool crc_res); int set_ul_snr(tti_point tti_rx, float ul_snr, uint32_t ul_ch_code); @@ -66,7 +71,6 @@ struct sched_ue_cell { tti_point dl_ri_tti_rx{}; uint32_t dl_pmi = 0; tti_point dl_pmi_tti_rx{}; - uint32_t ul_cqi = 1; tti_point ul_cqi_tti_rx{}; uint32_t max_mcs_dl = 28, max_mcs_ul = 28; @@ -84,6 +88,11 @@ private: tti_point current_tti; cc_st cc_state_ = cc_st::idle; + // CQI + float delta_down = 0, delta_up = 0; + float dl_cqi_coeff = 0, ul_snr_coeff = 0; + float max_cqi_coeff = -5, max_snr_coeff = 5; + sched_dl_cqi dl_cqi_ctxt; }; diff --git a/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h b/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h index 6de07c7dc..71bbd333f 100644 --- a/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h +++ b/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h @@ -88,10 +88,6 @@ public: for (size_t chidx = 0; chidx < 2; ++chidx) { float target_snr_dB = chidx == PUSCH_CODE ? target_pusch_snr_dB : target_pucch_snr_dB; auto& ch_snr = snr_estim_list[chidx]; - if (target_snr_dB < 0) { - ch_snr.pending_delta = 0; - continue; - } // Enqueue pending UL Channel SNR measurement if (ch_snr.pending_snr == null_snr) { @@ -105,7 +101,9 @@ public: ch_snr.pending_snr = null_snr; // Enqueue PUSCH/PUCCH TPC sent in last TTI (zero for both Delta_PUSCH/Delta_PUCCH=0 and TPC not sent) - ch_snr.win_tpc_values.push(ch_snr.pending_delta); + if (target_snr_dB >= 0) { + ch_snr.win_tpc_values.push(ch_snr.pending_delta); + } ch_snr.pending_delta = 0; } } @@ -126,6 +124,8 @@ public: uint32_t max_ul_prbs() const { return max_prbs_cached; } + float get_ul_snr_estim(uint32_t ul_ch_code = PUSCH_CODE) const { return snr_estim_list[ul_ch_code].snr_avg.value(); } + private: uint8_t encode_tpc_delta(int8_t delta) { diff --git a/srsenb/src/main.cc b/srsenb/src/main.cc index 80ba7258d..ac40533b3 100644 --- a/srsenb/src/main.cc +++ b/srsenb/src/main.cc @@ -149,6 +149,10 @@ void parse_args(all_args_t* args, int argc, char* argv[]) ("scheduler.max_nof_ctrl_symbols", bpo::value(&args->stack.mac.sched.max_nof_ctrl_symbols)->default_value(3), "Number of control symbols") ("scheduler.min_nof_ctrl_symbols", bpo::value(&args->stack.mac.sched.min_nof_ctrl_symbols)->default_value(1), "Minimum number of control symbols") ("scheduler.pucch_multiplex_enable", bpo::value(&args->stack.mac.sched.pucch_mux_enabled)->default_value(false), "Enable PUCCH multiplexing") + ("scheduler.target_bler", bpo::value(&args->stack.mac.sched.target_bler)->default_value(0.05), "Target BLER (in decimal) to achieve via adaptive link") + ("scheduler.max_delta_dl_cqi", bpo::value(&args->stack.mac.sched.max_delta_dl_cqi)->default_value(5.0), "Maximum shift in CQI for adaptive DL link") + ("scheduler.max_delta_ul_snr", bpo::value(&args->stack.mac.sched.max_delta_ul_snr)->default_value(5.0), "Maximum shift in UL SNR for adaptive UL link") + ("scheduler.adaptive_link_step_size", bpo::value(&args->stack.mac.sched.max_delta_ul_snr)->default_value(0.001), "Step size or learning rate used in adaptive link") /* Downlink Channel emulator section */ diff --git a/srsenb/src/stack/mac/sched_ue.cc b/srsenb/src/stack/mac/sched_ue.cc index 5d48a322f..2b5a42b5e 100644 --- a/srsenb/src/stack/mac/sched_ue.cc +++ b/srsenb/src/stack/mac/sched_ue.cc @@ -227,20 +227,7 @@ bool sched_ue::pusch_enabled(tti_point tti_rx, uint32_t enb_cc_idx, bool needs_p int sched_ue::set_ack_info(tti_point tti_rx, uint32_t enb_cc_idx, uint32_t tb_idx, bool ack) { - int tbs_acked = -1; - if (cells[enb_cc_idx].cc_state() != cc_st::idle) { - std::pair p2 = cells[enb_cc_idx].harq_ent.set_ack_info(tti_rx, tb_idx, ack); - tbs_acked = p2.second; - if (tbs_acked > 0) { - logger.debug( - "SCHED: Set DL ACK=%d for rnti=0x%x, pid=%d, tb=%d, tti=%d", ack, rnti, p2.first, tb_idx, tti_rx.to_uint()); - } else { - logger.warning("SCHED: Received ACK info for unknown TTI=%d", tti_rx.to_uint()); - } - } else { - logger.warning("Received DL ACK for invalid cell index %d", enb_cc_idx); - } - return tbs_acked; + return cells[enb_cc_idx].set_ack_info(tti_rx, tb_idx, ack); } void sched_ue::set_ul_crc(tti_point tti_rx, uint32_t enb_cc_idx, bool crc_res) @@ -815,7 +802,7 @@ uint32_t sched_ue::get_expected_dl_bitrate(uint32_t enb_cc_idx, int nof_rbgs) co auto& cc = cells[enb_cc_idx]; uint32_t nof_re = cc.cell_cfg->get_dl_lb_nof_re(to_tx_dl(current_tti), count_prb_per_tb_approx(nof_rbgs, cc.cell_cfg->nof_prb())); - float max_coderate = srsran_cqi_to_coderate(std::min(cc.dl_cqi().get_avg_cqi() + 1u, 15u), cfg.use_tbs_index_alt); + float max_coderate = srsran_cqi_to_coderate(std::min(cc.get_dl_cqi() + 1u, 15u), cfg.use_tbs_index_alt); // Inverse of srsran_coderate(tbs, nof_re) uint32_t tbs = max_coderate * nof_re - 24; @@ -829,7 +816,7 @@ uint32_t sched_ue::get_expected_ul_bitrate(uint32_t enb_cc_idx, int nof_prbs) co uint32_t N_srs = 0; uint32_t nof_symb = 2 * (SRSRAN_CP_NSYMB(cell.cp) - 1) - N_srs; uint32_t nof_re = nof_symb * nof_prbs_alloc * SRSRAN_NRE; - float max_coderate = srsran_cqi_to_coderate(std::min(cells[enb_cc_idx].ul_cqi + 1u, 15u), false); + float max_coderate = srsran_cqi_to_coderate(std::min(cells[enb_cc_idx].get_ul_cqi() + 1u, 15u), false); // Inverse of srsran_coderate(tbs, nof_re) uint32_t tbs = max_coderate * nof_re - 24; @@ -884,7 +871,7 @@ uint32_t sched_ue::get_pending_ul_data_total(tti_point tti_tx_ul, int this_enb_c uint32_t max_cqi = 0, max_cc_idx = 0; for (uint32_t cc = 0; cc < cells.size(); ++cc) { if (cells[cc].configured()) { - uint32_t sum_cqi = cells[cc].dl_cqi().get_avg_cqi() + cells[cc].ul_cqi; + uint32_t sum_cqi = cells[cc].get_dl_cqi() + cells[cc].get_ul_cqi(); if (cells[cc].cc_state() == cc_st::active and sum_cqi > max_cqi) { max_cqi = sum_cqi; max_cc_idx = cc; @@ -978,7 +965,7 @@ uint32_t sched_ue::get_aggr_level(uint32_t enb_cc_idx, uint32_t nof_bits) { const auto& cc = cells[enb_cc_idx]; return srsenb::get_aggr_level( - nof_bits, cc.dl_cqi().get_avg_cqi(), cc.max_aggr_level, cc.cell_cfg->nof_prb(), cfg.use_tbs_index_alt); + nof_bits, cc.get_dl_cqi(), cc.max_aggr_level, cc.cell_cfg->nof_prb(), cfg.use_tbs_index_alt); } void sched_ue::finish_tti(tti_point tti_rx, uint32_t enb_cc_idx) diff --git a/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc b/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc index 22cacb397..0a3e3e20f 100644 --- a/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc +++ b/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc @@ -13,10 +13,9 @@ #include "srsenb/hdr/stack/mac/sched_ue_ctrl/sched_ue_cell.h" #include "srsenb/hdr/stack/mac/sched_helpers.h" #include "srsenb/hdr/stack/mac/sched_phy_ch/sched_dci.h" -#include "srsenb/hdr/stack/mac/schedulers/sched_base.h" #include -#define CHECK_INVALID_FEEDBACK(feedback_type) \ +#define CHECK_VALID_CC(feedback_type) \ do { \ if (cc_state() == cc_st::idle) { \ logger.warning("SCHED: rnti=0x%x received " feedback_type " for idle cc=%d", cell_cfg->enb_cc_idx); \ @@ -47,6 +46,12 @@ sched_ue_cell::sched_ue_cell(uint16_t rnti_, const sched_cell_params_t& cell_cfg dl_cqi_ctxt(cell_cfg_.nof_prb(), 0, 1) { clear_feedback(); + + float target_bler = cell_cfg->sched_cfg->target_bler; + delta_down = cell_cfg->sched_cfg->adaptive_link_step_size; + delta_up = (1 - target_bler) * delta_down / target_bler; + max_cqi_coeff = cell_cfg->sched_cfg->max_delta_dl_cqi; + max_snr_coeff = cell_cfg->sched_cfg->max_delta_ul_snr; } void sched_ue_cell::set_ue_cfg(const sched_interface::ue_cfg_t& ue_cfg_) @@ -148,7 +153,6 @@ void sched_ue_cell::clear_feedback() dl_pmi = 0; dl_pmi_tti_rx = tti_point{}; dl_cqi_ctxt.reset_cqi(ue_cc_idx == 0 ? cell_cfg->cfg.initial_dl_cqi : 1); - ul_cqi = 1; ul_cqi_tti_rx = tti_point{}; } @@ -158,39 +162,84 @@ void sched_ue_cell::finish_tti(tti_point tti_rx) harq_ent.reset_pending_data(tti_rx); } -void sched_ue_cell::set_dl_wb_cqi(tti_point tti_rx, uint32_t dl_cqi_) +int sched_ue_cell::set_dl_wb_cqi(tti_point tti_rx, uint32_t dl_cqi_) { + CHECK_VALID_CC("DL CQI"); dl_cqi_ctxt.cqi_wb_info(tti_rx, dl_cqi_); if (ue_cc_idx > 0 and cc_state_ == cc_st::activating and dl_cqi_ > 0) { // Wait for SCell to receive a positive CQI before activating it cc_state_ = cc_st::active; logger.info("SCHED: SCell index=%d is now active", ue_cc_idx); } + return SRSRAN_SUCCESS; } int sched_ue_cell::set_ul_crc(tti_point tti_rx, bool crc_res) { - CHECK_INVALID_FEEDBACK("UL CRC"); + CHECK_VALID_CC("UL CRC"); // Update HARQ process int pid = harq_ent.set_ul_crc(tti_rx, 0, crc_res); if (pid < 0) { logger.warning("SCHED: rnti=0x%x received UL CRC for invalid tti_rx=%d", (int)tti_rx.to_uint()); return SRSRAN_ERROR; } + + ul_snr_coeff += delta_down - static_cast(not crc_res) * (delta_down + delta_up); + ul_snr_coeff = std::min(std::max(-max_snr_coeff, ul_snr_coeff), max_snr_coeff); + logger.info("SCHED: adjusting UL SNR by %f", ul_snr_coeff); return pid; } +int sched_ue_cell::set_ack_info(tti_point tti_rx, uint32_t tb_idx, bool ack) +{ + CHECK_VALID_CC("DL ACK Info"); + std::pair p2 = harq_ent.set_ack_info(tti_rx, tb_idx, ack); + int tbs_acked = p2.second; + if (tbs_acked > 0) { + logger.debug( + "SCHED: Set DL ACK=%d for rnti=0x%x, pid=%d, tb=%d, tti=%d", ack, rnti, p2.first, tb_idx, tti_rx.to_uint()); + + dl_cqi_coeff += delta_down - static_cast(not ack) * (delta_down + delta_up); + dl_cqi_coeff = std::min(std::max(-max_cqi_coeff, dl_cqi_coeff), max_cqi_coeff); + logger.info("SCHED: adjusting DL CQI by %f", dl_cqi_coeff); + } else { + logger.warning("SCHED: Received ACK info for unknown TTI=%d", tti_rx.to_uint()); + } + return tbs_acked; +} + int sched_ue_cell::set_ul_snr(tti_point tti_rx, float ul_snr, uint32_t ul_ch_code) { - CHECK_INVALID_FEEDBACK("UL SNR estimate"); + CHECK_VALID_CC("UL SNR estimate"); tpc_fsm.set_snr(ul_snr, ul_ch_code); if (ul_ch_code == tpc::PUSCH_CODE) { - ul_cqi = srsran_cqi_from_snr(ul_snr); ul_cqi_tti_rx = tti_rx; } return SRSRAN_SUCCESS; } +int sched_ue_cell::get_ul_cqi() const +{ + if (not ul_cqi_tti_rx.is_valid()) { + return 1; + } + float snr = tpc_fsm.get_ul_snr_estim(); + return srsran_cqi_from_snr(snr + ul_snr_coeff); +} + +int sched_ue_cell::get_dl_cqi(const rbgmask_t& rbgs) const +{ + float dl_cqi = std::get<1>(find_min_cqi_rbg(rbgs, dl_cqi_ctxt)); + return std::max(0, (int)std::min(dl_cqi + dl_cqi_coeff, 15.0f)); +} + +int sched_ue_cell::get_dl_cqi() const +{ + rbgmask_t rbgmask(cell_cfg->nof_rbgs); + rbgmask.fill(0, rbgmask.size()); + return get_dl_cqi(rbgmask); +} + /************************************************************* * TBS/MCS derivation ************************************************************/ @@ -280,7 +329,7 @@ tbs_info cqi_to_tbs_dl(const sched_ue_cell& cell, tbs_info ret; if (cell.fixed_mcs_dl < 0 or not cell.dl_cqi().is_cqi_info_received()) { // Dynamic MCS configured or first Tx - uint32_t dl_cqi = std::get<1>(find_min_cqi_rbg(rbgs, cell.dl_cqi())); + uint32_t dl_cqi = cell.get_dl_cqi(rbgs); ret = compute_min_mcs_and_tbs_from_required_bytes( nof_prbs, nof_re, dl_cqi, cell.max_mcs_dl, req_bytes, false, false, use_tbs_index_alt); @@ -309,7 +358,7 @@ tbs_info cqi_to_tbs_ul(const sched_ue_cell& cell, uint32_t nof_prb, uint32_t nof if (mcs < 0) { // Dynamic MCS ret = compute_min_mcs_and_tbs_from_required_bytes( - nof_prb, nof_re, cell.ul_cqi, cell.max_mcs_ul, req_bytes, true, ulqam64_enabled, false); + nof_prb, nof_re, cell.get_ul_cqi(), cell.max_mcs_ul, req_bytes, true, ulqam64_enabled, false); // If coderate > SRSRAN_MIN(max_coderate, 0.932 * Qm) we should set TBS=0. We don't because it's not correctly // handled by the scheduler, but we might be scheduling undecodable codewords at very low SNR diff --git a/srsenb/test/mac/sched_ue_cell_test.cc b/srsenb/test/mac/sched_ue_cell_test.cc index a6a90e81b..44ff63269 100644 --- a/srsenb/test/mac/sched_ue_cell_test.cc +++ b/srsenb/test/mac/sched_ue_cell_test.cc @@ -38,9 +38,8 @@ void test_neg_phr_scenario() ue_cc.set_ue_cfg(ue_cfg); float snr = 0; - ue_cc.tpc_fsm.set_snr(snr, 0); - ue_cc.tpc_fsm.set_snr(snr, 1); - ue_cc.ul_cqi = srsran_cqi_from_snr(snr); + ue_cc.set_ul_snr(tti_point(0), snr, 0); + ue_cc.set_ul_snr(tti_point(0), snr, 1); ue_cc.tpc_fsm.set_phr(-5); ue_cc.new_tti(tti_point(0)); From 1f1665bab7b81959cd20ccd3ad52ec801cc36895 Mon Sep 17 00:00:00 2001 From: Francisco Date: Fri, 21 May 2021 12:40:04 +0100 Subject: [PATCH 019/156] improve adaptive offset adjustment log lines --- srsenb/enb.conf.example | 8 ++++---- srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/srsenb/enb.conf.example b/srsenb/enb.conf.example index fc84d6df2..a6cdd0163 100644 --- a/srsenb/enb.conf.example +++ b/srsenb/enb.conf.example @@ -167,10 +167,10 @@ enable = false # pusch_max_mcs: Optional PUSCH MCS limit # min_nof_ctrl_symbols: Minimum number of control symbols # max_nof_ctrl_symbols: Maximum number of control symbols -# target_bler: Target BLER (in decimal) to achieve via adaptive link -# max_delta_dl_cqi: Maximum shift in CQI for adaptive DL link -# max_delta_ul_cqi: Maximum shift in UL SNR for adaptive UL link -# target_bler: Step size or learning rate used in adaptive link +# target_bler: Target BLER (in decimal) to achieve via adaptive link +# max_delta_dl_cqi: Maximum shift in CQI for adaptive DL link +# max_delta_ul_snr: Maximum shift in UL SNR for adaptive UL link +# adaptive_link_step_size: Step size or learning rate used in adaptive link # ##################################################################### [scheduler] diff --git a/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc b/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc index 0a3e3e20f..06ff64f27 100644 --- a/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc +++ b/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc @@ -186,7 +186,7 @@ int sched_ue_cell::set_ul_crc(tti_point tti_rx, bool crc_res) ul_snr_coeff += delta_down - static_cast(not crc_res) * (delta_down + delta_up); ul_snr_coeff = std::min(std::max(-max_snr_coeff, ul_snr_coeff), max_snr_coeff); - logger.info("SCHED: adjusting UL SNR by %f", ul_snr_coeff); + logger.info("SCHED: UL adaptive link: snr_estim=%f, snr_offset=%f", tpc_fsm.get_ul_snr_estim(), ul_snr_coeff); return pid; } @@ -201,7 +201,7 @@ int sched_ue_cell::set_ack_info(tti_point tti_rx, uint32_t tb_idx, bool ack) dl_cqi_coeff += delta_down - static_cast(not ack) * (delta_down + delta_up); dl_cqi_coeff = std::min(std::max(-max_cqi_coeff, dl_cqi_coeff), max_cqi_coeff); - logger.info("SCHED: adjusting DL CQI by %f", dl_cqi_coeff); + logger.info("SCHED: DL adaptive link: cqi=%d, cqi_offset=%f", dl_cqi_ctxt.get_avg_cqi(), dl_cqi_coeff); } else { logger.warning("SCHED: Received ACK info for unknown TTI=%d", tti_rx.to_uint()); } From fb4a363abd91a846a216e935aec8969be7816618 Mon Sep 17 00:00:00 2001 From: Francisco Date: Fri, 21 May 2021 17:42:11 +0100 Subject: [PATCH 020/156] fix formatting errors in scheduler --- srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc b/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc index 06ff64f27..4f1a97c57 100644 --- a/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc +++ b/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc @@ -18,7 +18,7 @@ #define CHECK_VALID_CC(feedback_type) \ do { \ if (cc_state() == cc_st::idle) { \ - logger.warning("SCHED: rnti=0x%x received " feedback_type " for idle cc=%d", cell_cfg->enb_cc_idx); \ + logger.warning("SCHED: rnti=0x%x received " feedback_type " for idle cc=%d", rnti, cell_cfg->enb_cc_idx); \ return SRSRAN_ERROR; \ } \ } while (0) @@ -180,7 +180,7 @@ int sched_ue_cell::set_ul_crc(tti_point tti_rx, bool crc_res) // Update HARQ process int pid = harq_ent.set_ul_crc(tti_rx, 0, crc_res); if (pid < 0) { - logger.warning("SCHED: rnti=0x%x received UL CRC for invalid tti_rx=%d", (int)tti_rx.to_uint()); + logger.warning("SCHED: rnti=0x%x received UL CRC for invalid tti_rx=%d", rnti, (int)tti_rx.to_uint()); return SRSRAN_ERROR; } From dedd9c09a7a58398c2467922bdd4faa2b0b34e06 Mon Sep 17 00:00:00 2001 From: Francisco Date: Mon, 24 May 2021 16:36:34 +0100 Subject: [PATCH 021/156] feature, scheduler: Add abitility to set minimum aggregation level in PDCCH, and disable adaptive aggregation level based on target BLER --- .../srsran/interfaces/sched_interface.h | 2 ++ srsenb/enb.conf.example | 6 +++++- srsenb/hdr/stack/mac/sched_helpers.h | 1 + .../stack/mac/sched_ue_ctrl/sched_ue_cell.h | 2 ++ srsenb/src/main.cc | 4 +++- srsenb/src/stack/mac/sched_helpers.cc | 10 +++++++--- srsenb/src/stack/mac/sched_ue.cc | 4 +--- .../stack/mac/sched_ue_ctrl/sched_ue_cell.cc | 20 ++++++++++++++++--- 8 files changed, 38 insertions(+), 11 deletions(-) diff --git a/lib/include/srsran/interfaces/sched_interface.h b/lib/include/srsran/interfaces/sched_interface.h index 7464592e4..cb946349d 100644 --- a/lib/include/srsran/interfaces/sched_interface.h +++ b/lib/include/srsran/interfaces/sched_interface.h @@ -53,7 +53,9 @@ public: int pusch_max_mcs = 28; uint32_t min_nof_ctrl_symbols = 1; uint32_t max_nof_ctrl_symbols = 3; + int min_aggr_level = 0; int max_aggr_level = 3; + bool adaptive_aggr_level = true; bool pucch_mux_enabled = false; float target_bler = 0.05; float max_delta_dl_cqi = 5; diff --git a/srsenb/enb.conf.example b/srsenb/enb.conf.example index a6cdd0163..fb2f73e7e 100644 --- a/srsenb/enb.conf.example +++ b/srsenb/enb.conf.example @@ -160,7 +160,9 @@ enable = false # Scheduler configuration options # # sched_policy: User MAC scheduling policy (E.g. time_rr, time_pf) +# min_aggr_level: Optional minimum aggregation level index (l=log2(L) can be 0, 1, 2 or 3) # max_aggr_level: Optional maximum aggregation level index (l=log2(L) can be 0, 1, 2 or 3) +# adaptive_aggr_level: Boolean flag to enable/disable adaptive aggregation level based on target BLER # pdsch_mcs: Optional fixed PDSCH MCS (ignores reported CQIs if specified) # pdsch_max_mcs: Optional PDSCH MCS limit # pusch_mcs: Optional fixed PUSCH MCS (ignores reported CQIs if specified) @@ -176,7 +178,9 @@ enable = false [scheduler] #policy = time_pf #policy_args = 2 -#max_aggr_level = -1 +#min_aggr_level = 0 +#max_aggr_level = 3 +#adaptive_aggr_level = true #pdsch_mcs = -1 #pdsch_max_mcs = -1 #pusch_mcs = -1 diff --git a/srsenb/hdr/stack/mac/sched_helpers.h b/srsenb/hdr/stack/mac/sched_helpers.h index 4db0546ec..83962c6ff 100644 --- a/srsenb/hdr/stack/mac/sched_helpers.h +++ b/srsenb/hdr/stack/mac/sched_helpers.h @@ -69,6 +69,7 @@ inline uint32_t get_tbs_bytes(uint32_t mcs, uint32_t nof_alloc_prb, bool use_tbs /// Find lowest DCI aggregation level supported by the UE spectral efficiency uint32_t get_aggr_level(uint32_t nof_bits, uint32_t dl_cqi, + uint32_t min_aggr_lvl, uint32_t max_aggr_lvl, uint32_t cell_nof_prb, bool use_tbs_index_alt); diff --git a/srsenb/hdr/stack/mac/sched_ue_ctrl/sched_ue_cell.h b/srsenb/hdr/stack/mac/sched_ue_ctrl/sched_ue_cell.h index 6f07424dc..5779fee8e 100644 --- a/srsenb/hdr/stack/mac/sched_ue_ctrl/sched_ue_cell.h +++ b/srsenb/hdr/stack/mac/sched_ue_ctrl/sched_ue_cell.h @@ -47,6 +47,8 @@ struct sched_ue_cell { int get_dl_cqi(const rbgmask_t& rbgs) const; int get_ul_cqi() const; + uint32_t get_aggr_level(uint32_t nof_bits) const; + int set_ack_info(tti_point tti_rx, uint32_t tb_idx, bool ack); int set_ul_crc(tti_point tti_rx, bool crc_res); int set_ul_snr(tti_point tti_rx, float ul_snr, uint32_t ul_ch_code); diff --git a/srsenb/src/main.cc b/srsenb/src/main.cc index ac40533b3..7b6be3828 100644 --- a/srsenb/src/main.cc +++ b/srsenb/src/main.cc @@ -145,7 +145,9 @@ void parse_args(all_args_t* args, int argc, char* argv[]) ("scheduler.pdsch_max_mcs", bpo::value(&args->stack.mac.sched.pdsch_max_mcs)->default_value(-1), "Optional PDSCH MCS limit") ("scheduler.pusch_mcs", bpo::value(&args->stack.mac.sched.pusch_mcs)->default_value(-1), "Optional fixed PUSCH MCS (ignores reported CQIs if specified)") ("scheduler.pusch_max_mcs", bpo::value(&args->stack.mac.sched.pusch_max_mcs)->default_value(-1), "Optional PUSCH MCS limit") - ("scheduler.max_aggr_level", bpo::value(&args->stack.mac.sched.max_aggr_level)->default_value(-1), "Optional maximum aggregation level index (l=log2(L)) ") + ("scheduler.min_aggr_level", bpo::value(&args->stack.mac.sched.min_aggr_level)->default_value(0), "Optional minimum aggregation level index (l=log2(L)) ") + ("scheduler.max_aggr_level", bpo::value(&args->stack.mac.sched.max_aggr_level)->default_value(3), "Optional maximum aggregation level index (l=log2(L)) ") + ("scheduler.adaptive_aggr_level", bpo::value(&args->stack.mac.sched.adaptive_aggr_level)->default_value(true), "Boolean flag to enable/disable adaptive aggregation level based on target BLER") ("scheduler.max_nof_ctrl_symbols", bpo::value(&args->stack.mac.sched.max_nof_ctrl_symbols)->default_value(3), "Number of control symbols") ("scheduler.min_nof_ctrl_symbols", bpo::value(&args->stack.mac.sched.min_nof_ctrl_symbols)->default_value(1), "Minimum number of control symbols") ("scheduler.pucch_multiplex_enable", bpo::value(&args->stack.mac.sched.pucch_mux_enabled)->default_value(false), "Enable PUCCH multiplexing") diff --git a/srsenb/src/stack/mac/sched_helpers.cc b/srsenb/src/stack/mac/sched_helpers.cc index a408edd78..14db2fea1 100644 --- a/srsenb/src/stack/mac/sched_helpers.cc +++ b/srsenb/src/stack/mac/sched_helpers.cc @@ -382,10 +382,13 @@ void generate_cce_location(srsran_regs_t* regs_, * DCI-specific helper functions *******************************************************/ -uint32_t -get_aggr_level(uint32_t nof_bits, uint32_t dl_cqi, uint32_t max_aggr_lvl, uint32_t cell_nof_prb, bool use_tbs_index_alt) +uint32_t get_aggr_level(uint32_t nof_bits, + uint32_t dl_cqi, + uint32_t min_aggr_lvl, + uint32_t max_aggr_lvl, + uint32_t cell_nof_prb, + bool use_tbs_index_alt) { - uint32_t l = 0; float max_coderate = srsran_cqi_to_coderate(dl_cqi, use_tbs_index_alt); float coderate; float factor = 1.5; @@ -396,6 +399,7 @@ get_aggr_level(uint32_t nof_bits, uint32_t dl_cqi, uint32_t max_aggr_lvl, uint32 } l_max = SRSRAN_MIN(max_aggr_lvl, l_max); + uint32_t l = min_aggr_lvl; do { coderate = srsran_pdcch_coderate(nof_bits, l); l++; diff --git a/srsenb/src/stack/mac/sched_ue.cc b/srsenb/src/stack/mac/sched_ue.cc index 2b5a42b5e..bbc55a486 100644 --- a/srsenb/src/stack/mac/sched_ue.cc +++ b/srsenb/src/stack/mac/sched_ue.cc @@ -963,9 +963,7 @@ std::pair sched_ue::get_active_cell_index(uint32_t enb_cc_idx) c uint32_t sched_ue::get_aggr_level(uint32_t enb_cc_idx, uint32_t nof_bits) { - const auto& cc = cells[enb_cc_idx]; - return srsenb::get_aggr_level( - nof_bits, cc.get_dl_cqi(), cc.max_aggr_level, cc.cell_cfg->nof_prb(), cfg.use_tbs_index_alt); + return cells[enb_cc_idx].get_aggr_level(nof_bits); } void sched_ue::finish_tti(tti_point tti_rx, uint32_t enb_cc_idx) diff --git a/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc b/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc index 4f1a97c57..8f1aca8eb 100644 --- a/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc +++ b/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc @@ -235,9 +235,23 @@ int sched_ue_cell::get_dl_cqi(const rbgmask_t& rbgs) const int sched_ue_cell::get_dl_cqi() const { - rbgmask_t rbgmask(cell_cfg->nof_rbgs); - rbgmask.fill(0, rbgmask.size()); - return get_dl_cqi(rbgmask); + return std::max(0, (int)std::min(dl_cqi_ctxt.get_avg_cqi() + dl_cqi_coeff, 15.0f)); +} + +uint32_t sched_ue_cell::get_aggr_level(uint32_t nof_bits) const +{ + uint32_t dl_cqi = 0; + if (cell_cfg->sched_cfg->adaptive_aggr_level) { + dl_cqi = get_dl_cqi(); + } else { + dl_cqi = dl_cqi_ctxt.get_avg_cqi(); + } + return srsenb::get_aggr_level(nof_bits, + dl_cqi, + cell_cfg->sched_cfg->min_aggr_level, + max_aggr_level, + cell_cfg->nof_prb(), + ue_cfg->use_tbs_index_alt); } /************************************************************* From a8cccd7a108234a5a95d50cec65e1d0283b0dd54 Mon Sep 17 00:00:00 2001 From: Francisco Date: Tue, 25 May 2021 17:23:04 +0100 Subject: [PATCH 022/156] bugfix, sched: fix aggregation level derivation to avoid L > 3 --- srsenb/src/stack/mac/sched_helpers.cc | 10 +++++++--- srsenb/test/mac/sched_common_test_suite.cc | 2 +- srsenb/test/mac/sched_test_rand.cc | 1 + 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/srsenb/src/stack/mac/sched_helpers.cc b/srsenb/src/stack/mac/sched_helpers.cc index 14db2fea1..587116b88 100644 --- a/srsenb/src/stack/mac/sched_helpers.cc +++ b/srsenb/src/stack/mac/sched_helpers.cc @@ -400,10 +400,14 @@ uint32_t get_aggr_level(uint32_t nof_bits, l_max = SRSRAN_MIN(max_aggr_lvl, l_max); uint32_t l = min_aggr_lvl; - do { + for (; l <= l_max; ++l) { coderate = srsran_pdcch_coderate(nof_bits, l); - l++; - } while (l < l_max && factor * coderate > max_coderate); + if (factor * coderate > max_coderate) { + break; + } + } + // make aggregation level more conservative + l = std::min(l_max, l + 1); Debug("SCHED: CQI=%d, l=%d, nof_bits=%d, coderate=%.2f, max_coderate=%.2f", dl_cqi, diff --git a/srsenb/test/mac/sched_common_test_suite.cc b/srsenb/test/mac/sched_common_test_suite.cc index 2d2554f87..d04999f9a 100644 --- a/srsenb/test/mac/sched_common_test_suite.cc +++ b/srsenb/test/mac/sched_common_test_suite.cc @@ -217,7 +217,7 @@ int test_pdcch_collisions(const sf_output_res_t& sf_out, // Helper Function: checks if there is any collision. If not, fills the PDCCH mask auto try_cce_fill = [&](const srsran_dci_location_t& dci_loc, const char* ch) { uint32_t cce_start = dci_loc.ncce, cce_stop = dci_loc.ncce + (1u << dci_loc.L); - CONDERROR(dci_loc.L == 0, "The aggregation level %d is not valid", dci_loc.L); + CONDERROR(dci_loc.L > 3, "The aggregation level %d is not valid", dci_loc.L); CONDERROR( cce_start >= ncce or cce_stop > ncce, "The CCE positions (%u, %u) do not fit in PDCCH", cce_start, cce_stop); CONDERROR( diff --git a/srsenb/test/mac/sched_test_rand.cc b/srsenb/test/mac/sched_test_rand.cc index e63519f06..7fea30e46 100644 --- a/srsenb/test/mac/sched_test_rand.cc +++ b/srsenb/test/mac/sched_test_rand.cc @@ -294,6 +294,7 @@ sched_sim_events rand_sim_params(uint32_t nof_ttis) boolean_dist() ? -1 : std::uniform_int_distribution<>{0, 24}(srsenb::get_rand_gen()); sim_gen.sim_args.sched_args.pusch_mcs = boolean_dist() ? -1 : std::uniform_int_distribution<>{0, 24}(srsenb::get_rand_gen()); + sim_gen.sim_args.sched_args.min_aggr_level = std::uniform_int_distribution<>{0, 3}(srsenb::get_rand_gen()); generator.tti_events.resize(nof_ttis); From 329cf02cd0c3cc53b07743ed65113e97b414e70a Mon Sep 17 00:00:00 2001 From: Francisco Date: Tue, 25 May 2021 17:52:32 +0100 Subject: [PATCH 023/156] bugfix, sched: ensure max_coderate is respected in scheduler --- srsenb/src/stack/mac/sched_helpers.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/srsenb/src/stack/mac/sched_helpers.cc b/srsenb/src/stack/mac/sched_helpers.cc index 587116b88..8094cb74e 100644 --- a/srsenb/src/stack/mac/sched_helpers.cc +++ b/srsenb/src/stack/mac/sched_helpers.cc @@ -402,7 +402,7 @@ uint32_t get_aggr_level(uint32_t nof_bits, uint32_t l = min_aggr_lvl; for (; l <= l_max; ++l) { coderate = srsran_pdcch_coderate(nof_bits, l); - if (factor * coderate > max_coderate) { + if (factor * coderate <= max_coderate) { break; } } From c75777c61871e659ae146446c130f9225177083a Mon Sep 17 00:00:00 2001 From: Francisco Date: Tue, 25 May 2021 18:38:09 +0100 Subject: [PATCH 024/156] bugfix, sched: avoid compilation issue due to uninitialized variable access --- srsenb/src/stack/mac/sched_helpers.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/srsenb/src/stack/mac/sched_helpers.cc b/srsenb/src/stack/mac/sched_helpers.cc index 8094cb74e..0978a3770 100644 --- a/srsenb/src/stack/mac/sched_helpers.cc +++ b/srsenb/src/stack/mac/sched_helpers.cc @@ -390,16 +390,16 @@ uint32_t get_aggr_level(uint32_t nof_bits, bool use_tbs_index_alt) { float max_coderate = srsran_cqi_to_coderate(dl_cqi, use_tbs_index_alt); - float coderate; - float factor = 1.5; - uint32_t l_max = 3; + float factor = 1.5; + uint32_t l_max = 3; if (cell_nof_prb == 6) { factor = 1.0; l_max = 2; } l_max = SRSRAN_MIN(max_aggr_lvl, l_max); - uint32_t l = min_aggr_lvl; + uint32_t l = min_aggr_lvl; + float coderate = 0; for (; l <= l_max; ++l) { coderate = srsran_pdcch_coderate(nof_bits, l); if (factor * coderate <= max_coderate) { From 4627ae98028a6c97d0a8962ae6a89aef24b18c74 Mon Sep 17 00:00:00 2001 From: Francisco Date: Mon, 24 May 2021 20:15:59 +0100 Subject: [PATCH 025/156] bugfix, scheduler: effectively disable adaptive mcs when target bler is unspecified --- srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h | 4 ++-- .../src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc | 16 ++++++++++------ 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h b/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h index 71bbd333f..ad6ad4b26 100644 --- a/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h +++ b/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h @@ -191,8 +191,8 @@ private: int pending_delta = 0; int acc_tpc_values = 0; - explicit ul_ch_snr_estim(float target_ul_snr = -1) : - snr_avg(0.1, target_ul_snr), win_tpc_values(FDD_HARQ_DELAY_UL_MS + FDD_HARQ_DELAY_DL_MS) + explicit ul_ch_snr_estim(float initial_snr) : + snr_avg(0.1, initial_snr < 0 ? 5 : initial_snr), win_tpc_values(FDD_HARQ_DELAY_UL_MS + FDD_HARQ_DELAY_DL_MS) {} }; std::array snr_estim_list; diff --git a/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc b/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc index 8f1aca8eb..9304ea8e0 100644 --- a/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc +++ b/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc @@ -184,9 +184,11 @@ int sched_ue_cell::set_ul_crc(tti_point tti_rx, bool crc_res) return SRSRAN_ERROR; } - ul_snr_coeff += delta_down - static_cast(not crc_res) * (delta_down + delta_up); - ul_snr_coeff = std::min(std::max(-max_snr_coeff, ul_snr_coeff), max_snr_coeff); - logger.info("SCHED: UL adaptive link: snr_estim=%f, snr_offset=%f", tpc_fsm.get_ul_snr_estim(), ul_snr_coeff); + if (cell_cfg->sched_cfg->target_bler > 0) { + ul_snr_coeff += delta_down - static_cast(not crc_res) * (delta_down + delta_up); + ul_snr_coeff = std::min(std::max(-max_snr_coeff, ul_snr_coeff), max_snr_coeff); + logger.info("SCHED: UL adaptive link: snr_estim=%f, snr_offset=%f", tpc_fsm.get_ul_snr_estim(), ul_snr_coeff); + } return pid; } @@ -199,9 +201,11 @@ int sched_ue_cell::set_ack_info(tti_point tti_rx, uint32_t tb_idx, bool ack) logger.debug( "SCHED: Set DL ACK=%d for rnti=0x%x, pid=%d, tb=%d, tti=%d", ack, rnti, p2.first, tb_idx, tti_rx.to_uint()); - dl_cqi_coeff += delta_down - static_cast(not ack) * (delta_down + delta_up); - dl_cqi_coeff = std::min(std::max(-max_cqi_coeff, dl_cqi_coeff), max_cqi_coeff); - logger.info("SCHED: DL adaptive link: cqi=%d, cqi_offset=%f", dl_cqi_ctxt.get_avg_cqi(), dl_cqi_coeff); + if (cell_cfg->sched_cfg->target_bler > 0) { + dl_cqi_coeff += delta_down - static_cast(not ack) * (delta_down + delta_up); + dl_cqi_coeff = std::min(std::max(-max_cqi_coeff, dl_cqi_coeff), max_cqi_coeff); + logger.info("SCHED: DL adaptive link: cqi=%d, cqi_offset=%f", dl_cqi_ctxt.get_avg_cqi(), dl_cqi_coeff); + } } else { logger.warning("SCHED: Received ACK info for unknown TTI=%d", tti_rx.to_uint()); } From 7076dbfef8cd00fc0ae89b43cc1654148a3669a2 Mon Sep 17 00:00:00 2001 From: Francisco Date: Mon, 24 May 2021 20:48:25 +0100 Subject: [PATCH 026/156] feature, scheduler: Add configuration parameter to set minimum TTI interval between TPCs --- .../srsran/interfaces/sched_interface.h | 1 + srsenb/enb.conf.example | 2 + srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h | 81 +++++++++++-------- srsenb/src/main.cc | 1 + .../stack/mac/sched_ue_ctrl/sched_ue_cell.cc | 3 +- 5 files changed, 54 insertions(+), 34 deletions(-) diff --git a/lib/include/srsran/interfaces/sched_interface.h b/lib/include/srsran/interfaces/sched_interface.h index cb946349d..f2b53188d 100644 --- a/lib/include/srsran/interfaces/sched_interface.h +++ b/lib/include/srsran/interfaces/sched_interface.h @@ -61,6 +61,7 @@ public: float max_delta_dl_cqi = 5; float max_delta_ul_snr = 5; float adaptive_link_step_size = 0.001; + uint32_t min_tpc_tti_interval = 1; }; struct cell_cfg_t { diff --git a/srsenb/enb.conf.example b/srsenb/enb.conf.example index fb2f73e7e..a0e73714e 100644 --- a/srsenb/enb.conf.example +++ b/srsenb/enb.conf.example @@ -173,6 +173,7 @@ enable = false # max_delta_dl_cqi: Maximum shift in CQI for adaptive DL link # max_delta_ul_snr: Maximum shift in UL SNR for adaptive UL link # adaptive_link_step_size: Step size or learning rate used in adaptive link +# min_tpc_tti_interval: Minimum TTI interval between TPCs different than 1 # ##################################################################### [scheduler] @@ -192,6 +193,7 @@ enable = false #max_delta_dl_cqi = 5 #max_delta_ul_snr = 5 #adaptive_link_step_size = 0.001 +#min_tpc_tti_interval = 1 ##################################################################### # eMBMS configuration options diff --git a/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h b/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h index ad6ad4b26..4844f1bc3 100644 --- a/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h +++ b/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h @@ -36,17 +36,19 @@ public: static constexpr int PHR_NEG_NOF_PRB = 1; explicit tpc(uint32_t cell_nof_prb, - float target_pucch_snr_dB_ = -1.0, - float target_pusch_sn_dB_ = -1.0, - bool phr_handling_flag_ = false) : + float target_pucch_snr_dB_ = -1.0, + float target_pusch_sn_dB_ = -1.0, + bool phr_handling_flag_ = false, + uint32_t min_tpc_tti_interval_ = 1) : nof_prb(cell_nof_prb), target_pucch_snr_dB(target_pucch_snr_dB_), target_pusch_snr_dB(target_pusch_sn_dB_), snr_estim_list({ul_ch_snr_estim{target_pusch_snr_dB}, ul_ch_snr_estim{target_pucch_snr_dB}}), - phr_handling_flag(phr_handling_flag_) - { - max_prbs_cached = nof_prb; - } + phr_handling_flag(phr_handling_flag_), + max_prbs_cached(nof_prb), + min_tpc_tti_interval(min_tpc_tti_interval_), + logger(srslog::fetch_basic_logger("MAC")) + {} void set_cfg(float target_pusch_snr_dB_, float target_pucch_snr_dB_) { target_pucch_snr_dB = target_pucch_snr_dB_; @@ -85,7 +87,8 @@ public: void new_tti() { - for (size_t chidx = 0; chidx < 2; ++chidx) { + tti_count++; + for (size_t chidx = 0; chidx < nof_ul_ch_code; ++chidx) { float target_snr_dB = chidx == PUSCH_CODE ? target_pusch_snr_dB : target_pucch_snr_dB; auto& ch_snr = snr_estim_list[chidx]; @@ -139,39 +142,50 @@ private: case 3: return 3; default: - srslog::fetch_basic_logger("MAC").warning("Invalid TPC delta value=%d", delta); + logger.warning("Invalid TPC delta value=%d", delta); return 1; } } uint8_t encode_tpc(uint32_t cc) { - float target_snr_dB = cc == PUSCH_CODE ? target_pusch_snr_dB : target_pucch_snr_dB; - auto& ch_snr = snr_estim_list[cc]; + auto& ch_snr = snr_estim_list[cc]; assert(ch_snr.pending_delta == 0); // ensure called once per {cc,tti} - if (target_snr_dB < 0) { - // undefined target sinr case. - ch_snr.pending_delta = 0; - } else { - // target SINR is finite and there is power headroom - float diff = target_snr_dB - ch_snr.snr_avg.value(); - diff -= ch_snr.win_tpc_values.value() + ch_snr.acc_tpc_values; - int8_t diff_round = roundf(diff); - if (diff_round >= 1) { - ch_snr.pending_delta = diff_round > 3 ? 3 : 1; - } else if (diff_round <= -1) { - ch_snr.pending_delta = -1; - } - if (last_phr <= 0) { - // In case there is no headroom, forbid power increases - ch_snr.pending_delta = std::min(ch_snr.pending_delta, 0); - } + + float target_snr_dB = cc == PUSCH_CODE ? target_pusch_snr_dB : target_pucch_snr_dB; + if (target_snr_dB < 0 or last_phr == 0) { + // undefined target sinr case, or no more PHR + return encode_tpc_delta(0); + } + if (last_phr < 0) { + // negative PHR + encode_tpc_delta(-1); + } + 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); + } + + // target SINR is finite and there is power headroom + float diff = target_snr_dB - ch_snr.snr_avg.value(); + diff -= ch_snr.win_tpc_values.value() + ch_snr.acc_tpc_values; + if (diff >= 1) { + ch_snr.pending_delta = diff > 3 ? 3 : 1; + 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; } return encode_tpc_delta(ch_snr.pending_delta); } - uint32_t nof_prb; - float target_pucch_snr_dB, target_pusch_snr_dB; - bool phr_handling_flag; + uint32_t nof_prb; + uint32_t min_tpc_tti_interval = 1; + float target_pucch_snr_dB, target_pusch_snr_dB; + bool phr_handling_flag; + srslog::basic_logger& logger; + + // state + uint32_t tti_count = 0; // PHR-related variables int last_phr = undefined_phr; @@ -188,8 +202,9 @@ private: srsran::exp_average_irreg_sampling snr_avg; // Accumulation of past TPC commands srsran::sliding_sum win_tpc_values; - int pending_delta = 0; - int acc_tpc_values = 0; + int8_t pending_delta = 0; + int acc_tpc_values = 0; + uint32_t last_tpc_tti_count = 0; explicit ul_ch_snr_estim(float initial_snr) : snr_avg(0.1, initial_snr < 0 ? 5 : initial_snr), win_tpc_values(FDD_HARQ_DELAY_UL_MS + FDD_HARQ_DELAY_DL_MS) diff --git a/srsenb/src/main.cc b/srsenb/src/main.cc index 7b6be3828..8ec826e56 100644 --- a/srsenb/src/main.cc +++ b/srsenb/src/main.cc @@ -155,6 +155,7 @@ void parse_args(all_args_t* args, int argc, char* argv[]) ("scheduler.max_delta_dl_cqi", bpo::value(&args->stack.mac.sched.max_delta_dl_cqi)->default_value(5.0), "Maximum shift in CQI for adaptive DL link") ("scheduler.max_delta_ul_snr", bpo::value(&args->stack.mac.sched.max_delta_ul_snr)->default_value(5.0), "Maximum shift in UL SNR for adaptive UL link") ("scheduler.adaptive_link_step_size", bpo::value(&args->stack.mac.sched.max_delta_ul_snr)->default_value(0.001), "Step size or learning rate used in adaptive link") + ("scheduler.min_tpc_tti_interval", bpo::value(&args->stack.mac.sched.min_tpc_tti_interval)->default_value(1), "Minimum TTI interval between positive or negative TPCs") /* Downlink Channel emulator section */ diff --git a/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc b/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc index 9304ea8e0..c34a6511c 100644 --- a/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc +++ b/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc @@ -38,7 +38,8 @@ sched_ue_cell::sched_ue_cell(uint16_t rnti_, const sched_cell_params_t& cell_cfg tpc_fsm(cell_cfg->nof_prb(), cell_cfg->cfg.target_pucch_ul_sinr, cell_cfg->cfg.target_pusch_ul_sinr, - cell_cfg->cfg.enable_phr_handling), + cell_cfg->cfg.enable_phr_handling, + cell_cfg->sched_cfg->min_tpc_tti_interval), fixed_mcs_dl(cell_cfg_.sched_cfg->pdsch_mcs), fixed_mcs_ul(cell_cfg_.sched_cfg->pusch_mcs), current_tti(current_tti_), From 8d2568ed2c11ddffe4862dffecae651a21fe6c99 Mon Sep 17 00:00:00 2001 From: yagoda Date: Fri, 21 May 2021 10:29:41 +0200 Subject: [PATCH 027/156] small fix for console print for cyclic prefix --- srsue/src/phy/search.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/srsue/src/phy/search.cc b/srsue/src/phy/search.cc index ee35fcadd..fc94da9bd 100644 --- a/srsue/src/phy/search.cc +++ b/srsue/src/phy/search.cc @@ -164,7 +164,7 @@ search::ret_code search::run(srsran_cell_t* cell_, std::array Date: Tue, 25 May 2021 11:56:44 +0100 Subject: [PATCH 028/156] bugfix, s1ap: fix failing s1ap_test --- srsenb/test/s1ap/s1ap_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/srsenb/test/s1ap/s1ap_test.cc b/srsenb/test/s1ap/s1ap_test.cc index 79930d590..78ceec7d9 100644 --- a/srsenb/test/s1ap/s1ap_test.cc +++ b/srsenb/test/s1ap/s1ap_test.cc @@ -87,7 +87,7 @@ struct dummy_socket_manager : public srsran::socket_manager_itf { return true; } - int s1u_fd; + int s1u_fd = -1; recv_callback_t callback; }; From fe0dc77c034d45a1096000274104ac9a64171dbe Mon Sep 17 00:00:00 2001 From: Francisco Date: Tue, 25 May 2021 13:17:20 +0100 Subject: [PATCH 029/156] bugfix, s1ap: fix uninitialized variable access in s1ap_test --- srsenb/src/stack/s1ap/s1ap.cc | 4 ++-- srsenb/test/s1ap/s1ap_test.cc | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/srsenb/src/stack/s1ap/s1ap.cc b/srsenb/src/stack/s1ap/s1ap.cc index 2f722be92..7cb15c4a6 100644 --- a/srsenb/src/stack/s1ap/s1ap.cc +++ b/srsenb/src/stack/s1ap/s1ap.cc @@ -2107,7 +2107,7 @@ bool s1ap::ue::send_enb_status_transfer_proc(std::vector& be void s1ap::log_s1ap_msg(const asn1::s1ap::s1ap_pdu_c& msg, srsran::const_span sdu, bool is_rx) { - std::string msg_type; + const char* msg_type; switch (msg.type().value) { case s1ap_pdu_c::types_opts::init_msg: @@ -2124,7 +2124,7 @@ void s1ap::log_s1ap_msg(const asn1::s1ap::s1ap_pdu_c& msg, srsran::const_spanerab_level_qos_params.alloc_retention_prio.pre_emption_vulnerability.value = asn1::s1ap::pre_emption_vulnerability_opts::not_pre_emptable; erab_ptr->nas_pdu.resize(1); - erab_list[1] = erab_list[0]; - erab_ptr = &erab_list[1].value.erab_to_be_modified_item_bearer_mod_req(); - erab_ptr->erab_id = event == test_event::repeated_erabid_mod ? 5 : 6; + erab_ptr->nas_pdu[0] = 0; + erab_list[1] = erab_list[0]; + erab_ptr = &erab_list[1].value.erab_to_be_modified_item_bearer_mod_req(); + erab_ptr->erab_id = event == test_event::repeated_erabid_mod ? 5 : 6; if (event == test_event::wrong_erabid_mod) { rrc.next_erabs_failed_to_modify.push_back(6); } From d66dac0ab297e0e51c226a1b76a6e09d276d6985 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Wed, 19 May 2021 18:29:50 +0200 Subject: [PATCH 030/156] Added bit sequence state apply --- lib/include/srsran/phy/common/sequence.h | 3 +++ lib/src/phy/common/sequence.c | 26 ++++++++++++++---------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/lib/include/srsran/phy/common/sequence.h b/lib/include/srsran/phy/common/sequence.h index 6d8bfeaf9..cf9f5f12d 100644 --- a/lib/include/srsran/phy/common/sequence.h +++ b/lib/include/srsran/phy/common/sequence.h @@ -38,6 +38,9 @@ SRSRAN_API void srsran_sequence_state_gen_f(srsran_sequence_state_t* s, float va SRSRAN_API void srsran_sequence_state_apply_f(srsran_sequence_state_t* s, const float* in, float* out, uint32_t length); +SRSRAN_API void +srsran_sequence_state_apply_bit(srsran_sequence_state_t* s, const uint8_t* in, uint8_t* out, uint32_t length); + SRSRAN_API void srsran_sequence_state_advance(srsran_sequence_state_t* s, uint32_t length); typedef struct SRSRAN_API { diff --git a/lib/src/phy/common/sequence.c b/lib/src/phy/common/sequence.c index c0a47667a..95e0c1089 100644 --- a/lib/src/phy/common/sequence.c +++ b/lib/src/phy/common/sequence.c @@ -611,16 +611,13 @@ void srsran_sequence_apply_c(const int8_t* in, int8_t* out, uint32_t length, uin } } -void srsran_sequence_apply_bit(const uint8_t* in, uint8_t* out, uint32_t length, uint32_t seed) +void srsran_sequence_state_apply_bit(srsran_sequence_state_t* s, const uint8_t* in, uint8_t* out, uint32_t length) { - uint32_t x1 = sequence_x1_init; // X1 initial state is fix - uint32_t x2 = sequence_get_x2_init(seed); // loads x2 initial state - uint32_t i = 0; if (length >= SEQUENCE_PAR_BITS) { for (; i < length - (SEQUENCE_PAR_BITS - 1); i += SEQUENCE_PAR_BITS) { - uint32_t c = (uint32_t)(x1 ^ x2); + uint32_t c = (uint32_t)(s->x1 ^ s->x2); uint32_t j = 0; #ifdef LV_HAVE_SSE @@ -656,20 +653,27 @@ void srsran_sequence_apply_bit(const uint8_t* in, uint8_t* out, uint32_t length, } // Step sequences - x1 = sequence_gen_LTE_pr_memless_step_par_x1(x1); - x2 = sequence_gen_LTE_pr_memless_step_par_x2(x2); + s->x1 = sequence_gen_LTE_pr_memless_step_par_x1(s->x1); + s->x2 = sequence_gen_LTE_pr_memless_step_par_x2(s->x2); } } for (; i < length; i++) { - out[i] = in[i] ^ ((x1 ^ x2) & 1U); + out[i] = in[i] ^ ((s->x1 ^ s->x2) & 1U); // Step sequences - x1 = sequence_gen_LTE_pr_memless_step_x1(x1); - x2 = sequence_gen_LTE_pr_memless_step_x2(x2); + s->x1 = sequence_gen_LTE_pr_memless_step_x1(s->x1); + s->x2 = sequence_gen_LTE_pr_memless_step_x2(s->x2); } } +void srsran_sequence_apply_bit(const uint8_t* in, uint8_t* out, uint32_t length, uint32_t seed) +{ + srsran_sequence_state_t sequence_state = {}; + srsran_sequence_state_init(&sequence_state, seed); + srsran_sequence_state_apply_bit(&sequence_state, in, out, length); +} + void srsran_sequence_apply_packed(const uint8_t* in, uint8_t* out, uint32_t length, uint32_t seed) { uint32_t x1 = sequence_x1_init; // X1 initial state is fix @@ -750,7 +754,7 @@ void srsran_sequence_apply_packed(const uint8_t* in, uint8_t* out, uint32_t leng out[i] = in[i] ^ reverse_lut[buffer & ((1U << rem8) - 1U) & 255U]; } -#else // SEQUENCE_PAR_BITS % 8 == 0 +#else // SEQUENCE_PAR_BITS % 8 == 0 while (i < (length / 8 - (SEQUENCE_PAR_BITS - 1) / 8)) { uint32_t c = (uint32_t)(x1 ^ x2); From 0aa5b141451c4c4385d7ba69569fe76f607e08ef Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Wed, 19 May 2021 18:30:47 +0200 Subject: [PATCH 031/156] Initial NR PBCH encoding --- lib/include/srsran/phy/phch/pbch_nr.h | 95 +++++- lib/include/srsran/phy/sync/ssb.h | 17 +- lib/include/srsran/srsran.h | 1 + lib/src/phy/fec/polar/polar_rm.c | 69 +++-- lib/src/phy/phch/pbch_nr.c | 404 ++++++++++++++++++++++++++ lib/src/phy/sync/ssb.c | 50 +++- 6 files changed, 599 insertions(+), 37 deletions(-) create mode 100644 lib/src/phy/phch/pbch_nr.c diff --git a/lib/include/srsran/phy/phch/pbch_nr.h b/lib/include/srsran/phy/phch/pbch_nr.h index 6bf9318e3..7a9a41d3d 100644 --- a/lib/include/srsran/phy/phch/pbch_nr.h +++ b/lib/include/srsran/phy/phch/pbch_nr.h @@ -13,13 +13,102 @@ #ifndef SRSRAN_PBCH_NR_H #define SRSRAN_PBCH_NR_H -#include "srsran/config.h" +#include "srsran/phy/common/phy_common_nr.h" +#include "srsran/phy/fec/crc.h" +#include "srsran/phy/fec/polar/polar_code.h" +#include "srsran/phy/fec/polar/polar_decoder.h" +#include "srsran/phy/fec/polar/polar_encoder.h" +#include "srsran/phy/fec/polar/polar_rm.h" +#include "srsran/phy/modem/modem_table.h" /** - * @brief Descibes the NR PBCH message + * @brief NR PBCH payload size generated by higher layers, deduced from TS 38.331 MIB description + */ +#define SRSRAN_PBCH_NR_PAYLOAD_SZ 24 + +/** + * @brief Describes the NR PBCH object initialisation arguments + */ +typedef struct SRSRAN_API { + bool enable_encode; ///< Enable encoder + bool enable_decode; ///< Enable decoder + bool disable_simd; ///< Disable SIMD polar encoder/decoder +} srsran_pbch_nr_args_t; + +/** + * @brief Describes the NR PBCH configuration */ typedef struct SRSRAN_API { - void* TBD; + uint32_t N_id; ///< Physical cell identifier + srsran_subcarrier_spacing_t ssb_scs; ///< SSB Subcarrier spacing + uint32_t Lmax; ///< Number of SSB opportunities, described in TS 38.213 4.1 ... + float beta; ///< Scaling factor for PBCH symbols, set to zero for default + float beta_dmrs; ///< Scaling factor for PBCH DM-RS, set to zero for default +} srsran_pbch_nr_cfg_t; + +/** + * @brief Describes the NR PBCH object initialisation arguments + */ +typedef struct SRSRAN_API { + srsran_polar_code_t code; + srsran_polar_encoder_t polar_encoder; + srsran_polar_decoder_t polar_decoder; + srsran_polar_rm_t polar_rm_tx; + srsran_polar_rm_t polar_rm_rx; + srsran_crc_t crc; + srsran_modem_table_t qpsk; +} srsran_pbch_nr_t; + +/** + * @brief Describes the PBCH message + */ +typedef struct SRSRAN_API { + uint8_t payload[SRSRAN_PBCH_NR_PAYLOAD_SZ]; ///< Actual PBCH payload provided by higher layers + uint32_t sfn_4lsb; ///< SFN 4 LSB + uint32_t ssb_idx; ///< SS/PBCH blocks index described in TS 38.213 4.1 + uint32_t k_ssb_msb; ///< Subcarrier offset MSB described in TS 38.211 7.4.3.1 + uint32_t hrf; ///< Half Radio Frame bit + bool crc; ///< Decoder only, it is true only if the received CRC matches } srsran_pbch_msg_nr_t; +/** + * @brief Initialises an NR PBCH object with the provided arguments + * @param q NR PBCH object + * @param args Arguments providing the desired configuration + * @return SRSRAN_SUCCESS if initialization is successful, SRSLTE_ERROR code otherwise + */ +SRSRAN_API int srsran_pbch_nr_init(srsran_pbch_nr_t* q, const srsran_pbch_nr_args_t* args); + +/** + * @brief Deallocates an NR PBCH object + * @param q NR PBCH object + */ +SRSRAN_API void srsran_pbch_nr_free(srsran_pbch_nr_t* q); + +/** + * @brief Encodes an NR PBCH message into a SSB resource grid + * @param q NR PBCH object + * @param cfg NR PBCH configuration + * @param msg NR PBCH message to transmit + * @param[out] ssb_grid SSB resource grid + * @return SRSRAN_SUCCESS if encoding is successful, SRSLTE_ERROR code otherwise + */ +SRSRAN_API int srsran_pbch_nr_encode(srsran_pbch_nr_t* q, + const srsran_pbch_nr_cfg_t* cfg, + const srsran_pbch_msg_nr_t* msg, + cf_t ssb_grid[SRSRAN_SSB_NOF_RE]); + +/** + * @brief Decodes an NR PBCH message in the SSB resource grid + * @param q NR PBCH object + * @param cfg NR PBCH configuration + * @param[in] ssb_grid SSB resource grid + * @param msg NR PBCH message received + * @return SRSRAN_SUCCESS if decoding is successful, SRSLTE_ERROR code otherwise + */ +SRSRAN_API int srsran_pbch_nr_decode(srsran_pbch_nr_t* q, + const srsran_pbch_nr_cfg_t* cfg, + const cf_t ssb_grid[SRSRAN_SSB_NOF_RE], + srsran_pbch_msg_nr_t* msg); + #endif // SRSRAN_PBCH_NR_H diff --git a/lib/include/srsran/phy/sync/ssb.h b/lib/include/srsran/phy/sync/ssb.h index 31db87415..3a65fe9d5 100644 --- a/lib/include/srsran/phy/sync/ssb.h +++ b/lib/include/srsran/phy/sync/ssb.h @@ -43,12 +43,13 @@ * @brief Describes SSB object initialization arguments */ typedef struct SRSRAN_API { - double max_srate_hz; ///< Maximum sampling rate in Hz, set to zero to use default - srsran_subcarrier_spacing_t min_scs; ///< Minimum subcarrier spacing - bool enable_search; ///< Enables PSS/SSS blind search - bool enable_measure; ///< Enables PSS/SSS CSI measurements and frequency domain search - bool enable_encode; ///< Enables PBCH Encoder - bool enable_decode; ///< Enables PBCH Decoder + double max_srate_hz; ///< Maximum sampling rate in Hz, set to zero to use default + srsran_subcarrier_spacing_t min_scs; ///< Minimum subcarrier spacing + bool enable_search; ///< Enables PSS/SSS blind search + bool enable_measure; ///< Enables PSS/SSS CSI measurements and frequency domain search + bool enable_encode; ///< Enables PBCH Encoder + bool enable_decode; ///< Enables PBCH Decoder + bool disable_polar_simd; ///< Disables polar encoder/decoder SIMD acceleration } srsran_ssb_args_t; /** @@ -87,11 +88,15 @@ typedef struct SRSRAN_API { uint32_t t_offset; ///< Current SSB integer time offset (number of samples) uint32_t cp_sz[SRSRAN_SSB_DURATION_NSYMB]; ///< CP length for each SSB symbol + /// Other parameters + uint32_t Lmax; ///< Number of SSB candidates + /// Internal Objects srsran_dft_plan_t ifft; ///< IFFT object for modulating the SSB srsran_dft_plan_t fft; ///< FFT object for demodulate the SSB. srsran_dft_plan_t fft_corr; ///< FFT for correlation srsran_dft_plan_t ifft_corr; ///< IFFT for correlation + srsran_pbch_nr_t pbch; ///< PBCH encoder and decoder /// Frequency/Time domain temporal data cf_t* tmp_freq; ///< Temporal frequency domain buffer diff --git a/lib/include/srsran/srsran.h b/lib/include/srsran/srsran.h index 81348d4a0..b3bfd641f 100644 --- a/lib/include/srsran/srsran.h +++ b/lib/include/srsran/srsran.h @@ -86,6 +86,7 @@ extern "C" { #include "srsran/phy/phch/dci.h" #include "srsran/phy/phch/dci_nr.h" #include "srsran/phy/phch/pbch.h" +#include "srsran/phy/phch/pbch_nr.h" #include "srsran/phy/phch/pcfich.h" #include "srsran/phy/phch/pdcch.h" #include "srsran/phy/phch/pdcch_nr.h" diff --git a/lib/src/phy/fec/polar/polar_rm.c b/lib/src/phy/fec/polar/polar_rm.c index b22b64cbf..bffd98dc4 100644 --- a/lib/src/phy/fec/polar/polar_rm.c +++ b/lib/src/phy/fec/polar/polar_rm.c @@ -380,7 +380,6 @@ int srsran_polar_rm_tx_init(srsran_polar_rm_t* p) int srsran_polar_rm_rx_init_f(srsran_polar_rm_t* p) { - if (p == NULL) { return -1; } @@ -405,7 +404,6 @@ int srsran_polar_rm_rx_init_f(srsran_polar_rm_t* p) int srsran_polar_rm_rx_init_s(srsran_polar_rm_t* p) { - if (p == NULL) { return -1; } @@ -430,7 +428,6 @@ int srsran_polar_rm_rx_init_s(srsran_polar_rm_t* p) int srsran_polar_rm_rx_init_c(srsran_polar_rm_t* p) { - if (p == NULL) { return -1; } @@ -455,41 +452,74 @@ int srsran_polar_rm_rx_init_c(srsran_polar_rm_t* p) void srsran_polar_rm_tx_free(srsran_polar_rm_t* q) { - if (q != NULL) { - struct pRM_tx* qq = q->ptr; + if (q == NULL) { + return; + } + + struct pRM_tx* qq = q->ptr; + if (qq == NULL) { + return; + } + + if (qq->y_e) { free(qq->y_e); - free(qq); } + + free(qq); } void srsran_polar_rm_rx_free_f(srsran_polar_rm_t* q) { - if (q != NULL) { - struct pRM_rx_f* qq = q->ptr; + if (q == NULL) { + return; + } + + struct pRM_rx_f* qq = q->ptr; + if (qq == NULL) { + return; + } + + if (qq->y_e) { free(qq->y_e); - // free(qq->indices); - free(qq); } + + free(qq); } void srsran_polar_rm_rx_free_s(srsran_polar_rm_t* q) { - if (q != NULL) { - struct pRM_rx_s* qq = q->ptr; + if (q == NULL) { + return; + } + + struct pRM_rx_s* qq = q->ptr; + if (qq == NULL) { + return; + } + + if (qq->y_e) { free(qq->y_e); - // free(qq->indices); - free(qq); } + + free(qq); } void srsran_polar_rm_rx_free_c(srsran_polar_rm_t* q) { - if (q != NULL) { - struct pRM_rx_c* qq = q->ptr; + if (q == NULL) { + return; + } + + struct pRM_rx_c* qq = q->ptr; + if (qq == NULL) { + return; + } + + if (qq->y_e) { free(qq->y_e); - // free(qq->indices); - free(qq); } + + free(qq); } int srsran_polar_rm_tx(srsran_polar_rm_t* q, @@ -529,7 +559,6 @@ int srsran_polar_rm_rx_f(srsran_polar_rm_t* q, const uint32_t K, const uint8_t ibil) { - struct pRM_rx_f* pp = q->ptr; float* y = NULL; float* e = pp->e; // length E @@ -557,7 +586,6 @@ int srsran_polar_rm_rx_s(srsran_polar_rm_t* q, const uint32_t K, const uint8_t ibil) { - struct pRM_rx_s* pp = q->ptr; int16_t* y = NULL; int16_t* e = pp->e; @@ -585,7 +613,6 @@ int srsran_polar_rm_rx_c(srsran_polar_rm_t* q, const uint32_t K, const uint8_t ibil) { - struct pRM_rx_c* pp = q->ptr; int8_t* y = NULL; int8_t* e = pp->e; diff --git a/lib/src/phy/phch/pbch_nr.c b/lib/src/phy/phch/pbch_nr.c new file mode 100644 index 000000000..015963ae1 --- /dev/null +++ b/lib/src/phy/phch/pbch_nr.c @@ -0,0 +1,404 @@ +/** + * + * \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/phch/pbch_nr.h" +#include "srsran/phy/common/sequence.h" +#include "srsran/phy/fec/polar/polar_chanalloc.h" +#include "srsran/phy/modem/mod.h" +#include "srsran/phy/utils/debug.h" +#include "srsran/phy/utils/vector.h" + +/* + * CRC Parameters + */ +#define PBCH_NR_CRC SRSRAN_LTE_CRC24C +#define PBCH_NR_CRC_LEN 24 + +/* + * Polar code N_max + */ +#define PBCH_NR_POLAR_N_MAX 9U + +/* + * Polar rate matching I_BIL + */ +#define pbch_nr_polar_rm_tx_IBIL 0 + +/* + * Number of generated payload bits, called A + */ +#define PBCH_NR_A (SRSRAN_PBCH_NR_PAYLOAD_SZ + 8) + +/* + * Number of payload bits plus CRC + */ +#define PBCH_NR_K (PBCH_NR_A + PBCH_NR_CRC_LEN) + +/* + * Number of Polar encoded bits + */ +#define PBCH_NR_N (1U << PBCH_NR_POLAR_N_MAX) + +/* + * Number of RM bits + */ +#define PBCH_NR_E (864) + +/* + * Number of symbols + */ +#define PBCH_NR_M (PBCH_NR_E / 2) + +/* + * Number of DMRS + */ +#define PBCH_NR_NOF_DMRS (143) + +static int pbch_nr_init_encoder(srsran_pbch_nr_t* q, const srsran_pbch_nr_args_t* args) +{ + // Skip encoder init if not requested + if (!args->enable_encode) { + return SRSRAN_SUCCESS; + } + + srsran_polar_encoder_type_t encoder_type = SRSRAN_POLAR_ENCODER_PIPELINED; + +#ifdef LV_HAVE_AVX2 + if (!args->disable_simd) { + encoder_type = SRSRAN_POLAR_ENCODER_AVX2; + } +#endif /* LV_HAVE_AVX2 */ + + if (srsran_polar_encoder_init(&q->polar_encoder, encoder_type, PBCH_NR_POLAR_N_MAX) < SRSRAN_SUCCESS) { + ERROR("Error initiating polar encoder"); + return SRSRAN_ERROR; + } + + if (srsran_polar_rm_tx_init(&q->polar_rm_tx) < SRSRAN_SUCCESS) { + ERROR("Error initiating polar RM"); + return SRSRAN_ERROR; + } + + if (srsran_modem_table_lte(&q->qpsk, SRSRAN_MOD_QPSK) < SRSRAN_SUCCESS) { + return SRSRAN_ERROR; + } + + return SRSRAN_SUCCESS; +} + +static int pbch_nr_init_decoder(srsran_pbch_nr_t* q, const srsran_pbch_nr_args_t* args) +{ + // Skip decoder init if not requested + if (!args->enable_decode) { + return SRSRAN_SUCCESS; + } + + srsran_polar_decoder_type_t decoder_type = SRSRAN_POLAR_DECODER_SSC_C; + +#ifdef LV_HAVE_AVX2 + if (!args->disable_simd) { + decoder_type = SRSRAN_POLAR_DECODER_SSC_C_AVX2; + } +#endif /* LV_HAVE_AVX2 */ + + if (srsran_polar_decoder_init(&q->polar_decoder, decoder_type, PBCH_NR_POLAR_N_MAX) < SRSRAN_SUCCESS) { + ERROR("Error initiating polar decoder"); + return SRSRAN_ERROR; + } + + if (srsran_polar_rm_rx_init_c(&q->polar_rm_rx) < SRSRAN_SUCCESS) { + ERROR("Error initiating polar RM"); + return SRSRAN_ERROR; + } + + return SRSRAN_SUCCESS; +} + +int srsran_pbch_nr_init(srsran_pbch_nr_t* q, const srsran_pbch_nr_args_t* args) +{ + if (q == NULL || args == NULL) { + return SRSRAN_ERROR_INVALID_INPUTS; + } + + if (!args->enable_encode && !args->enable_decode) { + ERROR("Encoder and decoder are disabled, at least one of them shall be active"); + return SRSRAN_ERROR; + } + + if (pbch_nr_init_encoder(q, args) < SRSRAN_SUCCESS) { + return SRSRAN_ERROR; + } + + if (pbch_nr_init_decoder(q, args) < SRSRAN_SUCCESS) { + return SRSRAN_ERROR; + } + + if (srsran_crc_init(&q->crc, PBCH_NR_CRC, PBCH_NR_CRC_LEN) < SRSRAN_SUCCESS) { + return SRSRAN_ERROR; + } + + if (srsran_polar_code_init(&q->code) < SRSRAN_SUCCESS) { + return SRSRAN_ERROR; + } + + if (srsran_polar_code_get(&q->code, PBCH_NR_K, PBCH_NR_E, PBCH_NR_POLAR_N_MAX) < SRSRAN_SUCCESS) { + ERROR("Error Getting polar code"); + return SRSRAN_ERROR; + } + + return SRSRAN_SUCCESS; +} + +void srsran_pbch_nr_free(srsran_pbch_nr_t* q) +{ + if (q == NULL) { + return; + } + srsran_polar_encoder_free(&q->polar_encoder); + srsran_polar_decoder_free(&q->polar_decoder); + srsran_polar_rm_rx_free_c(&q->polar_rm_rx); + srsran_polar_rm_tx_free(&q->polar_rm_tx); + srsran_polar_code_free(&q->code); + srsran_modem_table_free(&q->qpsk); + SRSRAN_MEM_ZERO(q, srsran_pbch_nr_t, 1); +} + +/* + * Implements TS 38.212 Table 7.1.1-1: Value of PBCH payload interleaver pattern G ( j ) + */ +static const uint32_t G[PBCH_NR_A] = {16, 23, 18, 17, 8, 30, 10, 6, 24, 7, 0, 5, 3, 2, 1, 4, + 9, 11, 12, 13, 14, 15, 19, 20, 21, 22, 25, 26, 27, 28, 29, 31}; + +static void +pbch_nr_pbch_msg_pack(const srsran_pbch_nr_cfg_t* cfg, const srsran_pbch_msg_nr_t* msg, uint8_t a[PBCH_NR_A]) +{ + // Extract actual payload size + uint32_t A_hat = SRSRAN_PBCH_NR_PAYLOAD_SZ; + + // Put SFN in a_hat[A_hat] to a_hat[A_hat + 3] + uint32_t j_sfn = 0; + a[G[j_sfn++]] = (uint8_t)((msg->sfn_4lsb >> 3U) & 1U); // 4th LSB of SFN + a[G[j_sfn++]] = (uint8_t)((msg->sfn_4lsb >> 2U) & 1U); // 3th LSB of SFN + a[G[j_sfn++]] = (uint8_t)((msg->sfn_4lsb >> 1U) & 1U); // 2th LSB of SFN + a[G[j_sfn++]] = (uint8_t)((msg->sfn_4lsb >> 0U) & 1U); // 1th LSB of SFN + + // Put HRF in a_hat[A_hat + 4] + a[G[10]] = (msg->hrf ? 1 : 0); + + // Put SSB related in a_hat[A_hat + 5] to a_hat[A_hat + 7] + if (cfg->Lmax == 64) { + a[G[11]] = (uint8_t)((msg->ssb_idx >> 5U) & 1U); // 6th bit of SSB index + a[G[12]] = (uint8_t)((msg->ssb_idx >> 4U) & 1U); // 5th bit of SSB index + a[G[13]] = (uint8_t)((msg->ssb_idx >> 3U) & 1U); // 4th bit of SSB index + } else { + a[G[11]] = (uint8_t)msg->k_ssb_msb; // 6th bit of SSB index + a[G[12]] = 0; // Reserved + a[G[13]] = 0; // Reserved + } + + // Put actual payload + uint32_t j_other = 14; + for (uint32_t i = 0; i < A_hat; i++) { + if (i > 0 && i < 7) { + a[G[j_sfn++]] = msg->payload[i]; + } else { + a[G[j_other++]] = msg->payload[i]; + } + } +} + +static void pbch_nr_scramble(const srsran_pbch_nr_cfg_t* cfg, const uint8_t a[PBCH_NR_A], uint8_t a_prime[PBCH_NR_A]) +{ + uint32_t i = 0; + uint32_t j = 0; + + // Initialise sequence + srsran_sequence_state_t sequence_state = {}; + srsran_sequence_state_init(&sequence_state, SRSRAN_SEQUENCE_MOD(cfg->N_id)); + + // Select value M + uint32_t M = PBCH_NR_A - 3; + if (cfg->Lmax == 64) { + M = PBCH_NR_A - 6; + } + + // Select value v + uint32_t v = 2 * a[G[1]] + a[G[2]]; + + // Advance sequence + srsran_sequence_state_advance(&sequence_state, M * v); + + // Generate actual sequence + uint8_t c[PBCH_NR_A] = {}; + srsran_sequence_state_apply_bit(&sequence_state, c, c, PBCH_NR_A); + + while (i < PBCH_NR_A) { + // a i corresponds to any one of the bits belonging to the SS/PBCH block index, the half frame index, and 2 nd and 3 + // rd least significant bits of the system frame number + uint8_t s_i = c[j]; + + // else + if (i == G[11] || i == G[12] || i == G[13] || i == G[10] || i == G[1] || i == G[2]) { + s_i = 0; + } else { + j++; + } + + a_prime[i] = a[i] ^ s_i; + i++; + } +} + +static int pbch_nr_polar_encode(srsran_pbch_nr_t* q, const uint8_t c[PBCH_NR_K], uint8_t d[PBCH_NR_K]) +{ + // Allocate channel + uint8_t allocated[PBCH_NR_N]; + srsran_polar_chanalloc_tx(c, allocated, q->code.N, q->code.K, q->code.nPC, q->code.K_set, q->code.PC_set); + + // Encode bits + if (srsran_polar_encoder_encode(&q->polar_encoder, allocated, d, q->code.n) < SRSRAN_SUCCESS) { + return SRSRAN_ERROR; + } + + return SRSRAN_SUCCESS; +} + +static int pbch_nr_polar_rm_tx(srsran_pbch_nr_t* q, const uint8_t d[PBCH_NR_K], uint8_t o[PBCH_NR_E]) +{ + if (srsran_polar_rm_tx(&q->polar_rm_tx, d, o, q->code.n, PBCH_NR_E, PBCH_NR_K, pbch_nr_polar_rm_tx_IBIL) < + SRSRAN_SUCCESS) { + return SRSRAN_ERROR; + } + + return SRSRAN_SUCCESS; +} + +static void pbch_nr_scramble_tx(const srsran_pbch_nr_cfg_t* cfg, + uint32_t ssb_idx, + const uint8_t b[PBCH_NR_E], + uint8_t b_hat[PBCH_NR_E]) +{ + // Initialise sequence + srsran_sequence_state_t sequence_state = {}; + srsran_sequence_state_init(&sequence_state, SRSRAN_SEQUENCE_MOD(cfg->N_id)); + + // Select value M + uint32_t M_bit = PBCH_NR_E; + + // Select value v + uint32_t v = (ssb_idx & 0x7U); + if (cfg->Lmax == 4) { + v = ssb_idx & 0x3U; + } + + // Advance sequence + srsran_sequence_state_advance(&sequence_state, v * M_bit); + + // Apply sequence + srsran_sequence_state_apply_bit(&sequence_state, b, b_hat, PBCH_NR_E); +} + +static void +pbch_nr_mapping(const srsran_pbch_nr_cfg_t* cfg, const cf_t symbols[PBCH_NR_E], cf_t ssb_grid[SRSRAN_SSB_NOF_RE]) +{ + uint32_t count = 0; + + // PBCH DMRS shift + uint32_t v = cfg->N_id % 4; + + // Symbol 1 + for (uint32_t k = 0; k < SRSRAN_SSB_BW_SUBC; k++) { + // Skip DMRS + if (k % 4 == v) { + continue; + } + + ssb_grid[1 * SRSRAN_SSB_BW_SUBC + k] = symbols[count++]; + } + + // Symbol 2 + for (uint32_t k = 0; k < 48; k++) { + // Skip DMRS + if (k % 4 == v) { + continue; + } + + ssb_grid[2 * SRSRAN_SSB_BW_SUBC + k] = symbols[count++]; + } + for (uint32_t k = 192; k < SRSRAN_SSB_BW_SUBC; k++) { + // Skip DMRS + if (k % 4 == v) { + continue; + } + + ssb_grid[2 * SRSRAN_SSB_BW_SUBC + k] = symbols[count++]; + } + + // Symbol 3 + for (uint32_t k = 0; k < SRSRAN_SSB_BW_SUBC; k++) { + // Skip DMRS + if (k % 4 == v) { + continue; + } + + ssb_grid[3 * SRSRAN_SSB_BW_SUBC + k] = symbols[count++]; + } +} + +int srsran_pbch_nr_encode(srsran_pbch_nr_t* q, + const srsran_pbch_nr_cfg_t* cfg, + const srsran_pbch_msg_nr_t* msg, + cf_t ssb_grid[SRSRAN_SSB_NOF_RE]) +{ + if (q == NULL || cfg == NULL || msg == NULL || ssb_grid == NULL) { + return SRSRAN_ERROR_INVALID_INPUTS; + } + + // TS 38.212 7.1 Broadcast channel + // 7.1.1 PBCH payload generation + uint8_t a[PBCH_NR_A]; + pbch_nr_pbch_msg_pack(cfg, msg, a); + + // 7.1.2 Scrambling + uint8_t b[PBCH_NR_K]; + pbch_nr_scramble(cfg, a, b); + + // 7.1.3 Transport block CRC attachment + uint32_t checksum = srsran_crc_attach(&q->crc, b, PBCH_NR_A); + INFO("NR-PBCH: checksum=%06x", checksum); + + // 7.1.4 Channel coding + uint8_t d[PBCH_NR_K]; + if (pbch_nr_polar_encode(q, b, d) < SRSRAN_SUCCESS) { + return SRSRAN_ERROR; + } + + // 7.1.5 Rate matching + uint8_t f[PBCH_NR_E]; + if (pbch_nr_polar_rm_tx(q, d, f) < SRSRAN_SUCCESS) { + return SRSRAN_ERROR; + } + + // TS 38.211 7.3.3 Physical broadcast channel + // 7.3.3.1 Scrambling + pbch_nr_scramble_tx(cfg, msg->ssb_idx, f, f); + + // 7.3.3.2 Modulation + cf_t symbols[PBCH_NR_M]; + srsran_mod_modulate(&q->qpsk, f, symbols, PBCH_NR_E); + + // 7.3.3.3 Mapping to physical resources + // 7.4.3.1.3 Mapping of PBCH and DM-RS within an SS/PBCH block + pbch_nr_mapping(cfg, symbols, ssb_grid); + + return SRSRAN_SUCCESS; +} diff --git a/lib/src/phy/sync/ssb.c b/lib/src/phy/sync/ssb.c index a5a08594e..9a7ecf91a 100644 --- a/lib/src/phy/sync/ssb.c +++ b/lib/src/phy/sync/ssb.c @@ -53,6 +53,25 @@ static int ssb_init_corr(srsran_ssb_t* q) return SRSRAN_SUCCESS; } +static int ssb_init_pbch(srsran_ssb_t* q) +{ + srsran_pbch_nr_args_t args = {}; + args.enable_encode = q->args.enable_encode; + args.enable_decode = q->args.enable_decode; + args.disable_simd = q->args.disable_polar_simd; + + if (!args.enable_encode && !args.enable_decode) { + return SRSRAN_SUCCESS; + } + + if (srsran_pbch_nr_init(&q->pbch, &args) < SRSRAN_SUCCESS) { + ERROR("Error init NR PBCH"); + return SRSRAN_SUCCESS; + } + + return SRSRAN_SUCCESS; +} + int srsran_ssb_init(srsran_ssb_t* q, const srsran_ssb_args_t* args) { // Verify input parameters @@ -86,6 +105,11 @@ int srsran_ssb_init(srsran_ssb_t* q, const srsran_ssb_args_t* args) return SRSRAN_ERROR; } + // PBCH + if (ssb_init_pbch(q) < SRSRAN_SUCCESS) { + return SRSRAN_ERROR; + } + return SRSRAN_SUCCESS; } @@ -118,6 +142,7 @@ void srsran_ssb_free(srsran_ssb_t* q) srsran_dft_plan_free(&q->fft); srsran_dft_plan_free(&q->fft_corr); srsran_dft_plan_free(&q->ifft_corr); + srsran_pbch_nr_free(&q->pbch); SRSRAN_MEM_ZERO(q, srsran_ssb_t, 1); } @@ -228,9 +253,8 @@ static uint32_t ssb_first_symbol_caseE(const srsran_ssb_cfg_t* cfg, uint32_t ind return count; } -static int ssb_first_symbol(const srsran_ssb_cfg_t* cfg, uint32_t ssb_i) +static uint32_t ssb_candidates(const srsran_ssb_cfg_t* cfg, uint32_t indexes[SRSRAN_SSB_NOF_POSITION]) { - uint32_t indexes[SRSRAN_SSB_NOF_POSITION]; uint32_t Lmax = 0; switch (cfg->pattern) { @@ -251,12 +275,17 @@ static int ssb_first_symbol(const srsran_ssb_cfg_t* cfg, uint32_t ssb_i) break; case SRSRAN_SSB_PATTERN_INVALID: ERROR("Invalid case"); - return SRSRAN_ERROR; } + return Lmax; +} - uint32_t ssb_count = 0; +static int ssb_first_symbol(const srsran_ssb_cfg_t* cfg, uint32_t ssb_i, uint32_t* Lmax) +{ + uint32_t indexes[SRSRAN_SSB_NOF_POSITION]; + *Lmax = ssb_candidates(cfg, indexes); - for (uint32_t i = 0; i < Lmax; i++) { + uint32_t ssb_count = 0; + for (uint32_t i = 0; i < *Lmax; i++) { // There is a SSB transmission opportunity if (cfg->position[i]) { // Return the SSB transmission in burst @@ -380,7 +409,7 @@ int srsran_ssb_set_cfg(srsran_ssb_t* q, const srsran_ssb_cfg_t* cfg) q->scs_hz = (float)SRSRAN_SUBC_SPACING_NR(cfg->scs); // Get first symbol - int l_begin = ssb_first_symbol(cfg, 0); + int l_begin = ssb_first_symbol(cfg, 0, &q->Lmax); if (l_begin < SRSRAN_SUCCESS) { // set it to 2 in case it is not selected l_begin = 2; @@ -531,7 +560,14 @@ int srsran_ssb_add(srsran_ssb_t* q, uint32_t N_id, const srsran_pbch_msg_nr_t* m // ... // Put PBCH payload - // ... + srsran_pbch_nr_cfg_t pbch_cfg = {}; + pbch_cfg.N_id = N_id; + pbch_cfg.ssb_scs = q->cfg.scs; + pbch_cfg.Lmax = q->Lmax; + if (srsran_pbch_nr_encode(&q->pbch, &pbch_cfg, msg, ssb_grid) < SRSRAN_SUCCESS) { + ERROR("Error encoding PBCH"); + return SRSRAN_ERROR; + } // Select input/ouput pointers considering the time offset in the slot const cf_t* in_ptr = &in[q->t_offset]; From 3634e96c3e9097315165ae4bc7d3360ce96b6651 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Wed, 19 May 2021 18:34:17 +0200 Subject: [PATCH 032/156] Added SSB measure test add/put/encode time measure --- lib/src/phy/sync/test/ssb_measure_test.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/src/phy/sync/test/ssb_measure_test.c b/lib/src/phy/sync/test/ssb_measure_test.c index a1dfe34b7..9f87da361 100644 --- a/lib/src/phy/sync/test/ssb_measure_test.c +++ b/lib/src/phy/sync/test/ssb_measure_test.c @@ -91,6 +91,7 @@ static int assert_measure(const srsran_csi_trs_measurements_t* meas) static int test_case_1(srsran_ssb_t* ssb) { // For benchmarking purposes + uint64_t t_add_usec = 0; uint64_t t_find_usec = 0; uint64_t t_meas_usec = 0; @@ -115,7 +116,11 @@ static int test_case_1(srsran_ssb_t* ssb) srsran_vec_cf_zero(buffer, sf_len); // Add the SSB base-band + gettimeofday(&t[1], NULL); TESTASSERT(srsran_ssb_add(ssb, pci, &pbch_msg, buffer, buffer) == SRSRAN_SUCCESS); + gettimeofday(&t[2], NULL); + get_time_interval(t); + t_add_usec += t[0].tv_usec + t[0].tv_sec * 1000000UL; // Run channel run_channel(); @@ -152,7 +157,8 @@ static int test_case_1(srsran_ssb_t* ssb) TESTASSERT(assert_measure(&meas) == SRSRAN_SUCCESS); } - INFO("test_case_1 - %.1f usec/search; Max srate %.1f MSps; %.1f usec/measurement", + INFO("test_case_1 - %.1f usec/encode; %.1f usec/search; Max srate %.1f MSps; %.1f usec/measurement", + (double)t_add_usec / (double)SRSRAN_NOF_NID_NR, (double)t_find_usec / (double)SRSRAN_NOF_NID_NR, (double)sf_len * (double)SRSRAN_NOF_NID_NR / (double)t_find_usec, (double)t_meas_usec / (double)SRSRAN_NOF_NID_NR); From bcb91d6173969db29b4a0ee8922800662fed2d3b Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Thu, 20 May 2021 13:42:29 +0200 Subject: [PATCH 033/156] srsran_vec_sprint_hex returns number of written characters --- lib/include/srsran/phy/utils/vector.h | 20 ++++++++++---------- lib/src/phy/utils/vector.c | 7 +++++-- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/lib/include/srsran/phy/utils/vector.h b/lib/include/srsran/phy/utils/vector.h index f62875cbf..e3f922ca9 100644 --- a/lib/include/srsran/phy/utils/vector.h +++ b/lib/include/srsran/phy/utils/vector.h @@ -123,16 +123,16 @@ SRSRAN_API void srsran_vec_u16_copy(uint16_t* dst, const uint16_t* src, uint32_t SRSRAN_API void srsran_vec_i16_copy(int16_t* dst, const int16_t* src, uint32_t len); /* print vectors */ -SRSRAN_API void srsran_vec_fprint_c(FILE* stream, const cf_t* x, const uint32_t len); -SRSRAN_API void srsran_vec_fprint_f(FILE* stream, const float* x, const uint32_t len); -SRSRAN_API void srsran_vec_fprint_b(FILE* stream, const uint8_t* x, const uint32_t len); -SRSRAN_API void srsran_vec_fprint_bs(FILE* stream, const int8_t* x, const uint32_t len); -SRSRAN_API void srsran_vec_fprint_byte(FILE* stream, const uint8_t* x, const uint32_t len); -SRSRAN_API void srsran_vec_fprint_i(FILE* stream, const int* x, const uint32_t len); -SRSRAN_API void srsran_vec_fprint_s(FILE* stream, const int16_t* x, const uint32_t len); -SRSRAN_API void srsran_vec_fprint_hex(FILE* stream, uint8_t* x, const uint32_t len); -SRSRAN_API void srsran_vec_sprint_hex(char* str, const uint32_t max_str_len, uint8_t* x, const uint32_t len); -SRSRAN_API void srsran_vec_sprint_bin(char* str, const uint32_t max_str_len, const uint8_t* x, const uint32_t len); +SRSRAN_API void srsran_vec_fprint_c(FILE* stream, const cf_t* x, const uint32_t len); +SRSRAN_API void srsran_vec_fprint_f(FILE* stream, const float* x, const uint32_t len); +SRSRAN_API void srsran_vec_fprint_b(FILE* stream, const uint8_t* x, const uint32_t len); +SRSRAN_API void srsran_vec_fprint_bs(FILE* stream, const int8_t* x, const uint32_t len); +SRSRAN_API void srsran_vec_fprint_byte(FILE* stream, const uint8_t* x, const uint32_t len); +SRSRAN_API void srsran_vec_fprint_i(FILE* stream, const int* x, const uint32_t len); +SRSRAN_API void srsran_vec_fprint_s(FILE* stream, const int16_t* x, const uint32_t len); +SRSRAN_API void srsran_vec_fprint_hex(FILE* stream, uint8_t* x, const uint32_t len); +SRSRAN_API uint32_t srsran_vec_sprint_hex(char* str, const uint32_t max_str_len, uint8_t* x, const uint32_t len); +SRSRAN_API void srsran_vec_sprint_bin(char* str, const uint32_t max_str_len, const uint8_t* x, const uint32_t len); /* Saves/loads a vector to a file */ SRSRAN_API void srsran_vec_save_file(char* filename, const void* buffer, const uint32_t len); diff --git a/lib/src/phy/utils/vector.c b/lib/src/phy/utils/vector.c index a9ead28da..f02f5959e 100644 --- a/lib/src/phy/utils/vector.c +++ b/lib/src/phy/utils/vector.c @@ -354,7 +354,7 @@ void srsran_vec_fprint_hex(FILE* stream, uint8_t* x, const uint32_t len) fprintf(stream, "];\n"); } -void srsran_vec_sprint_hex(char* str, const uint32_t max_str_len, uint8_t* x, const uint32_t len) +uint32_t srsran_vec_sprint_hex(char* str, const uint32_t max_str_len, uint8_t* x, const uint32_t len) { uint32_t i, nbytes; uint8_t byte; @@ -362,7 +362,7 @@ void srsran_vec_sprint_hex(char* str, const uint32_t max_str_len, uint8_t* x, co // check that hex string fits in buffer (every byte takes 3 characters, plus brackets) if ((3 * (len / 8 + ((len % 8) ? 1 : 0))) + 2 >= max_str_len) { ERROR("Buffer too small for printing hex string (max_str_len=%d, payload_len=%d).", max_str_len, len); - return; + return 0; } int n = 0; @@ -376,7 +376,10 @@ void srsran_vec_sprint_hex(char* str, const uint32_t max_str_len, uint8_t* x, co n += sprintf(&str[n], "%02x ", byte); } n += sprintf(&str[n], "]"); + str[n] = 0; str[max_str_len - 1] = 0; + + return n; } void srsran_vec_sprint_bin(char* str, const uint32_t max_str_len, const uint8_t* x, const uint32_t len) From 1f38817b3bdcc228cab46399bd944bf77e947d33 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Thu, 20 May 2021 13:42:56 +0200 Subject: [PATCH 034/156] Added random bit vector generator --- lib/include/srsran/phy/utils/random.h | 2 ++ lib/src/phy/utils/random.cpp | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/lib/include/srsran/phy/utils/random.h b/lib/include/srsran/phy/utils/random.h index 1cf42196a..4383f2d0c 100644 --- a/lib/include/srsran/phy/utils/random.h +++ b/lib/include/srsran/phy/utils/random.h @@ -39,6 +39,8 @@ SRSRAN_API float srsran_random_gauss_dist(srsran_random_t q, float std_dev); SRSRAN_API bool srsran_random_bool(srsran_random_t q, float prob_true); +SRSRAN_API void srsran_random_bit_vector(srsran_random_t q, uint8_t* c, uint32_t nsamples); + SRSRAN_API void srsran_random_free(srsran_random_t q); #ifdef __cplusplus diff --git a/lib/src/phy/utils/random.cpp b/lib/src/phy/utils/random.cpp index 4b192bcf9..b71c9a646 100644 --- a/lib/src/phy/utils/random.cpp +++ b/lib/src/phy/utils/random.cpp @@ -113,6 +113,13 @@ bool srsran_random_bool(srsran_random_t q, float prob_true) return srsran_random_uniform_real_dist(q, 0, 1) < prob_true; } +void srsran_random_bit_vector(srsran_random_t q, uint8_t* c, uint32_t nsamples) +{ + for (uint32_t i = 0; i < nsamples; i++) { + c[i] = (uint8_t)srsran_random_uniform_int_dist(q, 0, 1); + } +} + void srsran_random_free(srsran_random_t q) { if (q) { From de1b25558f200bf82bb6248010e4bee0632ed24e Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Thu, 20 May 2021 13:43:49 +0200 Subject: [PATCH 035/156] Added PRN sequence apply bit with state --- lib/include/srsran/phy/common/sequence.h | 5 ++++- lib/src/phy/common/sequence.c | 24 ++++++++++++++---------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/lib/include/srsran/phy/common/sequence.h b/lib/include/srsran/phy/common/sequence.h index cf9f5f12d..83cb35310 100644 --- a/lib/include/srsran/phy/common/sequence.h +++ b/lib/include/srsran/phy/common/sequence.h @@ -39,7 +39,10 @@ SRSRAN_API void srsran_sequence_state_gen_f(srsran_sequence_state_t* s, float va SRSRAN_API void srsran_sequence_state_apply_f(srsran_sequence_state_t* s, const float* in, float* out, uint32_t length); SRSRAN_API void -srsran_sequence_state_apply_bit(srsran_sequence_state_t* s, const uint8_t* in, uint8_t* out, uint32_t length); +srsran_sequence_state_apply_c(srsran_sequence_state_t* s, const int8_t* in, int8_t* out, uint32_t length); + +SRSRAN_API +void srsran_sequence_state_apply_bit(srsran_sequence_state_t* s, const uint8_t* in, uint8_t* out, uint32_t length); SRSRAN_API void srsran_sequence_state_advance(srsran_sequence_state_t* s, uint32_t length); diff --git a/lib/src/phy/common/sequence.c b/lib/src/phy/common/sequence.c index 95e0c1089..b9a86552d 100644 --- a/lib/src/phy/common/sequence.c +++ b/lib/src/phy/common/sequence.c @@ -551,16 +551,13 @@ void srsran_sequence_apply_s(const int16_t* in, int16_t* out, uint32_t length, u } } -void srsran_sequence_apply_c(const int8_t* in, int8_t* out, uint32_t length, uint32_t seed) +void srsran_sequence_state_apply_c(srsran_sequence_state_t* s, const int8_t* in, int8_t* out, uint32_t length) { - uint32_t x1 = sequence_x1_init; // X1 initial state is fix - uint32_t x2 = sequence_get_x2_init(seed); // loads x2 initial state - uint32_t i = 0; if (length >= SEQUENCE_PAR_BITS) { for (; i < length - (SEQUENCE_PAR_BITS - 1); i += SEQUENCE_PAR_BITS) { - uint32_t c = (uint32_t)(x1 ^ x2); + uint32_t c = (uint32_t)(s->x1 ^ s->x2); uint32_t j = 0; #ifdef LV_HAVE_SSE @@ -597,20 +594,27 @@ void srsran_sequence_apply_c(const int8_t* in, int8_t* out, uint32_t length, uin } // Step sequences - x1 = sequence_gen_LTE_pr_memless_step_par_x1(x1); - x2 = sequence_gen_LTE_pr_memless_step_par_x2(x2); + s->x1 = sequence_gen_LTE_pr_memless_step_par_x1(s->x1); + s->x2 = sequence_gen_LTE_pr_memless_step_par_x2(s->x2); } } for (; i < length; i++) { - out[i] = in[i] * (((x1 ^ x2) & 1U) ? -1 : +1); + out[i] = in[i] * (((s->x1 ^ s->x2) & 1U) ? -1 : +1); // Step sequences - x1 = sequence_gen_LTE_pr_memless_step_x1(x1); - x2 = sequence_gen_LTE_pr_memless_step_x2(x2); + s->x1 = sequence_gen_LTE_pr_memless_step_x1(s->x1); + s->x2 = sequence_gen_LTE_pr_memless_step_x2(s->x2); } } +void srsran_sequence_apply_c(const int8_t* in, int8_t* out, uint32_t length, uint32_t seed) +{ + srsran_sequence_state_t sequence_state; + srsran_sequence_state_init(&sequence_state, seed); + srsran_sequence_state_apply_c(&sequence_state, in, out, length); +} + void srsran_sequence_state_apply_bit(srsran_sequence_state_t* s, const uint8_t* in, uint8_t* out, uint32_t length) { uint32_t i = 0; From 48e0fc3c995df3a6e20328f43aa915e52bfe5b0e Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Thu, 20 May 2021 13:52:58 +0200 Subject: [PATCH 036/156] Implemented initial PBCH decoder and refactored SSB candidate selection --- .../interfaces/rrc_nr_interface_types.h | 6 +- lib/include/srsran/phy/phch/pbch_nr.h | 16 +- lib/include/srsran/phy/sync/ssb.h | 57 ++-- lib/src/asn1/rrc_nr_utils.cc | 6 +- lib/src/phy/phch/pbch_nr.c | 287 +++++++++++++++++- lib/src/phy/sync/ssb.c | 174 ++++++----- lib/src/phy/sync/test/CMakeLists.txt | 7 +- lib/src/phy/sync/test/ssb_decode_test.c | 205 +++++++++++++ lib/src/phy/sync/test/ssb_measure_test.c | 5 +- srsue/src/phy/nr/cc_worker.cc | 58 ++-- srsue/test/phy/nr_cell_search_test.cc | 3 +- 11 files changed, 675 insertions(+), 149 deletions(-) create mode 100644 lib/src/phy/sync/test/ssb_decode_test.c diff --git a/lib/include/srsran/interfaces/rrc_nr_interface_types.h b/lib/include/srsran/interfaces/rrc_nr_interface_types.h index e7eee83df..a1725e734 100644 --- a/lib/include/srsran/interfaces/rrc_nr_interface_types.h +++ b/lib/include/srsran/interfaces/rrc_nr_interface_types.h @@ -29,9 +29,9 @@ struct phy_cfg_nr_t { * SSB configuration */ struct ssb_cfg_t { - uint32_t periodicity_ms; - std::array position_in_burst; - srsran_subcarrier_spacing_t scs; + uint32_t periodicity_ms; + std::array position_in_burst; + srsran_subcarrier_spacing_t scs; }; srsran_tdd_config_nr_t tdd = {}; diff --git a/lib/include/srsran/phy/phch/pbch_nr.h b/lib/include/srsran/phy/phch/pbch_nr.h index 7a9a41d3d..f849f4285 100644 --- a/lib/include/srsran/phy/phch/pbch_nr.h +++ b/lib/include/srsran/phy/phch/pbch_nr.h @@ -63,12 +63,12 @@ typedef struct SRSRAN_API { * @brief Describes the PBCH message */ typedef struct SRSRAN_API { - uint8_t payload[SRSRAN_PBCH_NR_PAYLOAD_SZ]; ///< Actual PBCH payload provided by higher layers - uint32_t sfn_4lsb; ///< SFN 4 LSB - uint32_t ssb_idx; ///< SS/PBCH blocks index described in TS 38.213 4.1 - uint32_t k_ssb_msb; ///< Subcarrier offset MSB described in TS 38.211 7.4.3.1 - uint32_t hrf; ///< Half Radio Frame bit - bool crc; ///< Decoder only, it is true only if the received CRC matches + uint8_t payload[SRSRAN_PBCH_NR_PAYLOAD_SZ]; ///< Actual PBCH payload provided by higher layers + uint8_t sfn_4lsb; ///< SFN 4 LSB + uint8_t ssb_idx; ///< SS/PBCH blocks index described in TS 38.213 4.1 + uint8_t k_ssb_msb; ///< Subcarrier offset MSB described in TS 38.211 7.4.3.1 + bool hrf; ///< Half Radio Frame bit + bool crc; ///< Decoder only, it is true only if the received CRC matches } srsran_pbch_msg_nr_t; /** @@ -102,13 +102,17 @@ SRSRAN_API int srsran_pbch_nr_encode(srsran_pbch_nr_t* q, * @brief Decodes an NR PBCH message in the SSB resource grid * @param q NR PBCH object * @param cfg NR PBCH configuration + * @param ssb_idx SSB candidate index * @param[in] ssb_grid SSB resource grid * @param msg NR PBCH message received * @return SRSRAN_SUCCESS if decoding is successful, SRSLTE_ERROR code otherwise */ SRSRAN_API int srsran_pbch_nr_decode(srsran_pbch_nr_t* q, const srsran_pbch_nr_cfg_t* cfg, + uint32_t ssb_idx, const cf_t ssb_grid[SRSRAN_SSB_NOF_RE], srsran_pbch_msg_nr_t* msg); +SRSRAN_API uint32_t srsran_pbch_msg_info(const srsran_pbch_msg_nr_t* msg, char* str, uint32_t str_len); + #endif // SRSRAN_PBCH_NR_H diff --git a/lib/include/srsran/phy/sync/ssb.h b/lib/include/srsran/phy/sync/ssb.h index 3a65fe9d5..033d670a6 100644 --- a/lib/include/srsran/phy/sync/ssb.h +++ b/lib/include/srsran/phy/sync/ssb.h @@ -37,7 +37,7 @@ /** * @brief Maximum number of SSB positions in burst. Defined in TS 38.331 ServingCellConfigCommon, ssb-PositionsInBurst */ -#define SRSRAN_SSB_NOF_POSITION 64 +#define SRSRAN_SSB_NOF_CANDIDATES 64 /** * @brief Describes SSB object initialization arguments @@ -61,13 +61,12 @@ typedef struct SRSRAN_API { double ssb_freq_hz; ///< SSB center frequency srsran_subcarrier_spacing_t scs; ///< SSB configured Subcarrier spacing srsran_ssb_patern_t pattern; ///< SSB pattern as defined in TS 38.313 section 4.1 Cell search - bool position[SRSRAN_SSB_NOF_POSITION]; ///< Indicates the time domain positions of the transmitted SS-blocks - 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 + 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 } srsran_ssb_cfg_t; /** @@ -78,18 +77,18 @@ typedef struct SRSRAN_API { srsran_ssb_cfg_t cfg; ///< Stores last configuration /// Sampling rate dependent parameters - float scs_hz; ///< Subcarrier spacing in Hz - 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 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 - int32_t f_offset; ///< Current SSB integer frequency offset (multiple of SCS) - uint32_t t_offset; ///< Current SSB integer time offset (number of samples) - uint32_t cp_sz[SRSRAN_SSB_DURATION_NSYMB]; ///< CP length for each SSB symbol + float scs_hz; ///< Subcarrier spacing in Hz + 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 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 + int32_t f_offset; ///< Current SSB integer frequency offset (multiple of SCS) + uint32_t cp_sz; ///< CP length for the given symbol size /// Other parameters - uint32_t Lmax; ///< Number of SSB candidates + uint32_t l_first[SRSRAN_SSB_NOF_CANDIDATES]; ///< Start symbol for each SSB candidate in half radio frame + uint32_t Lmax; ///< Number of SSB candidates /// Internal Objects srsran_dft_plan_t ifft; ///< IFFT object for modulating the SSB @@ -129,9 +128,12 @@ SRSRAN_API int srsran_ssb_set_cfg(srsran_ssb_t* q, const srsran_ssb_cfg_t* cfg); /** * @brief Decodes PBCH in the given time domain signal * @param q SSB object + * @param N_id Physical Cell Identifier + * @param ssb_idx SSB candidate index * @return SRSRAN_SUCCESS if the parameters are valid, SRSRAN_ERROR code otherwise */ -SRSRAN_API int srsran_ssb_decode_pbch(srsran_ssb_t* q, const cf_t* in, srsran_pbch_msg_nr_t* msg); +SRSRAN_API int +srsran_ssb_decode_pbch(srsran_ssb_t* q, uint32_t N_id, uint32_t ssb_idx, const cf_t* in, srsran_pbch_msg_nr_t* msg); /** * @brief Decides if the SSB object is configured and a given subframe is configured for SSB transmission @@ -145,11 +147,16 @@ SRSRAN_API bool srsran_ssb_send(srsran_ssb_t* q, uint32_t sf_idx); * @brief Adds SSB to a given signal in time domain * @param q SSB object * @param N_id Physical Cell Identifier + * @param ssb_idx SSB candidate index * @param msg NR PBCH message to transmit * @return SRSRAN_SUCCESS if the parameters are valid, SRSRAN_ERROR code otherwise */ -SRSRAN_API int -srsran_ssb_add(srsran_ssb_t* q, uint32_t N_id, const srsran_pbch_msg_nr_t* msg, const cf_t* in, cf_t* out); +SRSRAN_API int srsran_ssb_add(srsran_ssb_t* q, + uint32_t N_id, + uint32_t ssb_idx, + const srsran_pbch_msg_nr_t* msg, + const cf_t* in, + cf_t* out); /** * @brief Perform cell search and measurement @@ -170,11 +177,15 @@ 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 N_id Physical Cell Identifier + * @param ssb_idx SSB candidate index * @param in Base-band signal * @param meas SSB-based CSI measurement * @return SRSRAN_SUCCESS if the parameters are valid, SRSRAN_ERROR code otherwise */ -SRSRAN_API int -srsran_ssb_csi_measure(srsran_ssb_t* q, uint32_t N_id, const cf_t* in, srsran_csi_trs_measurements_t* meas); +SRSRAN_API int srsran_ssb_csi_measure(srsran_ssb_t* q, + uint32_t N_id, + uint32_t ssb_idx, + const cf_t* in, + srsran_csi_trs_measurements_t* meas); #endif // SRSRAN_SSB_H diff --git a/lib/src/asn1/rrc_nr_utils.cc b/lib/src/asn1/rrc_nr_utils.cc index 022c4fc08..71746d106 100644 --- a/lib/src/asn1/rrc_nr_utils.cc +++ b/lib/src/asn1/rrc_nr_utils.cc @@ -1300,10 +1300,10 @@ bool make_phy_carrier_cfg(const freq_info_dl_s& asn1_freq_info_dl, srsran_carrie } template -static inline void make_ssb_positions_in_burst(const bitstring_t& ans1_position_in_burst, - std::array& position_in_burst) +static inline void make_ssb_positions_in_burst(const bitstring_t& ans1_position_in_burst, + std::array& position_in_burst) { - for (uint32_t i = 0; i < SRSRAN_SSB_NOF_POSITION; i++) { + for (uint32_t i = 0; i < SRSRAN_SSB_NOF_CANDIDATES; i++) { if (i < ans1_position_in_burst.length()) { position_in_burst[i] = ans1_position_in_burst.get(ans1_position_in_burst.length() - 1 - i); } else { diff --git a/lib/src/phy/phch/pbch_nr.c b/lib/src/phy/phch/pbch_nr.c index 015963ae1..d6ab4a288 100644 --- a/lib/src/phy/phch/pbch_nr.c +++ b/lib/src/phy/phch/pbch_nr.c @@ -13,10 +13,15 @@ #include "srsran/phy/phch/pbch_nr.h" #include "srsran/phy/common/sequence.h" #include "srsran/phy/fec/polar/polar_chanalloc.h" +#include "srsran/phy/fec/polar/polar_interleaver.h" +#include "srsran/phy/modem/demod_soft.h" #include "srsran/phy/modem/mod.h" #include "srsran/phy/utils/debug.h" #include "srsran/phy/utils/vector.h" +#define PBCH_NR_DEBUG_TX(...) DEBUG("PBCH-NR Tx: " __VA_ARGS__) +#define PBCH_NR_DEBUG_RX(...) DEBUG("PBCH-NR Rx: " __VA_ARGS__) + /* * CRC Parameters */ @@ -31,7 +36,7 @@ /* * Polar rate matching I_BIL */ -#define pbch_nr_polar_rm_tx_IBIL 0 +#define PBCH_NR_POLAR_RM_IBIL 0 /* * Number of generated payload bits, called A @@ -58,11 +63,6 @@ */ #define PBCH_NR_M (PBCH_NR_E / 2) -/* - * Number of DMRS - */ -#define PBCH_NR_NOF_DMRS (143) - static int pbch_nr_init_encoder(srsran_pbch_nr_t* q, const srsran_pbch_nr_args_t* args) { // Skip encoder init if not requested @@ -214,6 +214,53 @@ pbch_nr_pbch_msg_pack(const srsran_pbch_nr_cfg_t* cfg, const srsran_pbch_msg_nr_ a[G[j_other++]] = msg->payload[i]; } } + + if (srsran_verbose >= SRSRAN_VERBOSE_DEBUG && !handler_registered) { + PBCH_NR_DEBUG_TX("Packed PBCH bits: "); + srsran_vec_fprint_byte(stdout, a, PBCH_NR_A); + } +} +static void +pbch_nr_pbch_msg_unpack(const srsran_pbch_nr_cfg_t* cfg, const uint8_t a[PBCH_NR_A], srsran_pbch_msg_nr_t* msg) +{ + if (srsran_verbose >= SRSRAN_VERBOSE_DEBUG && !handler_registered) { + PBCH_NR_DEBUG_RX("Packed PBCH bits: "); + srsran_vec_fprint_byte(stdout, a, PBCH_NR_A); + } + + // Extract actual payload size + uint32_t A_hat = SRSRAN_PBCH_NR_PAYLOAD_SZ; + + // Put SFN in a_hat[A_hat] to a_hat[A_hat + 3] + uint32_t j_sfn = 0; + msg->sfn_4lsb = 0; + msg->sfn_4lsb |= (uint8_t)(a[G[j_sfn++]] << 3U); // 4th LSB of SFN + msg->sfn_4lsb |= (uint8_t)(a[G[j_sfn++]] << 2U); // 3th LSB of SFN + msg->sfn_4lsb |= (uint8_t)(a[G[j_sfn++]] << 1U); // 2th LSB of SFN + msg->sfn_4lsb |= (uint8_t)(a[G[j_sfn++]] << 0U); // 1th LSB of SFN + + // Put HRF in a_hat[A_hat + 4] + msg->hrf = (a[G[10]] == 1); + + // Put SSB related in a_hat[A_hat + 5] to a_hat[A_hat + 7] + if (cfg->Lmax == 64) { + msg->ssb_idx = msg->ssb_idx & 0b111; + msg->ssb_idx |= (uint8_t)(a[G[11]] << 5U); // 6th bit of SSB index + msg->ssb_idx |= (uint8_t)(a[G[12]] << 4U); // 5th bit of SSB index + msg->ssb_idx |= (uint8_t)(a[G[13]] << 3U); // 4th bit of SSB index + } else { + msg->k_ssb_msb = a[G[11]]; + } + + // Put actual payload + uint32_t j_other = 14; + for (uint32_t i = 0; i < A_hat; i++) { + if (i > 0 && i < 7) { + msg->payload[i] = a[G[j_sfn++]]; + } else { + msg->payload[i] = a[G[j_other++]]; + } + } } static void pbch_nr_scramble(const srsran_pbch_nr_cfg_t* cfg, const uint8_t a[PBCH_NR_A], uint8_t a_prime[PBCH_NR_A]) @@ -258,27 +305,85 @@ static void pbch_nr_scramble(const srsran_pbch_nr_cfg_t* cfg, const uint8_t a[PB } } -static int pbch_nr_polar_encode(srsran_pbch_nr_t* q, const uint8_t c[PBCH_NR_K], uint8_t d[PBCH_NR_K]) +static int pbch_nr_polar_encode(srsran_pbch_nr_t* q, const uint8_t c[PBCH_NR_K], uint8_t d[PBCH_NR_N]) { + // Interleave + uint8_t c_prime[SRSRAN_POLAR_INTERLEAVER_K_MAX_IL]; + srsran_polar_interleaver_run_u8(c, c_prime, PBCH_NR_K, true); + // Allocate channel uint8_t allocated[PBCH_NR_N]; - srsran_polar_chanalloc_tx(c, allocated, q->code.N, q->code.K, q->code.nPC, q->code.K_set, q->code.PC_set); + srsran_polar_chanalloc_tx(c_prime, allocated, q->code.N, q->code.K, q->code.nPC, q->code.K_set, q->code.PC_set); // Encode bits if (srsran_polar_encoder_encode(&q->polar_encoder, allocated, d, q->code.n) < SRSRAN_SUCCESS) { return SRSRAN_ERROR; } + if (srsran_verbose >= SRSRAN_VERBOSE_DEBUG && !handler_registered) { + PBCH_NR_DEBUG_TX("Allocated: "); + srsran_vec_fprint_byte(stdout, allocated, PBCH_NR_N); + } + + return SRSRAN_SUCCESS; +} + +static int pbch_nr_polar_decode(srsran_pbch_nr_t* q, const int8_t d[PBCH_NR_N], uint8_t c[PBCH_NR_K]) +{ + // Decode bits + uint8_t allocated[PBCH_NR_N]; + if (srsran_polar_decoder_decode_c(&q->polar_decoder, d, allocated, q->code.n, q->code.F_set, q->code.F_set_size) < + SRSRAN_SUCCESS) { + return SRSRAN_ERROR; + } + + if (srsran_verbose >= SRSRAN_VERBOSE_DEBUG && !handler_registered) { + PBCH_NR_DEBUG_RX("Allocated: "); + srsran_vec_fprint_byte(stdout, allocated, PBCH_NR_N); + } + + // Allocate channel + uint8_t c_prime[SRSRAN_POLAR_INTERLEAVER_K_MAX_IL]; + srsran_polar_chanalloc_rx(allocated, c_prime, q->code.K, q->code.nPC, q->code.K_set, q->code.PC_set); + + // Interleave + srsran_polar_interleaver_run_u8(c_prime, c, PBCH_NR_K, false); + + return SRSRAN_SUCCESS; +} + +static int pbch_nr_polar_rm_tx(srsran_pbch_nr_t* q, const uint8_t d[PBCH_NR_N], uint8_t o[PBCH_NR_E]) +{ + if (srsran_polar_rm_tx(&q->polar_rm_tx, d, o, q->code.n, PBCH_NR_E, PBCH_NR_K, PBCH_NR_POLAR_RM_IBIL) < + SRSRAN_SUCCESS) { + return SRSRAN_ERROR; + } + + if (srsran_verbose >= SRSRAN_VERBOSE_DEBUG && !handler_registered) { + PBCH_NR_DEBUG_TX("d: "); + srsran_vec_fprint_byte(stdout, d, PBCH_NR_N); + } + return SRSRAN_SUCCESS; } -static int pbch_nr_polar_rm_tx(srsran_pbch_nr_t* q, const uint8_t d[PBCH_NR_K], uint8_t o[PBCH_NR_E]) +static int pbch_nr_polar_rm_rx(srsran_pbch_nr_t* q, const int8_t llr[PBCH_NR_E], int8_t d[PBCH_NR_N]) { - if (srsran_polar_rm_tx(&q->polar_rm_tx, d, o, q->code.n, PBCH_NR_E, PBCH_NR_K, pbch_nr_polar_rm_tx_IBIL) < + if (srsran_polar_rm_rx_c(&q->polar_rm_rx, llr, d, PBCH_NR_E, q->code.n, PBCH_NR_K, PBCH_NR_POLAR_RM_IBIL) < SRSRAN_SUCCESS) { return SRSRAN_ERROR; } + // Negate all LLR + for (uint32_t i = 0; i < PBCH_NR_N; i++) { + d[i] *= -1; + } + + if (srsran_verbose >= SRSRAN_VERBOSE_DEBUG && !handler_registered) { + PBCH_NR_DEBUG_RX("d: "); + srsran_vec_fprint_bs(stdout, d, PBCH_NR_N); + } + return SRSRAN_SUCCESS; } @@ -307,8 +412,33 @@ static void pbch_nr_scramble_tx(const srsran_pbch_nr_cfg_t* cfg, srsran_sequence_state_apply_bit(&sequence_state, b, b_hat, PBCH_NR_E); } +static void pbch_nr_scramble_rx(const srsran_pbch_nr_cfg_t* cfg, + uint32_t ssb_idx, + const int8_t b_hat[PBCH_NR_E], + int8_t b[PBCH_NR_E]) +{ + // Initialise sequence + srsran_sequence_state_t sequence_state = {}; + srsran_sequence_state_init(&sequence_state, SRSRAN_SEQUENCE_MOD(cfg->N_id)); + + // Select value M + uint32_t M_bit = PBCH_NR_E; + + // Select value v + uint32_t v = (ssb_idx & 0x7U); + if (cfg->Lmax == 4) { + v = ssb_idx & 0x3U; + } + + // Advance sequence + srsran_sequence_state_advance(&sequence_state, v * M_bit); + + // Apply sequence + srsran_sequence_state_apply_c(&sequence_state, b_hat, b, PBCH_NR_E); +} + static void -pbch_nr_mapping(const srsran_pbch_nr_cfg_t* cfg, const cf_t symbols[PBCH_NR_E], cf_t ssb_grid[SRSRAN_SSB_NOF_RE]) +pbch_nr_mapping(const srsran_pbch_nr_cfg_t* cfg, const cf_t symbols[PBCH_NR_M], cf_t ssb_grid[SRSRAN_SSB_NOF_RE]) { uint32_t count = 0; @@ -352,6 +482,63 @@ pbch_nr_mapping(const srsran_pbch_nr_cfg_t* cfg, const cf_t symbols[PBCH_NR_E], ssb_grid[3 * SRSRAN_SSB_BW_SUBC + k] = symbols[count++]; } + + // if (srsran_verbose >= SRSRAN_VERBOSE_DEBUG && !handler_registered) { + // PBCH_NR_DEBUG_TX("Symbols: "); + // srsran_vec_fprint_c(stdout, symbols, PBCH_NR_M); + // } +} + +static void +pbch_nr_demapping(const srsran_pbch_nr_cfg_t* cfg, const cf_t ssb_grid[SRSRAN_SSB_NOF_RE], cf_t symbols[PBCH_NR_M]) +{ + uint32_t count = 0; + + // PBCH DMRS shift + uint32_t v = cfg->N_id % 4; + + // Symbol 1 + for (uint32_t k = 0; k < SRSRAN_SSB_BW_SUBC; k++) { + // Skip DMRS + if (k % 4 == v) { + continue; + } + + symbols[count++] = ssb_grid[1 * SRSRAN_SSB_BW_SUBC + k]; + } + + // Symbol 2 + for (uint32_t k = 0; k < 48; k++) { + // Skip DMRS + if (k % 4 == v) { + continue; + } + + symbols[count++] = ssb_grid[2 * SRSRAN_SSB_BW_SUBC + k]; + } + for (uint32_t k = 192; k < SRSRAN_SSB_BW_SUBC; k++) { + // Skip DMRS + if (k % 4 == v) { + continue; + } + + symbols[count++] = ssb_grid[2 * SRSRAN_SSB_BW_SUBC + k]; + } + + // Symbol 3 + for (uint32_t k = 0; k < SRSRAN_SSB_BW_SUBC; k++) { + // Skip DMRS + if (k % 4 == v) { + continue; + } + + symbols[count++] = ssb_grid[3 * SRSRAN_SSB_BW_SUBC + k]; + } + + // if (srsran_verbose >= SRSRAN_VERBOSE_DEBUG && !handler_registered) { + // PBCH_NR_DEBUG_RX("Symbols: "); + // srsran_vec_fprint_c(stdout, symbols, PBCH_NR_M); + // } } int srsran_pbch_nr_encode(srsran_pbch_nr_t* q, @@ -374,10 +561,10 @@ int srsran_pbch_nr_encode(srsran_pbch_nr_t* q, // 7.1.3 Transport block CRC attachment uint32_t checksum = srsran_crc_attach(&q->crc, b, PBCH_NR_A); - INFO("NR-PBCH: checksum=%06x", checksum); + PBCH_NR_DEBUG_TX("checksum=%06x", checksum); // 7.1.4 Channel coding - uint8_t d[PBCH_NR_K]; + uint8_t d[PBCH_NR_N]; if (pbch_nr_polar_encode(q, b, d) < SRSRAN_SUCCESS) { return SRSRAN_ERROR; } @@ -402,3 +589,77 @@ int srsran_pbch_nr_encode(srsran_pbch_nr_t* q, return SRSRAN_SUCCESS; } + +int srsran_pbch_nr_decode(srsran_pbch_nr_t* q, + const srsran_pbch_nr_cfg_t* cfg, + uint32_t ssb_idx, + const cf_t ssb_grid[SRSRAN_SSB_NOF_RE], + srsran_pbch_msg_nr_t* msg) +{ + if (q == NULL || cfg == NULL || msg == NULL || ssb_grid == NULL) { + return SRSRAN_ERROR_INVALID_INPUTS; + } + + // 7.3.3.3 Mapping to physical resources + // 7.4.3.1.3 Mapping of PBCH and DM-RS within an SS/PBCH block + cf_t symbols[PBCH_NR_M]; + pbch_nr_demapping(cfg, ssb_grid, symbols); + + // 7.3.3.2 Modulation + int8_t llr[PBCH_NR_E]; + srsran_demod_soft_demodulate_b(SRSRAN_MOD_QPSK, symbols, llr, PBCH_NR_M); + + // TS 38.211 7.3.3 Physical broadcast channel + // 7.3.3.1 Scrambling + pbch_nr_scramble_rx(cfg, ssb_idx, llr, llr); + + // 7.1.5 Rate matching + int8_t d[PBCH_NR_N]; + if (pbch_nr_polar_rm_rx(q, llr, d) < SRSRAN_SUCCESS) { + return SRSRAN_ERROR; + } + + // TS 38.212 7.1 Broadcast channel + // 7.1.4 Channel coding + uint8_t b[PBCH_NR_K]; + if (pbch_nr_polar_decode(q, d, b) < SRSRAN_SUCCESS) { + return SRSRAN_ERROR; + } + + // 7.1.3 Transport block CRC attachment + msg->crc = srsran_crc_match(&q->crc, b, PBCH_NR_A); + PBCH_NR_DEBUG_RX("crc=%s", msg->crc ? "OK" : "KO"); + + // 7.1.2 Scrambling + uint8_t a[PBCH_NR_A]; + pbch_nr_scramble(cfg, b, a); + + // 7.1.1 PBCH payload generation + pbch_nr_pbch_msg_unpack(cfg, a, msg); + + return SRSRAN_SUCCESS; +} + +uint32_t srsran_pbch_msg_info(const srsran_pbch_msg_nr_t* msg, char* str, uint32_t str_len) +{ + if (msg == NULL || str == NULL || str_len == 0) { + return 0; + } + + uint32_t len = 0; + + len = srsran_print_check(str, str_len, len, "payload="); + + len += srsran_vec_sprint_hex(&str[len], str_len - len, (uint8_t*)msg->payload, SRSRAN_PBCH_NR_PAYLOAD_SZ); + + len = srsran_print_check(str, + str_len, + len, + " sfn_lsb=%d ssb_idx=%d k_ssb_msb=%d hrf=%d ", + msg->sfn_4lsb, + msg->ssb_idx, + msg->k_ssb_msb, + msg->hrf); + + return len; +} diff --git a/lib/src/phy/sync/ssb.c b/lib/src/phy/sync/ssb.c index 9a7ecf91a..106f0f85b 100644 --- a/lib/src/phy/sync/ssb.c +++ b/lib/src/phy/sync/ssb.c @@ -147,7 +147,7 @@ void srsran_ssb_free(srsran_ssb_t* q) SRSRAN_MEM_ZERO(q, srsran_ssb_t, 1); } -static uint32_t ssb_first_symbol_caseA(const srsran_ssb_cfg_t* cfg, uint32_t indexes[SRSRAN_SSB_NOF_POSITION]) +static uint32_t ssb_first_symbol_caseA(const srsran_ssb_cfg_t* cfg, uint32_t indexes[SRSRAN_SSB_NOF_CANDIDATES]) { // Case A - 15 kHz SCS: the first symbols of the candidate SS/PBCH blocks have indexes of { 2 , 8 } + 14 â‹… n . For // carrier frequencies smaller than or equal to 3 GHz, n = 0 , 1 . For carrier frequencies within FR1 larger than 3 @@ -169,7 +169,7 @@ static uint32_t ssb_first_symbol_caseA(const srsran_ssb_cfg_t* cfg, uint32_t ind return count; } -static uint32_t ssb_first_symbol_caseB(const srsran_ssb_cfg_t* cfg, uint32_t indexes[SRSRAN_SSB_NOF_POSITION]) +static uint32_t ssb_first_symbol_caseB(const srsran_ssb_cfg_t* cfg, uint32_t indexes[SRSRAN_SSB_NOF_CANDIDATES]) { // Case B - 30 kHz SCS: the first symbols of the candidate SS/PBCH blocks have indexes { 4 , 8 , 16 , 20 } + 28 â‹… n . // For carrier frequencies smaller than or equal to 3 GHz, n = 0 . For carrier frequencies within FR1 larger than 3 @@ -191,7 +191,7 @@ static uint32_t ssb_first_symbol_caseB(const srsran_ssb_cfg_t* cfg, uint32_t ind return count; } -static uint32_t ssb_first_symbol_caseC(const srsran_ssb_cfg_t* cfg, uint32_t indexes[SRSRAN_SSB_NOF_POSITION]) +static uint32_t ssb_first_symbol_caseC(const srsran_ssb_cfg_t* cfg, uint32_t indexes[SRSRAN_SSB_NOF_CANDIDATES]) { // Case C - 30 kHz SCS: the first symbols of the candidate SS/PBCH blocks have indexes { 2 , 8 } +14 â‹… n . // - For paired spectrum operation @@ -218,7 +218,7 @@ static uint32_t ssb_first_symbol_caseC(const srsran_ssb_cfg_t* cfg, uint32_t ind return count; } -static uint32_t ssb_first_symbol_caseD(const srsran_ssb_cfg_t* cfg, uint32_t indexes[SRSRAN_SSB_NOF_POSITION]) +static uint32_t ssb_first_symbol_caseD(const srsran_ssb_cfg_t* cfg, uint32_t indexes[SRSRAN_SSB_NOF_CANDIDATES]) { // Case D - 120 kHz SCS: the first symbols of the candidate SS/PBCH blocks have indexes { 4 , 8 , 16 , 20 } + 28 â‹… n . // For carrier frequencies within FR2, n = 0 , 1 , 2 , 3 , 5 , 6 , 7 , 8 , 10 , 11 , 12 , 13 , 15 , 16 , 17 , 18 . @@ -235,7 +235,7 @@ static uint32_t ssb_first_symbol_caseD(const srsran_ssb_cfg_t* cfg, uint32_t ind return count; } -static uint32_t ssb_first_symbol_caseE(const srsran_ssb_cfg_t* cfg, uint32_t indexes[SRSRAN_SSB_NOF_POSITION]) +static uint32_t ssb_first_symbol_caseE(const srsran_ssb_cfg_t* cfg, uint32_t indexes[SRSRAN_SSB_NOF_CANDIDATES]) { // Case E - 240 kHz SCS: the first symbols of the candidate SS/PBCH blocks have indexes //{ 8 , 12 , 16 , 20 , 32 , 36 , 40 , 44 } + 56 â‹… n . For carrier frequencies within FR2, n = 0 , 1 , 2 , 3 , 5 , 6 , @@ -253,7 +253,7 @@ static uint32_t ssb_first_symbol_caseE(const srsran_ssb_cfg_t* cfg, uint32_t ind return count; } -static uint32_t ssb_candidates(const srsran_ssb_cfg_t* cfg, uint32_t indexes[SRSRAN_SSB_NOF_POSITION]) +static uint32_t ssb_first_symbol(const srsran_ssb_cfg_t* cfg, uint32_t indexes[SRSRAN_SSB_NOF_CANDIDATES]) { uint32_t Lmax = 0; @@ -279,27 +279,6 @@ static uint32_t ssb_candidates(const srsran_ssb_cfg_t* cfg, uint32_t indexes[SRS return Lmax; } -static int ssb_first_symbol(const srsran_ssb_cfg_t* cfg, uint32_t ssb_i, uint32_t* Lmax) -{ - uint32_t indexes[SRSRAN_SSB_NOF_POSITION]; - *Lmax = ssb_candidates(cfg, indexes); - - uint32_t ssb_count = 0; - for (uint32_t i = 0; i < *Lmax; i++) { - // There is a SSB transmission opportunity - if (cfg->position[i]) { - // Return the SSB transmission in burst - if (ssb_i == ssb_count) { - return (int)indexes[i]; - } - - ssb_count++; - } - } - - return SRSRAN_ERROR; -} - // Modulates a given symbol l and stores the time domain signal in q->tmp_time static void ssb_modulate_symbol(srsran_ssb_t* q, cf_t ssb_grid[SRSRAN_SSB_NOF_RE], uint32_t l) { @@ -398,6 +377,23 @@ static int ssb_setup_corr(srsran_ssb_t* q) return SRSRAN_SUCCESS; } +static inline int ssb_get_t_offset(srsran_ssb_t* q, uint32_t ssb_idx) +{ + // Get baseband time offset from the begining of the half radio frame to the first symbol + if (ssb_idx >= SRSRAN_SSB_NOF_CANDIDATES) { + ERROR("Invalid SSB candidate index (%d)", ssb_idx); + return SRSRAN_ERROR; + } + + float t_offset_s = srsran_symbol_offset_s(q->l_first[ssb_idx], q->cfg.scs); + if (isnan(t_offset_s) || isinf(t_offset_s) || t_offset_s < 0.0f) { + ERROR("Invalid first symbol (l_first=%d)", q->l_first[ssb_idx]); + return SRSRAN_ERROR; + } + + return (int)round(t_offset_s * q->cfg.srate_hz); +} + int srsran_ssb_set_cfg(srsran_ssb_t* q, const srsran_ssb_cfg_t* cfg) { // Verify input parameters @@ -409,34 +405,15 @@ int srsran_ssb_set_cfg(srsran_ssb_t* q, const srsran_ssb_cfg_t* cfg) q->scs_hz = (float)SRSRAN_SUBC_SPACING_NR(cfg->scs); // Get first symbol - int l_begin = ssb_first_symbol(cfg, 0, &q->Lmax); - if (l_begin < SRSRAN_SUCCESS) { - // set it to 2 in case it is not selected - l_begin = 2; - } - - float t_offset_s = srsran_symbol_offset_s((uint32_t)l_begin, cfg->scs); - if (isnan(t_offset_s) || isinf(t_offset_s) || t_offset_s < 0.0f) { - ERROR("Invalid first symbol (l_first=%d)", l_begin); - return SRSRAN_ERROR; - } + q->Lmax = ssb_first_symbol(cfg, q->l_first); - // Calculate SSB symbol size and integer offset + // Calculate SSB symbol size and integer frequency offset double freq_offset_hz = cfg->ssb_freq_hz - cfg->center_freq_hz; uint32_t symbol_sz = (uint32_t)round(cfg->srate_hz / q->scs_hz); q->f_offset = (int32_t)round(freq_offset_hz / q->scs_hz); - q->t_offset = (uint32_t)round(t_offset_s * cfg->srate_hz); - - for (uint32_t l = 0; l < SRSRAN_SSB_DURATION_NSYMB; l++) { - uint32_t l_real = l + (uint32_t)l_begin; - uint32_t ref_cp_sz = 144U; - if (l_real == 0 || l_real == SRSRAN_EXT_CP_SYMBOL(cfg->scs)) { - ref_cp_sz = 160U; - } - - q->cp_sz[l] = (ref_cp_sz * symbol_sz) / 2048U; - } + // Calculate cyclic prefix + q->cp_sz = (144U * symbol_sz) / 2048U; // Calculate SSB sampling error and check double ssb_srate_error_Hz = ((double)symbol_sz * q->scs_hz) - cfg->srate_hz; @@ -528,7 +505,12 @@ bool srsran_ssb_send(srsran_ssb_t* q, uint32_t sf_idx) return (sf_idx % q->cfg.periodicity_ms == 0); } -int srsran_ssb_add(srsran_ssb_t* q, uint32_t N_id, const srsran_pbch_msg_nr_t* msg, const cf_t* in, cf_t* out) +int srsran_ssb_add(srsran_ssb_t* q, + uint32_t N_id, + uint32_t ssb_idx, + const srsran_pbch_msg_nr_t* msg, + const cf_t* in, + cf_t* out) { // Verify input parameters if (q == NULL || N_id >= SRSRAN_NOF_NID_NR || msg == NULL || in == NULL || out == NULL) { @@ -569,22 +551,26 @@ int srsran_ssb_add(srsran_ssb_t* q, uint32_t N_id, const srsran_pbch_msg_nr_t* m return SRSRAN_ERROR; } + // Select start symbol from SSB candidate index + int t_offset = ssb_get_t_offset(q, ssb_idx); + if (t_offset < SRSRAN_SUCCESS) { + ERROR("Invalid SSB candidate index"); + return SRSRAN_ERROR; + } + // Select input/ouput pointers considering the time offset in the slot - const cf_t* in_ptr = &in[q->t_offset]; - cf_t* out_ptr = &out[q->t_offset]; + const cf_t* in_ptr = &in[t_offset]; + cf_t* out_ptr = &out[t_offset]; // For each SSB symbol, modulate for (uint32_t l = 0; l < SRSRAN_SSB_DURATION_NSYMB; l++) { - // Get CP length - uint32_t cp_len = q->cp_sz[l]; - // Map SSB in resource grid and perform IFFT ssb_modulate_symbol(q, ssb_grid, l); // Add cyclic prefix to input; - srsran_vec_sum_ccc(in_ptr, &q->tmp_time[q->symbol_sz - cp_len], out_ptr, cp_len); - in_ptr += cp_len; - out_ptr += cp_len; + srsran_vec_sum_ccc(in_ptr, &q->tmp_time[q->symbol_sz - q->cp_sz], out_ptr, q->cp_sz); + in_ptr += q->cp_sz; + out_ptr += q->cp_sz; // Add symbol to the input baseband srsran_vec_sum_ccc(in_ptr, q->tmp_time, out_ptr, q->symbol_sz); @@ -599,21 +585,18 @@ static int ssb_demodulate(srsran_ssb_t* q, const cf_t* in, uint32_t t_offset, cf { const cf_t* in_ptr = &in[t_offset]; for (uint32_t l = 0; l < SRSRAN_SSB_DURATION_NSYMB; l++) { - // Get CP length - uint32_t cp_len = q->cp_sz[l]; - // Advance half CP, to avoid inter symbol interference - in_ptr += SRSRAN_FLOOR(cp_len, 2); + in_ptr += SRSRAN_FLOOR(q->cp_sz, 2); // Copy FFT window in temporal time domain buffer srsran_vec_cf_copy(q->tmp_time, in_ptr, q->symbol_sz); - in_ptr += q->symbol_sz + SRSRAN_CEIL(cp_len, 2); + in_ptr += q->symbol_sz + SRSRAN_CEIL(q->cp_sz, 2); // Convert to frequency domain srsran_dft_run_guru_c(&q->fft); // Compensate half CP delay - srsran_vec_apply_cfo(q->tmp_freq, SRSRAN_CEIL(cp_len, 2) / (float)(q->symbol_sz), q->tmp_freq, q->symbol_sz); + srsran_vec_apply_cfo(q->tmp_freq, SRSRAN_CEIL(q->cp_sz, 2) / (float)(q->symbol_sz), q->tmp_freq, q->symbol_sz); // Select symbol in grid cf_t* ptr = &ssb_grid[l * SRSRAN_SSB_BW_SUBC]; @@ -825,8 +808,8 @@ int srsran_ssb_csi_search(srsran_ssb_t* q, } // Remove CP offset prior demodulation - if (t_offset >= q->cp_sz[0]) { - t_offset -= q->cp_sz[0]; + if (t_offset >= q->cp_sz) { + t_offset -= q->cp_sz; } else { t_offset = 0; } @@ -861,7 +844,11 @@ int srsran_ssb_csi_search(srsran_ssb_t* q, return SRSRAN_SUCCESS; } -int srsran_ssb_csi_measure(srsran_ssb_t* q, uint32_t N_id, const cf_t* in, srsran_csi_trs_measurements_t* meas) +int srsran_ssb_csi_measure(srsran_ssb_t* q, + uint32_t N_id, + uint32_t ssb_idx, + const cf_t* in, + srsran_csi_trs_measurements_t* meas) { // Verify inputs if (q == NULL || N_id >= SRSRAN_NOF_NID_NR || in == NULL || meas == NULL || !isnormal(q->scs_hz)) { @@ -869,14 +856,19 @@ int srsran_ssb_csi_measure(srsran_ssb_t* q, uint32_t N_id, const cf_t* in, srsra } if (!q->args.enable_measure) { - ERROR("SSB is not configured for measure"); + ERROR("SSB is not configured to measure"); return SRSRAN_ERROR; } - cf_t ssb_grid[SRSRAN_SSB_NOF_RE] = {}; + // Select start symbol from SSB candidate index + int t_offset = ssb_get_t_offset(q, ssb_idx); + if (t_offset < SRSRAN_SUCCESS) { + return SRSRAN_ERROR; + } // Demodulate - if (ssb_demodulate(q, in, q->t_offset, ssb_grid) < SRSRAN_SUCCESS) { + cf_t ssb_grid[SRSRAN_SSB_NOF_RE] = {}; + if (ssb_demodulate(q, in, (uint32_t)t_offset, ssb_grid) < SRSRAN_SUCCESS) { ERROR("Error demodulating"); return SRSRAN_ERROR; } @@ -889,3 +881,43 @@ int srsran_ssb_csi_measure(srsran_ssb_t* q, uint32_t N_id, const cf_t* in, srsra return SRSRAN_SUCCESS; } + +int srsran_ssb_decode_pbch(srsran_ssb_t* q, uint32_t N_id, uint32_t ssb_idx, const cf_t* in, srsran_pbch_msg_nr_t* msg) +{ + // Verify inputs + if (q == NULL || N_id >= SRSRAN_NOF_NID_NR || in == NULL || msg == NULL || !isnormal(q->scs_hz)) { + return SRSRAN_ERROR_INVALID_INPUTS; + } + + if (!q->args.enable_decode) { + ERROR("SSB is not configured to decode"); + return SRSRAN_ERROR; + } + + // Select start symbol from SSB candidate index + int t_offset = ssb_get_t_offset(q, ssb_idx); + if (t_offset < SRSRAN_SUCCESS) { + return SRSRAN_ERROR; + } + + // Demodulate + cf_t ssb_grid[SRSRAN_SSB_NOF_RE] = {}; + if (ssb_demodulate(q, in, (uint32_t)t_offset, ssb_grid) < SRSRAN_SUCCESS) { + ERROR("Error demodulating"); + return SRSRAN_ERROR; + } + + // Prepare configuration + srsran_pbch_nr_cfg_t pbch_cfg = {}; + pbch_cfg.N_id = N_id; + pbch_cfg.ssb_scs = q->cfg.scs; + pbch_cfg.Lmax = q->Lmax; + + // Decode + if (srsran_pbch_nr_decode(&q->pbch, &pbch_cfg, ssb_idx, ssb_grid, msg) < SRSRAN_SUCCESS) { + ERROR("Error decoding PBCH"); + return SRSRAN_ERROR; + } + + return SRSRAN_SUCCESS; +} diff --git a/lib/src/phy/sync/test/CMakeLists.txt b/lib/src/phy/sync/test/CMakeLists.txt index bfec15b99..0d2352563 100644 --- a/lib/src/phy/sync/test/CMakeLists.txt +++ b/lib/src/phy/sync/test/CMakeLists.txt @@ -124,10 +124,13 @@ add_test(cfo_test_2 cfo_test -f 0.99849 -n 1000) ######################################################################## -# NE TEST +# NR TEST ######################################################################## add_executable(ssb_measure_test ssb_measure_test.c) target_link_libraries(ssb_measure_test srsran_phy) +add_nr_test(ssb_measure_test ssb_measure_test) -add_test(ssb_measure_test ssb_measure_test) +add_executable(ssb_decode_test ssb_decode_test.c) +target_link_libraries(ssb_decode_test srsran_phy) +add_nr_test(ssb_decode_test ssb_decode_test) diff --git a/lib/src/phy/sync/test/ssb_decode_test.c b/lib/src/phy/sync/test/ssb_decode_test.c new file mode 100644 index 000000000..e85898b9a --- /dev/null +++ b/lib/src/phy/sync/test/ssb_decode_test.c @@ -0,0 +1,205 @@ +/** + * + * \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/sync/ssb.h" +#include "srsran/phy/utils/debug.h" +#include "srsran/phy/utils/vector.h" +#include +#include +#include + +// NR parameters +static uint32_t carrier_nof_prb = 52; +static srsran_subcarrier_spacing_t carrier_scs = srsran_subcarrier_spacing_15kHz; +static srsran_subcarrier_spacing_t ssb_scs = srsran_subcarrier_spacing_30kHz; + +// Channel parameters +static int32_t delay_n = 0; +static float cfo_hz = 0.0f; +static float n0_dB = -300.0f; + +// Test context +static srsran_random_t random_gen = NULL; +static srsran_channel_awgn_t awgn = {}; +static double srate_hz = 0.0f; // Base-band sampling rate +static uint32_t hf_len = 0; // Half-frame length +static cf_t* buffer = 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); + } + } +} + +static void run_channel() +{ + // Delay + for (uint32_t i = 0; i < hf_len; i++) { + buffer[i] = buffer[(i + delay_n) % hf_len]; + } + + // CFO + srsran_vec_apply_cfo(buffer, -cfo_hz / srate_hz, buffer, hf_len); + + // AWGN + srsran_channel_awgn_run_c(&awgn, buffer, buffer, hf_len); +} + +static void gen_pbch_msg(srsran_pbch_msg_nr_t* pbch_msg, uint32_t ssb_idx) +{ + // Default all to zero + SRSRAN_MEM_ZERO(pbch_msg, srsran_pbch_msg_nr_t, 1); + + // Generate payload + srsran_random_bit_vector(random_gen, pbch_msg->payload, SRSRAN_PBCH_NR_PAYLOAD_SZ); + + pbch_msg->ssb_idx = ssb_idx; +} + +static int test_case_1(srsran_ssb_t* ssb) +{ + // For benchmarking purposes + uint64_t t_encode_usec = 0; + uint64_t t_decode_usec = 0; + + // SSB configuration + srsran_ssb_cfg_t ssb_cfg = {}; + 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; + + TESTASSERT(srsran_ssb_set_cfg(ssb, &ssb_cfg) == SRSRAN_SUCCESS); + + // For each PCI... + uint64_t count = 0; + for (uint32_t pci = 0; pci < SRSRAN_NOF_NID_NR; pci += 23) { + for (uint32_t ssb_idx = 0; ssb_idx < ssb->Lmax; ssb_idx++, count++) { + struct timeval t[3] = {}; + + // Build PBCH message + srsran_pbch_msg_nr_t pbch_msg_tx = {}; + gen_pbch_msg(&pbch_msg_tx, ssb_idx); + + // Print encoded PBCH message + char str[512] = {}; + srsran_pbch_msg_info(&pbch_msg_tx, str, sizeof(str)); + INFO("test_case_1 - encoded pci=%d %s", pci, str); + + // Initialise baseband + srsran_vec_cf_zero(buffer, hf_len); + + // Add the SSB base-band + gettimeofday(&t[1], NULL); + TESTASSERT(srsran_ssb_add(ssb, pci, ssb_idx, &pbch_msg_tx, buffer, buffer) == SRSRAN_SUCCESS); + gettimeofday(&t[2], NULL); + get_time_interval(t); + t_encode_usec += t[0].tv_usec + t[0].tv_sec * 1000000UL; + + // Run channel + run_channel(); + + // Decode + gettimeofday(&t[1], NULL); + srsran_pbch_msg_nr_t pbch_msg_rx = {}; + TESTASSERT(srsran_ssb_decode_pbch(ssb, pci, ssb_idx, buffer, &pbch_msg_rx) == SRSRAN_SUCCESS); + gettimeofday(&t[2], NULL); + get_time_interval(t); + t_decode_usec += t[0].tv_usec + t[0].tv_sec * 1000000UL; + + // Print decoded PBCH message + srsran_pbch_msg_info(&pbch_msg_rx, str, sizeof(str)); + INFO("test_case_1 - decoded pci=%d %s crc=%s", pci, str, pbch_msg_rx.crc ? "OK" : "KO"); + + // Assert PBCH message CRC + TESTASSERT(pbch_msg_rx.crc); + } + } + + INFO("test_case_1 - %.1f usec/encode; %.1f usec/decode;", + (double)t_encode_usec / (double)(count), + (double)t_decode_usec / (double)(count)); + + return SRSRAN_SUCCESS; +} + +int main(int argc, char** argv) +{ + int ret = SRSRAN_ERROR; + parse_args(argc, argv); + + random_gen = srsran_random_init(1234); + srate_hz = (double)SRSRAN_SUBC_SPACING_NR(carrier_scs) * srsran_min_symbol_sz_rb(carrier_nof_prb); + hf_len = (uint32_t)ceil(srate_hz * (5.0 / 1000.0)); + buffer = srsran_vec_cf_malloc(hf_len); + + srsran_ssb_t ssb = {}; + srsran_ssb_args_t ssb_args = {}; + ssb_args.enable_encode = true; + ssb_args.enable_decode = true; + + if (buffer == NULL) { + ERROR("Malloc"); + goto clean_exit; + } + + if (srsran_channel_awgn_init(&awgn, 0x0) < SRSRAN_SUCCESS) { + ERROR("AWGN"); + goto clean_exit; + } + + if (srsran_channel_awgn_set_n0(&awgn, n0_dB) < SRSRAN_SUCCESS) { + ERROR("AWGN"); + goto clean_exit; + } + + if (srsran_ssb_init(&ssb, &ssb_args) < SRSRAN_SUCCESS) { + ERROR("Init"); + goto clean_exit; + } + + if (test_case_1(&ssb) != SRSRAN_SUCCESS) { + ERROR("test case failed"); + } + + ret = SRSRAN_SUCCESS; + +clean_exit: + srsran_random_free(random_gen); + srsran_ssb_free(&ssb); + + srsran_channel_awgn_free(&awgn); + + if (buffer) { + free(buffer); + } + + return ret; +} \ No newline at end of file diff --git a/lib/src/phy/sync/test/ssb_measure_test.c b/lib/src/phy/sync/test/ssb_measure_test.c index 9f87da361..b13815415 100644 --- a/lib/src/phy/sync/test/ssb_measure_test.c +++ b/lib/src/phy/sync/test/ssb_measure_test.c @@ -102,7 +102,6 @@ static int test_case_1(srsran_ssb_t* ssb) ssb_cfg.ssb_freq_hz = 3.5e9 - 960e3; ssb_cfg.scs = ssb_scs; ssb_cfg.pattern = SRSRAN_SSB_PATTERN_C; - ssb_cfg.position[0] = true; // Rest to false TESTASSERT(srsran_ssb_set_cfg(ssb, &ssb_cfg) == SRSRAN_SUCCESS); @@ -117,7 +116,7 @@ static int test_case_1(srsran_ssb_t* ssb) // Add the SSB base-band gettimeofday(&t[1], NULL); - TESTASSERT(srsran_ssb_add(ssb, pci, &pbch_msg, buffer, buffer) == SRSRAN_SUCCESS); + TESTASSERT(srsran_ssb_add(ssb, pci, 0, &pbch_msg, buffer, buffer) == SRSRAN_SUCCESS); gettimeofday(&t[2], NULL); get_time_interval(t); t_add_usec += t[0].tv_usec + t[0].tv_sec * 1000000UL; @@ -145,7 +144,7 @@ static int test_case_1(srsran_ssb_t* ssb) // Measure gettimeofday(&t[1], NULL); srsran_csi_trs_measurements_t meas = {}; - TESTASSERT(srsran_ssb_csi_measure(ssb, pci, buffer, &meas) == SRSRAN_SUCCESS); + TESTASSERT(srsran_ssb_csi_measure(ssb, pci, 0, buffer, &meas) == SRSRAN_SUCCESS); gettimeofday(&t[2], NULL); get_time_interval(t); t_meas_usec += t[0].tv_usec + t[0].tv_sec * 1000000UL; diff --git a/srsue/src/phy/nr/cc_worker.cc b/srsue/src/phy/nr/cc_worker.cc index 1798b4dd0..ba818bdfe 100644 --- a/srsue/src/phy/nr/cc_worker.cc +++ b/srsue/src/phy/nr/cc_worker.cc @@ -97,7 +97,6 @@ bool cc_worker::update_cfg() 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); - memcpy(ssb_cfg.position, phy->cfg.ssb.position_in_burst.data(), sizeof(bool) * SRSRAN_SSB_NOF_POSITION); ssb_cfg.duplex_mode = srsran::srsran_band_helper().get_duplex_mode(band); ssb_cfg.periodicity_ms = phy->cfg.ssb.periodicity_ms; @@ -334,31 +333,44 @@ bool cc_worker::measure_csi() if (srsran_ssb_send(&ssb, dl_slot_cfg.idx)) { srsran_csi_trs_measurements_t meas = {}; - if (srsran_ssb_csi_measure(&ssb, phy->cfg.carrier.pci, rx_buffer[0], &meas) < SRSRAN_SUCCESS) { - logger.error("Error measuring SSB"); - return false; - } + // Iterate all possible candidates + 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]) { + continue; + } - if (logger.debug.enabled()) { - std::array str = {}; - srsran_csi_meas_info(&meas, str.data(), (uint32_t)str.size()); - logger.debug("SSB-CSI: %s", str.data()); - } + // Measure SSB candidate + 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; + } - // Compute channel metrics and push it - ch_metrics_t ch_metrics = {}; - ch_metrics.sinr = meas.snr_dB; - ch_metrics.rsrp = meas.rsrp_dB; - 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); + if (logger.debug.enabled()) { + std::array str = {}; + srsran_csi_meas_info(&meas, str.data(), (uint32_t)str.size()); + logger.debug("SSB-CSI: %s", str.data()); + } - // 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); + // Compute channel metrics and push it + ch_metrics_t ch_metrics = {}; + ch_metrics.sinr = meas.snr_dB; + ch_metrics.rsrp = meas.rsrp_dB; + 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); + + // 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); + + // Report SSB candidate channel measurement to the PHY state + // ... + } } // Iterate all NZP-CSI-RS marked as TRS and perform channel measurements diff --git a/srsue/test/phy/nr_cell_search_test.cc b/srsue/test/phy/nr_cell_search_test.cc index 162d94aaa..3c9c7bf85 100644 --- a/srsue/test/phy/nr_cell_search_test.cc +++ b/srsue/test/phy/nr_cell_search_test.cc @@ -81,7 +81,6 @@ public: ssb_cfg.ssb_freq_hz = args.ssb_freq_hz; ssb_cfg.scs = args.ssb_scs; ssb_cfg.pattern = args.get_ssb_pattern(); - ssb_cfg.position[0] = true; ssb_cfg.duplex_mode = args.get_duplex_mode(); ssb_cfg.periodicity_ms = args.ssb_period_ms; if (srsran_ssb_set_cfg(&ssb, &ssb_cfg) < SRSRAN_SUCCESS) { @@ -106,7 +105,7 @@ public: srsran_pbch_msg_nr_t msg = {}; // Add SSB - if (srsran_ssb_add(&ssb, pci, &msg, buffer.data(), buffer.data()) < SRSRAN_SUCCESS) { + if (srsran_ssb_add(&ssb, pci, 0, &msg, buffer.data(), buffer.data()) < SRSRAN_SUCCESS) { logger.error("Error adding SSB"); return SRSRAN_ERROR; } From 66770a57e3078ed4c33106a6f4d9cceaeb4e4ea6 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Tue, 18 May 2021 06:30:37 +0200 Subject: [PATCH 037/156] enb_phy_test: fix concurrent access between PHY worker and Stack PHY and Stack are using a normal std::queue to communicate with each other. Concurrent access among the threads needs to be protected. --- srsenb/test/phy/enb_phy_test.cc | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/srsenb/test/phy/enb_phy_test.cc b/srsenb/test/phy/enb_phy_test.cc index 8b7862a60..ede958091 100644 --- a/srsenb/test/phy/enb_phy_test.cc +++ b/srsenb/test/phy/enb_phy_test.cc @@ -74,7 +74,7 @@ private: std::vector ringbuffers_rx; srsran::rf_timestamp_t ts_rx = {}; double rx_srate = 0.0; - bool running = true; + std::atomic running = {true}; CALLBACK(tx); CALLBACK(tx_end); @@ -318,6 +318,7 @@ private: uint32_t cqi; } tti_cqi_info_t; + std::mutex phy_mac_mutex; std::queue tti_dl_info_sched_queue; std::queue tti_dl_info_ack_queue; std::queue tti_ul_info_sched_queue; @@ -405,10 +406,16 @@ public: srsran_random_free(random_gen); } - void set_active_cell_list(std::vector& active_cell_list_) { active_cell_list = active_cell_list_; } + void set_active_cell_list(std::vector& active_cell_list_) + { + std::lock_guard lock(phy_mac_mutex); + active_cell_list = active_cell_list_; + } int sr_detected(uint32_t tti, uint16_t rnti) override { + std::lock_guard lock(phy_mac_mutex); + tti_sr_info_t tti_sr_info = {}; tti_sr_info.tti = tti; tti_sr_info_queue.push(tti_sr_info); @@ -441,6 +448,8 @@ public: } int cqi_info(uint32_t tti, uint16_t rnti, uint32_t cc_idx, uint32_t cqi_value) override { + std::lock_guard lock(phy_mac_mutex); + tti_cqi_info_t tti_cqi_info = {}; tti_cqi_info.tti = tti; tti_cqi_info.cc_idx = cc_idx; @@ -466,6 +475,8 @@ public: } int ack_info(uint32_t tti, uint16_t rnti, uint32_t cc_idx, uint32_t tb_idx, bool ack) override { + std::lock_guard lock(phy_mac_mutex); + // Push grant info in queue tti_dl_info_t tti_dl_info = {}; tti_dl_info.tti = tti; @@ -480,6 +491,8 @@ public: } int crc_info(uint32_t tti, uint16_t rnti, uint32_t cc_idx, uint32_t nof_bytes, bool crc_res) override { + std::lock_guard lock(phy_mac_mutex); + // Push grant info in queue tti_ul_info_t tti_ul_info = {}; tti_ul_info.tti = tti; @@ -501,6 +514,8 @@ public: } int get_dl_sched(uint32_t tti, dl_sched_list_t& dl_sched_res) override { + std::lock_guard lock(phy_mac_mutex); + // Notify test engine notify_get_dl_sched(); @@ -613,6 +628,8 @@ public: // Notify test engine notify_get_ul_sched(); + std::lock_guard lock(phy_mac_mutex); + // Iterate for each carrier following the eNb/Cell order for (uint32_t cc_idx = 0; cc_idx < ul_sched_res.size(); cc_idx++) { auto scell_idx = active_cell_list.size(); @@ -688,6 +705,8 @@ public: void tti_clock() override { notify_tti_clock(); } int run_tti(bool enable_assert) { + std::lock_guard lock(phy_mac_mutex); + // Check DL ACKs match with grants while (not tti_dl_info_ack_queue.empty()) { // Get both Info From f1e6a975de08d4155d18acc599c9bd0ddaf4c9c6 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Tue, 18 May 2021 06:32:23 +0200 Subject: [PATCH 038/156] thread_pool: fix concurrent access of state variable the thread workers need access to their current state to exit properly when they are set to state STOP. However, since the state is kept in a std::vector for all workers, it seems more appropiate to add a per-thread running variable rather then mutexing the entire vector. --- lib/include/srsran/common/thread_pool.h | 3 +++ lib/src/common/thread_pool.cc | 10 ++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/include/srsran/common/thread_pool.h b/lib/include/srsran/common/thread_pool.h index a2ad3f1c6..0c3eb1674 100644 --- a/lib/include/srsran/common/thread_pool.h +++ b/lib/include/srsran/common/thread_pool.h @@ -23,6 +23,7 @@ #include "srsran/adt/circular_buffer.h" #include "srsran/adt/move_callback.h" #include "srsran/srslog/srslog.h" +#include #include #include #include @@ -45,6 +46,7 @@ public: worker(); ~worker() = default; void setup(uint32_t id, thread_pool* parent, uint32_t prio = 0, uint32_t mask = 255); + void stop(); uint32_t get_id(); void release(); @@ -54,6 +56,7 @@ public: private: uint32_t my_id = 0; thread_pool* my_parent = nullptr; + std::atomic running = {true}; void run_thread(); void wait_to_start(); diff --git a/lib/src/common/thread_pool.cc b/lib/src/common/thread_pool.cc index ea40aa6c8..e74111d6b 100644 --- a/lib/src/common/thread_pool.cc +++ b/lib/src/common/thread_pool.cc @@ -42,15 +42,20 @@ void thread_pool::worker::setup(uint32_t id, thread_pool* parent, uint32_t prio, void thread_pool::worker::run_thread() { set_name(std::string("WORKER") + std::to_string(my_id)); - while (my_parent->status[my_id] != STOP) { + while (running.load(std::memory_order_relaxed)) { wait_to_start(); - if (my_parent->status[my_id] != STOP) { + if (running.load(std::memory_order_relaxed)) { work_imp(); finished(); } } } +void thread_pool::worker::stop() +{ + running = false; +} + uint32_t thread_pool::worker::get_id() { return my_id; @@ -92,6 +97,7 @@ void thread_pool::stop() for (uint32_t i = 0; i < nof_workers; i++) { if (workers[i]) { debug_thread("stop(): stopping %d\n", i); + workers[i]->stop(); status[i] = STOP; cvar_worker[i].notify_all(); cvar_queue.notify_all(); From d8b2cfcef889ac1db07c1d1b01a522cd43ac5c9d Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Tue, 18 May 2021 12:32:05 +0200 Subject: [PATCH 039/156] zmq,ringbuffer: protect concurrent access some issue found through TSAN execution --- lib/src/phy/rf/rf_zmq_imp_rx.c | 22 ++++++++++++++++++---- lib/src/phy/rf/rf_zmq_imp_tx.c | 4 ++++ lib/src/phy/utils/ringbuffer.c | 6 +++++- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/lib/src/phy/rf/rf_zmq_imp_rx.c b/lib/src/phy/rf/rf_zmq_imp_rx.c index bb84f7506..4d0678c61 100644 --- a/lib/src/phy/rf/rf_zmq_imp_rx.c +++ b/lib/src/phy/rf/rf_zmq_imp_rx.c @@ -17,11 +17,20 @@ #include #include +bool is_rx_running(rf_zmq_rx_t* q) +{ + bool running = false; + pthread_mutex_lock(&q->mutex); + running = q->running; + pthread_mutex_unlock(&q->mutex); + return running; +} + static void* rf_zmq_async_rx_thread(void* h) { rf_zmq_rx_t* q = (rf_zmq_rx_t*)h; - while (q->sock && q->running) { + while (q->sock && is_rx_running(q)) { int nbytes = 0; int n = SRSRAN_ERROR; uint8_t dummy = 0xFF; @@ -30,7 +39,7 @@ static void* rf_zmq_async_rx_thread(void* h) // Send request if socket type is REQUEST if (q->socket_type == ZMQ_REQ) { - while (n < 0 && q->running) { + while (n < 0 && is_rx_running(q)) { rf_zmq_info(q->id, " - tx'ing rx request\n"); n = zmq_send(q->sock, &dummy, sizeof(dummy), 0); if (n < 0) { @@ -44,7 +53,7 @@ static void* rf_zmq_async_rx_thread(void* h) } // Receive baseband - for (n = (n < 0) ? 0 : -1; n < 0 && q->running;) { + for (n = (n < 0) ? 0 : -1; n < 0 && is_rx_running(q);) { n = zmq_recv(q->sock, q->temp_buffer, ZMQ_MAX_BUFFER_SIZE, 0); if (n == -1) { if (rf_zmq_handle_error(q->id, "asynchronous rx baseband receive")) { @@ -68,7 +77,7 @@ static void* rf_zmq_async_rx_thread(void* h) n = -1; // Try to write in ring buffer - while (n < 0 && q->running) { + while (n < 0 && is_rx_running(q)) { n = srsran_ringbuffer_write_timed(&q->ringbuffer, q->temp_buffer, nbytes, q->trx_timeout_ms); if (n == SRSRAN_ERROR_TIMEOUT && q->log_trx_timeout) { fprintf(stderr, "Error: timeout writing samples to ringbuffer after %dms\n", q->trx_timeout_ms); @@ -253,13 +262,18 @@ bool rf_zmq_rx_match_freq(rf_zmq_rx_t* q, uint32_t freq_hz) void rf_zmq_rx_close(rf_zmq_rx_t* q) { rf_zmq_info(q->id, "Closing ...\n"); + + pthread_mutex_lock(&q->mutex); q->running = false; + pthread_mutex_unlock(&q->mutex); if (q->thread) { pthread_join(q->thread, NULL); pthread_detach(q->thread); } + pthread_mutex_destroy(&q->mutex); + srsran_ringbuffer_free(&q->ringbuffer); if (q->temp_buffer) { diff --git a/lib/src/phy/rf/rf_zmq_imp_tx.c b/lib/src/phy/rf/rf_zmq_imp_tx.c index 81417b53c..078a5b92f 100644 --- a/lib/src/phy/rf/rf_zmq_imp_tx.c +++ b/lib/src/phy/rf/rf_zmq_imp_tx.c @@ -223,7 +223,11 @@ bool rf_zmq_tx_match_freq(rf_zmq_tx_t* q, uint32_t freq_hz) void rf_zmq_tx_close(rf_zmq_tx_t* q) { + pthread_mutex_lock(&q->mutex); q->running = false; + pthread_mutex_unlock(&q->mutex); + + pthread_mutex_destroy(&q->mutex); if (q->zeros) { free(q->zeros); diff --git a/lib/src/phy/utils/ringbuffer.c b/lib/src/phy/utils/ringbuffer.c index 53359c356..cdd6ee7f7 100644 --- a/lib/src/phy/utils/ringbuffer.c +++ b/lib/src/phy/utils/ringbuffer.c @@ -78,7 +78,11 @@ int srsran_ringbuffer_resize(srsran_ringbuffer_t* q, int capacity) int srsran_ringbuffer_status(srsran_ringbuffer_t* q) { - return q->count; + int status = 0; + pthread_mutex_lock(&q->mutex); + status = q->count; + pthread_mutex_unlock(&q->mutex); + return status; } int srsran_ringbuffer_space(srsran_ringbuffer_t* q) From c1ad867824e93a443ae1411157ac88e076773ddb Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Tue, 18 May 2021 12:40:58 +0200 Subject: [PATCH 040/156] epoll_helper: use std::atomic to protect exit called from different thread --- lib/include/srsran/common/epoll_helper.h | 7 ++++--- srsue/test/ttcn3/hdr/ttcn3_syssim.h | 5 +++-- srsue/test/ttcn3/src/ttcn3_syssim.cc | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/include/srsran/common/epoll_helper.h b/lib/include/srsran/common/epoll_helper.h index 6382b08a8..e5955334d 100644 --- a/lib/include/srsran/common/epoll_helper.h +++ b/lib/include/srsran/common/epoll_helper.h @@ -17,6 +17,7 @@ #ifndef SRSRAN_EPOLL_HELPER_H #define SRSRAN_EPOLL_HELPER_H +#include #include #include #include @@ -58,7 +59,7 @@ private: class epoll_signal_handler : public epoll_handler { public: - epoll_signal_handler(bool* running_) : running(running_) {} + epoll_signal_handler(std::atomic& running_) : running(running_) {} int handle_event(int fd, epoll_event e, int epoll_fd) { @@ -72,7 +73,7 @@ public: case SIGINT: case SIGHUP: case SIGQUIT: - *running = false; + running = false; break; default: fprintf(stderr, "got signal %d\n", info.ssi_signo); @@ -82,7 +83,7 @@ public: } private: - bool* running = nullptr; + std::atomic& running; }; ///< Create periodic epoll timer every 1ms diff --git a/srsue/test/ttcn3/hdr/ttcn3_syssim.h b/srsue/test/ttcn3/hdr/ttcn3_syssim.h index 14fe4e76a..827563841 100644 --- a/srsue/test/ttcn3/hdr/ttcn3_syssim.h +++ b/srsue/test/ttcn3/hdr/ttcn3_syssim.h @@ -25,6 +25,7 @@ #include "ttcn3_sys_interface.h" #include "ttcn3_ue.h" #include "ttcn3_ut_interface.h" +#include #include class ttcn3_syssim : public syssim_interface_phy, @@ -223,8 +224,8 @@ private: all_args_t args = {}; // Simulator vars - ttcn3_ue* ue = nullptr; - bool running = false; + ttcn3_ue* ue = nullptr; + std::atomic running = {false}; typedef enum { UE_SWITCH_ON = 0, UE_SWITCH_OFF, ENABLE_DATA, DISABLE_DATA } ss_events_t; block_queue event_queue; diff --git a/srsue/test/ttcn3/src/ttcn3_syssim.cc b/srsue/test/ttcn3/src/ttcn3_syssim.cc index 4472d5d47..8978e861b 100644 --- a/srsue/test/ttcn3/src/ttcn3_syssim.cc +++ b/srsue/test/ttcn3/src/ttcn3_syssim.cc @@ -49,7 +49,7 @@ ttcn3_syssim::ttcn3_syssim(ttcn3_ue* ue_) : mac_msg_dl(20, ss_mac_logger), pdus(logger), ue(ue_), - signal_handler(&running), + signal_handler(running), timer_handler(create_tti_timer(), [&](uint64_t res) { new_tti_indication(res); }) { if (ue->init(all_args_t{}, this, "INIT_TEST") != SRSRAN_SUCCESS) { From b40867ffece52ef886d49119f9229504889c0cad Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Thu, 20 May 2021 10:17:58 +0200 Subject: [PATCH 041/156] ue,rrc: add simple connection setup procedure this is an attempt to fix #2850 by defering the transmission of the connection setup complete until the PHY has applied the dedicated config in the connection setup. --- srsue/hdr/stack/rrc/rrc.h | 2 + srsue/hdr/stack/rrc/rrc_procedures.h | 18 +++++++++ srsue/src/stack/rrc/rrc.cc | 18 ++++----- srsue/src/stack/rrc/rrc_procedures.cc | 54 +++++++++++++++++++++++++++ 4 files changed, 83 insertions(+), 9 deletions(-) diff --git a/srsue/hdr/stack/rrc/rrc.h b/srsue/hdr/stack/rrc/rrc.h index 48a168974..003c6cb70 100644 --- a/srsue/hdr/stack/rrc/rrc.h +++ b/srsue/hdr/stack/rrc/rrc.h @@ -282,6 +282,7 @@ private: class si_acquire_proc; class serving_cell_config_proc; class cell_selection_proc; + class connection_setup_proc; class connection_request_proc; class connection_reconf_no_ho_proc; class plmn_search_proc; @@ -297,6 +298,7 @@ private: srsran::proc_t idle_setter; srsran::proc_t pcch_processor; srsran::proc_t conn_req_proc; + srsran::proc_t conn_setup_proc; srsran::proc_t plmn_searcher; srsran::proc_t cell_reselector; srsran::proc_t connection_reest; diff --git a/srsue/hdr/stack/rrc/rrc_procedures.h b/srsue/hdr/stack/rrc/rrc_procedures.h index 71a399f9c..20e1c5646 100644 --- a/srsue/hdr/stack/rrc/rrc_procedures.h +++ b/srsue/hdr/stack/rrc/rrc_procedures.h @@ -193,6 +193,24 @@ private: srsran::proc_future_t serv_cfg_fut; }; +class rrc::connection_setup_proc +{ +public: + explicit connection_setup_proc(rrc* parent_); + srsran::proc_outcome_t init(const asn1::rrc::rr_cfg_ded_s* cnfg_, srsran::unique_byte_buffer_t dedicated_info_nas_); + srsran::proc_outcome_t step() { return srsran::proc_outcome_t::yield; } + void then(const srsran::proc_state_t& result); + srsran::proc_outcome_t react(const bool& config_complete); + static const char* name() { return "Connection Setup"; } + +private: + // const + rrc* rrc_ptr; + srslog::basic_logger& logger; + // args + srsran::unique_byte_buffer_t dedicated_info_nas; +}; + class rrc::connection_reconf_no_ho_proc { public: diff --git a/srsue/src/stack/rrc/rrc.cc b/srsue/src/stack/rrc/rrc.cc index 39f69d6eb..928547935 100644 --- a/srsue/src/stack/rrc/rrc.cc +++ b/srsue/src/stack/rrc/rrc.cc @@ -66,6 +66,7 @@ rrc::rrc(stack_interface_rrc* stack_, srsran::task_sched_handle task_sched_) : plmn_searcher(this), cell_reselector(this), connection_reest(this), + conn_setup_proc(this), ho_handler(this), conn_recfg_proc(this), meas_cells_nr(task_sched_), @@ -364,6 +365,9 @@ void rrc::set_config_complete(bool status) { // Signal Reconfiguration Procedure that PHY configuration has completed phy_ctrl->set_config_complete(); + if (conn_setup_proc.is_busy()) { + conn_setup_proc.trigger(status); + } if (conn_recfg_proc.is_busy()) { conn_recfg_proc.trigger(status); } @@ -2538,16 +2542,12 @@ void rrc::handle_con_setup(const rrc_conn_setup_s& setup) t302.stop(); srsran::console("RRC Connected\n"); - // Apply the Radio Resource configuration - apply_rr_config_dedicated(&setup.crit_exts.c1().rrc_conn_setup_r8().rr_cfg_ded); - - nas->set_barring(srsran::barring_t::none); - - if (dedicated_info_nas.get()) { - send_con_setup_complete(std::move(dedicated_info_nas)); - } else { - logger.error("Pending to transmit a ConnectionSetupComplete but no dedicatedInfoNAS was in queue"); + // defer transmission of Setup Complete until PHY reconfiguration has been completed + if (not conn_setup_proc.launch(&setup.crit_exts.c1().rrc_conn_setup_r8().rr_cfg_ded, std::move(dedicated_info_nas))) { + logger.error("Failed to initiate connection setup procedure"); + return; } + callback_list.add_proc(conn_setup_proc); } /* Reception of RRCConnectionReestablishment by the UE 5.3.7.5 */ diff --git a/srsue/src/stack/rrc/rrc_procedures.cc b/srsue/src/stack/rrc/rrc_procedures.cc index 870246320..47f9daabb 100644 --- a/srsue/src/stack/rrc/rrc_procedures.cc +++ b/srsue/src/stack/rrc/rrc_procedures.cc @@ -934,6 +934,60 @@ srsran::proc_outcome_t rrc::connection_request_proc::react(const cell_selection_ } } +/****************************************** + * Connection Setup Procedure + *****************************************/ + +// Simple procedure mainly do defer the transmission of the SetupComplete until all PHY reconfiguration are done +rrc::connection_setup_proc::connection_setup_proc(srsue::rrc* parent_) : + rrc_ptr(parent_), logger(srslog::fetch_basic_logger("RRC")) +{} + +srsran::proc_outcome_t rrc::connection_setup_proc::init(const asn1::rrc::rr_cfg_ded_s* cnfg_, + srsran::unique_byte_buffer_t dedicated_info_nas_) +{ + Info("Starting..."); + + if (dedicated_info_nas_.get() == nullptr) { + rrc_ptr->logger.error("Connection Setup Failed, no dedicatedInfoNAS available"); + return proc_outcome_t::error; + } + + dedicated_info_nas = std::move(dedicated_info_nas_); + + // Apply the Radio Resource configuration + if (!rrc_ptr->apply_rr_config_dedicated(cnfg_)) { + return proc_outcome_t::error; + } + + rrc_ptr->nas->set_barring(srsran::barring_t::none); + + // No phy config was scheduled, run config completion immediately + if (rrc_ptr->phy_ctrl->is_config_pending()) { + return react(true); + } + return proc_outcome_t::yield; +} + +srsran::proc_outcome_t rrc::connection_setup_proc::react(const bool& config_complete) +{ + if (not config_complete) { + rrc_ptr->logger.error("Connection Setup Failed"); + return proc_outcome_t::error; + } + + rrc_ptr->send_con_setup_complete(std::move(dedicated_info_nas)); + return proc_outcome_t::success; +} + +void rrc::connection_setup_proc::then(const srsran::proc_state_t& result) +{ + if (result.is_success()) { + rrc_ptr->logger.info("Finished %s successfully", name()); + return; + } +} + /****************************************** * Connection Reconfiguration Procedure *****************************************/ From c74b2dd6330208c1342ebec3428abf983e7d47b6 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Tue, 25 May 2021 10:56:30 +0100 Subject: [PATCH 042/156] Fix some warnings in PHY due to array parameter mismatch for a few functions --- lib/include/srsran/phy/mimo/precoding.h | 2 +- lib/include/srsran/phy/phch/cqi.h | 3 ++- lib/include/srsran/phy/phch/pusch_nr.h | 2 +- lib/include/srsran/phy/ue/ue_dl.h | 2 +- lib/src/phy/phch/pdsch_nr.c | 5 ++--- lib/src/phy/phch/pusch_nr.c | 9 ++++----- lib/src/phy/phch/test/pbch_file_test.c | 2 +- lib/src/phy/phch/test/pcfich_file_test.c | 2 +- lib/src/phy/phch/test/pdcch_file_test.c | 2 +- lib/src/phy/phch/test/pdsch_pdcch_file_test.c | 2 +- lib/src/phy/phch/test/phich_file_test.c | 2 +- lib/src/phy/phch/test/pmch_file_test.c | 9 ++++++--- lib/src/phy/phch/test/pucch_test.c | 2 +- lib/src/phy/phch/test/pusch_nr_test.c | 4 +++- lib/src/phy/phch/uci.c | 9 +++++---- lib/src/phy/rf/rf_zmq_imp.c | 7 +------ lib/src/phy/ue/ue_dl_nr.c | 10 +++++----- lib/test/phy/phy_dl_nr_test.c | 6 ++++-- 18 files changed, 41 insertions(+), 39 deletions(-) diff --git a/lib/include/srsran/phy/mimo/precoding.h b/lib/include/srsran/phy/mimo/precoding.h index 3a29172c1..ebe44f2c9 100644 --- a/lib/include/srsran/phy/mimo/precoding.h +++ b/lib/include/srsran/phy/mimo/precoding.h @@ -80,7 +80,7 @@ SRSRAN_API int srsran_predecoding_diversity(cf_t* y, SRSRAN_API int srsran_predecoding_diversity_multi(cf_t* y[SRSRAN_MAX_PORTS], cf_t* h[SRSRAN_MAX_PORTS][SRSRAN_MAX_PORTS], cf_t* x[SRSRAN_MAX_LAYERS], - float* csi[SRSRAN_MAX_LAYERS], + float* csi[SRSRAN_MAX_CODEWORDS], int nof_rxant, int nof_ports, int nof_symbols, diff --git a/lib/include/srsran/phy/phch/cqi.h b/lib/include/srsran/phy/phch/cqi.h index ab9ddd3b4..fb2d6b60b 100644 --- a/lib/include/srsran/phy/phch/cqi.h +++ b/lib/include/srsran/phy/phch/cqi.h @@ -135,7 +135,8 @@ typedef struct { SRSRAN_API int srsran_cqi_size(srsran_cqi_cfg_t* cfg); -SRSRAN_API int srsran_cqi_value_pack(srsran_cqi_cfg_t* cfg, srsran_cqi_value_t* value, uint8_t* buff); +SRSRAN_API int +srsran_cqi_value_pack(srsran_cqi_cfg_t* cfg, srsran_cqi_value_t* value, uint8_t buff[SRSRAN_CQI_MAX_BITS]); SRSRAN_API int srsran_cqi_value_unpack(srsran_cqi_cfg_t* cfg, uint8_t buff[SRSRAN_CQI_MAX_BITS], srsran_cqi_value_t* value); diff --git a/lib/include/srsran/phy/phch/pusch_nr.h b/lib/include/srsran/phy/phch/pusch_nr.h index 5073fd9ec..f917dd195 100644 --- a/lib/include/srsran/phy/phch/pusch_nr.h +++ b/lib/include/srsran/phy/phch/pusch_nr.h @@ -104,7 +104,7 @@ SRSRAN_API int srsran_pusch_nr_decode(srsran_pusch_nr_t* q, const srsran_sch_grant_nr_t* grant, srsran_chest_dl_res_t* channel, cf_t* sf_symbols[SRSRAN_MAX_PORTS], - srsran_pusch_res_nr_t data[SRSRAN_MAX_TB]); + srsran_pusch_res_nr_t* data[SRSRAN_MAX_TB]); SRSRAN_API uint32_t srsran_pusch_nr_rx_info(const srsran_pusch_nr_t* q, const srsran_sch_cfg_nr_t* cfg, diff --git a/lib/include/srsran/phy/ue/ue_dl.h b/lib/include/srsran/phy/ue/ue_dl.h index 366b062dc..7d6012579 100644 --- a/lib/include/srsran/phy/ue/ue_dl.h +++ b/lib/include/srsran/phy/ue/ue_dl.h @@ -199,7 +199,7 @@ SRSRAN_API int srsran_ue_dl_decode_pdsch(srsran_ue_dl_t* q, SRSRAN_API int srsran_ue_dl_decode_pmch(srsran_ue_dl_t* q, srsran_dl_sf_cfg_t* sf, srsran_pmch_cfg_t* pmch_cfg, - srsran_pdsch_res_t* data); + srsran_pdsch_res_t data[SRSRAN_MAX_CODEWORDS]); SRSRAN_API int srsran_ue_dl_decode_phich(srsran_ue_dl_t* q, srsran_dl_sf_cfg_t* sf, diff --git a/lib/src/phy/phch/pdsch_nr.c b/lib/src/phy/phch/pdsch_nr.c index c44ffc992..d23fa9380 100644 --- a/lib/src/phy/phch/pdsch_nr.c +++ b/lib/src/phy/phch/pdsch_nr.c @@ -482,7 +482,7 @@ int srsran_pdsch_nr_decode(srsran_pdsch_nr_t* q, srsran_pdsch_res_nr_t* data) { // Check input pointers - if (!q || !cfg || !grant || !data || !sf_symbols) { + if (!q || !cfg || !grant || !data || !sf_symbols || !channel) { return SRSRAN_ERROR_INVALID_INPUTS; } @@ -528,8 +528,7 @@ int srsran_pdsch_nr_decode(srsran_pdsch_nr_t* q, // Antenna port demapping // ... Not implemented - srsran_predecoding_type( - q->x, channel->ce, q->d, NULL, 1, 1, 1, 0, nof_re, SRSRAN_TXSCHEME_PORT0, 1.0f, channel->noise_estimate); + srsran_predecoding_single(q->x[0], channel->ce[0][0], q->d[0], NULL, nof_re, 1.0f, channel->noise_estimate); // Layer demapping if (grant->nof_layers > 1) { diff --git a/lib/src/phy/phch/pusch_nr.c b/lib/src/phy/phch/pusch_nr.c index 6c94788a7..504136d06 100644 --- a/lib/src/phy/phch/pusch_nr.c +++ b/lib/src/phy/phch/pusch_nr.c @@ -909,10 +909,10 @@ int srsran_pusch_nr_decode(srsran_pusch_nr_t* q, const srsran_sch_grant_nr_t* grant, srsran_chest_dl_res_t* channel, cf_t* sf_symbols[SRSRAN_MAX_PORTS], - srsran_pusch_res_nr_t* data) + srsran_pusch_res_nr_t* data[SRSRAN_MAX_TB]) { // Check input pointers - if (!q || !cfg || !grant || !data || !sf_symbols) { + if (!q || !cfg || !grant || !data || !sf_symbols || !channel) { return SRSRAN_ERROR_INVALID_INPUTS; } @@ -969,8 +969,7 @@ int srsran_pusch_nr_decode(srsran_pusch_nr_t* q, // Antenna port demapping // ... Not implemented - srsran_predecoding_type( - q->x, channel->ce, q->d, NULL, 1, 1, 1, 0, nof_re, SRSRAN_TXSCHEME_PORT0, 1.0f, channel->noise_estimate); + srsran_predecoding_single(q->x[0], channel->ce[0][0], q->d[0], NULL, nof_re, 1.0f, channel->noise_estimate); // Layer demapping if (grant->nof_layers > 1) { @@ -979,7 +978,7 @@ int srsran_pusch_nr_decode(srsran_pusch_nr_t* q, // SCH decode for (uint32_t tb = 0; tb < SRSRAN_MAX_TB; tb++) { - if (pusch_nr_decode_codeword(q, cfg, &grant->tb[tb], data, grant->rnti) < SRSRAN_SUCCESS) { + if (pusch_nr_decode_codeword(q, cfg, &grant->tb[tb], data[0], grant->rnti) < SRSRAN_SUCCESS) { ERROR("Error encoding TB %d", tb); return SRSRAN_ERROR; } diff --git a/lib/src/phy/phch/test/pbch_file_test.c b/lib/src/phy/phch/test/pbch_file_test.c index be7cc06ed..1d52ec98a 100644 --- a/lib/src/phy/phch/test/pbch_file_test.c +++ b/lib/src/phy/phch/test/pbch_file_test.c @@ -39,7 +39,7 @@ uint8_t bch_payload_file[SRSRAN_BCH_PAYLOAD_LEN] = {0, 1, 1, 0, 1, 0, 0, 0, 0, 0 #define FLEN (10 * SRSRAN_SF_LEN(srsran_symbol_sz(cell.nof_prb))) srsran_filesource_t fsrc; -cf_t * input_buffer, *fft_buffer[SRSRAN_MAX_CODEWORDS]; +cf_t * input_buffer, *fft_buffer[SRSRAN_MAX_PORTS]; srsran_pbch_t pbch; srsran_ofdm_t fft; srsran_chest_dl_t chest; diff --git a/lib/src/phy/phch/test/pcfich_file_test.c b/lib/src/phy/phch/test/pcfich_file_test.c index 8622d373d..a744262bc 100644 --- a/lib/src/phy/phch/test/pcfich_file_test.c +++ b/lib/src/phy/phch/test/pcfich_file_test.c @@ -33,7 +33,7 @@ int flen; FILE* fmatlab = NULL; srsran_filesource_t fsrc; -cf_t * input_buffer, *fft_buffer[SRSRAN_MAX_CODEWORDS]; +cf_t * input_buffer, *fft_buffer[SRSRAN_MAX_PORTS]; srsran_pcfich_t pcfich; srsran_regs_t regs; srsran_ofdm_t fft; diff --git a/lib/src/phy/phch/test/pdcch_file_test.c b/lib/src/phy/phch/test/pdcch_file_test.c index a46ec6b56..c3adfa35a 100644 --- a/lib/src/phy/phch/test/pdcch_file_test.c +++ b/lib/src/phy/phch/test/pdcch_file_test.c @@ -39,7 +39,7 @@ int max_frames = 10; srsran_dci_format_t dci_format = SRSRAN_DCI_FORMAT1A; srsran_filesource_t fsrc; srsran_pdcch_t pdcch; -cf_t * input_buffer, *fft_buffer[SRSRAN_MAX_CODEWORDS]; +cf_t * input_buffer, *fft_buffer[SRSRAN_MAX_PORTS]; srsran_regs_t regs; srsran_ofdm_t fft; srsran_chest_dl_t chest; diff --git a/lib/src/phy/phch/test/pdsch_pdcch_file_test.c b/lib/src/phy/phch/test/pdsch_pdcch_file_test.c index 238984289..a3a00c899 100644 --- a/lib/src/phy/phch/test/pdsch_pdcch_file_test.c +++ b/lib/src/phy/phch/test/pdsch_pdcch_file_test.c @@ -165,7 +165,7 @@ int main(int argc, char** argv) exit(-1); } - uint8_t* data[] = {malloc(100000)}; + uint8_t* data[SRSRAN_MAX_CODEWORDS] = {malloc(100000)}; if (!data[0]) { perror("malloc"); exit(-1); diff --git a/lib/src/phy/phch/test/phich_file_test.c b/lib/src/phy/phch/test/phich_file_test.c index dc9e61c9a..b82fa7845 100644 --- a/lib/src/phy/phch/test/phich_file_test.c +++ b/lib/src/phy/phch/test/phich_file_test.c @@ -39,7 +39,7 @@ int numsubframe = 0; FILE* fmatlab = NULL; srsran_filesource_t fsrc; -cf_t * input_buffer, *fft_buffer[SRSRAN_MAX_CODEWORDS]; +cf_t * input_buffer, *fft_buffer[SRSRAN_MAX_PORTS]; srsran_phich_t phich; srsran_regs_t regs; srsran_ofdm_t fft; diff --git a/lib/src/phy/phch/test/pmch_file_test.c b/lib/src/phy/phch/test/pmch_file_test.c index 4188bc9ed..c1e2246a2 100644 --- a/lib/src/phy/phch/test/pmch_file_test.c +++ b/lib/src/phy/phch/test/pmch_file_test.c @@ -207,9 +207,12 @@ int main(int argc, char** argv) SRSRAN_DCI_TB_DISABLE(dci.tb[1]); srsran_ra_dl_dci_to_grant(&cell, &dl_sf, SRSRAN_TM1, false, &dci, &pmch_cfg.pdsch_cfg.grant); - srsran_pdsch_res_t pdsch_res; - pdsch_res.payload = data; - ret = srsran_ue_dl_decode_pmch(&ue_dl, &dl_sf, &pmch_cfg, &pdsch_res); + srsran_pdsch_res_t pdsch_res = {}; + pdsch_res.payload = data; + + srsran_pdsch_res_t pdsch_res_vec[SRSRAN_MAX_CODEWORDS]; + pdsch_res_vec[0] = pdsch_res; + ret = srsran_ue_dl_decode_pmch(&ue_dl, &dl_sf, &pmch_cfg, pdsch_res_vec); if (pdsch_res.crc == 1) { printf("PMCH Decoded OK!\n"); } else if (pdsch_res.crc == 0) { diff --git a/lib/src/phy/phch/test/pucch_test.c b/lib/src/phy/phch/test/pucch_test.c index ca8f98d26..76edd6e09 100644 --- a/lib/src/phy/phch/test/pucch_test.c +++ b/lib/src/phy/phch/test/pucch_test.c @@ -80,7 +80,7 @@ int test_uci_cqi_pucch(void) int ret = SRSRAN_SUCCESS; __attribute__((aligned(256))) uint8_t o_bits[SRSRAN_UCI_MAX_CQI_LEN_PUCCH] = {0}; __attribute__((aligned(256))) uint8_t e_bits[SRSRAN_UCI_CQI_CODED_PUCCH_B] = {0}; - __attribute__((aligned(256))) int16_t e_symb[SRSRAN_UCI_CQI_CODED_PUCCH_B] = {0}; + __attribute__((aligned(256))) int16_t e_symb[SRSRAN_CQI_MAX_BITS] = {0}; __attribute__((aligned(256))) uint8_t d_bits[SRSRAN_UCI_MAX_CQI_LEN_PUCCH] = {0}; srsran_uci_cqi_pucch_t uci_cqi_pucch = {0}; diff --git a/lib/src/phy/phch/test/pusch_nr_test.c b/lib/src/phy/phch/test/pusch_nr_test.c index f88e1b938..f1357c130 100644 --- a/lib/src/phy/phch/test/pusch_nr_test.c +++ b/lib/src/phy/phch/test/pusch_nr_test.c @@ -266,7 +266,9 @@ int main(int argc, char** argv) } chest.nof_re = pusch_cfg.grant.tb->nof_re; - if (srsran_pusch_nr_decode(&pusch_rx, &pusch_cfg, &pusch_cfg.grant, &chest, sf_symbols, &data_rx) < + srsran_pusch_res_nr_t* data_rx_vec[SRSRAN_MAX_TB] = {}; + data_rx_vec[0] = &data_rx; + if (srsran_pusch_nr_decode(&pusch_rx, &pusch_cfg, &pusch_cfg.grant, &chest, sf_symbols, data_rx_vec) < SRSRAN_SUCCESS) { ERROR("Error encoding"); goto clean_exit; diff --git a/lib/src/phy/phch/uci.c b/lib/src/phy/phch/uci.c index f2545fb1e..aa8e2689c 100644 --- a/lib/src/phy/phch/uci.c +++ b/lib/src/phy/phch/uci.c @@ -120,7 +120,7 @@ int16_t srsran_uci_decode_cqi_pucch(srsran_uci_cqi_pucch_t* q, uint8_t* cqi_data, uint32_t cqi_len) { - if (cqi_len < SRSRAN_UCI_MAX_CQI_LEN_PUCCH && b_bits != NULL && cqi_data != NULL) { + if (q != NULL && cqi_len < SRSRAN_UCI_MAX_CQI_LEN_PUCCH && b_bits != NULL && cqi_data != NULL) { uint32_t max_w = 0; int32_t max_corr = INT32_MIN; uint32_t nwords = 1 << SRSRAN_UCI_MAX_CQI_LEN_PUCCH; @@ -646,9 +646,10 @@ int srsran_uci_decode_ack_ri(srsran_pusch_cfg_t* cfg, uint32_t Qm = srsran_mod_bits_x_symbol(cfg->grant.tb.mod); int16_t llr_acc[32] = {}; ///< LLR accumulator - uint32_t nof_acc = - (nof_bits == 1) ? Qm : (nof_bits == 2) ? Qm * 3 : SRSRAN_FEC_BLOCK_SIZE; ///< Number of required LLR - uint32_t count_acc = 0; ///< LLR counter + uint32_t nof_acc = (nof_bits == 1) ? Qm + : (nof_bits == 2) ? Qm * 3 + : SRSRAN_FEC_BLOCK_SIZE; ///< Number of required LLR + uint32_t count_acc = 0; ///< LLR counter for (uint32_t i = 0; i < Qprime; i++) { if (is_ri) { diff --git a/lib/src/phy/rf/rf_zmq_imp.c b/lib/src/phy/rf/rf_zmq_imp.c index c63c4e878..09eb3e7fd 100644 --- a/lib/src/phy/rf/rf_zmq_imp.c +++ b/lib/src/phy/rf/rf_zmq_imp.c @@ -597,12 +597,7 @@ int rf_zmq_recv_with_time(void* h, void* data, uint32_t nsamples, bool blocking, return rf_zmq_recv_with_time_multi(h, &data, nsamples, blocking, secs, frac_secs); } -int rf_zmq_recv_with_time_multi(void* h, - void* data[4], - uint32_t nsamples, - bool blocking, - time_t* secs, - double* frac_secs) +int rf_zmq_recv_with_time_multi(void* h, void** data, uint32_t nsamples, bool blocking, time_t* secs, double* frac_secs) { int ret = SRSRAN_ERROR; diff --git a/lib/src/phy/ue/ue_dl_nr.c b/lib/src/phy/ue/ue_dl_nr.c index fab77bdf7..0611f5993 100644 --- a/lib/src/phy/ue/ue_dl_nr.c +++ b/lib/src/phy/ue/ue_dl_nr.c @@ -573,11 +573,11 @@ int srsran_ue_dl_nr_decode_pdsch(srsran_ue_dl_nr_t* q, return SRSRAN_SUCCESS; } -int srsran_ue_dl_nr_pdsch_info(const srsran_ue_dl_nr_t* q, - const srsran_sch_cfg_nr_t* cfg, - const srsran_pdsch_res_nr_t* res, - char* str, - uint32_t str_len) +int srsran_ue_dl_nr_pdsch_info(const srsran_ue_dl_nr_t* q, + const srsran_sch_cfg_nr_t* cfg, + const srsran_pdsch_res_nr_t res[SRSRAN_MAX_CODEWORDS], + char* str, + uint32_t str_len) { int len = 0; diff --git a/lib/test/phy/phy_dl_nr_test.c b/lib/test/phy/phy_dl_nr_test.c index 9447488df..d9fd1960f 100644 --- a/lib/test/phy/phy_dl_nr_test.c +++ b/lib/test/phy/phy_dl_nr_test.c @@ -471,8 +471,10 @@ int main(int argc, char** argv) } if (srsran_verbose >= SRSRAN_VERBOSE_INFO) { - char str[512]; - srsran_ue_dl_nr_pdsch_info(&ue_dl, &pdsch_cfg, &pdsch_res, str, (uint32_t)sizeof(str)); + char str[512]; + srsran_pdsch_res_nr_t pdsch_res_vec[SRSRAN_MAX_CODEWORDS] = {}; + pdsch_res_vec[0] = pdsch_res; + srsran_ue_dl_nr_pdsch_info(&ue_dl, &pdsch_cfg, pdsch_res_vec, str, (uint32_t)sizeof(str)); char str_extra[2048]; srsran_sch_cfg_nr_info(&pdsch_cfg, str_extra, (uint32_t)sizeof(str_extra)); From 997f7db23ab76a3cad1f48013e82b4382390e03b Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Wed, 26 May 2021 11:48:53 +0100 Subject: [PATCH 043/156] Small fixes for observer.h missing std::size_t --- lib/include/srsran/adt/observer.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/include/srsran/adt/observer.h b/lib/include/srsran/adt/observer.h index a0498557b..d98917b5c 100644 --- a/lib/include/srsran/adt/observer.h +++ b/lib/include/srsran/adt/observer.h @@ -20,8 +20,8 @@ namespace srsran { -using observer_id = std::size_t; -const size_t invalid_observer_id = std::numeric_limits::max(); +using observer_id = std::size_t; +const std::size_t invalid_observer_id = std::numeric_limits::max(); template class observer; @@ -84,7 +84,7 @@ public: template observer_id subscribe(Args2&&... args) { - size_t id = 0; + std::size_t id = 0; for (auto& slot : observers) { if (not static_cast(slot)) { // empty slot found @@ -108,9 +108,9 @@ public: return false; } - size_t nof_observers() const + std::size_t nof_observers() const { - size_t count = 0; + std::size_t count = 0; for (auto& slot : observers) { count += static_cast(slot) ? 1 : 0; } From a245039cf35a5e5992be0c49e80f40c99230ced5 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Wed, 26 May 2021 18:10:40 +0200 Subject: [PATCH 044/156] Initial NR-PBCH-DMRS integration --- .../srsran/phy/ch_estimation/dmrs_pbch.h | 62 +++++ lib/include/srsran/phy/phch/pbch_nr.h | 8 +- lib/include/srsran/phy/sync/ssb.h | 12 +- lib/src/phy/ch_estimation/dmrs_pbch.c | 218 ++++++++++++++++++ lib/src/phy/phch/pbch_nr.c | 14 +- lib/src/phy/sync/ssb.c | 58 ++++- lib/src/phy/sync/test/ssb_decode_test.c | 13 +- 7 files changed, 367 insertions(+), 18 deletions(-) create mode 100644 lib/include/srsran/phy/ch_estimation/dmrs_pbch.h create mode 100644 lib/src/phy/ch_estimation/dmrs_pbch.c diff --git a/lib/include/srsran/phy/ch_estimation/dmrs_pbch.h b/lib/include/srsran/phy/ch_estimation/dmrs_pbch.h new file mode 100644 index 000000000..588c11787 --- /dev/null +++ b/lib/include/srsran/phy/ch_estimation/dmrs_pbch.h @@ -0,0 +1,62 @@ +/** + * + * \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_DMRS_PBCH_H +#define SRSRAN_DMRS_PBCH_H + +#include "srsran/phy/common/phy_common_nr.h" + +/** + * @brief Describes the DeModulation Reference Signals (DMRS) for NR PBCH configuration + */ +typedef struct SRSRAN_API { + uint32_t N_id; ///< Physical cell identifier + uint32_t n_hf; ///< Number of half radio frame, 0 or 1 + uint32_t ssb_idx; ///< SSB candidate index + uint32_t L_max; ///< Number of SSB opportunities in half radio frame + float beta; ///< Power allocation specified in TS 38.213 + srsran_subcarrier_spacing_t scs; ///< SSB configured subcarrier spacing +} srsran_dmrs_pbch_cfg_t; + +/** + * @brief Describes an NR PBCH DMRS based measurement + */ +typedef struct SRSRAN_API { + float corr; ///< Normalised correlation + float epre; ///< Linear energy per resource element + float rsrp; ///< Linear RSRP + float cfo_hz; ///< CFO in Hz + float avg_delay_us; ///< Average delay in us +} srsran_dmrs_pbch_meas_t; + +/** + * @brief Put NR PBCH DMRS in the SSB resource grid + * @param cfg PBCH DMRS configuration + * @param[out] ssb_grid SSB resource grid + * @return SRSRAN_SUCCESS if the inputs and configuration are valid, SRSRAN_ERROR code otherwise + */ +SRSRAN_API int srsran_dmrs_pbch_put(const srsran_dmrs_pbch_cfg_t* cfg, cf_t ssb_grid[SRSRAN_SSB_NOF_RE]); + +/** + * @brief Estimates NR PBCH DMRS + * @param cfg PBCH DMRS configuration + * @param ssb_grid Demodulated SSB resource grid + * @param[out] ce Estimated channel + * @param[out] meas Estimated channel measurements + * @return SRSRAN_SUCCESS if the inputs and configuration are valid, SRSRAN_ERROR code otherwise + */ +SRSRAN_API int srsran_dmrs_pbch_estimate(const srsran_dmrs_pbch_cfg_t* cfg, + const cf_t ssb_grid[SRSRAN_SSB_NOF_RE], + cf_t ce[SRSRAN_SSB_NOF_RE], + srsran_dmrs_pbch_meas_t* meas); + +#endif // SRSRAN_DMRS_PBCH_H diff --git a/lib/include/srsran/phy/phch/pbch_nr.h b/lib/include/srsran/phy/phch/pbch_nr.h index f849f4285..65d22a7a3 100644 --- a/lib/include/srsran/phy/phch/pbch_nr.h +++ b/lib/include/srsran/phy/phch/pbch_nr.h @@ -75,7 +75,7 @@ typedef struct SRSRAN_API { * @brief Initialises an NR PBCH object with the provided arguments * @param q NR PBCH object * @param args Arguments providing the desired configuration - * @return SRSRAN_SUCCESS if initialization is successful, SRSLTE_ERROR code otherwise + * @return SRSRAN_SUCCESS if initialization is successful, SRSRAN_ERROR code otherwise */ SRSRAN_API int srsran_pbch_nr_init(srsran_pbch_nr_t* q, const srsran_pbch_nr_args_t* args); @@ -91,7 +91,7 @@ SRSRAN_API void srsran_pbch_nr_free(srsran_pbch_nr_t* q); * @param cfg NR PBCH configuration * @param msg NR PBCH message to transmit * @param[out] ssb_grid SSB resource grid - * @return SRSRAN_SUCCESS if encoding is successful, SRSLTE_ERROR code otherwise + * @return SRSRAN_SUCCESS if encoding is successful, SRSRAN_ERROR code otherwise */ SRSRAN_API int srsran_pbch_nr_encode(srsran_pbch_nr_t* q, const srsran_pbch_nr_cfg_t* cfg, @@ -104,13 +104,15 @@ SRSRAN_API int srsran_pbch_nr_encode(srsran_pbch_nr_t* q, * @param cfg NR PBCH configuration * @param ssb_idx SSB candidate index * @param[in] ssb_grid SSB resource grid + * @param[in] ce Channel estimates for the SSB resource grid * @param msg NR PBCH message received - * @return SRSRAN_SUCCESS if decoding is successful, SRSLTE_ERROR code otherwise + * @return SRSRAN_SUCCESS if decoding is successful, SRSRAN_ERROR code otherwise */ SRSRAN_API int srsran_pbch_nr_decode(srsran_pbch_nr_t* q, const srsran_pbch_nr_cfg_t* cfg, uint32_t ssb_idx, const cf_t ssb_grid[SRSRAN_SSB_NOF_RE], + const cf_t ce[SRSRAN_SSB_NOF_RE], srsran_pbch_msg_nr_t* msg); SRSRAN_API uint32_t srsran_pbch_msg_info(const srsran_pbch_msg_nr_t* msg, char* str, uint32_t str_len); diff --git a/lib/include/srsran/phy/sync/ssb.h b/lib/include/srsran/phy/sync/ssb.h index 033d670a6..bf05901d9 100644 --- a/lib/include/srsran/phy/sync/ssb.h +++ b/lib/include/srsran/phy/sync/ssb.h @@ -50,6 +50,7 @@ typedef struct SRSRAN_API { bool enable_encode; ///< Enables PBCH Encoder bool enable_decode; ///< Enables PBCH Decoder bool disable_polar_simd; ///< Disables polar encoder/decoder SIMD acceleration + float pbch_dmrs_thr; ///< NR-PBCH DMRS threshold for blind decoding, set to 0 for default } srsran_ssb_args_t; /** @@ -127,13 +128,20 @@ SRSRAN_API void srsran_ssb_free(srsran_ssb_t* q); SRSRAN_API int srsran_ssb_set_cfg(srsran_ssb_t* q, const srsran_ssb_cfg_t* cfg); /** * @brief Decodes PBCH in the given time domain signal + * @note It currently expects an input buffer of half radio frame * @param q SSB object * @param N_id Physical Cell Identifier * @param ssb_idx SSB candidate index + * @param n_hf Number of hald radio frame, 0 or 1 + * @param in Input baseband buffer * @return SRSRAN_SUCCESS if the parameters are valid, SRSRAN_ERROR code otherwise */ -SRSRAN_API int -srsran_ssb_decode_pbch(srsran_ssb_t* q, uint32_t N_id, uint32_t ssb_idx, const cf_t* in, srsran_pbch_msg_nr_t* msg); +SRSRAN_API int srsran_ssb_decode_pbch(srsran_ssb_t* q, + uint32_t N_id, + uint32_t ssb_idx, + uint32_t n_hf, + const cf_t* in, + srsran_pbch_msg_nr_t* msg); /** * @brief Decides if the SSB object is configured and a given subframe is configured for SSB transmission diff --git a/lib/src/phy/ch_estimation/dmrs_pbch.c b/lib/src/phy/ch_estimation/dmrs_pbch.c new file mode 100644 index 000000000..c6d38862b --- /dev/null +++ b/lib/src/phy/ch_estimation/dmrs_pbch.c @@ -0,0 +1,218 @@ +/** + * + * \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/ch_estimation/dmrs_pbch.h" +#include "srsran/phy/common/sequence.h" +#include "srsran/phy/utils/debug.h" +#include "srsran/phy/utils/vector.h" +#include +#include + +/* + * Number of NR PBCH DMRS resource elements present in an SSB resource grid + */ +#define DMRS_PBCH_NOF_RE 144 + +static uint32_t dmrs_pbch_cinit(const srsran_dmrs_pbch_cfg_t* cfg) +{ + // Default values for L_max == 4 + uint64_t i_ssb = (cfg->ssb_idx & 0b11U) + 4UL * cfg->n_hf; // Least 2 significant bits + + if (cfg->L_max == 8 || cfg->L_max == 64) { + i_ssb = cfg->ssb_idx & 0b111U; // Least 3 significant bits + } + + return SRSRAN_SEQUENCE_MOD(((i_ssb + 1UL) * (SRSRAN_FLOOR(cfg->N_id, 4UL) + 1UL) << 11UL) + ((i_ssb + 1UL) << 6UL) + + (cfg->N_id % 4)); +} + +int srsran_dmrs_pbch_put(const srsran_dmrs_pbch_cfg_t* cfg, cf_t ssb_grid[SRSRAN_SSB_NOF_RE]) +{ + // Validate inputs + if (cfg == NULL || ssb_grid == NULL) { + return SRSRAN_ERROR_INVALID_INPUTS; + } + + // Calculate index shift + uint32_t v = cfg->N_id % 4; + + // Calculate power allocation + float beta = M_SQRT1_2; + if (isnormal(cfg->beta)) { + beta = cfg->beta; + } + + // Initialise sequence + uint32_t cinit = dmrs_pbch_cinit(cfg); + srsran_sequence_state_t sequence_state = {}; + srsran_sequence_state_init(&sequence_state, cinit); + + // Generate sequence + cf_t r[DMRS_PBCH_NOF_RE]; + srsran_sequence_state_gen_f(&sequence_state, beta, (float*)r, DMRS_PBCH_NOF_RE * 2); + + // r sequence read index + uint32_t r_idx = 0; + + // Put sequence in symbol 1 + for (uint32_t k = v; k < SRSRAN_SSB_BW_SUBC; k += 4) { + ssb_grid[SRSRAN_SSB_BW_SUBC * 1 + k] = r[r_idx++]; + } + + // Put sequence in symbol 2, lower section + for (uint32_t k = v; k < 48; k += 4) { + ssb_grid[SRSRAN_SSB_BW_SUBC * 2 + k] = r[r_idx++]; + } + + // Put sequence in symbol 2, upper section + for (uint32_t k = 192 + v; k < SRSRAN_SSB_BW_SUBC; k += 4) { + ssb_grid[SRSRAN_SSB_BW_SUBC * 2 + k] = r[r_idx++]; + } + + // Put sequence in symbol 3 + for (uint32_t k = v; k < SRSRAN_SSB_BW_SUBC; k += 4) { + ssb_grid[SRSRAN_SSB_BW_SUBC * 3 + k] = r[r_idx++]; + } + + return SRSRAN_SUCCESS; +} + +int dmrs_pbch_extract_lse(const srsran_dmrs_pbch_cfg_t* cfg, + const cf_t ssb_grid[SRSRAN_SSB_NOF_RE], + cf_t lse[DMRS_PBCH_NOF_RE]) +{ + // Calculate index shift + uint32_t v = cfg->N_id % 4; + + // Calculate power allocation + float beta = M_SQRT1_2; + if (isnormal(cfg->beta)) { + beta = cfg->beta; + } + + // Initialise sequence + uint32_t cinit = dmrs_pbch_cinit(cfg); + srsran_sequence_state_t sequence_state = {}; + srsran_sequence_state_init(&sequence_state, cinit); + + // Generate sequence + cf_t r[DMRS_PBCH_NOF_RE]; + srsran_sequence_state_gen_f(&sequence_state, beta, (float*)r, DMRS_PBCH_NOF_RE * 2); + + // r sequence read index + uint32_t r_idx = 0; + + // Put sequence in symbol 1 + for (uint32_t k = v; k < SRSRAN_SSB_BW_SUBC; k += 4) { + lse[r_idx++] = ssb_grid[SRSRAN_SSB_BW_SUBC * 1 + k]; + } + + // Put sequence in symbol 2, lower section + for (uint32_t k = v; k < 48; k += 4) { + lse[r_idx++] = ssb_grid[SRSRAN_SSB_BW_SUBC * 2 + k]; + } + + // Put sequence in symbol 2, upper section + for (uint32_t k = 192 + v; k < SRSRAN_SSB_BW_SUBC; k += 4) { + lse[r_idx++] = ssb_grid[SRSRAN_SSB_BW_SUBC * 2 + k]; + } + + // Put sequence in symbol 3 + for (uint32_t k = v; k < SRSRAN_SSB_BW_SUBC; k += 4) { + lse[r_idx++] = ssb_grid[SRSRAN_SSB_BW_SUBC * 3 + k]; + } + + // Calculate actual least square estimates + srsran_vec_prod_conj_ccc(lse, r, lse, DMRS_PBCH_NOF_RE); + + return SRSRAN_SUCCESS; +} + +int srsran_dmrs_pbch_estimate(const srsran_dmrs_pbch_cfg_t* cfg, + const cf_t ssb_grid[SRSRAN_SSB_NOF_RE], + cf_t ce[SRSRAN_SSB_NOF_RE], + srsran_dmrs_pbch_meas_t* meas) +{ + // Validate inputs + if (cfg == NULL || ssb_grid == NULL || ce == NULL || meas == NULL) { + return SRSRAN_ERROR_INVALID_INPUTS; + } + + // Extract least square estimates + cf_t lse[DMRS_PBCH_NOF_RE]; + if (dmrs_pbch_extract_lse(cfg, ssb_grid, lse) < SRSRAN_SUCCESS) { + return SRSRAN_ERROR; + } + + float scs_hz = SRSRAN_SUBC_SPACING_NR(cfg->scs); + if (!isnormal(scs_hz)) { + ERROR("Invalid SCS"); + return SRSRAN_ERROR; + } + + // Compute average delay in microseconds from the symbols 1 and 3 (symbol 2 does not carry PBCH in all the grid) + float avg_delay1_norm = srsran_vec_estimate_frequency(&lse[0], 60) / 4.0f; + float avg_delay3_norm = srsran_vec_estimate_frequency(&lse[84], 60) / 4.0f; + float avg_delay_norm = (avg_delay1_norm + avg_delay3_norm) / 2.0f; + float avg_delay_us = avg_delay_norm / scs_hz; + + // Generate a second SSB grid with the corrected average delay + cf_t ssb_grid_corrected[SRSRAN_SSB_NOF_RE]; + for (uint32_t l = 0; l < SRSRAN_SSB_DURATION_NSYMB; l++) { + srsran_vec_apply_cfo(&ssb_grid[SRSRAN_SSB_BW_SUBC * l], + avg_delay_norm, + &ssb_grid_corrected[SRSRAN_SSB_BW_SUBC * l], + SRSRAN_SSB_BW_SUBC); + } + + // Extract LSE from corrected grid + if (dmrs_pbch_extract_lse(cfg, ssb_grid_corrected, lse) < SRSRAN_SUCCESS) { + return SRSRAN_ERROR; + } + + // Compute correlation of symbols 1 and 3 + cf_t corr1 = srsran_vec_acc_cc(&lse[0], 60) / 60.0f; + cf_t corr3 = srsran_vec_acc_cc(&lse[84], 60) / 60.0f; + + // Estimate CFO from correlation + float distance_s = srsran_symbol_distance_s(1, 3, cfg->scs); + float cfo_hz = 0.0f; + if (isnormal(distance_s)) { + cfo_hz = cargf(corr1 * conjf(corr3)) / (2.0f * (float)M_PI * distance_s); + } + + // Estimate wideband gain at symbol 0 + cf_t wideband_gain = (srsran_vec_acc_cc(lse, DMRS_PBCH_NOF_RE) / DMRS_PBCH_NOF_RE) * + cexpf(I * 2.0f * M_PI * srsran_symbol_offset_s(2, cfg->scs) * cfo_hz); + + // Compute RSRP from correlation + float rsrp = SRSRAN_CSQABS((corr1 + corr3) / 2.0f); + + // Compute EPRE + float epre = srsran_vec_avg_power_cf(lse, DMRS_PBCH_NOF_RE); + + // Write measurements + meas->corr = rsrp / epre; + meas->epre = epre; + meas->rsrp = rsrp; + meas->cfo_hz = cfo_hz; + meas->avg_delay_us = avg_delay_us; + + // Compute channel estimates + for (uint32_t l = 0; l < SRSRAN_SSB_DURATION_NSYMB; l++) { + float t_s = srsran_symbol_offset_s(l, cfg->scs); + cf_t symbol_wideband_gain = cexpf(-I * 2.0f * M_PI * cfo_hz * t_s) * wideband_gain; + srsran_vec_gen_sine(symbol_wideband_gain, -avg_delay_norm, &ce[l * SRSRAN_SSB_BW_SUBC], SRSRAN_SSB_BW_SUBC); + } + + return SRSRAN_SUCCESS; +} \ No newline at end of file diff --git a/lib/src/phy/phch/pbch_nr.c b/lib/src/phy/phch/pbch_nr.c index d6ab4a288..1a34ab903 100644 --- a/lib/src/phy/phch/pbch_nr.c +++ b/lib/src/phy/phch/pbch_nr.c @@ -14,9 +14,11 @@ #include "srsran/phy/common/sequence.h" #include "srsran/phy/fec/polar/polar_chanalloc.h" #include "srsran/phy/fec/polar/polar_interleaver.h" +#include "srsran/phy/mimo/precoding.h" #include "srsran/phy/modem/demod_soft.h" #include "srsran/phy/modem/mod.h" #include "srsran/phy/utils/debug.h" +#include "srsran/phy/utils/simd.h" #include "srsran/phy/utils/vector.h" #define PBCH_NR_DEBUG_TX(...) DEBUG("PBCH-NR Tx: " __VA_ARGS__) @@ -594,6 +596,7 @@ int srsran_pbch_nr_decode(srsran_pbch_nr_t* q, const srsran_pbch_nr_cfg_t* cfg, uint32_t ssb_idx, const cf_t ssb_grid[SRSRAN_SSB_NOF_RE], + const cf_t ce_grid[SRSRAN_SSB_NOF_RE], srsran_pbch_msg_nr_t* msg) { if (q == NULL || cfg == NULL || msg == NULL || ssb_grid == NULL) { @@ -602,9 +605,18 @@ int srsran_pbch_nr_decode(srsran_pbch_nr_t* q, // 7.3.3.3 Mapping to physical resources // 7.4.3.1.3 Mapping of PBCH and DM-RS within an SS/PBCH block - cf_t symbols[PBCH_NR_M]; + srsran_simd_aligned cf_t symbols[PBCH_NR_M]; pbch_nr_demapping(cfg, ssb_grid, symbols); + srsran_simd_aligned cf_t ce[PBCH_NR_M]; + pbch_nr_demapping(cfg, ce_grid, ce); + + // Channel equalizer + if (srsran_predecoding_single(symbols, ce, symbols, NULL, PBCH_NR_M, 1.0f, 0.0f) < SRSRAN_SUCCESS) { + ERROR("Error in predecoder"); + return SRSRAN_ERROR; + } + // 7.3.3.2 Modulation int8_t llr[PBCH_NR_E]; srsran_demod_soft_demodulate_b(SRSRAN_MOD_QPSK, symbols, llr, PBCH_NR_M); diff --git a/lib/src/phy/sync/ssb.c b/lib/src/phy/sync/ssb.c index 106f0f85b..3c64282b4 100644 --- a/lib/src/phy/sync/ssb.c +++ b/lib/src/phy/sync/ssb.c @@ -11,6 +11,7 @@ */ #include "srsran/phy/sync/ssb.h" +#include "srsran/phy/ch_estimation/dmrs_pbch.h" #include "srsran/phy/sync/pss_nr.h" #include "srsran/phy/sync/sss_nr.h" #include "srsran/phy/utils/debug.h" @@ -33,6 +34,11 @@ */ #define SSB_CORR_SZ(SYMB_SZ) SRSRAN_MIN(1U << (uint32_t)ceil(log2((double)(SYMB_SZ)) + 3.0), 1U << 13U) +/* + * Default NR-PBCH DMRS normalised correlation (RSRP/EPRE) threshold + */ +#define SSB_PBCH_DMRS_DEFAULT_CORR_THR 0.6f + static int ssb_init_corr(srsran_ssb_t* q) { // Initialise correlation only if it is enabled @@ -83,9 +89,8 @@ int srsran_ssb_init(srsran_ssb_t* q, const srsran_ssb_args_t* args) q->args = *args; // Check if the maximum sampling rate is in range, force default otherwise - if (!isnormal(q->args.max_srate_hz) || q->args.max_srate_hz < 0.0) { - q->args.max_srate_hz = SRSRAN_SSB_DEFAULT_MAX_SRATE_HZ; - } + q->args.max_srate_hz = (!isnormal(q->args.max_srate_hz)) ? SRSRAN_SSB_DEFAULT_MAX_SRATE_HZ : q->args.max_srate_hz; + 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_symbol_sz = (uint32_t)round(q->args.max_srate_hz / q->scs_hz); @@ -539,7 +544,16 @@ int srsran_ssb_add(srsran_ssb_t* q, } // Put PBCH DMRS - // ... + srsran_dmrs_pbch_cfg_t pbch_dmrs_cfg = {}; + pbch_dmrs_cfg.N_id = N_id; + pbch_dmrs_cfg.n_hf = msg->hrf ? 0 : 1; + pbch_dmrs_cfg.ssb_idx = msg->ssb_idx; + pbch_dmrs_cfg.L_max = q->Lmax; + pbch_dmrs_cfg.beta = 0.0f; + if (srsran_dmrs_pbch_put(&pbch_dmrs_cfg, ssb_grid) < SRSRAN_SUCCESS) { + ERROR("Error putting PBCH DMRS"); + return SRSRAN_ERROR; + } // Put PBCH payload srsran_pbch_nr_cfg_t pbch_cfg = {}; @@ -630,7 +644,7 @@ ssb_measure(srsran_ssb_t* q, const cf_t ssb_grid[SRSRAN_SSB_NOF_RE], uint32_t N_ uint32_t N_id_1 = SRSRAN_NID_1_NR(N_id); uint32_t N_id_2 = SRSRAN_NID_2_NR(N_id); - // Extract PSS LSE + // Extract PSS and SSS LSE cf_t pss_lse[SRSRAN_PSS_NR_LEN]; cf_t sss_lse[SRSRAN_SSS_NR_LEN]; if (srsran_pss_nr_extract_lse(ssb_grid, N_id_2, pss_lse) < SRSRAN_SUCCESS || @@ -882,7 +896,12 @@ int srsran_ssb_csi_measure(srsran_ssb_t* q, return SRSRAN_SUCCESS; } -int srsran_ssb_decode_pbch(srsran_ssb_t* q, uint32_t N_id, uint32_t ssb_idx, const cf_t* in, srsran_pbch_msg_nr_t* msg) +int srsran_ssb_decode_pbch(srsran_ssb_t* q, + uint32_t N_id, + uint32_t ssb_idx, + uint32_t n_hf, + const cf_t* in, + srsran_pbch_msg_nr_t* msg) { // Verify inputs if (q == NULL || N_id >= SRSRAN_NOF_NID_NR || in == NULL || msg == NULL || !isnormal(q->scs_hz)) { @@ -907,14 +926,37 @@ int srsran_ssb_decode_pbch(srsran_ssb_t* q, uint32_t N_id, uint32_t ssb_idx, con return SRSRAN_ERROR; } - // Prepare configuration + // Prepare PBCH DMRS configuration + srsran_dmrs_pbch_cfg_t pbch_dmrs_cfg = {}; + pbch_dmrs_cfg.N_id = N_id; + pbch_dmrs_cfg.n_hf = n_hf; + pbch_dmrs_cfg.ssb_idx = ssb_idx; + pbch_dmrs_cfg.L_max = q->Lmax; + pbch_dmrs_cfg.beta = 0.0f; + pbch_dmrs_cfg.scs = q->cfg.scs; + + // Compute PBCH channel estimates + srsran_dmrs_pbch_meas_t meas = {}; + cf_t ce[SRSRAN_SSB_NOF_RE] = {}; + if (srsran_dmrs_pbch_estimate(&pbch_dmrs_cfg, ssb_grid, ce, &meas) < SRSRAN_SUCCESS) { + ERROR("Error estimating channel"); + return SRSRAN_ERROR; + } + + // Compare measurement with threshold + if (meas.corr < q->args.pbch_dmrs_thr) { + msg->crc = false; + return SRSRAN_SUCCESS; + } + + // Prepare PBCH configuration srsran_pbch_nr_cfg_t pbch_cfg = {}; pbch_cfg.N_id = N_id; pbch_cfg.ssb_scs = q->cfg.scs; pbch_cfg.Lmax = q->Lmax; // Decode - if (srsran_pbch_nr_decode(&q->pbch, &pbch_cfg, ssb_idx, ssb_grid, msg) < SRSRAN_SUCCESS) { + if (srsran_pbch_nr_decode(&q->pbch, &pbch_cfg, ssb_idx, ssb_grid, ce, msg) < SRSRAN_SUCCESS) { ERROR("Error decoding PBCH"); return SRSRAN_ERROR; } diff --git a/lib/src/phy/sync/test/ssb_decode_test.c b/lib/src/phy/sync/test/ssb_decode_test.c index e85898b9a..181beb33b 100644 --- a/lib/src/phy/sync/test/ssb_decode_test.c +++ b/lib/src/phy/sync/test/ssb_decode_test.c @@ -15,6 +15,7 @@ #include "srsran/phy/sync/ssb.h" #include "srsran/phy/utils/debug.h" #include "srsran/phy/utils/vector.h" +#include #include #include #include @@ -25,9 +26,10 @@ static srsran_subcarrier_spacing_t carrier_scs = srsran_subcarrier_spacing_1 static srsran_subcarrier_spacing_t ssb_scs = srsran_subcarrier_spacing_30kHz; // Channel parameters -static int32_t delay_n = 0; -static float cfo_hz = 0.0f; -static float n0_dB = -300.0f; +static cf_t wideband_gain = 1.0f + 0.5 * I; +static int32_t delay_n = 1; +static float cfo_hz = 1000.0f; +static float n0_dB = -10.0f; // Test context static srsran_random_t random_gen = NULL; @@ -69,6 +71,9 @@ static void run_channel() // AWGN srsran_channel_awgn_run_c(&awgn, buffer, buffer, hf_len); + + // Wideband gain + srsran_vec_sc_prod_ccc(buffer, wideband_gain, buffer, hf_len); } static void gen_pbch_msg(srsran_pbch_msg_nr_t* pbch_msg, uint32_t ssb_idx) @@ -129,7 +134,7 @@ static int test_case_1(srsran_ssb_t* ssb) // Decode gettimeofday(&t[1], NULL); srsran_pbch_msg_nr_t pbch_msg_rx = {}; - TESTASSERT(srsran_ssb_decode_pbch(ssb, pci, ssb_idx, buffer, &pbch_msg_rx) == SRSRAN_SUCCESS); + TESTASSERT(srsran_ssb_decode_pbch(ssb, pci, ssb_idx, 0, buffer, &pbch_msg_rx) == SRSRAN_SUCCESS); gettimeofday(&t[2], NULL); get_time_interval(t); t_decode_usec += t[0].tv_usec + t[0].tv_sec * 1000000UL; From d9a5d3f95a98c8fb4218ace24b4770dec058e63a Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Tue, 18 May 2021 12:20:57 +0200 Subject: [PATCH 045/156] pcap_base: increase PDU queue length some systems with slower HDD seem to have issues writing the PDUs to disk. increasing length to see if that helps. --- lib/include/srsran/common/mac_pcap_base.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/include/srsran/common/mac_pcap_base.h b/lib/include/srsran/common/mac_pcap_base.h index c56f18346..8eed68c9e 100644 --- a/lib/include/srsran/common/mac_pcap_base.h +++ b/lib/include/srsran/common/mac_pcap_base.h @@ -93,11 +93,11 @@ protected: virtual void write_pdu(pcap_pdu_t& pdu) = 0; void run_thread() final; - std::mutex mutex; - srslog::basic_logger& logger; - bool running = false; - static_blocking_queue queue; - uint16_t ue_id = 0; + std::mutex mutex; + srslog::basic_logger& logger; + bool running = false; + static_blocking_queue queue; + uint16_t ue_id = 0; private: void pack_and_queue(uint8_t* payload, From 70d232c91786dbf4e2d8af5d41a66875b8fb429f Mon Sep 17 00:00:00 2001 From: David Rupprecht Date: Wed, 26 May 2021 22:23:52 +0200 Subject: [PATCH 046/156] Fix run_lte script --- test/run_lte.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/run_lte.sh b/test/run_lte.sh index e9f2b210d..3186fecd6 100755 --- a/test/run_lte.sh +++ b/test/run_lte.sh @@ -300,8 +300,8 @@ ue_args="$build_path/../srsue/ue.conf.example \ --gw.netns=$ue_netns \ --log.all_level=info \ --log.filename=./${nof_prb}prb_ue.log \ - --pcap.enable=true \ - --pcap.filename=./${nof_prb}prb_ue.pcap" + --pcap.enable=mac \ + --pcap.mac_filename=./${nof_prb}prb_ue.pcap" if ([ "$num_cc" == "2" ]) then From f33731ecd4ef927f716642ba0b9810507b2724a5 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Wed, 26 May 2021 18:32:28 +0200 Subject: [PATCH 047/156] Disable irrelevant unit/component test by default --- CMakeLists.txt | 14 ++++++++++++++ lib/src/phy/fec/ldpc/test/CMakeLists.txt | 14 +++++++------- lib/src/phy/fec/polar/test/CMakeLists.txt | 8 ++++---- lib/src/phy/phch/test/CMakeLists.txt | 10 +++------- 4 files changed, 28 insertions(+), 18 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 61a102d05..3b9e86333 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,6 +85,8 @@ option(ENABLE_SRSLOG_TRACING "Enable event tracing using srslog" OFF) option(ASSERTS_ENABLED "Enable srsRAN asserts" ON) option(STOP_ON_WARNING "Interrupt application on warning" OFF) +option(ENABLE_ALL_TEST "Enable all unit/component test" OFF) + # Users that want to try this feature need to make sure the lto plugin is # loaded by bintools (ar, nm, ...). Older versions of bintools will not do # it automatically so it is necessary to use the gcc wrappers of the compiler @@ -593,6 +595,18 @@ function(add_nr_test) set_tests_properties(${TNAME} PROPERTIES LABELS "nr;${CTEST_LABELS}") endfunction() +function(add_nr_advanced_test) + if (NOT ${ENABLE_ALL_TEST}) + return() + endif() + add_test(${ARGN}) + set(TNAME ${ARGV0}) + if(${TNAME} STREQUAL NAME) + set(TNAME ${ARGV1}) + endif() + set_tests_properties(${TNAME} PROPERTIES LABELS "nr;${CTEST_LABELS}") +endfunction() + ######################################################################## # Add general includes and dependencies ######################################################################## diff --git a/lib/src/phy/fec/ldpc/test/CMakeLists.txt b/lib/src/phy/fec/ldpc/test/CMakeLists.txt index 8a53a3c5e..ebdfadcf0 100644 --- a/lib/src/phy/fec/ldpc/test/CMakeLists.txt +++ b/lib/src/phy/fec/ldpc/test/CMakeLists.txt @@ -48,7 +48,7 @@ endif(HAVE_AVX512) ### Test LDPC libs function(ldpc_unit_tests) foreach(i IN LISTS ARGN) - add_nr_test(NAME ${test_name}-LS${i} COMMAND ${test_command} -l${i} + add_nr_advanced_test(NAME ${test_name}-LS${i} COMMAND ${test_command} -l${i} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/ ) endforeach() @@ -167,36 +167,36 @@ function(ldpc_rm_unit_tests) math(EXPR tmpN "${N} - (${N} % ${Div})") math(EXPR E "${Ordval}*(${tmpN})/${Div}") #twice the rate - add_nr_test(NAME ${test_name}-b${bgval}-l${i}-e${E}-f10-m${Modval}-r${rvval}-M${N} COMMAND ${test_command} -b${bgval} -l${i} -e${E} -f10 -m${Modval} -r${rvval} -M${N} + add_nr_advanced_test(NAME ${test_name}-b${bgval}-l${i}-e${E}-f10-m${Modval}-r${rvval}-M${N} COMMAND ${test_command} -b${bgval} -l${i} -e${E} -f10 -m${Modval} -r${rvval} -M${N} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/ ) math(EXPR M "${N} / 2") # Half size buffer - add_nr_test(NAME ${test_name}-b${bgval}-l${i}-e${E}-f10-m${Modval}-r${rvval}-M${M} COMMAND ${test_command} -b${bgval} -l${i} -e${E} -f10 -m${Modval} -r${rvval} -M${M} + add_nr_advanced_test(NAME ${test_name}-b${bgval}-l${i}-e${E}-f10-m${Modval}-r${rvval}-M${M} COMMAND ${test_command} -b${bgval} -l${i} -e${E} -f10 -m${Modval} -r${rvval} -M${M} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/ ) math(EXPR Div "2*${Ordval}") math(EXPR tmpN "${N} - (${N} % ${Div})") math(EXPR E "${Ordval}*(${tmpN})/${Div}") #twice the rate - add_nr_test(NAME ${test_name}-b${bgval}-l${i}-e${E}-f10-m${Modval}-r${rvval}-M${N} COMMAND ${test_command} -b${bgval} -l${i} -e${E} -f10 -m${Modval} -r${rvval} -M${N} + add_nr_advanced_test(NAME ${test_name}-b${bgval}-l${i}-e${E}-f10-m${Modval}-r${rvval}-M${N} COMMAND ${test_command} -b${bgval} -l${i} -e${E} -f10 -m${Modval} -r${rvval} -M${N} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/ ) math(EXPR M "${N}/ 2") # Half size buffer - add_nr_test(NAME ${test_name}-b${bgval}-l${i}-e${E}-f10-m${Modval}-r${rvval}-M${M} COMMAND ${test_command} -b${bgval} -l${i} -e${E} -f10 -m${Modval} -r${rvval} -M${M} + add_nr_advanced_test(NAME ${test_name}-b${bgval}-l${i}-e${E}-f10-m${Modval}-r${rvval}-M${M} COMMAND ${test_command} -b${bgval} -l${i} -e${E} -f10 -m${Modval} -r${rvval} -M${M} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/ ) math(EXPR Div "${Ordval}") math(EXPR tmpN "2*${N} - (2*${N} % ${Div})") #Half the rate math(EXPR E "${Ordval}*(${tmpN})/${Div}") - add_nr_test(NAME ${test_name}-b${bgval}-l${i}-e${E}-f10-m${Modval}-r${rvval}-M${N} COMMAND ${test_command} -b${bgval} -l${i} -e${E} -f10 -m${Modval} -r${rvval} -M${N} + add_nr_advanced_test(NAME ${test_name}-b${bgval}-l${i}-e${E}-f10-m${Modval}-r${rvval}-M${N} COMMAND ${test_command} -b${bgval} -l${i} -e${E} -f10 -m${Modval} -r${rvval} -M${N} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/ ) math(EXPR M "${N}/ 2") # Half size buffer - add_nr_test(NAME ${test_name}-b${bgval}-l${i}-e${E}-f10-m${Modval}-r${rvval}-M${M} COMMAND ${test_command} -b${bgval} -l${i} -e${E} -f10 -m${Modval} -r${rvval} -M${M} + add_nr_advanced_test(NAME ${test_name}-b${bgval}-l${i}-e${E}-f10-m${Modval}-r${rvval}-M${M} COMMAND ${test_command} -b${bgval} -l${i} -e${E} -f10 -m${Modval} -r${rvval} -M${M} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/ ) endforeach() diff --git a/lib/src/phy/fec/polar/test/CMakeLists.txt b/lib/src/phy/fec/polar/test/CMakeLists.txt index 299266e94..967317e5a 100644 --- a/lib/src/phy/fec/polar/test/CMakeLists.txt +++ b/lib/src/phy/fec/polar/test/CMakeLists.txt @@ -28,7 +28,7 @@ function(polar_tests_lite) list(GET listE ${num} eval) list(GET listK ${num} kval) list(GET listI ${num} ival) - add_nr_test(NAME ${test_name}-s${S}-n${nval}-e${eval}-k${kval}-i${ival} + add_nr_advanced_test(NAME ${test_name}-s${S}-n${nval}-e${eval}-k${kval}-i${ival} COMMAND ${test_command} -s${S} -n${nval} -e${eval} -k${kval} -i${ival} ) endforeach() @@ -42,7 +42,7 @@ function(polar_tests) foreach(Kval RANGE 36 164 32) math(EXPR Emin "${Kval} + 1") foreach(Eval RANGE ${Emin} 8192 128) - add_nr_test(NAME ${test_name}-s${S}-k${Kval}-e${Eval}-n${nval}-i0 + add_nr_advanced_test(NAME ${test_name}-s${S}-k${Kval}-e${Eval}-n${nval}-i0 COMMAND ${test_command} -s${S} -k${Kval} -e${Eval} -n${nval} -i0 ) endforeach() @@ -54,7 +54,7 @@ function(polar_tests) foreach(Kval RANGE 18 25) math(EXPR Emin "${Kval} + 3 + 1") foreach(Eval RANGE ${Emin} 8192 128) - add_nr_test(NAME ${test_name}-s${S}-k${Kval}-e${Eval}-n${nval}-i1 + add_nr_advanced_test(NAME ${test_name}-s${S}-k${Kval}-e${Eval}-n${nval}-i1 COMMAND ${test_command} -s${S} -k${Kval} -e${Eval} -n${nval} -i1 ) endforeach() @@ -63,7 +63,7 @@ function(polar_tests) foreach(Kval RANGE 32 1023 32) math(EXPR Emin "${Kval} + 1") foreach(Eval RANGE ${Emin} 8192 128) - add_nr_test(NAME ${test_name}-s${S}-k${Kval}-e${Eval}-n${nval}-i1 + add_nr_advanced_test(NAME ${test_name}-s${S}-k${Kval}-e${Eval}-n${nval}-i1 COMMAND ${test_command} -s${S} -k${Kval} -e${Eval} -n${nval} -i1 ) endforeach() diff --git a/lib/src/phy/phch/test/CMakeLists.txt b/lib/src/phy/phch/test/CMakeLists.txt index 22f2d654d..98835024d 100644 --- a/lib/src/phy/phch/test/CMakeLists.txt +++ b/lib/src/phy/phch/test/CMakeLists.txt @@ -453,11 +453,7 @@ add_lte_test(npdsch_npdcch_dci_formatN1_test npdsch_npdcch_file_test -c 0 -s 1 - add_executable(pusch_test pusch_test.c) target_link_libraries(pusch_test srsran_phy) -if (NOT DEFINED TEST_EXTENSION) - set(TEST_EXTENSION Normal) -endif(NOT DEFINED TEST_EXTENSION) - -if (TEST_EXTENSION STREQUAL Paranoid) +if (${ENABLE_ALL_TEST}) # All valid number of PRBs for PUSCH set(cell_n_prb_valid 1 2 3 4 5 6 8 9 10 12 15 16 18 20 24 25 27 30 32 36 40 45 48 50 54 60 64 72 75 80 81 90 96 100) @@ -469,7 +465,7 @@ if (TEST_EXTENSION STREQUAL Paranoid) set(pusch_cqi none wideband) -else (TEST_EXTENSION STREQUAL Paranoid) +else () set(cell_n_prb_valid 50) set(pusch_min_mcs 0) @@ -480,7 +476,7 @@ else (TEST_EXTENSION STREQUAL Paranoid) set(pusch_cqi none wideband) -endif (TEST_EXTENSION STREQUAL Paranoid) +endif () foreach (cell_n_prb 6 15 25 50 75 100) set(pusch_cell_n_prb) From 574459fd90fa3553b43f9b3be8899c8b39b133f0 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Wed, 26 May 2021 23:24:39 +0200 Subject: [PATCH 048/156] rf: remove srsran.h include --- lib/src/phy/rf/rf_blade_imp.c | 4 +++- lib/src/phy/rf/rf_imp.c | 2 +- lib/src/phy/rf/rf_soapy_imp.c | 4 +++- lib/src/phy/rf/rf_uhd_imp.cc | 2 +- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/src/phy/rf/rf_blade_imp.c b/lib/src/phy/rf/rf_blade_imp.c index 52fca3fcb..888f8a421 100644 --- a/lib/src/phy/rf/rf_blade_imp.c +++ b/lib/src/phy/rf/rf_blade_imp.c @@ -15,7 +15,9 @@ #include #include "rf_blade_imp.h" -#include "srsran/srsran.h" +#include "srsran/phy/common/timestamp.h" +#include "srsran/phy/utils/debug.h" +#include "srsran/phy/utils/vector.h" #define UNUSED __attribute__((unused)) #define CONVERT_BUFFER_SIZE (240 * 1024) diff --git a/lib/src/phy/rf/rf_imp.c b/lib/src/phy/rf/rf_imp.c index 59f2e6920..8ed99f0c0 100644 --- a/lib/src/phy/rf/rf_imp.c +++ b/lib/src/phy/rf/rf_imp.c @@ -14,7 +14,7 @@ #include "rf_dev.h" #include "srsran/phy/rf/rf.h" -#include "srsran/srsran.h" +#include "srsran/phy/utils/debug.h" int rf_get_available_devices(char** devnames, int max_strlen) { diff --git a/lib/src/phy/rf/rf_soapy_imp.c b/lib/src/phy/rf/rf_soapy_imp.c index aa28efe90..ffa282bab 100644 --- a/lib/src/phy/rf/rf_soapy_imp.c +++ b/lib/src/phy/rf/rf_soapy_imp.c @@ -17,7 +17,9 @@ #include "rf_helper.h" #include "rf_soapy_imp.h" -#include "srsran/srsran.h" +#include "srsran/phy/common/phy_common.h" +#include "srsran/phy/utils/debug.h" +#include "srsran/phy/utils/vector.h" #include #include diff --git a/lib/src/phy/rf/rf_uhd_imp.cc b/lib/src/phy/rf/rf_uhd_imp.cc index bf0e3d1dc..32ca0e25a 100644 --- a/lib/src/phy/rf/rf_uhd_imp.cc +++ b/lib/src/phy/rf/rf_uhd_imp.cc @@ -19,7 +19,7 @@ #include #include "rf_helper.h" -#include "srsran/srsran.h" +#include "srsran/phy/utils/debug.h" #include "rf_uhd_generic.h" #include "rf_uhd_imp.h" From 28399dd876e7c1a9ac0d0c8beaed9867086c2f90 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Wed, 26 May 2021 23:25:18 +0200 Subject: [PATCH 049/156] rf_zmq_imp: remove sleep --- lib/src/phy/rf/rf_zmq_imp.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/src/phy/rf/rf_zmq_imp.c b/lib/src/phy/rf/rf_zmq_imp.c index 09eb3e7fd..bae0cf24f 100644 --- a/lib/src/phy/rf/rf_zmq_imp.c +++ b/lib/src/phy/rf/rf_zmq_imp.c @@ -668,9 +668,6 @@ int rf_zmq_recv_with_time_multi(void* h, void** data, uint32_t nsamples, bool bl rf_zmq_info(handler->id, " - next rx time: %d + %.3f\n", ts_rx.full_secs, ts_rx.frac_secs); rf_zmq_info(handler->id, " - next tx time: %d + %.3f\n", ts_tx.full_secs, ts_tx.frac_secs); - // Leave time for the Tx to transmit - usleep((1000000 * nsamples_baserate) / handler->base_srate); - // check for tx gap if we're also transmitting on this radio for (int i = 0; i < handler->nof_channels; i++) { if (handler->transmitter[i].running) { From bb6a5ebe80950dc6c69b121746542a9db07ebbe9 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Wed, 26 May 2021 23:27:06 +0200 Subject: [PATCH 050/156] tsan: add TSAN options file to set some default flags and exclude some libs from checks --- lib/include/srsran/common/tsan_options.h | 49 ++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 lib/include/srsran/common/tsan_options.h diff --git a/lib/include/srsran/common/tsan_options.h b/lib/include/srsran/common/tsan_options.h new file mode 100644 index 000000000..96a4f2544 --- /dev/null +++ b/lib/include/srsran/common/tsan_options.h @@ -0,0 +1,49 @@ +/** + * + * \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_TSAN_OPTIONS_H +#define SRSRAN_TSAN_OPTIONS_H + +// Options taken from Mozilla project +// abort_on_error=1 - Causes TSan to abort instead of using exit(). +// halt_on_error=1 - Causes TSan to stop on the first race detected. +// +// report_signal_unsafe=0 - Required to avoid TSan deadlocks when +// receiving external signals (e.g. SIGINT manually on console). +// +// allocator_may_return_null=1 - Tell TSan to return NULL when an allocation +// fails instead of aborting the program. This allows us to handle failing +// allocations the same way we would handle them with a regular allocator and +// also uncovers potential bugs that might occur in these situations. + +#ifdef __cplusplus +extern "C" { +#endif + +const char* __tsan_default_options() +{ + return "halt_on_error=1:abort_on_error=1:report_signal_unsafe=0" + ":allocator_may_return_null=1"; +} + +const char* __tsan_default_suppressions() +{ + // External uninstrumented libraries + return "called_from_lib:libzmq.so\n" + "called_from_lib:libpgm-5.2.so\n"; +} + +#ifdef __cplusplus +} +#endif + +#endif // SRSRAN_TSAN_OPTIONS_H From e7aa4843084ff9f9926f52e71137448832d2f021 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Wed, 26 May 2021 23:31:06 +0200 Subject: [PATCH 051/156] rf_zmq_test: remove srsran.h include --- lib/src/phy/rf/rf_zmq_test.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/src/phy/rf/rf_zmq_test.c b/lib/src/phy/rf/rf_zmq_test.c index 1418fc9a8..d9a99335f 100644 --- a/lib/src/phy/rf/rf_zmq_test.c +++ b/lib/src/phy/rf/rf_zmq_test.c @@ -11,7 +11,10 @@ */ #include "rf_zmq_imp.h" -#include "srsran/srsran.h" +#include "srsran/common/tsan_options.h" +#include "srsran/phy/common/timestamp.h" +#include "srsran/phy/utils/debug.h" +#include #include #include #include From 02cceee997db4267dfcd1b38493fbc529a1a9198 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Fri, 28 May 2021 09:27:13 +0200 Subject: [PATCH 052/156] rf_zmq_imp: revert 28399dd876e7c1a9ac0d0c8beaed9867086c2f90 and fix unit although the manual test with Amarisoft eNB worked fine it seems the delay is still needed in the default case. Over 50% of the tests failed in the nightly with: [zmq] Error: tx time is 0.067 ms in the past (138240 < 139776) [zmq] Error: tx time is 1.100 ms in the past (184320 < 209664) While this usleep() should increase the pass likelihood it still doesn't guarantee error-free runs, so we might need to revisit it again as some stage. --- lib/src/phy/rf/rf_zmq_imp.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/src/phy/rf/rf_zmq_imp.c b/lib/src/phy/rf/rf_zmq_imp.c index bae0cf24f..793c0862b 100644 --- a/lib/src/phy/rf/rf_zmq_imp.c +++ b/lib/src/phy/rf/rf_zmq_imp.c @@ -668,6 +668,9 @@ int rf_zmq_recv_with_time_multi(void* h, void** data, uint32_t nsamples, bool bl rf_zmq_info(handler->id, " - next rx time: %d + %.3f\n", ts_rx.full_secs, ts_rx.frac_secs); rf_zmq_info(handler->id, " - next tx time: %d + %.3f\n", ts_tx.full_secs, ts_tx.frac_secs); + // Leave time for the Tx to transmit + usleep((1000000UL * nsamples_baserate) / handler->base_srate); + // check for tx gap if we're also transmitting on this radio for (int i = 0; i < handler->nof_channels; i++) { if (handler->transmitter[i].running) { From 957ca453e98eb11f9f0c29164990647e4f401ec2 Mon Sep 17 00:00:00 2001 From: Francisco Date: Thu, 27 May 2021 11:51:01 +0100 Subject: [PATCH 053/156] bugfix,rrc: change mechanism to delete old paging messages to avoid deleting messages not yet sent --- srsenb/hdr/stack/rrc/rrc_paging.h | 32 ++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/srsenb/hdr/stack/rrc/rrc_paging.h b/srsenb/hdr/stack/rrc/rrc_paging.h index ce13a60c6..83e27702d 100644 --- a/srsenb/hdr/stack/rrc/rrc_paging.h +++ b/srsenb/hdr/stack/rrc/rrc_paging.h @@ -13,6 +13,7 @@ #ifndef SRSRAN_RRC_PAGING_H #define SRSRAN_RRC_PAGING_H +#include "srsran/adt/pool/cached_alloc.h" #include "srsran/adt/span.h" #include "srsran/asn1/rrc/paging.h" #include "srsran/common/tti_point.h" @@ -116,7 +117,12 @@ private: uint32_t Ns; srslog::basic_logger& logger; - mutable std::array sf_idx_mutex; + struct subframe_info { + mutable std::mutex mutex; + srsran::deque transmitted_pcch; + }; + + std::array sf_info; std::vector > pending_paging; }; @@ -157,12 +163,13 @@ bool paging_manager::add_paging_record(uint32_t ueid, const asn1::rrc::paging_re } size_t sf_key = static_cast(get_sf_idx_key(sf_idx)); + subframe_info& locked_sf = sf_info[static_cast(sf_key)]; + std::lock_guard lock(locked_sf.mutex); + size_t sfn_cycle_idx = (T / N) * (ueid % N); pcch_info& pending_pcch = pending_paging[sfn_cycle_idx][sf_key]; auto& record_list = pending_pcch.pcch_msg.msg.c1().paging().paging_record_list; - std::lock_guard lock(sf_idx_mutex[sf_key]); - if (record_list.size() >= ASN1_RRC_MAX_PAGE_REC) { logger.warning("Failed to add new paging record for ueid=%d. Cause: no paging record space left.", ueid); return false; @@ -197,12 +204,13 @@ size_t paging_manager::pending_pcch_bytes(tti_point tti_tx_dl) return 0; } - std::lock_guard lock(sf_idx_mutex[static_cast(sf_key)]); + subframe_info& locked_sf = sf_info[static_cast(sf_key)]; + std::lock_guard lock(locked_sf.mutex); // clear old PCCH that has been transmitted at this point - pcch_info* old_pcch = get_pcch_info(tti_tx_dl - SRSRAN_NOF_SF_X_FRAME); - if (old_pcch != nullptr and not old_pcch->empty()) { - old_pcch->clear(); + while (not locked_sf.transmitted_pcch.empty() and locked_sf.transmitted_pcch.front()->tti_tx_dl < tti_tx_dl) { + locked_sf.transmitted_pcch.front()->clear(); + locked_sf.transmitted_pcch.pop_front(); } const pcch_info* pending_pcch = get_pcch_info(tti_tx_dl); @@ -221,7 +229,8 @@ bool paging_manager::read_pdu_pcch(tti_point tti_tx_dl, const Callable& func) return false; } - std::lock_guard lock(sf_idx_mutex[static_cast(sf_key)]); + subframe_info& locked_sf = sf_info[static_cast(sf_key)]; + std::lock_guard lock(locked_sf.mutex); pcch_info* pending_pcch = get_pcch_info(tti_tx_dl); @@ -232,7 +241,12 @@ bool paging_manager::read_pdu_pcch(tti_point tti_tx_dl, const Callable& func) // Call callable for existing PCCH pdu if (func(*pending_pcch->pdu, pending_pcch->pcch_msg, not pending_pcch->is_tx())) { - pending_pcch->tti_tx_dl = tti_tx_dl; + if (not pending_pcch->is_tx()) { + // first tx. Enqueue in list of transmitted pcch. We do not erase the PCCH yet because it may be transmitted + // by other carriers + pending_pcch->tti_tx_dl = tti_tx_dl; + locked_sf.transmitted_pcch.push_back(pending_pcch); + } return true; } return false; From 692bd193d5c4d59ca55d7a0a87274b26891a9dc0 Mon Sep 17 00:00:00 2001 From: Francisco Date: Thu, 27 May 2021 12:15:37 +0100 Subject: [PATCH 054/156] rrc,improvements - use single subframe-indexed struct to access pending PCCH. The scheduler now doesnt lock checking for pending paging --- srsenb/hdr/stack/rrc/rrc_paging.h | 74 +++++++++++++++---------------- 1 file changed, 36 insertions(+), 38 deletions(-) diff --git a/srsenb/hdr/stack/rrc/rrc_paging.h b/srsenb/hdr/stack/rrc/rrc_paging.h index 83e27702d..3c8750551 100644 --- a/srsenb/hdr/stack/rrc/rrc_paging.h +++ b/srsenb/hdr/stack/rrc/rrc_paging.h @@ -21,7 +21,9 @@ namespace srsenb { /** - * Class that handles the buffering of paging records and encoding of PCCH messages. It's thread-safe + * Class that handles the buffering of paging records and encoding of PCCH messages. + * It's thread-safe, and, assuming that threads contend for pending PCCH messages using different subframe indexes, + * should rarely blocking on mutexes */ class paging_manager { @@ -31,11 +33,11 @@ public: Nb(T * nb_), N(std::min(T, Nb)), Ns(std::max(nb_, 1u)), - pending_paging(T), logger(srslog::fetch_basic_logger("RRC")) { - for (auto& sfn_pcch_msgs : pending_paging) { - for (pcch_info& pcch : sfn_pcch_msgs) { + for (subframe_info& sf_obj : sf_pending_pcch) { + sf_obj.pending_paging.resize(T); + for (pcch_info& pcch : sf_obj.pending_paging) { pcch.pcch_msg.msg.set_c1().paging().paging_record_list_present = true; } } @@ -53,7 +55,10 @@ public: /** * Invoke "callable" for PCCH indexed by tti_tx_dl in a mutexed context. * Callable signature is bool(const_byte_span pdu, const pcch_msg& msg, bool is_first_tx) - * - "is_first_tx" tells if the PDU hasn't been transmitted yet. + * - "pdu" encoded ASN1 PCCH message + * - "msg" PCCH message in ASN1 form + * - "is_first_tx" tells if the PDU hasn't been transmitted yet. This may be useful to log the PCCH only for one + * of the carriers * - the return should be true if the PDU is being transmitted, and false otherwise */ template @@ -76,23 +81,8 @@ private: }; const static size_t nof_paging_subframes = 4; - bool add_paging_record(uint32_t ueid, const asn1::rrc::paging_record_s& paging_record); - pcch_info* get_pcch_info(tti_point tti_tx_dl) - { - int sf_key = get_sf_idx_key(tti_tx_dl.sf_idx()); - if (sf_key < 0) { - return nullptr; - } - return &pending_paging[tti_tx_dl.sfn() % T][sf_key]; - } - const pcch_info* get_pcch_info(tti_point tti_tx_dl) const - { - int sf_key = get_sf_idx_key(tti_tx_dl.sf_idx()); - if (sf_key < 0) { - return nullptr; - } - return &pending_paging[tti_tx_dl.sfn() % T][sf_key]; - } + bool add_paging_record(uint32_t ueid, const asn1::rrc::paging_record_s& paging_record); + static int get_sf_idx_key(uint32_t sf_idx) { switch (sf_idx) { @@ -120,10 +110,10 @@ private: struct subframe_info { mutable std::mutex mutex; srsran::deque transmitted_pcch; + std::vector pending_paging; }; - std::array sf_info; - std::vector > pending_paging; + std::array sf_pending_pcch; }; bool paging_manager::add_imsi_paging(uint32_t ueid, srsran::const_byte_span imsi) @@ -163,17 +153,21 @@ bool paging_manager::add_paging_record(uint32_t ueid, const asn1::rrc::paging_re } size_t sf_key = static_cast(get_sf_idx_key(sf_idx)); - subframe_info& locked_sf = sf_info[static_cast(sf_key)]; + subframe_info& locked_sf = sf_pending_pcch[static_cast(sf_key)]; std::lock_guard lock(locked_sf.mutex); size_t sfn_cycle_idx = (T / N) * (ueid % N); - pcch_info& pending_pcch = pending_paging[sfn_cycle_idx][sf_key]; + pcch_info& pending_pcch = locked_sf.pending_paging[sfn_cycle_idx]; auto& record_list = pending_pcch.pcch_msg.msg.c1().paging().paging_record_list; if (record_list.size() >= ASN1_RRC_MAX_PAGE_REC) { logger.warning("Failed to add new paging record for ueid=%d. Cause: no paging record space left.", ueid); return false; } + if (pending_pcch.is_tx()) { + logger.warning("Adding Paging records to ueid=%d PCCH that has been already sent but not cleared.", ueid); + pending_pcch.clear(); + } if (pending_pcch.pdu == nullptr) { pending_pcch.pdu = srsran::make_byte_buffer(); @@ -204,8 +198,12 @@ size_t paging_manager::pending_pcch_bytes(tti_point tti_tx_dl) return 0; } - subframe_info& locked_sf = sf_info[static_cast(sf_key)]; - std::lock_guard lock(locked_sf.mutex); + subframe_info& locked_sf = sf_pending_pcch[static_cast(sf_key)]; + std::unique_lock lock(locked_sf.mutex, std::try_to_lock); + if (not lock.owns_lock()) { + // Wait for the next paging cycle + return 0; + } // clear old PCCH that has been transmitted at this point while (not locked_sf.transmitted_pcch.empty() and locked_sf.transmitted_pcch.front()->tti_tx_dl < tti_tx_dl) { @@ -213,11 +211,11 @@ size_t paging_manager::pending_pcch_bytes(tti_point tti_tx_dl) locked_sf.transmitted_pcch.pop_front(); } - const pcch_info* pending_pcch = get_pcch_info(tti_tx_dl); - if (pending_pcch->empty()) { + const pcch_info& pending_pcch = locked_sf.pending_paging[tti_tx_dl.sfn() % T]; + if (pending_pcch.empty()) { return 0; } - return pending_pcch->pdu->size(); + return pending_pcch.pdu->size(); } template @@ -229,23 +227,23 @@ bool paging_manager::read_pdu_pcch(tti_point tti_tx_dl, const Callable& func) return false; } - subframe_info& locked_sf = sf_info[static_cast(sf_key)]; + subframe_info& locked_sf = sf_pending_pcch[static_cast(sf_key)]; std::lock_guard lock(locked_sf.mutex); - pcch_info* pending_pcch = get_pcch_info(tti_tx_dl); + pcch_info& pending_pcch = locked_sf.pending_paging[tti_tx_dl.sfn() % T]; - if (pending_pcch->empty()) { + if (pending_pcch.empty()) { logger.warning("read_pdu_pdcch(...) called for tti=%d, but there is no pending pcch message", tti_tx_dl.to_uint()); return false; } // Call callable for existing PCCH pdu - if (func(*pending_pcch->pdu, pending_pcch->pcch_msg, not pending_pcch->is_tx())) { - if (not pending_pcch->is_tx()) { + if (func(*pending_pcch.pdu, pending_pcch.pcch_msg, not pending_pcch.is_tx())) { + if (not pending_pcch.is_tx()) { // first tx. Enqueue in list of transmitted pcch. We do not erase the PCCH yet because it may be transmitted // by other carriers - pending_pcch->tti_tx_dl = tti_tx_dl; - locked_sf.transmitted_pcch.push_back(pending_pcch); + pending_pcch.tti_tx_dl = tti_tx_dl; + locked_sf.transmitted_pcch.push_back(&pending_pcch); } return true; } From 52247a46e5ea298b4a2e2ade3617145cc1c9e1c0 Mon Sep 17 00:00:00 2001 From: Francisco Date: Thu, 27 May 2021 13:19:03 +0100 Subject: [PATCH 055/156] rrc,refactor - change log level for paging try lock --- srsenb/hdr/stack/rrc/rrc_paging.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/srsenb/hdr/stack/rrc/rrc_paging.h b/srsenb/hdr/stack/rrc/rrc_paging.h index 3c8750551..b232c5f06 100644 --- a/srsenb/hdr/stack/rrc/rrc_paging.h +++ b/srsenb/hdr/stack/rrc/rrc_paging.h @@ -165,7 +165,7 @@ bool paging_manager::add_paging_record(uint32_t ueid, const asn1::rrc::paging_re return false; } if (pending_pcch.is_tx()) { - logger.warning("Adding Paging records to ueid=%d PCCH that has been already sent but not cleared.", ueid); + logger.error("Adding Paging records to ueid=%d PCCH that has been already sent but not cleared.", ueid); pending_pcch.clear(); } @@ -201,7 +201,7 @@ size_t paging_manager::pending_pcch_bytes(tti_point tti_tx_dl) subframe_info& locked_sf = sf_pending_pcch[static_cast(sf_key)]; std::unique_lock lock(locked_sf.mutex, std::try_to_lock); if (not lock.owns_lock()) { - // Wait for the next paging cycle + // If the scheduler fails to lock, it will postpone the PCCH transmission to the next paging cycle return 0; } From 0996e50dce22e4e1921c709de63250c376f656b0 Mon Sep 17 00:00:00 2001 From: Francisco Date: Tue, 25 May 2021 19:25:03 +0100 Subject: [PATCH 056/156] bugfix, s1ap: allow source enb to release old UE ctxt in case a connectionRequest arrives with repeated m-TMSI --- srsenb/src/stack/rrc/rrc_ue.cc | 2 +- srsenb/src/stack/s1ap/s1ap.cc | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/srsenb/src/stack/rrc/rrc_ue.cc b/srsenb/src/stack/rrc/rrc_ue.cc index ef7fab433..4181a6579 100644 --- a/srsenb/src/stack/rrc/rrc_ue.cc +++ b/srsenb/src/stack/rrc/rrc_ue.cc @@ -392,7 +392,7 @@ void rrc::ue::handle_rrc_con_req(rrc_conn_request_s* msg) if (user.first != rnti && user.second->has_tmsi && user.second->mmec == mmec && user.second->m_tmsi == m_tmsi) { parent->logger.info("RRC connection request: UE context already exists. M-TMSI=%d", m_tmsi); user.second->state = RRC_STATE_IDLE; // Set old rnti to IDLE so that enb doesn't send RRC Connection Release - parent->s1ap->user_release(user.first, asn1::s1ap::cause_radio_network_opts::radio_conn_with_ue_lost); + parent->s1ap->user_release(user.first, asn1::s1ap::cause_radio_network_opts::interaction_with_other_proc); break; } } diff --git a/srsenb/src/stack/s1ap/s1ap.cc b/srsenb/src/stack/s1ap/s1ap.cc index 7cb15c4a6..8f408627c 100644 --- a/srsenb/src/stack/s1ap/s1ap.cc +++ b/srsenb/src/stack/s1ap/s1ap.cc @@ -1402,10 +1402,13 @@ bool s1ap::ue::send_uectxtreleaserequest(const cause_c& cause) return false; } - if (ts1_reloc_overall.is_running()) { + if (ts1_reloc_overall.is_running() and cause.type().value == asn1::s1ap::cause_c::types_opts::radio_network and + (cause.radio_network().value == asn1::s1ap::cause_radio_network_opts::user_inactivity or + cause.radio_network().value == asn1::s1ap::cause_radio_network_opts::radio_conn_with_ue_lost)) { logger.info("Ignoring UE context release request from lower layers for UE rnti=0x%x performing S1 Handover.", ctxt.rnti); - // leave the UE context alive until ts1_reloc_overall expiry + // Leave the UE context alive during S1 Handover until ts1_reloc_overall expiry. Ignore releases due to + // UE inactivity or RLF return false; } From a587d202521a2382bcbff119f178cf1738ebe68d Mon Sep 17 00:00:00 2001 From: Francisco Date: Wed, 26 May 2021 09:24:47 +0100 Subject: [PATCH 057/156] allow specification of subset of valid measurement gap offsets in rr.conf --- .../interfaces/enb_rrc_interface_types.h | 1 + srsenb/hdr/stack/rrc/rrc_cell_cfg.h | 8 +++--- srsenb/rr.conf.example | 1 + srsenb/src/enb_cfg_parser.cc | 8 ++++++ srsenb/src/stack/rrc/rrc_cell_cfg.cc | 26 +++++++++++++++++-- 5 files changed, 38 insertions(+), 6 deletions(-) diff --git a/lib/include/srsran/interfaces/enb_rrc_interface_types.h b/lib/include/srsran/interfaces/enb_rrc_interface_types.h index 182e52824..6674fc43b 100644 --- a/lib/include/srsran/interfaces/enb_rrc_interface_types.h +++ b/lib/include/srsran/interfaces/enb_rrc_interface_types.h @@ -42,6 +42,7 @@ struct rrc_meas_cfg_t { std::vector meas_reports; asn1::rrc::quant_cfg_eutra_s quant_cfg; uint32_t meas_gap_period; + std::vector meas_gap_offset_subframe; uint32_t allowed_meas_bw; }; diff --git a/srsenb/hdr/stack/rrc/rrc_cell_cfg.h b/srsenb/hdr/stack/rrc/rrc_cell_cfg.h index ba6ecede3..de72d6b9b 100644 --- a/srsenb/hdr/stack/rrc/rrc_cell_cfg.h +++ b/srsenb/hdr/stack/rrc/rrc_cell_cfg.h @@ -73,10 +73,10 @@ public: const static uint32_t N_PUCCH_MAX_PRB = 4; // Maximum number of PRB to use for PUCCH ACK/NACK in CS mode const static uint32_t N_PUCCH_MAX_RES = 3 * SRSRAN_NRE * N_PUCCH_MAX_PRB; - uint32_t next_measgap_offset = 0; - pucch_idx_sched_t sr_sched = {}; - pucch_idx_sched_t cqi_sched = {}; - std::array n_pucch_cs_used = {}; + pucch_idx_sched_t sr_sched = {}; + pucch_idx_sched_t cqi_sched = {}; + std::array n_pucch_cs_used = {}; + std::array meas_gap_alloc_map = {}; }; /** Storage of CQI/SR/PUCCH CS resources across multiple frequencies and for multiple users */ diff --git a/srsenb/rr.conf.example b/srsenb/rr.conf.example index 37db345cd..bdf62cc9a 100644 --- a/srsenb/rr.conf.example +++ b/srsenb/rr.conf.example @@ -62,6 +62,7 @@ cell_list = //ul_earfcn = 21400; ho_active = false; //meas_gap_period = 0; // 0 (inactive), 40 or 80 + //meas_gap_offset_subframe = [6, 12, 18, 24, 30]; // target_pusch_sinr = -1; // target_pucch_sinr = -1; // allowed_meas_bw = 6; diff --git a/srsenb/src/enb_cfg_parser.cc b/srsenb/src/enb_cfg_parser.cc index 4aac6d7b6..3149f0360 100644 --- a/srsenb/src/enb_cfg_parser.cc +++ b/srsenb/src/enb_cfg_parser.cc @@ -760,6 +760,14 @@ static int parse_cell_list(all_args_t* args, rrc_cfg_t* rrc_cfg, Setting& root) cell_cfg.root_seq_idx, cellroot, "root_seq_idx", rrc_cfg->sibs[1].sib2().rr_cfg_common.prach_cfg.root_seq_idx); parse_default_field(cell_cfg.initial_dl_cqi, cellroot, "initial_dl_cqi", 5u); parse_default_field(cell_cfg.meas_cfg.meas_gap_period, cellroot, "meas_gap_period", 0u); + if (cellroot.exists("meas_gap_offset_subframe")) { + cell_cfg.meas_cfg.meas_gap_offset_subframe.resize(cellroot["meas_gap_offset_subframe"].getLength()); + for (uint32_t j = 0; j < (uint32_t)cellroot["meas_gap_offset_subframe"].getLength(); ++j) { + cell_cfg.meas_cfg.meas_gap_offset_subframe[j] = (uint32_t)cellroot["meas_gap_offset_subframe"][j]; + srsran_assert(cell_cfg.meas_cfg.meas_gap_offset_subframe[j] < cell_cfg.meas_cfg.meas_gap_period, + "meas gap offsets must be smaller than meas gap period"); + } + } HANDLEPARSERCODE(parse_default_field(cell_cfg.target_pusch_sinr_db, cellroot, "target_pusch_sinr", -1)); HANDLEPARSERCODE(parse_default_field(cell_cfg.target_pucch_sinr_db, cellroot, "target_pucch_sinr", -1)); HANDLEPARSERCODE(parse_default_field(cell_cfg.enable_phr_handling, cellroot, "enable_phr_handling", false)); diff --git a/srsenb/src/stack/rrc/rrc_cell_cfg.cc b/srsenb/src/stack/rrc/rrc_cell_cfg.cc index 770942d4d..096978e1b 100644 --- a/srsenb/src/stack/rrc/rrc_cell_cfg.cc +++ b/srsenb/src/stack/rrc/rrc_cell_cfg.cc @@ -218,6 +218,7 @@ bool ue_cell_ded_list::rem_last_cell() bool ue_cell_ded_list::alloc_cell_resources(uint32_t ue_cc_idx) { + const uint32_t meas_gap_duration = 6; // Allocate CQI, SR, and PUCCH CS resources. If failure, do not add new cell if (ue_cc_idx == UE_PCELL_CC_IDX) { if (not alloc_sr_resources(cfg.sr_cfg.period)) { @@ -226,9 +227,30 @@ bool ue_cell_ded_list::alloc_cell_resources(uint32_t ue_cc_idx) } ue_cell_ded* cell = get_ue_cc_idx(UE_PCELL_CC_IDX); + cell->meas_gap_offset = 0; cell->meas_gap_period = cell->cell_common->cell_cfg.meas_cfg.meas_gap_period; - cell->meas_gap_offset = pucch_res->next_measgap_offset; - pucch_res->next_measgap_offset += 6; + if (cell->meas_gap_period > 0) { + if (not cell->cell_common->cell_cfg.meas_cfg.meas_gap_offset_subframe.empty()) { + // subframes specified + uint32_t min_users = std::numeric_limits::max(); + for (uint32_t i = 0; i < cell->cell_common->cell_cfg.meas_cfg.meas_gap_offset_subframe.size(); ++i) { + uint32_t idx_offset = cell->cell_common->cell_cfg.meas_cfg.meas_gap_offset_subframe[i] / meas_gap_duration; + if (pucch_res->meas_gap_alloc_map[idx_offset] < min_users) { + min_users = pucch_res->meas_gap_alloc_map[idx_offset]; + cell->meas_gap_offset = cell->cell_common->cell_cfg.meas_cfg.meas_gap_offset_subframe[i]; + } + } + } else { + uint32_t min_users = std::numeric_limits::max(); + for (uint32_t meas_offset = 0; meas_offset < cell->cell_common->cell_cfg.meas_cfg.meas_gap_period; + meas_offset += meas_gap_duration) { + if (pucch_res->meas_gap_alloc_map[meas_offset / meas_gap_duration] < min_users) { + min_users = pucch_res->meas_gap_alloc_map[meas_offset / meas_gap_duration]; + cell->meas_gap_offset = meas_offset; + } + } + } + } } else { if (ue_cc_idx == 1 and not n_pucch_cs_present) { // Allocate resources for Format1b CS (will be optional PUCCH3/CS) From 0dafe4dd58ecb2b92274457b758ae0ba8f5dfef9 Mon Sep 17 00:00:00 2001 From: Francisco Date: Wed, 26 May 2021 13:27:50 +0100 Subject: [PATCH 058/156] fix coderate derivation in PDCCH based on aggregation level --- lib/src/phy/phch/pdcch.c | 3 ++- srsenb/src/stack/mac/sched_helpers.cc | 14 +++++--------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/lib/src/phy/phch/pdcch.c b/lib/src/phy/phch/pdcch.c index eaffc0aa8..badcba244 100644 --- a/lib/src/phy/phch/pdcch.c +++ b/lib/src/phy/phch/pdcch.c @@ -36,7 +36,8 @@ float srsran_pdcch_coderate(uint32_t nof_bits, uint32_t l) { - return (float)(nof_bits + 16) / (4 * PDCCH_FORMAT_NOF_REGS(l)); + static const int nof_bits_x_symbol = 2; //QPSK + return (float)(nof_bits + 16) / (nof_bits_x_symbol * PDCCH_FORMAT_NOF_REGS(l)); } /** Initializes the PDCCH transmitter and receiver */ diff --git a/srsenb/src/stack/mac/sched_helpers.cc b/srsenb/src/stack/mac/sched_helpers.cc index 0978a3770..0dd785551 100644 --- a/srsenb/src/stack/mac/sched_helpers.cc +++ b/srsenb/src/stack/mac/sched_helpers.cc @@ -396,18 +396,14 @@ uint32_t get_aggr_level(uint32_t nof_bits, factor = 1.0; l_max = 2; } - l_max = SRSRAN_MIN(max_aggr_lvl, l_max); + l_max = std::min(max_aggr_lvl, l_max); - uint32_t l = min_aggr_lvl; - float coderate = 0; - for (; l <= l_max; ++l) { + uint32_t l = std::min(min_aggr_lvl, l_max); + float coderate = srsran_pdcch_coderate(nof_bits, l); + while (factor * coderate > max_coderate and l < l_max) { + l++; coderate = srsran_pdcch_coderate(nof_bits, l); - if (factor * coderate <= max_coderate) { - break; - } } - // make aggregation level more conservative - l = std::min(l_max, l + 1); Debug("SCHED: CQI=%d, l=%d, nof_bits=%d, coderate=%.2f, max_coderate=%.2f", dl_cqi, From 200006c4b75a6332be374b6c68c8c9451c2df70c Mon Sep 17 00:00:00 2001 From: Francisco Date: Thu, 27 May 2021 18:39:22 +0100 Subject: [PATCH 059/156] bugfix,scheduler: avoid offset to increase decrease unboundedly when mcs is equal to 0 or max_mcs --- srsenb/enb.conf.example | 2 +- .../hdr/stack/mac/sched_ue_ctrl/sched_harq.h | 5 +- .../stack/mac/sched_ue_ctrl/sched_ue_cell.h | 2 +- srsenb/src/main.cc | 2 +- .../src/stack/mac/sched_ue_ctrl/sched_harq.cc | 8 +-- .../stack/mac/sched_ue_ctrl/sched_ue_cell.cc | 56 ++++++++++++------- 6 files changed, 47 insertions(+), 28 deletions(-) diff --git a/srsenb/enb.conf.example b/srsenb/enb.conf.example index a0e73714e..1672bfcdb 100644 --- a/srsenb/enb.conf.example +++ b/srsenb/enb.conf.example @@ -181,7 +181,7 @@ enable = false #policy_args = 2 #min_aggr_level = 0 #max_aggr_level = 3 -#adaptive_aggr_level = true +#adaptive_aggr_level = false #pdsch_mcs = -1 #pdsch_max_mcs = -1 #pusch_mcs = -1 diff --git a/srsenb/hdr/stack/mac/sched_ue_ctrl/sched_harq.h b/srsenb/hdr/stack/mac/sched_ue_ctrl/sched_harq.h index ecc76b1f8..d274296e9 100644 --- a/srsenb/hdr/stack/mac/sched_ue_ctrl/sched_harq.h +++ b/srsenb/hdr/stack/mac/sched_ue_ctrl/sched_harq.h @@ -36,6 +36,7 @@ public: srsran::tti_point get_tti() const; bool get_ndi(uint32_t tb_idx) const; uint32_t max_nof_retx() const; + int get_mcs(uint32_t tb_idx) const { return last_mcs[tb_idx]; } protected: void new_tx_common(uint32_t tb_idx, srsran::tti_point tti, int mcs, int tbs, uint32_t max_retx_); @@ -147,9 +148,9 @@ public: * @param tti_rx tti the DL ACK was received * @param tb_idx TB index for the given ACK * @param ack true for ACK and false for NACK - * @return pair with pid and size of TB of the DL harq that was ACKed + * @return tuple with pid, TBS and MCS of the DL harq that was ACKed */ - std::pair set_ack_info(tti_point tti_rx, uint32_t tb_idx, bool ack); + std::tuple set_ack_info(tti_point tti_rx, uint32_t tb_idx, bool ack); //! Get UL Harq for a given tti_tx_ul ul_harq_proc* get_ul_harq(tti_point tti_tx_ul); diff --git a/srsenb/hdr/stack/mac/sched_ue_ctrl/sched_ue_cell.h b/srsenb/hdr/stack/mac/sched_ue_ctrl/sched_ue_cell.h index 5779fee8e..4e0020b41 100644 --- a/srsenb/hdr/stack/mac/sched_ue_ctrl/sched_ue_cell.h +++ b/srsenb/hdr/stack/mac/sched_ue_ctrl/sched_ue_cell.h @@ -91,7 +91,7 @@ private: cc_st cc_state_ = cc_st::idle; // CQI - float delta_down = 0, delta_up = 0; + float delta_inc = 0, delta_dec = 0; float dl_cqi_coeff = 0, ul_snr_coeff = 0; float max_cqi_coeff = -5, max_snr_coeff = 5; diff --git a/srsenb/src/main.cc b/srsenb/src/main.cc index 8ec826e56..d03812f52 100644 --- a/srsenb/src/main.cc +++ b/srsenb/src/main.cc @@ -147,7 +147,7 @@ void parse_args(all_args_t* args, int argc, char* argv[]) ("scheduler.pusch_max_mcs", bpo::value(&args->stack.mac.sched.pusch_max_mcs)->default_value(-1), "Optional PUSCH MCS limit") ("scheduler.min_aggr_level", bpo::value(&args->stack.mac.sched.min_aggr_level)->default_value(0), "Optional minimum aggregation level index (l=log2(L)) ") ("scheduler.max_aggr_level", bpo::value(&args->stack.mac.sched.max_aggr_level)->default_value(3), "Optional maximum aggregation level index (l=log2(L)) ") - ("scheduler.adaptive_aggr_level", bpo::value(&args->stack.mac.sched.adaptive_aggr_level)->default_value(true), "Boolean flag to enable/disable adaptive aggregation level based on target BLER") + ("scheduler.adaptive_aggr_level", bpo::value(&args->stack.mac.sched.adaptive_aggr_level)->default_value(false), "Boolean flag to enable/disable adaptive aggregation level based on target BLER") ("scheduler.max_nof_ctrl_symbols", bpo::value(&args->stack.mac.sched.max_nof_ctrl_symbols)->default_value(3), "Number of control symbols") ("scheduler.min_nof_ctrl_symbols", bpo::value(&args->stack.mac.sched.min_nof_ctrl_symbols)->default_value(1), "Minimum number of control symbols") ("scheduler.pucch_multiplex_enable", bpo::value(&args->stack.mac.sched.pucch_mux_enabled)->default_value(false), "Enable PUCCH multiplexing") diff --git a/srsenb/src/stack/mac/sched_ue_ctrl/sched_harq.cc b/srsenb/src/stack/mac/sched_ue_ctrl/sched_harq.cc index 92dffcf2e..97d963bdf 100644 --- a/srsenb/src/stack/mac/sched_ue_ctrl/sched_harq.cc +++ b/srsenb/src/stack/mac/sched_ue_ctrl/sched_harq.cc @@ -366,17 +366,17 @@ dl_harq_proc* harq_entity::get_pending_dl_harq(tti_point tti_tx_dl) return get_oldest_dl_harq(tti_tx_dl); } -std::pair harq_entity::set_ack_info(tti_point tti_rx, uint32_t tb_idx, bool ack) +std::tuple harq_entity::set_ack_info(tti_point tti_rx, uint32_t tb_idx, bool ack) { for (auto& h : dl_harqs) { if (h.get_tti() + FDD_HARQ_DELAY_DL_MS == tti_rx) { if (h.set_ack(tb_idx, ack) == SRSRAN_SUCCESS) { - return {h.get_id(), h.get_tbs(tb_idx)}; + return {h.get_id(), h.get_tbs(tb_idx), h.get_mcs(tb_idx)}; } - return {h.get_id(), -1}; + return {h.get_id(), -1, -1}; } } - return {dl_harqs.size(), -1}; + return {dl_harqs.size(), -1, -1}; } ul_harq_proc* harq_entity::get_ul_harq(tti_point tti_tx_ul) diff --git a/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc b/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc index c34a6511c..1a6bd1294 100644 --- a/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc +++ b/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc @@ -49,8 +49,8 @@ sched_ue_cell::sched_ue_cell(uint16_t rnti_, const sched_cell_params_t& cell_cfg clear_feedback(); float target_bler = cell_cfg->sched_cfg->target_bler; - delta_down = cell_cfg->sched_cfg->adaptive_link_step_size; - delta_up = (1 - target_bler) * delta_down / target_bler; + delta_inc = cell_cfg->sched_cfg->adaptive_link_step_size; // delta_{down} of OLLA + delta_dec = (1 - target_bler) * delta_inc / target_bler; max_cqi_coeff = cell_cfg->sched_cfg->max_delta_dl_cqi; max_snr_coeff = cell_cfg->sched_cfg->max_delta_ul_snr; } @@ -178,6 +178,24 @@ int sched_ue_cell::set_dl_wb_cqi(tti_point tti_rx, uint32_t dl_cqi_) int sched_ue_cell::set_ul_crc(tti_point tti_rx, bool crc_res) { CHECK_VALID_CC("UL CRC"); + + // Adapt UL MCS based on BLER + if (cell_cfg->sched_cfg->target_bler > 0 and fixed_mcs_ul < 0) { + auto* ul_harq = harq_ent.get_ul_harq(tti_rx); + if (ul_harq != nullptr) { + int mcs = ul_harq->get_mcs(0); + // Note: Avoid keeping increasing the snr delta offset, if MCS is already is at its limit + float delta_dec_eff = mcs <= 0 ? 0 : delta_dec; + float delta_inc_eff = mcs >= (int)max_mcs_ul ? 0 : delta_inc; + ul_snr_coeff += crc_res ? delta_inc_eff : -delta_dec_eff; + ul_snr_coeff = std::min(std::max(-max_snr_coeff, ul_snr_coeff), max_snr_coeff); + logger.info("SCHED: UL adaptive link: snr_estim=%.2f, last_mcs=%d, snr_offset=%f", + tpc_fsm.get_ul_snr_estim(), + mcs, + ul_snr_coeff); + } + } + // Update HARQ process int pid = harq_ent.set_ul_crc(tti_rx, 0, crc_res); if (pid < 0) { @@ -185,30 +203,30 @@ int sched_ue_cell::set_ul_crc(tti_point tti_rx, bool crc_res) return SRSRAN_ERROR; } - if (cell_cfg->sched_cfg->target_bler > 0) { - ul_snr_coeff += delta_down - static_cast(not crc_res) * (delta_down + delta_up); - ul_snr_coeff = std::min(std::max(-max_snr_coeff, ul_snr_coeff), max_snr_coeff); - logger.info("SCHED: UL adaptive link: snr_estim=%f, snr_offset=%f", tpc_fsm.get_ul_snr_estim(), ul_snr_coeff); - } return pid; } int sched_ue_cell::set_ack_info(tti_point tti_rx, uint32_t tb_idx, bool ack) { CHECK_VALID_CC("DL ACK Info"); - std::pair p2 = harq_ent.set_ack_info(tti_rx, tb_idx, ack); - int tbs_acked = p2.second; - if (tbs_acked > 0) { - logger.debug( - "SCHED: Set DL ACK=%d for rnti=0x%x, pid=%d, tb=%d, tti=%d", ack, rnti, p2.first, tb_idx, tti_rx.to_uint()); - - if (cell_cfg->sched_cfg->target_bler > 0) { - dl_cqi_coeff += delta_down - static_cast(not ack) * (delta_down + delta_up); - dl_cqi_coeff = std::min(std::max(-max_cqi_coeff, dl_cqi_coeff), max_cqi_coeff); - logger.info("SCHED: DL adaptive link: cqi=%d, cqi_offset=%f", dl_cqi_ctxt.get_avg_cqi(), dl_cqi_coeff); - } - } else { + + std::tuple p2 = harq_ent.set_ack_info(tti_rx, tb_idx, ack); + int tbs_acked = std::get<1>(p2); + if (tbs_acked <= 0) { logger.warning("SCHED: Received ACK info for unknown TTI=%d", tti_rx.to_uint()); + return tbs_acked; + } + + // Adapt DL MCS based on BLER + if (cell_cfg->sched_cfg->target_bler > 0 and fixed_mcs_dl < 0) { + int mcs = std::get<2>(p2); + // Note: Avoid keeping increasing the snr delta offset, if MCS is already is at its limit + float delta_dec_eff = mcs <= 0 ? 0 : delta_dec; + float delta_inc_eff = mcs >= (int)max_mcs_dl ? 0 : delta_inc; + dl_cqi_coeff += ack ? delta_inc_eff : -delta_dec_eff; + dl_cqi_coeff = std::min(std::max(-max_cqi_coeff, dl_cqi_coeff), max_cqi_coeff); + logger.info( + "SCHED: DL adaptive link: cqi=%d, last_mcs=%d, cqi_offset=%f", dl_cqi_ctxt.get_avg_cqi(), mcs, dl_cqi_coeff); } return tbs_acked; } From a8790abd7e690751ed483f6486e15a18a54fce8e Mon Sep 17 00:00:00 2001 From: Francisco Date: Thu, 27 May 2021 19:03:46 +0100 Subject: [PATCH 060/156] fix centos7 tuple compilation issue --- srsenb/src/stack/mac/sched_ue_ctrl/sched_harq.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/srsenb/src/stack/mac/sched_ue_ctrl/sched_harq.cc b/srsenb/src/stack/mac/sched_ue_ctrl/sched_harq.cc index 97d963bdf..eb39f1bb2 100644 --- a/srsenb/src/stack/mac/sched_ue_ctrl/sched_harq.cc +++ b/srsenb/src/stack/mac/sched_ue_ctrl/sched_harq.cc @@ -371,12 +371,12 @@ std::tuple harq_entity::set_ack_info(tti_point tti_rx, uint3 for (auto& h : dl_harqs) { if (h.get_tti() + FDD_HARQ_DELAY_DL_MS == tti_rx) { if (h.set_ack(tb_idx, ack) == SRSRAN_SUCCESS) { - return {h.get_id(), h.get_tbs(tb_idx), h.get_mcs(tb_idx)}; + return std::make_tuple(h.get_id(), h.get_tbs(tb_idx), h.get_mcs(tb_idx)); } - return {h.get_id(), -1, -1}; + return std::make_tuple(h.get_id(), -1, -1); } } - return {dl_harqs.size(), -1, -1}; + return std::make_tuple(dl_harqs.size(), -1, -1); } ul_harq_proc* harq_entity::get_ul_harq(tti_point tti_tx_ul) From 83228871351ba32e665dcbe32f5c1d090296c549 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Fri, 28 May 2021 10:47:33 +0200 Subject: [PATCH 061/156] enb,rrc: increase RRC PDU queue size to 128 --- 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 164a747d5..58e6840ae 100644 --- a/srsenb/src/stack/rrc/rrc.cc +++ b/srsenb/src/stack/rrc/rrc.cc @@ -31,7 +31,7 @@ using namespace asn1::rrc; namespace srsenb { rrc::rrc(srsran::task_sched_handle task_sched_) : - logger(srslog::fetch_basic_logger("RRC")), task_sched(task_sched_), rx_pdu_queue(64) + logger(srslog::fetch_basic_logger("RRC")), task_sched(task_sched_), rx_pdu_queue(128) {} rrc::~rrc() {} From fcba67ca84dda16e44ce2f4ae40ca6994fb8035f Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Fri, 28 May 2021 10:47:51 +0200 Subject: [PATCH 062/156] enb,rrc: fix logging text --- srsenb/src/stack/rrc/rrc.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/srsenb/src/stack/rrc/rrc.cc b/srsenb/src/stack/rrc/rrc.cc index 58e6840ae..77cd7aecf 100644 --- a/srsenb/src/stack/rrc/rrc.cc +++ b/srsenb/src/stack/rrc/rrc.cc @@ -137,7 +137,7 @@ void rrc::set_radiolink_dl_state(uint16_t rnti, bool crc_res) rrc_pdu p = {rnti, LCID_RADLINK_DL, crc_res, nullptr}; if (not rx_pdu_queue.try_push(std::move(p))) { - logger.error("Failed to push UE activity command to RRC queue"); + logger.error("Failed to push radio link DL state"); } } @@ -147,7 +147,7 @@ void rrc::set_radiolink_ul_state(uint16_t rnti, bool crc_res) rrc_pdu p = {rnti, LCID_RADLINK_UL, crc_res, nullptr}; if (not rx_pdu_queue.try_push(std::move(p))) { - logger.error("Failed to push UE activity command to RRC queue"); + logger.error("Failed to push radio link UL state"); } } From 3102861ee3619ff5461cf60c2cce34fea530be57 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Fri, 28 May 2021 17:26:50 +0200 Subject: [PATCH 063/156] rlc_am_lte: make func param const& --- lib/include/srsran/upper/rlc_am_lte.h | 2 +- lib/src/upper/rlc_am_lte.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/include/srsran/upper/rlc_am_lte.h b/lib/include/srsran/upper/rlc_am_lte.h index a18f2aae0..d5afc0aa4 100644 --- a/lib/include/srsran/upper/rlc_am_lte.h +++ b/lib/include/srsran/upper/rlc_am_lte.h @@ -392,7 +392,7 @@ private: void debug_state(); - int required_buffer_size(rlc_amd_retx_t retx); + int required_buffer_size(const rlc_amd_retx_t& retx); void retransmit_pdu(uint32_t sn); // Helpers diff --git a/lib/src/upper/rlc_am_lte.cc b/lib/src/upper/rlc_am_lte.cc index 4e74c3577..a17b0803b 100644 --- a/lib/src/upper/rlc_am_lte.cc +++ b/lib/src/upper/rlc_am_lte.cc @@ -1316,7 +1316,7 @@ void rlc_am_lte::rlc_am_lte_tx::debug_state() logger.debug("%s vt_a = %d, vt_ms = %d, vt_s = %d, poll_sn = %d", RB_NAME, vt_a, vt_ms, vt_s, poll_sn); } -int rlc_am_lte::rlc_am_lte_tx::required_buffer_size(rlc_amd_retx_t retx) +int rlc_am_lte::rlc_am_lte_tx::required_buffer_size(const rlc_amd_retx_t& retx) { if (!retx.is_segment) { if (tx_window.has_sn(retx.sn)) { From 531acc0a9817b1db8b2be56c27fb1f4b96156aed Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Fri, 28 May 2021 17:27:20 +0200 Subject: [PATCH 064/156] rlc_am_test: add check for RLC buffer state return during retx --- lib/test/upper/rlc_am_test.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/test/upper/rlc_am_test.cc b/lib/test/upper/rlc_am_test.cc index 28a892905..89e163e60 100644 --- a/lib/test/upper/rlc_am_test.cc +++ b/lib/test/upper/rlc_am_test.cc @@ -651,6 +651,7 @@ int segment_retx_test() // Step timers again until poll Retx timeout expires for (int cnt = 0; cnt < 5; cnt++) { + TESTASSERT(rlc1.get_buffer_state() == 0); // No status transmissions until pollRetx expires timers.step_all(); } From 65d51f585503fe6ada6fd4048105b3b537f05ad0 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Wed, 26 May 2021 10:25:15 +0200 Subject: [PATCH 065/156] Fix unitialised value --- srsue/hdr/phy/scell/intra_measure_lte.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/srsue/hdr/phy/scell/intra_measure_lte.h b/srsue/hdr/phy/scell/intra_measure_lte.h index 92692e6d1..fab9df810 100644 --- a/srsue/hdr/phy/scell/intra_measure_lte.h +++ b/srsue/hdr/phy/scell/intra_measure_lte.h @@ -72,8 +72,8 @@ private: bool measure_rat(measure_context_t context, std::vector& buffer) override; srslog::basic_logger& logger; - srsran_cell_t serving_cell = {}; ///< Current serving cell in the EARFCN, to avoid reporting it - uint32_t current_earfcn; ///< Current EARFCN + srsran_cell_t serving_cell = {}; ///< Current serving cell in the EARFCN, to avoid reporting it + uint32_t current_earfcn = 0; ///< Current EARFCN /// LTE-based measuring objects scell_recv scell_rx; ///< Secondary cell searcher From cc2a6dc269b3f0e0a8b7dd074e111e54d165b7fb Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Wed, 26 May 2021 10:53:11 +0200 Subject: [PATCH 066/156] Review cell selection and SCell configuration during HO --- srsue/hdr/phy/scell/scell_state.h | 20 ++++++++++++++++---- srsue/src/phy/phy.cc | 9 ++++++--- srsue/src/phy/sync.cc | 11 ++++++++--- 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/srsue/hdr/phy/scell/scell_state.h b/srsue/hdr/phy/scell/scell_state.h index 6fe33b913..76089e69a 100644 --- a/srsue/hdr/phy/scell/scell_state.h +++ b/srsue/hdr/phy/scell/scell_state.h @@ -100,7 +100,6 @@ public: std::unique_lock lock(mutex); switch (activation_state) { - case idle: // waiting for receiving a command, do nothing break; @@ -114,7 +113,6 @@ public: case transition: // Detect when the TTI has increased enough to make sure there arent workers, set the configuration if (TTI_SUB(tti, activation_tti) >= activation_margin_tti) { - // Reload cell states for (uint32_t i = 1; i < SRSRAN_MAX_CARRIERS; i++) { // Get Activation command value @@ -149,7 +147,6 @@ public: bool is_active(uint32_t cc_idx, uint32_t tti) const { - if (cc_idx == 0) { return true; } @@ -171,7 +168,6 @@ public: bool is_configured(uint32_t cc_idx) const { - if (cc_idx == 0) { return true; } @@ -185,6 +181,22 @@ public: return scell_cfg[cc_idx].status != cfg::none; } + void reset(uint32_t cc_idx) + { + if (cc_idx == 0 or cc_idx >= SRSRAN_MAX_CARRIERS) { + return; + } + + std::unique_lock lock(mutex); + + activation_state = idle; + + cfg& e = scell_cfg[cc_idx]; + e.status = cfg::none; + e.earfcn = 0; + e.pci = UINT32_MAX; + } + void reset() { std::unique_lock lock(mutex); diff --git a/srsue/src/phy/phy.cc b/srsue/src/phy/phy.cc index f0116863a..341db976e 100644 --- a/srsue/src/phy/phy.cc +++ b/srsue/src/phy/phy.cc @@ -500,10 +500,10 @@ bool phy::set_scell(srsran_cell_t cell_info, uint32_t cc_idx, uint32_t earfcn) // Set inter-frequency measurement sfsync.set_inter_frequency_measurement(cc_idx, earfcn, cell_info); - // Store secondary serving cell EARFCN and PCI - common.cell_state.configure(cc_idx, earfcn, cell_info.id); + // Reset secondary serving cell state, prevents this component carrier from executing any PHY processing + common.cell_state.reset(cc_idx); - // Reset cell configuration + // Reset secondary serving cell configuration for (uint32_t i = 0; i < args.nof_phy_threads; i++) { lte_workers[i]->reset_cell_unlocked(cc_idx); } @@ -534,6 +534,9 @@ bool phy::set_scell(srsran_cell_t cell_info, uint32_t cc_idx, uint32_t earfcn) logger_phy.info("Finished setting new SCell configuration cc_idx=%d, earfcn=%d", cc_idx, earfcn); + // Configure secondary serving cell, allows this component carrier to execute PHY processing + common.cell_state.configure(cc_idx, earfcn, cell_info.id); + stack->set_scell_complete(true); }); return true; diff --git a/srsue/src/phy/sync.cc b/srsue/src/phy/sync.cc index 9aedcaa80..aa10b9d9f 100644 --- a/srsue/src/phy/sync.cc +++ b/srsue/src/phy/sync.cc @@ -301,7 +301,6 @@ bool sync::cell_select_init(phy_cell_t new_cell) Info("Cell Select: Going to IDLE"); phy_state.go_idle(); - worker_com->reset(); // Stop intra-frequency measurements if need to change frequency if ((int)new_cell.earfcn != current_earfcn) { @@ -325,11 +324,11 @@ bool sync::cell_select_start(phy_cell_t new_cell) rrc_proc_state = PROC_SELECT_RUNNING; + // Reset SFN and cell search FSMs. They can safely be done while it is CAMPING or IDLE sfn_p.reset(); search_p.reset(); - srsran_ue_sync_reset(&ue_sync); - /* Reconfigure cell if necessary */ + // Reconfigure cell if necessary cell.id = new_cell.pci; if (not set_cell(new_cell.cfo_hz)) { Error("Cell Select: Reconfiguring cell"); @@ -796,6 +795,12 @@ bool sync::set_cell(float cfo) return false; } + // Reset UE sync. Attention: doing this reset when the FSM is NOT IDLE can cause PSS/SSS out-of-sync + srsran_ue_sync_reset(&ue_sync); + + // Reset worker once SYNC is IDLE to flush any worker states such as ACKs and pending grants + worker_com->reset(); + if (!srsran_cell_isvalid(&cell)) { Error("SYNC: Setting cell: invalid cell (nof_prb=%d, pci=%d, ports=%d)", cell.nof_prb, cell.id, cell.nof_ports); return false; From a7dcd629efd4a1d4f0cde30f89d33de920258476 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Thu, 27 May 2021 11:38:23 +0200 Subject: [PATCH 067/156] Cell search waits for IDLE transition before launch --- srsue/src/phy/sync.cc | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/srsue/src/phy/sync.cc b/srsue/src/phy/sync.cc index aa10b9d9f..603e8b9cc 100644 --- a/srsue/src/phy/sync.cc +++ b/srsue/src/phy/sync.cc @@ -195,7 +195,6 @@ bool sync::cell_search_init() // Move state to IDLE Info("Cell Search: Start EARFCN index=%u/%zd", cellsearch_earfcn_index, worker_com->args->dl_earfcn_list.size()); phy_state.go_idle(); - worker_com->reset(); // Stop all intra-frequency measurement before changing frequency meas_stop(); @@ -220,6 +219,21 @@ rrc_interface_phy_lte::cell_search_ret_t sync::cell_search_start(phy_cell_t* fou rrc_proc_state = PROC_SEARCH_RUNNING; + // Wait for SYNC thread to transition to IDLE (max. 2000ms) + uint32_t cnt = 0; + while (!phy_state.is_idle() && cnt <= 4000) { + Info("Cell Search: PHY state is_idle=%d, cnt=%d", phy_state.is_idle(), cnt); + usleep(500); + cnt++; + } + if (!phy_state.is_idle()) { + Error("Can not change Cell while not in IDLE"); + return ret; + } + + // Reset worker once SYNC is IDLE to flush any worker states such as ACKs and pending grants + worker_com->reset(); + if (srate_mode != SRATE_FIND) { srate_mode = SRATE_FIND; radio_h->set_rx_srate(1.92e6); From aab221105814c53bf824db7d14d5e9cb4171b2d0 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Fri, 28 May 2021 11:08:01 +0200 Subject: [PATCH 068/156] Protect UE PHY SCell configuration --- srsue/src/phy/phy.cc | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/srsue/src/phy/phy.cc b/srsue/src/phy/phy.cc index 341db976e..4b0faecc6 100644 --- a/srsue/src/phy/phy.cc +++ b/srsue/src/phy/phy.cc @@ -500,23 +500,27 @@ bool phy::set_scell(srsran_cell_t cell_info, uint32_t cc_idx, uint32_t earfcn) // Set inter-frequency measurement sfsync.set_inter_frequency_measurement(cc_idx, earfcn, cell_info); - // Reset secondary serving cell state, prevents this component carrier from executing any PHY processing + // Reset secondary serving cell state, prevents this component carrier from executing any new PHY processing. It does + // not stop any current work common.cell_state.reset(cc_idx); - // Reset secondary serving cell configuration - for (uint32_t i = 0; i < args.nof_phy_threads; i++) { - lte_workers[i]->reset_cell_unlocked(cc_idx); - } - // Component carrier index zero should be reserved for PCell // Send configuration to workers cmd_worker.add_cmd([this, cell_info, cc_idx, earfcn, earfcn_is_different]() { logger_phy.info("Setting new SCell configuration cc_idx=%d, earfcn=%d...", cc_idx, earfcn); for (uint32_t i = 0; i < args.nof_phy_threads; i++) { - // set_cell is not protected so run when worker is finished + // set_cell is not protected so run when worker has finished to ensure no PHY processing is done at the time of + // cell setting lte::sf_worker* w = lte_workers.wait_worker_id(i); if (w) { + // Reset secondary serving cell configuration, this needs to be done when the sf_worker is reserved to prevent + // resetting the cell while it is working + w->reset_cell_unlocked(cc_idx); + + // Set the new cell w->set_cell_unlocked(cc_idx, cell_info); + + // Release the new worker, it should not start processing until the SCell state is set to configured w->release(); } } From 235a66412061c6a82fe1a31a6a461ca6ddaecd34 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Fri, 28 May 2021 14:37:35 +0200 Subject: [PATCH 069/156] SRSUE: Removed PUSCH-DMRS/SRS pregeneration methods --- lib/include/srsran/interfaces/ue_phy_interfaces.h | 2 -- lib/include/srsran/test/ue_test_interfaces.h | 2 -- srsue/hdr/phy/lte/cc_worker.h | 2 -- srsue/hdr/phy/lte/sf_worker.h | 2 -- srsue/hdr/phy/phy.h | 2 -- srsue/src/phy/lte/cc_worker.cc | 12 ------------ srsue/src/phy/lte/sf_worker.cc | 7 ------- srsue/src/phy/phy.cc | 10 ---------- srsue/test/ttcn3/hdr/lte_ttcn3_phy.h | 1 - srsue/test/ttcn3/src/lte_ttcn3_phy.cc | 5 ----- srsue/test/upper/rrc_meas_test.cc | 1 - 11 files changed, 46 deletions(-) diff --git a/lib/include/srsran/interfaces/ue_phy_interfaces.h b/lib/include/srsran/interfaces/ue_phy_interfaces.h index 9425de364..f628295db 100644 --- a/lib/include/srsran/interfaces/ue_phy_interfaces.h +++ b/lib/include/srsran/interfaces/ue_phy_interfaces.h @@ -159,8 +159,6 @@ public: virtual bool cell_search() = 0; virtual bool cell_select(phy_cell_t cell) = 0; virtual bool cell_is_camping() = 0; - - virtual void enable_pregen_signals(bool enable) = 0; }; // Combined interface for stack (MAC and RRC) to access PHY diff --git a/lib/include/srsran/test/ue_test_interfaces.h b/lib/include/srsran/test/ue_test_interfaces.h index e871c8f28..4263eb6b8 100644 --- a/lib/include/srsran/test/ue_test_interfaces.h +++ b/lib/include/srsran/test/ue_test_interfaces.h @@ -76,8 +76,6 @@ class phy_dummy_interface : public phy_interface_rrc_lte bool cell_search() override { return true; } bool cell_select(phy_cell_t cell) override { return true; } bool cell_is_camping() override { return false; } - - void enable_pregen_signals(bool enable) override {} }; } // namespace srsue diff --git a/srsue/hdr/phy/lte/cc_worker.h b/srsue/hdr/phy/lte/cc_worker.h index 1ec1e0a8d..5df6cbde1 100644 --- a/srsue/hdr/phy/lte/cc_worker.h +++ b/srsue/hdr/phy/lte/cc_worker.h @@ -42,7 +42,6 @@ public: void set_tdd_config_unlocked(srsran_tdd_config_t config); void set_config_unlocked(srsran::phy_cfg_t& phy_cfg); void upd_config_dci_unlocked(srsran_dci_cfg_t& dci_cfg); - void enable_pregen_signals_unlocked(bool enabled); void set_uci_periodic_cqi(srsran_uci_data_t* uci_data); @@ -93,7 +92,6 @@ private: srsran_ul_sf_cfg_t sf_cfg_ul = {}; uint32_t cc_idx = 0; - bool pregen_enabled = false; bool cell_initiated = false; cf_t* signal_buffer_rx[SRSRAN_MAX_PORTS] = {}; cf_t* signal_buffer_tx[SRSRAN_MAX_PORTS] = {}; diff --git a/srsue/hdr/phy/lte/sf_worker.h b/srsue/hdr/phy/lte/sf_worker.h index a581eab09..4eb855c5d 100644 --- a/srsue/hdr/phy/lte/sf_worker.h +++ b/srsue/hdr/phy/lte/sf_worker.h @@ -49,8 +49,6 @@ public: void set_tdd_config_unlocked(srsran_tdd_config_t config); void set_config_unlocked(uint32_t cc_idx, srsran::phy_cfg_t phy_cfg); - void set_crnti_unlocked(uint16_t rnti); - void enable_pregen_signals_unlocked(bool enabled); ///< Methods for plotting called from GUI thread int read_ce_abs(float* ce_abs, uint32_t tx_antenna, uint32_t rx_antenna); diff --git a/srsue/hdr/phy/phy.h b/srsue/hdr/phy/phy.h index b3a30576b..7c887c585 100644 --- a/srsue/hdr/phy/phy.h +++ b/srsue/hdr/phy/phy.h @@ -94,8 +94,6 @@ public: void get_metrics(const srsran::srsran_rat_t& rat, phy_metrics_t* m) final; void srsran_phy_logger(phy_logger_level_t log_level, char* str); - void enable_pregen_signals(bool enable) final; - void radio_overflow() final; void radio_failure() final; diff --git a/srsue/src/phy/lte/cc_worker.cc b/srsue/src/phy/lte/cc_worker.cc index 6dd7978cf..ece6ddfe4 100644 --- a/srsue/src/phy/lte/cc_worker.cc +++ b/srsue/src/phy/lte/cc_worker.cc @@ -187,11 +187,6 @@ void cc_worker::set_tdd_config_unlocked(srsran_tdd_config_t config) sf_cfg_ul.tdd_config = config; } -void cc_worker::enable_pregen_signals_unlocked(bool enabled) -{ - pregen_enabled = enabled; -} - /************ * * Downlink Functions @@ -872,13 +867,6 @@ void cc_worker::set_config_unlocked(srsran::phy_cfg_t& phy_cfg) ue_ul_cfg.ul_cfg = phy_cfg.ul_cfg; phy->set_pdsch_cfg(&ue_dl_cfg.cfg.pdsch); - - // Update signals - if (pregen_enabled) { - Info("Pre-generating UL signals..."); - srsran_ue_ul_pregen_signals(&ue_ul, &ue_ul_cfg); - Info("Done pre-generating signals worker..."); - } } void cc_worker::upd_config_dci_unlocked(srsran_dci_cfg_t& dci_cfg) diff --git a/srsue/src/phy/lte/sf_worker.cc b/srsue/src/phy/lte/sf_worker.cc index ea1c4ab3f..9c5a5a841 100644 --- a/srsue/src/phy/lte/sf_worker.cc +++ b/srsue/src/phy/lte/sf_worker.cc @@ -138,13 +138,6 @@ void sf_worker::set_tdd_config_unlocked(srsran_tdd_config_t config) tdd_config = config; } -void sf_worker::enable_pregen_signals_unlocked(bool enabled) -{ - for (auto& cc_worker : cc_workers) { - cc_worker->enable_pregen_signals_unlocked(enabled); - } -} - void sf_worker::set_config_unlocked(uint32_t cc_idx, srsran::phy_cfg_t phy_cfg) { if (cc_idx < cc_workers.size()) { diff --git a/srsue/src/phy/phy.cc b/srsue/src/phy/phy.cc index 4b0faecc6..e06bba64e 100644 --- a/srsue/src/phy/phy.cc +++ b/srsue/src/phy/phy.cc @@ -146,9 +146,6 @@ void phy::run_thread() sfsync.init( radio, stack, &prach_buffer, <e_workers, &nr_workers, &common, SF_RECV_THREAD_PRIO, args.sync_cpu_affinity); - // Disable UL signal pregeneration until the attachment - enable_pregen_signals(false); - is_configured = true; config_cond.notify_all(); } @@ -420,13 +417,6 @@ void phy::start_plot() } } -void phy::enable_pregen_signals(bool enable) -{ - for (uint32_t i = 0; i < args.nof_phy_threads; i++) { - lte_workers[i]->enable_pregen_signals_unlocked(enable); - } -} - bool phy::set_config(const srsran::phy_cfg_t& config_, uint32_t cc_idx) { if (!is_initiated()) { diff --git a/srsue/test/ttcn3/hdr/lte_ttcn3_phy.h b/srsue/test/ttcn3/hdr/lte_ttcn3_phy.h index a1cc99ec7..72ebf41ed 100644 --- a/srsue/test/ttcn3/hdr/lte_ttcn3_phy.h +++ b/srsue/test/ttcn3/hdr/lte_ttcn3_phy.h @@ -55,7 +55,6 @@ public: void set_cell_map(const cell_list_t& cells_); // phy_interface_rrc_lte - void enable_pregen_signals(bool enable) override; void deactivate_scells() override; void set_activation_deactivation_scell(uint32_t cmd, uint32_t tti) override; bool set_config(const srsran::phy_cfg_t& config, uint32_t cc_idx = 0) override; diff --git a/srsue/test/ttcn3/src/lte_ttcn3_phy.cc b/srsue/test/ttcn3/src/lte_ttcn3_phy.cc index d34a75e01..05b8f31a4 100644 --- a/srsue/test/ttcn3/src/lte_ttcn3_phy.cc +++ b/srsue/test/ttcn3/src/lte_ttcn3_phy.cc @@ -61,11 +61,6 @@ void lte_ttcn3_phy::set_cell_map(const cell_list_t& cells_) void lte_ttcn3_phy::set_config_tdd(srsran_tdd_config_t& tdd_config) {} -void lte_ttcn3_phy::enable_pregen_signals(bool enable) -{ - logger.debug("%s not implemented.", __FUNCTION__); -} - void lte_ttcn3_phy::deactivate_scells() { logger.debug("%s not implemented.", __FUNCTION__); diff --git a/srsue/test/upper/rrc_meas_test.cc b/srsue/test/upper/rrc_meas_test.cc index e966ab42e..60ae59593 100644 --- a/srsue/test/upper/rrc_meas_test.cc +++ b/srsue/test/upper/rrc_meas_test.cc @@ -48,7 +48,6 @@ public: last_selected_cell = cell; return true; } - void enable_pregen_signals(bool enable) override {} void set_cells_to_meas(uint32_t earfcn, const std::set& pci) override { From 7185ec6beb21f86412da2dd8dcb83392dcb2edc3 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Fri, 28 May 2021 15:29:00 +0200 Subject: [PATCH 070/156] PHY CC configuration is stashed and applied in the next TTI --- srsue/hdr/phy/lte/cc_worker.h | 4 +-- srsue/hdr/phy/lte/sf_worker.h | 2 +- srsue/hdr/phy/lte/worker_pool.h | 24 +++++++++++++ srsue/src/phy/lte/cc_worker.cc | 4 +-- srsue/src/phy/lte/sf_worker.cc | 2 +- srsue/src/phy/lte/worker_pool.cc | 58 ++++++++++++++++++++++++++++++-- srsue/src/phy/phy.cc | 17 +++------- 7 files changed, 91 insertions(+), 20 deletions(-) diff --git a/srsue/hdr/phy/lte/cc_worker.h b/srsue/hdr/phy/lte/cc_worker.h index 5df6cbde1..ada77a0c7 100644 --- a/srsue/hdr/phy/lte/cc_worker.h +++ b/srsue/hdr/phy/lte/cc_worker.h @@ -40,8 +40,8 @@ public: void reset_cell_unlocked(); bool set_cell_unlocked(srsran_cell_t cell_); void set_tdd_config_unlocked(srsran_tdd_config_t config); - void set_config_unlocked(srsran::phy_cfg_t& phy_cfg); - void upd_config_dci_unlocked(srsran_dci_cfg_t& dci_cfg); + void set_config_unlocked(const srsran::phy_cfg_t& phy_cfg); + void upd_config_dci_unlocked(const srsran_dci_cfg_t& dci_cfg); void set_uci_periodic_cqi(srsran_uci_data_t* uci_data); diff --git a/srsue/hdr/phy/lte/sf_worker.h b/srsue/hdr/phy/lte/sf_worker.h index 4eb855c5d..c9b0ee2d8 100644 --- a/srsue/hdr/phy/lte/sf_worker.h +++ b/srsue/hdr/phy/lte/sf_worker.h @@ -48,7 +48,7 @@ public: void set_cfo_unlocked(const uint32_t& cc_idx, float cfo); void set_tdd_config_unlocked(srsran_tdd_config_t config); - void set_config_unlocked(uint32_t cc_idx, srsran::phy_cfg_t phy_cfg); + void set_config_unlocked(uint32_t cc_idx, const srsran::phy_cfg_t& phy_cfg); ///< Methods for plotting called from GUI thread int read_ce_abs(float* ce_abs, uint32_t tx_antenna, uint32_t rx_antenna); diff --git a/srsue/hdr/phy/lte/worker_pool.h b/srsue/hdr/phy/lte/worker_pool.h index 4c3b6e312..b548cc10c 100644 --- a/srsue/hdr/phy/lte/worker_pool.h +++ b/srsue/hdr/phy/lte/worker_pool.h @@ -21,9 +21,25 @@ namespace lte { class worker_pool { +private: srsran::thread_pool pool; std::vector > workers; + class phy_cfg_stash_t + { + private: + std::vector pending; ///< Indicates for each SF worker if it has pending configuration + srsran::phy_cfg_t cfg; ///< Actual CC configuration + + public: + phy_cfg_stash_t(uint32_t max_workers) : pending(max_workers) {} + void set_cfg(const srsran::phy_cfg_t& c); + bool is_pending(uint32_t sf_idx); + const srsran::phy_cfg_t& get_cfg(uint32_t sf_idx); + }; + std::mutex phy_cfg_mutex; ///< Protects configuration stash + std::array phy_cfg_stash; ///< Stores the latest worker configuration + public: sf_worker* operator[](std::size_t pos) { return workers.at(pos).get(); } @@ -33,6 +49,14 @@ public: sf_worker* wait_worker_id(uint32_t id); void start_worker(sf_worker* w); void stop(); + + /** + * @brief Sets a new configuration for a given CC, it copies the new configuration into the stash and it will be + * applied to the sf_worker at the time it is reserved. + * @param cc_idx CC index + * @param phy_cfg Actual PHY configuration + */ + void set_config_unlocked(uint32_t cc_idx, srsran::phy_cfg_t phy_cfg); }; } // namespace lte diff --git a/srsue/src/phy/lte/cc_worker.cc b/srsue/src/phy/lte/cc_worker.cc index ece6ddfe4..e25ec70e2 100644 --- a/srsue/src/phy/lte/cc_worker.cc +++ b/srsue/src/phy/lte/cc_worker.cc @@ -860,7 +860,7 @@ void cc_worker::set_uci_ack(srsran_uci_data_t* uci_data, /* Translates RRC structs into PHY structs */ -void cc_worker::set_config_unlocked(srsran::phy_cfg_t& phy_cfg) +void cc_worker::set_config_unlocked(const srsran::phy_cfg_t& phy_cfg) { // Save configuration ue_dl_cfg.cfg = phy_cfg.dl_cfg; @@ -869,7 +869,7 @@ void cc_worker::set_config_unlocked(srsran::phy_cfg_t& phy_cfg) phy->set_pdsch_cfg(&ue_dl_cfg.cfg.pdsch); } -void cc_worker::upd_config_dci_unlocked(srsran_dci_cfg_t& dci_cfg) +void cc_worker::upd_config_dci_unlocked(const srsran_dci_cfg_t& dci_cfg) { ue_dl_cfg.cfg.dci = dci_cfg; } diff --git a/srsue/src/phy/lte/sf_worker.cc b/srsue/src/phy/lte/sf_worker.cc index 9c5a5a841..2ff948e9e 100644 --- a/srsue/src/phy/lte/sf_worker.cc +++ b/srsue/src/phy/lte/sf_worker.cc @@ -138,7 +138,7 @@ void sf_worker::set_tdd_config_unlocked(srsran_tdd_config_t config) tdd_config = config; } -void sf_worker::set_config_unlocked(uint32_t cc_idx, srsran::phy_cfg_t phy_cfg) +void sf_worker::set_config_unlocked(uint32_t cc_idx, const srsran::phy_cfg_t& phy_cfg) { if (cc_idx < cc_workers.size()) { cc_workers[cc_idx]->set_config_unlocked(phy_cfg); diff --git a/srsue/src/phy/lte/worker_pool.cc b/srsue/src/phy/lte/worker_pool.cc index 109b0aa4b..7ce8f8808 100644 --- a/srsue/src/phy/lte/worker_pool.cc +++ b/srsue/src/phy/lte/worker_pool.cc @@ -14,7 +14,34 @@ namespace srsue { namespace lte { -worker_pool::worker_pool(uint32_t max_workers) : pool(max_workers) {} +void worker_pool::phy_cfg_stash_t::set_cfg(const srsran::phy_cfg_t& c) +{ + for (auto it = pending.begin(); it < pending.end(); it++) { + *it = true; + } + + cfg = c; +} + +bool worker_pool::phy_cfg_stash_t::is_pending(uint32_t sf_idx) +{ + if (sf_idx >= (uint32_t)pending.size()) { + return false; + } + return pending[sf_idx]; +} + +const srsran::phy_cfg_t& worker_pool::phy_cfg_stash_t::get_cfg(uint32_t sf_idx) +{ + if (sf_idx < (uint32_t)pending.size()) { + pending[sf_idx] = false; + } + return cfg; +} + +worker_pool::worker_pool(uint32_t max_workers) : + pool(max_workers), phy_cfg_stash{{max_workers, max_workers, max_workers, max_workers, max_workers}} +{} bool worker_pool::init(phy_common* common, int prio) { @@ -39,7 +66,23 @@ void worker_pool::start_worker(sf_worker* w) sf_worker* worker_pool::wait_worker(uint32_t tti) { - return (sf_worker*)pool.wait_worker(tti); + sf_worker* w = (sf_worker*)pool.wait_worker(tti); + if (w == nullptr) { + return w; + } + + // Protect configuration + std::unique_lock lock(phy_cfg_mutex); + + // Iterate all CC searching for a pending configuration + uint32_t worker_id = w->get_id(); + for (uint32_t cc_idx = 0; cc_idx < SRSRAN_MAX_CARRIERS; cc_idx++) { + if (phy_cfg_stash[cc_idx].is_pending(worker_id)) { + w->set_config_unlocked(cc_idx, phy_cfg_stash[cc_idx].get_cfg(worker_id)); + } + } + + return w; } sf_worker* worker_pool::wait_worker_id(uint32_t id) @@ -52,5 +95,16 @@ void worker_pool::stop() pool.stop(); } +void worker_pool::set_config_unlocked(uint32_t cc_idx, srsran::phy_cfg_t phy_cfg) +{ + // Protect CC index bounds + if (cc_idx >= SRSRAN_MAX_CARRIERS) { + return; + } + + // Protect configuration + std::unique_lock lock(phy_cfg_mutex); + phy_cfg_stash[cc_idx].set_cfg(phy_cfg); +} }; // namespace lte }; // namespace srsue \ No newline at end of file diff --git a/srsue/src/phy/phy.cc b/srsue/src/phy/phy.cc index e06bba64e..fe6785529 100644 --- a/srsue/src/phy/phy.cc +++ b/srsue/src/phy/phy.cc @@ -440,18 +440,10 @@ bool phy::set_config(const srsran::phy_cfg_t& config_, uint32_t cc_idx) prach_cfg = config_.prach_cfg; } - // Apply configuration after the worker is finished to avoid race conditions + // Apply configurations asynchronously to avoid race conditions cmd_worker.add_cmd([this, config_, cc_idx]() { logger_phy.info("Setting new PHY configuration cc_idx=%d...", cc_idx); - for (uint32_t i = 0; i < args.nof_phy_threads; i++) { - // set_cell is not protected so run when worker is finished - lte::sf_worker* w = lte_workers.wait_worker_id(i); - if (w) { - w->set_config_unlocked(cc_idx, config_); - w->release(); - } - } - logger_phy.info("Finished setting new PHY configuration cc_idx=%d", cc_idx); + lte_workers.set_config_unlocked(cc_idx, config_); // It is up to the PRACH component to detect whether the cell or the configuration have changed to reconfigure configure_prach_params(); @@ -497,7 +489,7 @@ bool phy::set_scell(srsran_cell_t cell_info, uint32_t cc_idx, uint32_t earfcn) // Component carrier index zero should be reserved for PCell // Send configuration to workers cmd_worker.add_cmd([this, cell_info, cc_idx, earfcn, earfcn_is_different]() { - logger_phy.info("Setting new SCell configuration cc_idx=%d, earfcn=%d...", cc_idx, earfcn); + logger_phy.info("Setting new SCell configuration cc_idx=%d, earfcn=%d, pci=%d...", cc_idx, earfcn, cell_info.id); for (uint32_t i = 0; i < args.nof_phy_threads; i++) { // set_cell is not protected so run when worker has finished to ensure no PHY processing is done at the time of // cell setting @@ -526,7 +518,8 @@ bool phy::set_scell(srsran_cell_t cell_info, uint32_t cc_idx, uint32_t earfcn) // Set secondary serving cell synchronization sfsync.scell_sync_set(cc_idx, cell_info); - logger_phy.info("Finished setting new SCell configuration cc_idx=%d, earfcn=%d", cc_idx, earfcn); + logger_phy.info( + "Finished setting new SCell configuration cc_idx=%d, earfcn=%d, pci=%d", cc_idx, earfcn, cell_info.id); // Configure secondary serving cell, allows this component carrier to execute PHY processing common.cell_state.configure(cc_idx, earfcn, cell_info.id); From 93b35676e7e234c0206cc0b1d45345a36b785f73 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Fri, 28 May 2021 15:29:31 +0200 Subject: [PATCH 071/156] Solve concurrency issue when setting up SCell measurement --- srsue/src/phy/phy.cc | 65 ++++++++++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 30 deletions(-) diff --git a/srsue/src/phy/phy.cc b/srsue/src/phy/phy.cc index fe6785529..d034cdd5a 100644 --- a/srsue/src/phy/phy.cc +++ b/srsue/src/phy/phy.cc @@ -249,42 +249,47 @@ void phy::configure_prach_params() void phy::set_cells_to_meas(uint32_t earfcn, const std::set& pci) { - // Check if the EARFCN matches with serving cell - uint32_t pcell_earfcn = 0; - sfsync.get_current_cell(nullptr, &pcell_earfcn); - bool available = (pcell_earfcn == earfcn); - - // Find if there is secondary serving cell configured with the specified EARFCN - uint32_t cc_empty = 0; - for (uint32_t cc = 1; cc < args.nof_lte_carriers and not available; cc++) { - // If it is configured... - if (common.cell_state.is_configured(cc)) { - // ... Check if the EARFCN match - if (common.cell_state.get_earfcn(cc) == earfcn) { - available = true; + // As the SCell configuration is performed asynchronously through the cmd_worker, append the command adding the + // measurements to avoid a concurrency issue + cmd_worker.add_cmd([this, earfcn, pci]() { + // Check if the EARFCN matches with serving cell + uint32_t pcell_earfcn = 0; + sfsync.get_current_cell(nullptr, &pcell_earfcn); + bool available = (pcell_earfcn == earfcn); + + // Find if there is secondary serving cell configured with the specified EARFCN + uint32_t cc_empty = 0; + for (uint32_t cc = 1; cc < args.nof_lte_carriers and not available; cc++) { + // If it is configured... + if (common.cell_state.is_configured(cc)) { + // ... Check if the EARFCN match + if (common.cell_state.get_earfcn(cc) == earfcn) { + available = true; + } + } else if (cc_empty == 0) { + // ... otherwise, save the CC as non-configured + cc_empty = cc; } - } else if (cc_empty == 0) { - // ... otherwise, save the CC as non-configured - cc_empty = cc; } - } - // If not available and a non-configured carrier is available, configure it. - if (not available and cc_empty != 0) { - // Copy all attributes from serving cell - srsran_cell_t cell = selected_cell; + // If not available and a non-configured carrier is available, configure it. + if (not available and cc_empty != 0) { + // Copy all attributes from serving cell + srsran_cell_t cell = selected_cell; - // Select the first PCI in the list - if (not pci.empty()) { - cell.id = *pci.begin(); - } + // Select the first PCI in the list + if (not pci.empty()) { + cell.id = *pci.begin(); + } - // Configure a the empty carrier as it was CA - set_scell(cell, cc_empty, earfcn); - } + // Configure a the empty carrier as it was CA + logger_phy.info("Setting new SCell measurement cc_idx=%d, earfcn=%d, pci=%d...", cc_empty, earfcn, cell.id); + set_scell(cell, cc_empty, earfcn); + } - // Finally, set the serving cell measure - sfsync.set_cells_to_meas(earfcn, pci); + // Finally, set the serving cell measure + sfsync.set_cells_to_meas(earfcn, pci); + }); } void phy::meas_stop() From 3c93d5ba4325be7f2c606b72799869ffc8212452 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Fri, 28 May 2021 17:05:44 +0200 Subject: [PATCH 072/156] Fix carrier mapping concurrency issue --- lib/include/srsran/radio/channel_mapping.h | 8 +++++--- lib/src/radio/channel_mapping.cc | 23 +++++++++++++++------- lib/src/radio/radio.cc | 6 ------ 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/lib/include/srsran/radio/channel_mapping.h b/lib/include/srsran/radio/channel_mapping.h index 5e8f9f79e..7c5ddac84 100644 --- a/lib/include/srsran/radio/channel_mapping.h +++ b/lib/include/srsran/radio/channel_mapping.h @@ -93,10 +93,10 @@ public: void set_channels(const std::list& channels_) { available_channels = channels_; } /** - * Finds an unused physical channel that supports the provided frequency and assigns it to logical channel - * logical_ch + * It deallocates the logical channel if it has been already allocated and it is not suitable, then finds an unused + * physical channel that supports the provided frequency and assigns it to logical channel logical_ch * @param logical_ch logical channel index - * @param freq Frequency (in Hz) that we want to receive/transmitt + * @param freq Frequency (in Hz) that we want to receive/transmit * @return true if a physical channel supporting this frequency was found or false otherwise */ bool allocate_freq(const uint32_t& logical_ch, const float& freq); @@ -138,6 +138,8 @@ private: mutable std::mutex mutex = {}; uint32_t nof_antennas = 1; uint32_t nof_channels_x_dev = 1; + + void release_freq_(const uint32_t& logical_ch); }; } // namespace srsran diff --git a/lib/src/radio/channel_mapping.cc b/lib/src/radio/channel_mapping.cc index c393c37a7..d5bd7e52a 100644 --- a/lib/src/radio/channel_mapping.cc +++ b/lib/src/radio/channel_mapping.cc @@ -26,11 +26,15 @@ bool channel_mapping::allocate_freq(const uint32_t& logical_ch, const float& fre { std::lock_guard lock(mutex); - if (allocated_channels.count(logical_ch)) { - ERROR("allocate_freq: Carrier logical_ch=%d already allocated to channel=%d", - logical_ch, - allocated_channels[logical_ch].carrier_idx); - return false; + // Check if the logical channel has already been allocated + if (allocated_channels.count(logical_ch) > 0) { + // If the current channel contains the frequency, do nothing else + if (allocated_channels[logical_ch].band.contains(freq)) { + return true; + } + + // Otherwise, release logical channel before searching for a new available channel + release_freq_(logical_ch); } // Find first available channel that supports this frequency and allocated it @@ -45,12 +49,17 @@ bool channel_mapping::allocate_freq(const uint32_t& logical_ch, const float& fre return false; } +void channel_mapping::release_freq_(const uint32_t& logical_ch) +{ + available_channels.push_back(allocated_channels[logical_ch]); + allocated_channels.erase(logical_ch); +} + bool channel_mapping::release_freq(const uint32_t& logical_ch) { std::lock_guard lock(mutex); if (allocated_channels.count(logical_ch)) { - available_channels.push_back(allocated_channels[logical_ch]); - allocated_channels.erase(logical_ch); + release_freq_(logical_ch); return true; } return false; diff --git a/lib/src/radio/radio.cc b/lib/src/radio/radio.cc index 831635c52..f9b77dc82 100644 --- a/lib/src/radio/radio.cc +++ b/lib/src/radio/radio.cc @@ -622,9 +622,6 @@ void radio::set_rx_freq(const uint32_t& carrier_idx, const double& freq) return; } - // First release mapping - rx_channel_mapping.release_freq(carrier_idx); - // Map carrier index to physical channel if (rx_channel_mapping.allocate_freq(carrier_idx, freq)) { channel_mapping::device_mapping_t device_mapping = rx_channel_mapping.get_device_mapping(carrier_idx); @@ -740,9 +737,6 @@ void radio::set_tx_freq(const uint32_t& carrier_idx, const double& freq) return; } - // First release mapping - tx_channel_mapping.release_freq(carrier_idx); - // Map carrier index to physical channel if (tx_channel_mapping.allocate_freq(carrier_idx, freq)) { channel_mapping::device_mapping_t device_mapping = tx_channel_mapping.get_device_mapping(carrier_idx); From 807b60988d23867e6edb879e4348f113563a624a Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Fri, 28 May 2021 17:28:34 +0200 Subject: [PATCH 073/156] Wait for PHY workers to transmit before considering SYNC in IDLE --- srsue/hdr/phy/sync_state.h | 26 ++++++++++++++++++++++++++ srsue/src/phy/sync.cc | 26 ++++++++++---------------- 2 files changed, 36 insertions(+), 16 deletions(-) diff --git a/srsue/hdr/phy/sync_state.h b/srsue/hdr/phy/sync_state.h index af9d7c0c3..9e7715026 100644 --- a/srsue/hdr/phy/sync_state.h +++ b/srsue/hdr/phy/sync_state.h @@ -87,6 +87,32 @@ public: /* Helpers below this */ bool is_idle() { return cur_state == IDLE; } bool is_camping() { return cur_state == CAMPING; } + bool wait_idle(uint32_t timeout_ms) + { + std::unique_lock lock(outside); + + // Avoid wasting time if the next state will not be IDLE + if (next_state != IDLE) { + return false; + } + + // Calculate timeout + std::chrono::system_clock::time_point expire_time = std::chrono::system_clock::now(); + expire_time += std::chrono::milliseconds(timeout_ms); + + // Wait until the state is IDLE + while (cur_state != IDLE) { + std::cv_status cv_status = cvar.wait_until(lock, expire_time); + + // Returns false if it timeouts + if (cv_status != std::cv_status::timeout) { + return false; + } + } + + // Return true if the state is IDLE + return true; + } const char* to_string() { diff --git a/srsue/src/phy/sync.cc b/srsue/src/phy/sync.cc index 603e8b9cc..567e27ea4 100644 --- a/srsue/src/phy/sync.cc +++ b/srsue/src/phy/sync.cc @@ -220,17 +220,14 @@ rrc_interface_phy_lte::cell_search_ret_t sync::cell_search_start(phy_cell_t* fou rrc_proc_state = PROC_SEARCH_RUNNING; // Wait for SYNC thread to transition to IDLE (max. 2000ms) - uint32_t cnt = 0; - while (!phy_state.is_idle() && cnt <= 4000) { - Info("Cell Search: PHY state is_idle=%d, cnt=%d", phy_state.is_idle(), cnt); - usleep(500); - cnt++; - } - if (!phy_state.is_idle()) { - Error("Can not change Cell while not in IDLE"); + if (not phy_state.wait_idle(2)) { + Error("SYNC: Can not search while not in IDLE"); return ret; } + // Wait for workers to finish PHY processing + worker_com->semaphore.wait_all(); + // Reset worker once SYNC is IDLE to flush any worker states such as ACKs and pending grants worker_com->reset(); @@ -798,20 +795,17 @@ void sync::set_ue_sync_opts(srsran_ue_sync_t* q, float cfo) bool sync::set_cell(float cfo) { // Wait for SYNC thread to transition to IDLE (max. 2000ms) - uint32_t cnt = 0; - while (!phy_state.is_idle() && cnt <= 4000) { - Info("SYNC: PHY state is_idle=%d, cnt=%d", phy_state.is_idle(), cnt); - usleep(500); - cnt++; - } - if (!phy_state.is_idle()) { - Error("Can not change Cell while not in IDLE"); + if (not phy_state.wait_idle(2)) { + Error("SYNC: Can not change Cell while not in IDLE"); return false; } // Reset UE sync. Attention: doing this reset when the FSM is NOT IDLE can cause PSS/SSS out-of-sync srsran_ue_sync_reset(&ue_sync); + // Wait for workers to finish PHY processing + worker_com->semaphore.wait_all(); + // Reset worker once SYNC is IDLE to flush any worker states such as ACKs and pending grants worker_com->reset(); From 44b6a2b55fe5faf4573bd350ba588364ed367674 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Sat, 29 May 2021 08:39:07 +0200 Subject: [PATCH 074/156] Fix SYNC wait for IDLE if the state is reached --- srsue/hdr/phy/sync_state.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/srsue/hdr/phy/sync_state.h b/srsue/hdr/phy/sync_state.h index 9e7715026..2c10ebb6c 100644 --- a/srsue/hdr/phy/sync_state.h +++ b/srsue/hdr/phy/sync_state.h @@ -93,7 +93,7 @@ public: // Avoid wasting time if the next state will not be IDLE if (next_state != IDLE) { - return false; + return cur_state == IDLE; } // Calculate timeout @@ -104,9 +104,9 @@ public: while (cur_state != IDLE) { std::cv_status cv_status = cvar.wait_until(lock, expire_time); - // Returns false if it timeouts + // Return if it timeouts if (cv_status != std::cv_status::timeout) { - return false; + return cur_state == IDLE; } } From 5c55ff24ec26124a81ff6092ec7824badd8524e5 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 31 May 2021 08:08:15 +0200 Subject: [PATCH 075/156] Minor UE aesthetical changes --- srsue/hdr/phy/lte/worker_pool.h | 2 +- srsue/hdr/phy/sync.h | 8 ++++---- srsue/src/phy/lte/worker_pool.cc | 2 +- srsue/src/phy/phy.cc | 2 +- srsue/src/phy/sync.cc | 6 +++--- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/srsue/hdr/phy/lte/worker_pool.h b/srsue/hdr/phy/lte/worker_pool.h index b548cc10c..9a20ea532 100644 --- a/srsue/hdr/phy/lte/worker_pool.h +++ b/srsue/hdr/phy/lte/worker_pool.h @@ -56,7 +56,7 @@ public: * @param cc_idx CC index * @param phy_cfg Actual PHY configuration */ - void set_config_unlocked(uint32_t cc_idx, srsran::phy_cfg_t phy_cfg); + void set_config(uint32_t cc_idx, const srsran::phy_cfg_t& phy_cfg); }; } // namespace lte diff --git a/srsue/hdr/phy/sync.h b/srsue/hdr/phy/sync.h index 8dc055ae2..793abed94 100644 --- a/srsue/hdr/phy/sync.h +++ b/srsue/hdr/phy/sync.h @@ -268,10 +268,10 @@ private: float dl_freq = -1; float ul_freq = -1; - const static int MIN_TTI_JUMP = 1; // Time gap reported to stack after receiving subframe - const static int MAX_TTI_JUMP = 1000; // Maximum time gap tolerance in RF stream metadata - - const uint8_t SYNC_CC_IDX = 0; ///< From the sync POV, the CC idx is always the first + const static int MIN_TTI_JUMP = 1; ///< Time gap reported to stack after receiving subframe + const static int MAX_TTI_JUMP = 1000; ///< Maximum time gap tolerance in RF stream metadata + const uint8_t SYNC_CC_IDX = 0; ///< From the sync POV, the CC idx is always the first + const uint32_t TIMEOUT_TO_IDLE_MS = 2; ///< Timeout in milliseconds for transitioning to IDLE }; } // namespace srsue diff --git a/srsue/src/phy/lte/worker_pool.cc b/srsue/src/phy/lte/worker_pool.cc index 7ce8f8808..f65bc9b0a 100644 --- a/srsue/src/phy/lte/worker_pool.cc +++ b/srsue/src/phy/lte/worker_pool.cc @@ -95,7 +95,7 @@ void worker_pool::stop() pool.stop(); } -void worker_pool::set_config_unlocked(uint32_t cc_idx, srsran::phy_cfg_t phy_cfg) +void worker_pool::set_config(uint32_t cc_idx, const srsran::phy_cfg_t& phy_cfg) { // Protect CC index bounds if (cc_idx >= SRSRAN_MAX_CARRIERS) { diff --git a/srsue/src/phy/phy.cc b/srsue/src/phy/phy.cc index d034cdd5a..e8df18a33 100644 --- a/srsue/src/phy/phy.cc +++ b/srsue/src/phy/phy.cc @@ -448,7 +448,7 @@ bool phy::set_config(const srsran::phy_cfg_t& config_, uint32_t cc_idx) // Apply configurations asynchronously to avoid race conditions cmd_worker.add_cmd([this, config_, cc_idx]() { logger_phy.info("Setting new PHY configuration cc_idx=%d...", cc_idx); - lte_workers.set_config_unlocked(cc_idx, config_); + lte_workers.set_config(cc_idx, config_); // It is up to the PRACH component to detect whether the cell or the configuration have changed to reconfigure configure_prach_params(); diff --git a/srsue/src/phy/sync.cc b/srsue/src/phy/sync.cc index 567e27ea4..76a8649bb 100644 --- a/srsue/src/phy/sync.cc +++ b/srsue/src/phy/sync.cc @@ -220,8 +220,8 @@ rrc_interface_phy_lte::cell_search_ret_t sync::cell_search_start(phy_cell_t* fou rrc_proc_state = PROC_SEARCH_RUNNING; // Wait for SYNC thread to transition to IDLE (max. 2000ms) - if (not phy_state.wait_idle(2)) { - Error("SYNC: Can not search while not in IDLE"); + if (not phy_state.wait_idle(TIMEOUT_TO_IDLE_MS)) { + Error("SYNC: Error transitioning to IDLE. Cell search cannot start."); return ret; } @@ -795,7 +795,7 @@ void sync::set_ue_sync_opts(srsran_ue_sync_t* q, float cfo) bool sync::set_cell(float cfo) { // Wait for SYNC thread to transition to IDLE (max. 2000ms) - if (not phy_state.wait_idle(2)) { + if (not phy_state.wait_idle(TIMEOUT_TO_IDLE_MS)) { Error("SYNC: Can not change Cell while not in IDLE"); return false; } From 018c734b093bce536b5df118879f18f410e00bbc Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Thu, 27 May 2021 15:51:50 +0200 Subject: [PATCH 076/156] dl_harq: fix unlocking of unlocked mutex bug detected by TSAN in the mac_test the tb_decoded() method was called twice for the 2nd codeword, causig TSAN to complain about an unlocked mutex being unlocked. The patch resolves the potential issue only calling tb_decoded for a grant/tb thas has a non-zero MCS. The patch also adjusts the reset function to have a safe and "unsafe" version to be called from inside the class, similar to other classes where we do the same. --- srsue/hdr/stack/mac/dl_harq.h | 5 ++++- srsue/src/stack/mac/dl_harq.cc | 28 +++++++++++++++------------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/srsue/hdr/stack/mac/dl_harq.h b/srsue/hdr/stack/mac/dl_harq.h index 6741d0b68..035311fc1 100644 --- a/srsue/hdr/stack/mac/dl_harq.h +++ b/srsue/hdr/stack/mac/dl_harq.h @@ -63,7 +63,7 @@ private: ~dl_tb_process(); bool init(int pid, dl_harq_entity* parent, uint32_t tb_idx); - void reset(bool lock = true); + void reset(); void reset_ndi(); void new_grant_dl(mac_interface_phy_lte::mac_grant_dl_t grant, mac_interface_phy_lte::tb_action_dl_t* action); @@ -73,6 +73,9 @@ private: // Determine if it's a new transmission 5.3.2.2 bool calc_is_new_transmission(mac_interface_phy_lte::mac_grant_dl_t grant); + // Internal function to reset process, caller must hold the mutex + void reset_unsafe(); + std::mutex mutex; bool is_initiated; diff --git a/srsue/src/stack/mac/dl_harq.cc b/srsue/src/stack/mac/dl_harq.cc index 8893d2501..f72533780 100644 --- a/srsue/src/stack/mac/dl_harq.cc +++ b/srsue/src/stack/mac/dl_harq.cc @@ -149,7 +149,9 @@ void dl_harq_entity::dl_harq_process::tb_decoded(mac_interface_phy_lte::mac_gran { /* For each subprocess... */ for (uint32_t i = 0; i < SRSRAN_MAX_TB; i++) { - subproc[i].tb_decoded(grant, &ack[i]); + if (grant.tb[i].tbs) { + subproc[i].tb_decoded(grant, &ack[i]); + } } } @@ -196,12 +198,14 @@ bool dl_harq_entity::dl_harq_process::dl_tb_process::init(int pid, dl_harq_entit return true; } -void dl_harq_entity::dl_harq_process::dl_tb_process::reset(bool lock) +void dl_harq_entity::dl_harq_process::dl_tb_process::reset() { - if (lock) { - mutex.lock(); - } + std::lock_guard lock(mutex); + reset_unsafe(); +} +void dl_harq_entity::dl_harq_process::dl_tb_process::reset_unsafe() +{ bzero(&cur_grant, sizeof(mac_interface_phy_lte::mac_grant_dl_t)); is_first_tb = true; ack = false; @@ -213,10 +217,6 @@ void dl_harq_entity::dl_harq_process::dl_tb_process::reset(bool lock) } payload_buffer_ptr = NULL; } - - if (lock) { - mutex.unlock(); - } } void dl_harq_entity::dl_harq_process::dl_tb_process::reset_ndi() @@ -293,7 +293,8 @@ void dl_harq_entity::dl_harq_process::dl_tb_process::new_grant_dl(mac_interface_ n_retx, n_retx > RESET_DUPLICATE_TIMEOUT ? "yes" : "no"); if (n_retx > RESET_DUPLICATE_TIMEOUT) { - reset(false); + // reset without trying to acquire the mutex again + reset_unsafe(); } } @@ -351,11 +352,12 @@ void dl_harq_entity::dl_harq_process::dl_tb_process::tb_decoded(mac_interface_ph cur_grant.tb[tid].ndi); } - mutex.unlock(); - if (ack && is_bcch) { - reset(); + // reset without trying to acquire the mutex again + reset_unsafe(); } + + mutex.unlock(); } // Determine if it's a new transmission 5.3.2.2 From 11a6d3160ffd437c3462e1611ef3e1e3b5cf101e Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Thu, 27 May 2021 15:54:47 +0200 Subject: [PATCH 077/156] mac_test: include TSAN options header --- srsue/test/mac_test.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/srsue/test/mac_test.cc b/srsue/test/mac_test.cc index d24c55370..9d2b65b13 100644 --- a/srsue/test/mac_test.cc +++ b/srsue/test/mac_test.cc @@ -14,6 +14,7 @@ #include "srsran/asn1/rrc_utils.h" #include "srsran/common/mac_pcap.h" #include "srsran/common/test_common.h" +#include "srsran/common/tsan_options.h" #include "srsran/test/ue_test_interfaces.h" #include "srsue/hdr/stack/mac/mac.h" #include "srsue/hdr/stack/mac/mux.h" From 50f7fc644b910388d4d77b05f39c56719e5a8e02 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Mon, 31 May 2021 12:40:17 +0200 Subject: [PATCH 078/156] rlc_am_lte: log event when status prohibit timer expires --- lib/src/upper/rlc_am_lte.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/src/upper/rlc_am_lte.cc b/lib/src/upper/rlc_am_lte.cc index a17b0803b..1fa934fa1 100644 --- a/lib/src/upper/rlc_am_lte.cc +++ b/lib/src/upper/rlc_am_lte.cc @@ -582,6 +582,8 @@ void rlc_am_lte::rlc_am_lte_tx::timer_expired(uint32_t timeout_id) if ((retx_queue.empty() && tx_sdu_queue.size() == 0) || tx_window.size() >= RLC_AM_WINDOW_SIZE) { retransmit_pdu(vt_a); // TODO: TS says to send vt_s - 1 here } + } else if (status_prohibit_timer.is_valid() && status_prohibit_timer.id() == timeout_id) { + logger.debug("%s Status prohibit timer expired after %dms", RB_NAME, status_prohibit_timer.duration()); } lock.unlock(); From dddb3ede7113ea6f01aed1e13d887488255285fc Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 31 May 2021 17:48:16 +0200 Subject: [PATCH 079/156] Fix zero parity --- lib/src/phy/phch/sch.c | 12 +++++++++++- lib/src/phy/phch/test/pdsch_test.c | 26 +++++++++++++++++++++----- lib/src/phy/phch/test/pusch_test.c | 5 +++++ 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/lib/src/phy/phch/sch.c b/lib/src/phy/phch/sch.c index 0968ac41a..c740659c9 100644 --- a/lib/src/phy/phch/sch.c +++ b/lib/src/phy/phch/sch.c @@ -541,7 +541,17 @@ static int decode_tb(srsran_sch_t* q, par_tx = ((uint32_t)data[cb_segm->tbs / 8 + 0]) << 16 | ((uint32_t)data[cb_segm->tbs / 8 + 1]) << 8 | ((uint32_t)data[cb_segm->tbs / 8 + 2]); - if (par_rx == par_tx && par_rx) { + // Check if all the bytes are zeros + bool all_zeros = true; + for (uint32_t i = 0; i < cb_segm->tbs / 8 && all_zeros; i++) { + all_zeros = (data[i] == 0); + } + if (all_zeros) { + INFO("Error in TB decode: it is all zeros!"); + return SRSRAN_ERROR; + } + + if (par_rx == par_tx) { INFO("TB decoded OK"); return SRSRAN_SUCCESS; } else { diff --git a/lib/src/phy/phch/test/pdsch_test.c b/lib/src/phy/phch/test/pdsch_test.c index f8ea93227..e13f96a48 100644 --- a/lib/src/phy/phch/test/pdsch_test.c +++ b/lib/src/phy/phch/test/pdsch_test.c @@ -150,7 +150,7 @@ static int check_softbits(srsran_pdsch_t* pdsch_enb, if (!pdsch_ue->llr_is_8bit && !tb_cw_swap) { // Scramble - srsran_sequence_pdsch_apply_c(pdsch_ue->e[tb], + srsran_sequence_pdsch_apply_s(pdsch_ue->e[tb], pdsch_ue->e[tb], rnti, pdsch_cfg->grant.tb[tb].cw_idx, @@ -168,6 +168,10 @@ static int check_softbits(srsran_pdsch_t* pdsch_enb, rx_bytes[i] = w; } if (memcmp(pdsch_ue->e[tb], pdsch_enb->e[tb], pdsch_cfg->grant.tb[tb].nof_bits / 8) != 0) { + printf("tx="); + srsran_vec_fprint_byte(stdout, pdsch_enb->e[tb], pdsch_cfg->grant.tb[tb].nof_bits / 8); + printf("rx="); + srsran_vec_fprint_byte(stdout, pdsch_ue->e[tb], pdsch_cfg->grant.tb[tb].nof_bits / 8); ret = SRSRAN_ERROR; } } @@ -195,6 +199,7 @@ int main(int argc, char** argv) srsran_chest_dl_res_t chest_res; srsran_pdsch_res_t pdsch_res[SRSRAN_MAX_CODEWORDS]; srsran_random_t random_gen = srsran_random_init(0x1234); + srsran_crc_t crc_tb; /* Initialise to zeros */ ZERO_OBJECT(softbuffers_tx); @@ -212,6 +217,7 @@ int main(int argc, char** argv) ZERO_OBJECT(chest); ZERO_OBJECT(chest_res); ZERO_OBJECT(pdsch_res); + ZERO_OBJECT(crc_tb); parse_args(argc, argv); @@ -384,11 +390,19 @@ int main(int argc, char** argv) } } + if (srsran_crc_init(&crc_tb, SRSRAN_LTE_CRC24A, 24) < SRSRAN_SUCCESS) { + ERROR("Error initiating CRC24A"); + goto quit; + } + + // Generate random data for (int tb = 0; tb < SRSRAN_MAX_CODEWORDS; tb++) { if (pdsch_cfg.grant.tb[tb].enabled) { for (int byte = 0; byte < pdsch_cfg.grant.tb[tb].tbs / 8; byte++) { data_tx[tb][byte] = (uint8_t)srsran_random_uniform_int_dist(random_gen, 0, 255); } + // Attach CRC for making sure TB with 0 CRC are detected + srsran_crc_attach_byte(&crc_tb, data_tx[tb], pdsch_cfg.grant.tb[tb].tbs - 24); } } @@ -499,10 +513,12 @@ int main(int argc, char** argv) for (int tb = 0; tb < SRSRAN_MAX_CODEWORDS; tb++) { if (pdsch_cfg.grant.tb[tb].enabled) { if (check_softbits(&pdsch_tx, &pdsch_rx, &pdsch_cfg, subframe, tb)) { - printf("TB%d: The received softbits in subframe %d DO NOT match the encoded bits (crc=%d)\n", - tb, - subframe, - pdsch_res[tb].crc); + ERROR("TB%d: The received softbits in subframe %d DO NOT match the encoded bits (crc=%d)\n", + tb, + subframe, + pdsch_res[tb].crc); + ret = SRSRAN_ERROR; + goto quit; } else { for (int byte = 0; byte < pdsch_cfg.grant.tb[tb].tbs / 8; byte++) { if (data_tx[tb][byte] != data_rx[tb][byte]) { diff --git a/lib/src/phy/phch/test/pusch_test.c b/lib/src/phy/phch/test/pusch_test.c index d4c1a2bc8..7febc9b43 100644 --- a/lib/src/phy/phch/test/pusch_test.c +++ b/lib/src/phy/phch/test/pusch_test.c @@ -184,8 +184,10 @@ int main(int argc, char** argv) srsran_pusch_cfg_t cfg; srsran_softbuffer_tx_t softbuffer_tx; srsran_softbuffer_rx_t softbuffer_rx; + srsran_crc_t crc_tb; ZERO_OBJECT(uci_data_tx); + ZERO_OBJECT(crc_tb); bzero(&cfg, sizeof(srsran_pusch_cfg_t)); @@ -283,9 +285,12 @@ int main(int argc, char** argv) srsran_softbuffer_tx_reset(&softbuffer_tx); srsran_softbuffer_rx_reset(&softbuffer_rx); + // Generate random data for (uint32_t i = 0; i < cfg.grant.tb.tbs / 8; i++) { data[i] = (uint8_t)srsran_random_uniform_int_dist(random_h, 0, 255); } + // Attach CRC for making sure TB with 0 CRC are detected + srsran_crc_attach_byte(&crc_tb, data, cfg.grant.tb.tbs - 24); for (uint32_t a = 0; a < uci_data_tx.cfg.ack[0].nof_acks; a++) { uci_data_tx.value.ack.ack_value[a] = (uint8_t)srsran_random_uniform_int_dist(random_h, 0, 1); From f36f5271d3553c17be70f45b8f719508dcb1eafd Mon Sep 17 00:00:00 2001 From: Francisco Date: Fri, 28 May 2021 20:31:34 +0100 Subject: [PATCH 080/156] timers,feature: make timers thread-safe by using atomic to store timers state. --- lib/include/srsran/common/timers.h | 187 ++++++++++++++++++----------- lib/test/common/timer_test.cc | 72 ++++++----- 2 files changed, 159 insertions(+), 100 deletions(-) diff --git a/lib/include/srsran/common/timers.h b/lib/include/srsran/common/timers.h index a0fb6fc32..b1c1784e8 100644 --- a/lib/include/srsran/common/timers.h +++ b/lib/include/srsran/common/timers.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -37,8 +38,9 @@ public: }; /** - * Class that manages stack timers. It allows creation of unique_timers, with different ids. Each unique_timer duration, + * Class that manages stack timers. It allows creation of unique_timers with different ids. Each unique_timer duration, * and callback can be set via the set(...) method. A timer can be started/stopped via run()/stop() methods. + * The timers access/alteration is thread-safe. Just beware non-atomic uses of its getters. * Internal Data structures: * - timer_list - std::deque that stores timer objects via push_back() to keep pointer/reference validity. * The timer index in the timer_list matches the timer object id field. @@ -53,20 +55,34 @@ public: */ class timer_handler { - using tic_diff_t = uint32_t; - using tic_t = uint32_t; - constexpr static uint32_t INVALID_ID = std::numeric_limits::max(); - constexpr static tic_diff_t INVALID_TIME_DIFF = std::numeric_limits::max(); - constexpr static size_t WHEEL_SHIFT = 16U; - constexpr static size_t WHEEL_SIZE = 1U << WHEEL_SHIFT; - constexpr static size_t WHEEL_MASK = WHEEL_SIZE - 1U; + using tic_diff_t = uint32_t; + using tic_t = uint32_t; + constexpr static uint32_t INVALID_ID = std::numeric_limits::max(); + constexpr static size_t WHEEL_SHIFT = 16U; + constexpr static size_t WHEEL_SIZE = 1U << WHEEL_SHIFT; + constexpr static size_t WHEEL_MASK = WHEEL_SIZE - 1U; + + constexpr static uint64_t STOPPED_FLAG = 0U; + constexpr static uint64_t RUNNING_FLAG = static_cast(1U) << 63U; + constexpr static uint64_t EXPIRED_FLAG = static_cast(1U) << 62U; + constexpr static tic_diff_t MAX_TIMER_DURATION = 0x3FFFFFFFU; + + static bool decode_is_running(uint64_t value) { return (value & RUNNING_FLAG) != 0; } + static bool decode_is_expired(uint64_t value) { return (value & EXPIRED_FLAG) != 0; } + static tic_diff_t decode_duration(uint64_t value) { return (value >> 32U) & MAX_TIMER_DURATION; } + static tic_t decode_timeout(uint64_t value) { return static_cast(value & 0xFFFFFFFFU); } + static uint64_t encode_state(uint64_t mode_flag, uint32_t duration, uint32_t timeout) + { + return mode_flag + (static_cast(duration) << 32U) + timeout; + } struct timer_impl : public intrusive_double_linked_list_element<>, public intrusive_forward_list_element<> { - timer_handler& parent; + // const const uint32_t id; - tic_diff_t duration = INVALID_TIME_DIFF; - tic_t timeout = 0; - enum state_t : int8_t { empty, stopped, running, expired } state = empty; + timer_handler& parent; + // writes protected by backend lock + bool allocated = false; + std::atomic state{0}; ///< read can be without lock, thus writes must be atomic srsran::move_callback callback; explicit timer_impl(timer_handler& parent_, uint32_t id_) : parent(parent_), id(id_) {} @@ -75,32 +91,38 @@ class timer_handler timer_impl& operator=(const timer_impl&) = delete; timer_impl& operator=(timer_impl&&) = delete; - bool is_empty() const { return state == empty; } - bool is_running() const { return state == running; } - bool is_expired() const { return state == expired; } - tic_diff_t time_left() const { return is_running() ? timeout - parent.cur_time : (is_expired() ? 0 : duration); } - uint32_t time_elapsed() const { return duration - time_left(); } + // unprotected + bool is_running_() const { return decode_is_running(state.load(std::memory_order_relaxed)); } + bool is_expired_() const { return decode_is_expired(state.load(std::memory_order_relaxed)); } + uint32_t duration_() const { return decode_duration(state.load(std::memory_order_relaxed)); } + bool is_set_() const { return duration_() > 0; } + tic_diff_t time_elapsed_() const + { + uint64_t state_snapshot = state.load(std::memory_order_relaxed); + bool running = decode_is_running(state_snapshot), expired = decode_is_expired(state_snapshot); + uint32_t duration = decode_duration(state_snapshot), timeout = decode_timeout(state_snapshot); + return running ? duration - (timeout - parent.cur_time) : (expired ? duration : 0); + } - bool set(uint32_t duration_) + void set(uint32_t duration_) { - duration = std::max(duration_, 1U); // the next step will be one place ahead of current one - if (is_running()) { - // if already running, just extends timer lifetime - run(); - } else { - state = stopped; - timeout = 0; - } - return true; + srsran_assert(duration_ <= MAX_TIMER_DURATION, + "Invalid timer duration=%" PRIu32 ">%" PRIu32, + duration_, + MAX_TIMER_DURATION); + std::lock_guard lock(parent.mutex); + set_(duration_); } - bool set(uint32_t duration_, srsran::move_callback callback_) + void set(uint32_t duration_, srsran::move_callback callback_) { - if (set(duration_)) { - callback = std::move(callback_); - return true; - } - return false; + srsran_assert(duration_ <= MAX_TIMER_DURATION, + "Invalid timer duration=%" PRIu32 ">%" PRIu32, + duration_, + MAX_TIMER_DURATION); + std::lock_guard lock(parent.mutex); + set_(duration_); + callback = std::move(callback_); } void run() @@ -116,7 +138,25 @@ class timer_handler parent.stop_timer_(*this, false); } - void deallocate() { parent.dealloc_timer(*this); } + void deallocate() + { + std::lock_guard lock(parent.mutex); + parent.dealloc_timer_(*this); + } + + private: + void set_(uint32_t duration_) + { + duration_ = std::max(duration_, 1U); // the next step will be one place ahead of current one + // called in locked context + uint64_t old_state = state.load(std::memory_order_relaxed); + if (decode_is_running(old_state)) { + // if already running, just extends timer lifetime + parent.start_run_(*this, duration_); + } else { + state.store(encode_state(STOPPED_FLAG, duration_, 0), std::memory_order_relaxed); + } + } }; public: @@ -151,17 +191,12 @@ public: handle->set(duration_); } - bool is_set() const { return is_valid() and handle->duration != INVALID_TIME_DIFF; } - - bool is_running() const { return is_valid() and handle->is_running(); } - - bool is_expired() const { return is_valid() and handle->is_expired(); } - - tic_diff_t time_elapsed() const { return is_valid() ? handle->time_elapsed() : INVALID_TIME_DIFF; } - - uint32_t id() const { return is_valid() ? handle->id : INVALID_ID; } - - tic_diff_t duration() const { return is_valid() ? handle->duration : INVALID_TIME_DIFF; } + uint32_t id() const { return is_valid() ? handle->id : INVALID_ID; } + bool is_set() const { return is_valid() and handle->is_set_(); } + bool is_running() const { return is_valid() and handle->is_running_(); } + bool is_expired() const { return is_valid() and handle->is_expired_(); } + tic_diff_t time_elapsed() const { return is_valid() ? handle->time_elapsed_() : 0; } + tic_diff_t duration() const { return is_valid() ? handle->duration_() : 0; } void run() { @@ -205,13 +240,13 @@ public: void step_all() { std::unique_lock lock(mutex); - cur_time++; - auto& wheel_list = time_wheel[cur_time & WHEEL_MASK]; + uint32_t cur_time_local = cur_time.load(std::memory_order_relaxed) + 1; + auto& wheel_list = time_wheel[cur_time_local & WHEEL_MASK]; for (auto it = wheel_list.begin(); it != wheel_list.end();) { timer_impl& timer = timer_list[it->id]; ++it; - if (timer.timeout == cur_time) { + if (decode_timeout(timer.state.load(std::memory_order_relaxed)) == cur_time_local) { // stop timer (callback has to see the timer has already expired) stop_timer_(timer, true); @@ -227,6 +262,8 @@ public: } } } + + cur_time.fetch_add(1, std::memory_order_relaxed); } void stop_all() @@ -252,6 +289,8 @@ public: return nof_timers_running_; } + constexpr static uint32_t max_timer_duration() { return MAX_TIMER_DURATION; } + template void defer_callback(uint32_t duration, const F& func) { @@ -275,7 +314,7 @@ private: timer_impl* t; if (not free_list.empty()) { t = &free_list.front(); - srsran_assert(t->is_empty(), "Invalid timer id=%d state", t->id); + srsran_assert(not t->allocated, "Invalid timer id=%d state", t->id); free_list.pop_front(); nof_free_timers--; } else { @@ -283,63 +322,71 @@ private: timer_list.emplace_back(*this, timer_list.size()); t = &timer_list.back(); } - t->state = timer_impl::stopped; + t->allocated = true; return *t; } - void dealloc_timer(timer_impl& timer) + void dealloc_timer_(timer_impl& timer) { - std::lock_guard lock(mutex); - if (timer.is_empty()) { + if (not timer.allocated) { // already deallocated return; } stop_timer_(timer, false); - timer.state = timer_impl::empty; - timer.duration = INVALID_TIME_DIFF; - timer.timeout = 0; + timer.allocated = false; + timer.state.store(encode_state(STOPPED_FLAG, 0, 0), std::memory_order_relaxed); timer.callback = srsran::move_callback(); free_list.push_front(&timer); nof_free_timers++; // leave id unchanged. } - void start_run_(timer_impl& timer) + void start_run_(timer_impl& timer, uint32_t duration_ = 0) { - uint32_t timeout = cur_time + timer.duration; - size_t new_wheel_pos = timeout & WHEEL_MASK; - if (timer.is_running() and (timer.timeout & WHEEL_MASK) == new_wheel_pos) { + uint64_t timer_old_state = timer.state.load(std::memory_order_relaxed); + duration_ = duration_ == 0 ? decode_duration(timer_old_state) : duration_; + uint32_t new_timeout = cur_time.load(std::memory_order_relaxed) + duration_; + size_t new_wheel_pos = new_timeout & WHEEL_MASK; + + uint32_t old_timeout = decode_timeout(timer_old_state); + bool was_running = decode_is_running(timer_old_state); + if (was_running and (old_timeout & WHEEL_MASK) == new_wheel_pos) { // If no change in timer wheel position. Just update absolute timeout - timer.timeout = timeout; + timer.state.store(encode_state(RUNNING_FLAG, duration_, new_timeout), std::memory_order_relaxed); return; } // Stop timer if it was running, removing it from wheel in the process - stop_timer_(timer, false); + if (was_running) { + time_wheel[old_timeout & WHEEL_MASK].pop(&timer); + nof_timers_running_--; + } // Insert timer in wheel time_wheel[new_wheel_pos].push_front(&timer); - timer.timeout = timeout; - timer.state = timer_impl::running; + timer.state.store(encode_state(RUNNING_FLAG, duration_, new_timeout), std::memory_order_relaxed); nof_timers_running_++; } /// called when user manually stops timer (as an alternative to expiry) void stop_timer_(timer_impl& timer, bool expiry) { - if (not timer.is_running()) { + uint64_t timer_old_state = timer.state.load(std::memory_order_relaxed); + if (not decode_is_running(timer_old_state)) { return; } // If already running, need to disconnect it from previous wheel - time_wheel[timer.timeout & WHEEL_MASK].pop(&timer); - - timer.state = expiry ? timer_impl::expired : timer_impl::stopped; + uint32_t old_timeout = decode_timeout(timer_old_state); + time_wheel[old_timeout & WHEEL_MASK].pop(&timer); + uint64_t new_state = + encode_state(expiry ? EXPIRED_FLAG : STOPPED_FLAG, decode_duration(timer_old_state), old_timeout); + timer.state.store(new_state, std::memory_order_relaxed); nof_timers_running_--; } - tic_t cur_time = 0; - size_t nof_timers_running_ = 0, nof_free_timers = 0; + std::atomic cur_time{0}; + size_t nof_timers_running_ = 0, nof_free_timers = 0; // using a deque to maintain reference validity on emplace_back. Also, this deque will only grow. std::deque timer_list; srsran::intrusive_forward_list free_list; diff --git a/lib/test/common/timer_test.cc b/lib/test/common/timer_test.cc index 8663f8940..c1f265272 100644 --- a/lib/test/common/timer_test.cc +++ b/lib/test/common/timer_test.cc @@ -19,6 +19,8 @@ using namespace srsran; +static_assert(timer_handler::max_timer_duration() == 1073741823, "Invalid max duration"); + int timers_test1() { timer_handler timers; @@ -179,19 +181,23 @@ int timers_test3() } struct timers_test4_ctxt { - std::vector timers; - srsran::tti_sync_cv tti_sync1; - srsran::tti_sync_cv tti_sync2; - const uint32_t duration = 1000; + std::vector timers; + srsran::tti_sync_cv tti_sync1; + srsran::tti_sync_cv tti_sync2; + const uint32_t duration = 1000; }; static void timers2_test4_thread(timers_test4_ctxt* ctx) { - std::mt19937 mt19937(4); + std::random_device rd; + std::mt19937 mt19937(rd()); std::uniform_real_distribution real_dist(0.0f, 1.0f); for (uint32_t d = 0; d < ctx->duration; d++) { // make random events for (uint32_t i = 1; i < ctx->timers.size(); i++) { + // ensure the getters always return reasonable values + TESTASSERT(ctx->timers[i].time_elapsed() <= ctx->duration); + if (0.1f > real_dist(mt19937)) { ctx->timers[i].run(); } @@ -214,76 +220,82 @@ static void timers2_test4_thread(timers_test4_ctxt* ctx) int timers_test4() { - timers_test4_ctxt* ctx = new timers_test4_ctxt; timer_handler timers; + timers_test4_ctxt ctx; uint32_t nof_timers = 32; std::mt19937 mt19937(4); std::uniform_real_distribution real_dist(0.0f, 1.0f); // Generate all timers and start them for (uint32_t i = 0; i < nof_timers; i++) { - ctx->timers.push_back(timers.get_unique_timer()); - ctx->timers[i].set(ctx->duration); - ctx->timers[i].run(); + ctx.timers.push_back(timers.get_unique_timer()); + ctx.timers[i].set(ctx.duration); + ctx.timers[i].run(); } + /* ========== multithreaded region begin =========== */ + // Create side thread - std::thread thread(timers2_test4_thread, ctx); + std::thread thread(timers2_test4_thread, &ctx); - for (uint32_t d = 0; d < ctx->duration; d++) { + for (uint32_t d = 0; d < ctx.duration; d++) { // make random events for (uint32_t i = 1; i < nof_timers; i++) { + // ensure the getters always return reasonable values + TESTASSERT(ctx.timers[i].time_elapsed() <= ctx.duration); + if (0.1f > real_dist(mt19937)) { - ctx->timers[i].run(); + ctx.timers[i].run(); // restart run } if (0.1f > real_dist(mt19937)) { - ctx->timers[i].stop(); + ctx.timers[i].stop(); // stop run } if (0.1f > real_dist(mt19937)) { - ctx->timers[i].set(static_cast(ctx->duration * real_dist(mt19937))); - ctx->timers[i].run(); + ctx.timers[i].set(static_cast(ctx.duration * real_dist(mt19937))); + ctx.timers[i].run(); // start run with new duration } } - // first times, does not have event, it shall keep running - TESTASSERT(ctx->timers[0].is_running()); + // first timer does not get updated, so it shall keep running + TESTASSERT(ctx.timers[0].is_running()); // Increment time timers.step_all(); // wait second thread to finish events - ctx->tti_sync1.wait(); + ctx.tti_sync1.wait(); // assert no timer got wrong values for (uint32_t i = 0; i < nof_timers; i++) { - if (ctx->timers[i].is_running()) { - TESTASSERT(ctx->timers[i].time_elapsed() <= ctx->timers[i].duration()); + if (ctx.timers[i].is_running()) { + TESTASSERT(ctx.timers[i].time_elapsed() <= ctx.timers[i].duration()); + TESTASSERT(ctx.timers[i].duration() <= ctx.duration); } } // Start new TTI - ctx->tti_sync2.increase(); + ctx.tti_sync2.increase(); } // Finish asynchronous thread thread.join(); + /* ========== multithreaded region end =========== */ + // First timer should have expired - TESTASSERT(ctx->timers[0].is_expired()); - TESTASSERT(not ctx->timers[0].is_running()); + TESTASSERT(ctx.timers[0].is_expired()); + TESTASSERT(not ctx.timers[0].is_running()); // Run for the maximum period - for (uint32_t d = 0; d < ctx->duration; d++) { + for (uint32_t d = 0; d < ctx.duration; d++) { timers.step_all(); } // No timer should be running for (uint32_t i = 0; i < nof_timers; i++) { - TESTASSERT(not ctx->timers[i].is_running()); + TESTASSERT(not ctx.timers[i].is_running()); } - delete ctx; - return SRSRAN_SUCCESS; } @@ -355,12 +367,12 @@ int timers_test6() std::vector vals; - // Event: Add a timer that gets erased 1 tti after. + // Event: Add a timer that gets erased 1 tti after, and before expiring. { timer_handler::unique_timer t = timers.get_unique_timer(); t.set(2, [&vals](uint32_t tid) { vals.push_back(1); }); t.run(); - TESTASSERT(timers.nof_running_timers() == 1); + TESTASSERT(timers.nof_running_timers() == 1 and t.duration() == 2 and t.is_running()); timers.step_all(); } TESTASSERT(timers.nof_running_timers() == 0); @@ -375,7 +387,7 @@ int timers_test6() timer_handler::unique_timer t = timers.get_unique_timer(); t.set(2, [&vals](uint32_t tid) { vals.push_back(2); }); t.run(); - TESTASSERT(timers.nof_running_timers() == 1); + TESTASSERT(timers.nof_running_timers() == 1 and t.is_running()); timers.step_all(); TESTASSERT(t.time_elapsed() == 1); } From 2cdda3b6db78828969ea787135a686eb47b27170 Mon Sep 17 00:00:00 2001 From: Francisco Date: Mon, 31 May 2021 17:32:51 +0100 Subject: [PATCH 081/156] sched,enhancement: allow PUSCH allocations when PHICH falls in measurement Gap by resuming UL HARQ --- srsenb/hdr/stack/mac/sched_ue.h | 1 + .../hdr/stack/mac/sched_ue_ctrl/sched_harq.h | 8 ++- srsenb/src/stack/mac/sched_grid.cc | 37 ++++++---- srsenb/src/stack/mac/sched_ue.cc | 20 +++++- .../src/stack/mac/sched_ue_ctrl/sched_harq.cc | 64 ++++++++++------- .../stack/mac/sched_ue_ctrl/sched_ue_cell.cc | 2 +- srsenb/test/mac/sched_sim_ue.cc | 19 +++-- srsenb/test/mac/sched_test_rand.cc | 2 +- srsenb/test/mac/sched_ue_ded_test_suite.cc | 69 +++++++++++++------ 9 files changed, 148 insertions(+), 74 deletions(-) diff --git a/srsenb/hdr/stack/mac/sched_ue.h b/srsenb/hdr/stack/mac/sched_ue.h index 3b168080a..24b120cb4 100644 --- a/srsenb/hdr/stack/mac/sched_ue.h +++ b/srsenb/hdr/stack/mac/sched_ue.h @@ -138,6 +138,7 @@ public: bool pdsch_enabled(tti_point tti_rx, uint32_t enb_cc_idx) const; bool pusch_enabled(tti_point tti_rx, uint32_t enb_cc_idx, bool needs_pdcch) const; + bool phich_enabled(tti_point tti_rx, uint32_t enb_cc_idx) const; private: bool is_sr_triggered(); diff --git a/srsenb/hdr/stack/mac/sched_ue_ctrl/sched_harq.h b/srsenb/hdr/stack/mac/sched_ue_ctrl/sched_harq.h index d274296e9..7805a8b87 100644 --- a/srsenb/hdr/stack/mac/sched_ue_ctrl/sched_harq.h +++ b/srsenb/hdr/stack/mac/sched_ue_ctrl/sched_harq.h @@ -106,12 +106,14 @@ public: uint32_t get_pending_data() const; bool has_pending_phich() const; bool pop_pending_phich(); + void phich_alloc_failed(); private: prb_interval allocation; int pending_data; - bool pending_phich = false; - bool is_msg3_ = false; + bool pending_phich = false; + bool is_msg3_ = false; + bool pdcch_required = false; }; class harq_entity @@ -161,7 +163,7 @@ public: int set_ul_crc(srsran::tti_point tti_tx_ul, uint32_t tb_idx, bool ack_); //! Resets pending harq ACKs and cleans UL Harqs with maxretx == 0 - void reset_pending_data(srsran::tti_point tti_rx); + void finish_tti(srsran::tti_point tti_rx); private: dl_harq_proc* get_oldest_dl_harq(tti_point tti_tx_dl); diff --git a/srsenb/src/stack/mac/sched_grid.cc b/srsenb/src/stack/mac/sched_grid.cc index 4d1905dbc..755feb496 100644 --- a/srsenb/src/stack/mac/sched_grid.cc +++ b/srsenb/src/stack/mac/sched_grid.cc @@ -623,12 +623,6 @@ alloc_result sf_sched::alloc_phich(sched_ue* user) { using phich_t = sched_interface::ul_sched_phich_t; - auto* ul_sf_result = &cc_results->get_cc(cc_cfg->enb_cc_idx)->ul_sched_result; - if (ul_sf_result->phich.full()) { - logger.warning("SCHED: Maximum number of PHICH allocations has been reached"); - return alloc_result::no_grant_space; - } - auto p = user->get_active_cell_index(cc_cfg->enb_cc_idx); if (not p.first) { // user does not support this carrier @@ -636,15 +630,32 @@ alloc_result sf_sched::alloc_phich(sched_ue* user) } ul_harq_proc* h = user->get_ul_harq(get_tti_tx_ul(), cc_cfg->enb_cc_idx); + if (not h->has_pending_phich()) { + // No PHICH pending + return alloc_result::no_rnti_opportunity; + } - /* Indicate PHICH acknowledgment if needed */ - if (h->has_pending_phich()) { - ul_sf_result->phich.emplace_back(); - ul_sf_result->phich.back().rnti = user->get_rnti(); - ul_sf_result->phich.back().phich = h->pop_pending_phich() ? phich_t::ACK : phich_t::NACK; - return alloc_result::success; + auto* ul_sf_result = &cc_results->get_cc(cc_cfg->enb_cc_idx)->ul_sched_result; + if (ul_sf_result->phich.full()) { + logger.warning("SCHED: Maximum number of PHICH allocations has been reached"); + h->phich_alloc_failed(); + return alloc_result::no_grant_space; } - return alloc_result::no_rnti_opportunity; + + if (not user->phich_enabled(get_tti_rx(), cc_cfg->enb_cc_idx)) { + // PHICH falls in measGap. PHICH hi=1 is assumed by UE. In case of NACK, the HARQ is going to be resumed later on. + logger.debug("SCHED: HARQ pid=%d for rnti=0x%x is being resumed due to PHICH - MeasGap collision", + h->get_id(), + user->get_rnti()); + h->phich_alloc_failed(); + return alloc_result::no_cch_space; + } + + /* Indicate PHICH acknowledgment if needed */ + ul_sf_result->phich.emplace_back(); + ul_sf_result->phich.back().rnti = user->get_rnti(); + ul_sf_result->phich.back().phich = h->pop_pending_phich() ? phich_t::ACK : phich_t::NACK; + return alloc_result::success; } void sf_sched::set_dl_data_sched_result(const sf_cch_allocator::alloc_result_t& dci_result, diff --git a/srsenb/src/stack/mac/sched_ue.cc b/srsenb/src/stack/mac/sched_ue.cc index bbc55a486..7f56d6b99 100644 --- a/srsenb/src/stack/mac/sched_ue.cc +++ b/srsenb/src/stack/mac/sched_ue.cc @@ -214,7 +214,7 @@ bool sched_ue::pusch_enabled(tti_point tti_rx, uint32_t enb_cc_idx, bool needs_p tti_interval meas_gap{mgap_tti, mgap_tti + 6}; // disable TTIs that leads to PUSCH tx or PHICH rx falling in measGap - if (meas_gap.contains(tti_tx_ul) or meas_gap.contains(to_tx_ul_ack(tti_rx))) { + if (meas_gap.contains(tti_tx_ul)) { return false; } // disable TTIs which respective PDCCH falls in measGap (in case PDCCH is needed) @@ -225,6 +225,24 @@ bool sched_ue::pusch_enabled(tti_point tti_rx, uint32_t enb_cc_idx, bool needs_p return true; } +bool sched_ue::phich_enabled(tti_point tti_rx, uint32_t enb_cc_idx) const +{ + if (cfg.supported_cc_list[0].enb_cc_idx != enb_cc_idx) { + return true; + } + + // Check measGap collision with PHICH + if (cfg.measgap_period > 0) { + tti_point tti_tx_dl = to_tx_dl(tti_rx); + tti_point mgap_tti = nearest_meas_gap(tti_tx_dl, cfg.measgap_period, cfg.measgap_offset); + tti_interval meas_gap{mgap_tti, mgap_tti + 6}; + if (meas_gap.contains(tti_tx_dl)) { + return false; + } + } + return true; +} + int sched_ue::set_ack_info(tti_point tti_rx, uint32_t enb_cc_idx, uint32_t tb_idx, bool ack) { return cells[enb_cc_idx].set_ack_info(tti_rx, tb_idx, ack); diff --git a/srsenb/src/stack/mac/sched_ue_ctrl/sched_harq.cc b/srsenb/src/stack/mac/sched_ue_ctrl/sched_harq.cc index eb39f1bb2..fc7ab9c8d 100644 --- a/srsenb/src/stack/mac/sched_ue_ctrl/sched_harq.cc +++ b/srsenb/src/stack/mac/sched_ue_ctrl/sched_harq.cc @@ -112,11 +112,8 @@ void harq_proc::new_retx_common(uint32_t tb_idx, tti_point tti_, int* mcs, int* void harq_proc::reset_pending_data_common() { - // reuse harqs with no retxs - if (max_retx == 0 and not is_empty()) { - for (bool& tb : active) { - tb = false; - } + for (bool& tb : active) { + tb = false; } } @@ -250,9 +247,10 @@ void ul_harq_proc::new_tx(tti_point tti_, int mcs, int tbs, prb_interval alloc, { allocation = alloc; new_tx_common(0, tti_point{tti_}, mcs, tbs, max_retx_); - pending_data = tbs; - pending_phich = true; - is_msg3_ = is_msg3; + pending_data = tbs; + pending_phich = true; + is_msg3_ = is_msg3; + pdcch_required = false; } void ul_harq_proc::new_retx(tti_point tti_, int* mcs, int* tbs, prb_interval alloc) @@ -260,12 +258,15 @@ void ul_harq_proc::new_retx(tti_point tti_, int* mcs, int* tbs, prb_interval all // If PRBs changed, or there was no tx in last oportunity (e.g. HARQ is being resumed) allocation = alloc; new_retx_common(0, tti_point{tti_}, mcs, tbs); - pending_phich = true; + pending_phich = true; + pdcch_required = false; } -bool ul_harq_proc::retx_requires_pdcch(srsran::tti_point tti_, prb_interval alloc) const +bool ul_harq_proc::retx_requires_pdcch(tti_point tti_, prb_interval alloc) const { - return alloc != allocation or tti_ != to_tx_ul(tti); + // Adaptive retx if: (1) PRBs changed, (2) HARQ resumed due to last PUSCH retx being skipped (3) HARQ resumed due to + // last PHICH alloc being skipped (e.g. due to measGaps) + return alloc != allocation or tti_ != to_tx_ul(tti) or pdcch_required; } bool ul_harq_proc::set_ack(uint32_t tb_idx, bool ack_) @@ -282,15 +283,23 @@ bool ul_harq_proc::has_pending_phich() const return pending_phich; } +void ul_harq_proc::phich_alloc_failed() +{ + pop_pending_phich(); + if (not is_empty(0)) { + // HARQ needs to be resumed. This is signalled by pending_phich flag + pdcch_required = true; + } +} + bool ul_harq_proc::pop_pending_phich() { - assert(pending_phich); + srsran_assert(pending_phich, "pop_pending_phich called for HARQ with no pending PHICH"); bool ret = ack_state[0]; pending_phich = false; if (is_empty(0)) { - // fully reset UL HARQ once PHICH is dispatched - is_msg3_ = false; - pending_data = 0; + // fully reset HARQ info once PHICH is dispatched for an acked / maxretx reached HARQ + reset_pending_data(); } return ret; } @@ -298,10 +307,9 @@ bool ul_harq_proc::pop_pending_phich() void ul_harq_proc::reset_pending_data() { reset_pending_data_common(); - if (is_empty(0)) { - pending_data = 0; - is_msg3_ = false; - } + pending_data = 0; + is_msg3_ = false; + pdcch_required = false; } uint32_t ul_harq_proc::get_pending_data() const @@ -391,16 +399,20 @@ int harq_entity::set_ul_crc(tti_point tti_rx, uint32_t tb_idx, bool ack_) return h->set_ack(tb_idx, ack_) ? pid : -1; } -void harq_entity::reset_pending_data(tti_point tti_rx) +void harq_entity::finish_tti(tti_point tti_rx) { - tti_point tti_tx_ul = to_tx_ul(tti_rx); - - // Reset ACK state of UL Harq - get_ul_harq(tti_tx_ul)->reset_pending_data(); + // Reset UL HARQ if no retxs + auto* hul = get_ul_harq(to_tx_ul(tti_rx)); + if (not hul->is_empty() and hul->max_nof_retx() == 0) { + hul->reset_pending_data(); + } - // Reset any DL harq which has 0 retxs + // Reset DL harq which has 0 retxs for (auto& h : dl_harqs) { - h.reset_pending_data(); + if (not h.is_empty() and h.max_nof_retx() == 0) { + // reuse harqs with no retxs + h.reset_pending_data(); + } } } diff --git a/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc b/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc index 1a6bd1294..01e9d7efd 100644 --- a/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc +++ b/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc @@ -160,7 +160,7 @@ void sched_ue_cell::clear_feedback() void sched_ue_cell::finish_tti(tti_point tti_rx) { // clear_feedback PIDs with pending data or blocked - harq_ent.reset_pending_data(tti_rx); + harq_ent.finish_tti(tti_rx); } int sched_ue_cell::set_dl_wb_cqi(tti_point tti_rx, uint32_t dl_cqi_) diff --git a/srsenb/test/mac/sched_sim_ue.cc b/srsenb/test/mac/sched_sim_ue.cc index f359961b3..c510d6750 100644 --- a/srsenb/test/mac/sched_sim_ue.cc +++ b/srsenb/test/mac/sched_sim_ue.cc @@ -106,17 +106,19 @@ void ue_sim::update_ul_harqs(const sf_output_res_t& sf_out) { uint32_t pid = to_tx_ul(sf_out.tti_rx).to_uint() % (FDD_HARQ_DELAY_UL_MS + FDD_HARQ_DELAY_DL_MS); for (uint32_t cc = 0; cc < sf_out.cc_params.size(); ++cc) { + const auto *cc_cfg = ctxt.get_cc_cfg(cc), *start = &ctxt.ue_cfg.supported_cc_list[0]; + uint32_t ue_cc_idx = std::distance(start, cc_cfg); + auto& ue_cc_ctxt = ctxt.cc_list[ue_cc_idx]; + auto& h = ue_cc_ctxt.ul_harqs[pid]; + // Update UL harqs with PHICH info + bool found_phich = false; for (uint32_t i = 0; i < sf_out.ul_cc_result[cc].phich.size(); ++i) { const auto& phich = sf_out.ul_cc_result[cc].phich[i]; if (phich.rnti != ctxt.rnti) { continue; } - - const auto *cc_cfg = ctxt.get_cc_cfg(cc), *start = &ctxt.ue_cfg.supported_cc_list[0]; - uint32_t ue_cc_idx = std::distance(start, cc_cfg); - auto& ue_cc_ctxt = ctxt.cc_list[ue_cc_idx]; - auto& h = ue_cc_ctxt.ul_harqs[pid]; + found_phich = true; bool is_ack = phich.phich == phich_t::ACK; bool is_msg3 = @@ -126,6 +128,11 @@ void ue_sim::update_ul_harqs(const sf_output_res_t& sf_out) h.active = false; } } + if (h.active and not found_phich) { + // HARQ being resumed. Possibly due to measGap, PHICH may not be allocated. + logger.info("TESTER: rnti=0x%x, HARQ pid=%d being resumed.", ctxt.rnti, pid); + h.active = false; + } // Update UL harqs with PUSCH grants for (uint32_t i = 0; i < sf_out.ul_cc_result[cc].pusch.size(); ++i) { @@ -133,8 +140,6 @@ void ue_sim::update_ul_harqs(const sf_output_res_t& sf_out) if (data.dci.rnti != ctxt.rnti) { continue; } - auto& ue_cc_ctxt = ctxt.cc_list[data.dci.ue_cc_idx]; - auto& h = ue_cc_ctxt.ul_harqs[to_tx_ul(sf_out.tti_rx).to_uint() % ue_cc_ctxt.ul_harqs.size()]; if (h.nof_txs == 0 or h.ndi != data.dci.tb.ndi) { // newtx diff --git a/srsenb/test/mac/sched_test_rand.cc b/srsenb/test/mac/sched_test_rand.cc index 7fea30e46..76f56cc87 100644 --- a/srsenb/test/mac/sched_test_rand.cc +++ b/srsenb/test/mac/sched_test_rand.cc @@ -285,7 +285,7 @@ sched_sim_events rand_sim_params(uint32_t nof_ttis) sim_gen.sim_args.default_ue_sim_cfg.prob_ul_ack_mask.back() = 1; sim_gen.sim_args.default_ue_sim_cfg.ue_cfg.measgap_period = pick_random_uniform({0, 40, 80}); sim_gen.sim_args.default_ue_sim_cfg.ue_cfg.measgap_offset = std::uniform_int_distribution{ - 0, sim_gen.sim_args.default_ue_sim_cfg.ue_cfg.measgap_period}(srsenb::get_rand_gen()); + 0, std::max(sim_gen.sim_args.default_ue_sim_cfg.ue_cfg.measgap_period, 1u) - 1}(srsenb::get_rand_gen()); sim_gen.sim_args.default_ue_sim_cfg.ue_cfg.pucch_cfg.n_pucch_sr = std::uniform_int_distribution{0, 2047}(srsenb::get_rand_gen()); diff --git a/srsenb/test/mac/sched_ue_ded_test_suite.cc b/srsenb/test/mac/sched_ue_ded_test_suite.cc index 526a73ec3..63fc56b87 100644 --- a/srsenb/test/mac/sched_ue_ded_test_suite.cc +++ b/srsenb/test/mac/sched_ue_ded_test_suite.cc @@ -41,6 +41,13 @@ int sim_ue_ctxt_t::enb_to_ue_cc_idx(uint32_t enb_cc_idx) const return it == ue_cfg.supported_cc_list.end() ? -1 : std::distance(ue_cfg.supported_cc_list.begin(), it); } +const phich_t* find_phich_grant(uint16_t rnti, const sched_interface::ul_sched_res_t& ul_cc_res) +{ + const phich_t* phich_ptr = std::find_if( + ul_cc_res.phich.begin(), ul_cc_res.phich.end(), [rnti](const phich_t& phich) { return phich.rnti == rnti; }); + return phich_ptr == ul_cc_res.phich.end() ? nullptr : phich_ptr; +} + const pusch_t* find_pusch_grant(uint16_t rnti, const sched_interface::ul_sched_res_t& ul_cc_res) { const pusch_t* ptr = std::find_if( @@ -129,6 +136,22 @@ int test_dl_sched_result(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& return SRSRAN_SUCCESS; } +bool is_in_measgap(srsran::tti_point tti, uint32_t period, uint32_t offset) +{ + if (period == 0) { + return false; + } + uint32_t T = period / 10; + for (uint32_t i = 0; i < 6; ++i) { + tti_point tti_gap_start = tti - i; + bool is_gap_start = (tti_gap_start.sfn() % T == offset / 10) and (tti_gap_start.sf_idx() == offset % 10); + if (is_gap_start) { + return true; + } + } + return false; +} + int test_ul_sched_result(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& sf_out) { uint32_t pid = to_tx_ul(sf_out.tti_rx).to_uint() % (FDD_HARQ_DELAY_UL_MS + FDD_HARQ_DELAY_DL_MS); @@ -156,9 +179,7 @@ int test_ul_sched_result(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& uint16_t rnti = ue.rnti; int ue_cc_idx = ue.enb_to_ue_cc_idx(cc); - const phich_t* phich_ptr = - std::find_if(phich_begin, phich_end, [rnti](const phich_t& phich) { return phich.rnti == rnti; }); - phich_ptr = phich_ptr == phich_end ? nullptr : phich_ptr; + const phich_t* phich_ptr = find_phich_grant(rnti, sf_out.ul_cc_result[cc]); const pusch_t* pusch_ptr = find_pusch_grant(rnti, sf_out.ul_cc_result[cc]); // TEST: Check that idle CCs do not receive PUSCH grants or PHICH @@ -171,19 +192,26 @@ int test_ul_sched_result(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& const auto& h = ue.cc_list[ue_cc_idx].ul_harqs[pid]; bool phich_ack = phich_ptr != nullptr and phich_ptr->phich == phich_t::ACK; bool is_msg3 = h.first_tti_rx == ue.msg3_tti_rx and h.nof_txs == h.nof_retxs + 1; - bool last_retx = h.nof_retxs + 1 >= (is_msg3 ? sf_out.cc_params[0].cfg.maxharq_msg3tx : ue.ue_cfg.maxharq_tx); - bool h_inactive = (not h.active) or (phich_ack or last_retx); - - // TEST: Already active UL HARQs have to receive PHICH - CONDERROR(h.active and phich_ptr == nullptr, "PHICH not received for rnti=0x%x active UL HARQ pid=%d", rnti, pid); + bool last_retx = h.nof_retxs + 1 >= (is_msg3 ? sf_out.cc_params[0].cfg.maxharq_msg3tx : ue.ue_cfg.maxharq_tx); + tti_point tti_tx_phich = to_tx_dl(sf_out.tti_rx); + bool phich_in_meas_gap = is_in_measgap(tti_tx_phich, ue.ue_cfg.measgap_period, ue.ue_cfg.measgap_offset); + bool h_inactive_now = (not h.active) or (phich_ack or last_retx or phich_in_meas_gap); + + // TEST: Already active UL HARQs have to receive PHICH (unless MeasGap collision) + CONDERROR(h.active and phich_ptr == nullptr and not phich_in_meas_gap, + "PHICH not received for rnti=0x%x active UL HARQ pid=%d", + rnti, + pid); CONDERROR(not h.active and phich_ptr != nullptr, "PHICH for rnti=0x%x corresponds to inactive UL HARQ pid=%d", rnti, pid); // TEST: absent PUSCH grants for active UL HARQs must be either ACKs, last retx, or interrupted HARQs - if ((phich_ptr != nullptr) and (pusch_ptr == nullptr)) { - CONDERROR(not h_inactive, "PHICH NACK received for rnti=0x%x but no PUSCH retx reallocated", rnti); + if (phich_ptr != nullptr) { + CONDERROR(not h_inactive_now and pusch_ptr == nullptr, + "PHICH NACK received for rnti=0x%x but no PUSCH retx reallocated", + rnti); } if (pusch_ptr != nullptr) { @@ -196,7 +224,7 @@ int test_ul_sched_result(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& // newtx CONDERROR(nof_retx != 0, "Invalid rv index for new UL tx"); CONDERROR(pusch_ptr->current_tx_nb != 0, "UL HARQ retxs need to have been previously transmitted"); - CONDERROR(not h_inactive, "New tx for already active UL HARQ"); + CONDERROR(not h_inactive_now, "New tx for already active UL HARQ"); CONDERROR(not pusch_ptr->needs_pdcch and ue.msg3_tti_rx.is_valid() and sf_out.tti_rx > ue.msg3_tti_rx, "In case of newtx, PDCCH allocation is required, unless it is Msg3"); } else { @@ -211,11 +239,11 @@ int test_ul_sched_result(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& } else { // non-adaptive retx CONDERROR(pusch_ptr->dci.type2_alloc.riv != h.riv, "Non-adaptive retx must keep the same riv"); + CONDERROR(to_tx_ul(h.last_tti_rx) > sf_out.tti_rx, "UL harq pid=%d was reused too soon", h.pid); } } CONDERROR(get_rvidx(h.nof_retxs + 1) != (uint32_t)pusch_ptr->dci.tb.rv, "Invalid rv index for retx"); CONDERROR(h.tbs != pusch_ptr->tbs, "TBS changed during HARQ retx"); - CONDERROR(to_tx_ul(h.last_tti_rx) > sf_out.tti_rx, "UL harq pid=%d was reused too soon", h.pid); } } } @@ -355,12 +383,6 @@ int test_ra(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& sf_out) return SRSRAN_SUCCESS; } -bool is_in_measgap(srsran::tti_point tti, uint32_t period, uint32_t offset) -{ - uint32_t T = period / 10; - return (tti.sfn() % T == offset / 10) and (tti.sf_idx() == offset % 10); -} - int test_meas_gaps(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& sf_out) { for (uint32_t cc = 0; cc < enb_ctxt.cell_params.size(); ++cc) { @@ -371,16 +393,19 @@ int test_meas_gaps(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& sf_out uint16_t rnti = ue.rnti; uint32_t ue_cc_idx = ue.enb_to_ue_cc_idx(cc); srsran::tti_point tti_tx_ul = to_tx_ul(sf_out.tti_rx), tti_tx_dl = to_tx_dl(sf_out.tti_rx), - tti_tx_dl_ack = to_tx_dl_ack(sf_out.tti_rx), tti_tx_phich = to_tx_ul_ack(sf_out.tti_rx); + tti_tx_dl_ack = to_tx_dl_ack(sf_out.tti_rx); if (ue_cc_idx != 0 or ue.ue_cfg.measgap_period == 0) { continue; } - if (is_in_measgap(tti_tx_ul, ue.ue_cfg.measgap_period, ue.ue_cfg.measgap_offset) or - is_in_measgap(tti_tx_phich, ue.ue_cfg.measgap_period, ue.ue_cfg.measgap_offset)) { + if (is_in_measgap(tti_tx_dl, ue.ue_cfg.measgap_period, ue.ue_cfg.measgap_offset)) { + const phich_t* phich_ptr = find_phich_grant(rnti, ul_cc_res); + CONDERROR(phich_ptr != nullptr, "PHICH grants cannot fall in UE measGap"); + } + if (is_in_measgap(tti_tx_ul, ue.ue_cfg.measgap_period, ue.ue_cfg.measgap_offset)) { const pusch_t* pusch_ptr = find_pusch_grant(rnti, ul_cc_res); - CONDERROR(pusch_ptr != nullptr, "PUSCH grants and PHICH cannot fall in UE measGap"); + CONDERROR(pusch_ptr != nullptr, "PUSCH grants cannot fall in UE measGap"); } if (is_in_measgap(tti_tx_dl, ue.ue_cfg.measgap_period, ue.ue_cfg.measgap_offset) or is_in_measgap(tti_tx_dl_ack, ue.ue_cfg.measgap_period, ue.ue_cfg.measgap_offset)) { From f80c59112709a5bafe59007a64860d2a4999941d Mon Sep 17 00:00:00 2001 From: Francisco Date: Mon, 31 May 2021 18:18:44 +0100 Subject: [PATCH 082/156] sched,bugfix: fix scheduler CA test --- srsenb/test/mac/sched_sim_ue.cc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/srsenb/test/mac/sched_sim_ue.cc b/srsenb/test/mac/sched_sim_ue.cc index c510d6750..4ce4dc4ac 100644 --- a/srsenb/test/mac/sched_sim_ue.cc +++ b/srsenb/test/mac/sched_sim_ue.cc @@ -107,9 +107,12 @@ void ue_sim::update_ul_harqs(const sf_output_res_t& sf_out) uint32_t pid = to_tx_ul(sf_out.tti_rx).to_uint() % (FDD_HARQ_DELAY_UL_MS + FDD_HARQ_DELAY_DL_MS); for (uint32_t cc = 0; cc < sf_out.cc_params.size(); ++cc) { const auto *cc_cfg = ctxt.get_cc_cfg(cc), *start = &ctxt.ue_cfg.supported_cc_list[0]; - uint32_t ue_cc_idx = std::distance(start, cc_cfg); - auto& ue_cc_ctxt = ctxt.cc_list[ue_cc_idx]; - auto& h = ue_cc_ctxt.ul_harqs[pid]; + if (cc_cfg == nullptr) { + continue; + } + uint32_t ue_cc_idx = std::distance(start, cc_cfg); + auto& ue_cc_ctxt = ctxt.cc_list[ue_cc_idx]; + auto& h = ue_cc_ctxt.ul_harqs[pid]; // Update UL harqs with PHICH info bool found_phich = false; From 10a268fdbada5e1dc58a29aa17b9cda1874f966d Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 3 May 2021 15:21:53 +0200 Subject: [PATCH 083/156] Added SNR to phy_dl_test --- lib/test/phy/phy_dl_test.c | 39 +++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/lib/test/phy/phy_dl_test.c b/lib/test/phy/phy_dl_test.c index 81d2646d8..07b95edb7 100644 --- a/lib/test/phy/phy_dl_test.c +++ b/lib/test/phy/phy_dl_test.c @@ -35,6 +35,7 @@ static bool print_dci_table; static uint32_t mcs = 20; static int cross_carrier_indicator = -1; static bool enable_256qam = false; +static float snr_db = NAN; // SNR in dB void usage(char* prog) { @@ -47,6 +48,7 @@ void usage(char* prog) printf("\t-d Print DCI table [Default %s]\n", print_dci_table ? "yes" : "no"); printf("\t-t Transmission mode: 1,2,3,4 [Default %d]\n", transmission_mode + 1); printf("\t-m mcs [Default %d]\n", mcs); + printf("\t-S SNR in dB [Default %+.2f]\n", snr_db); printf("\tAdvanced parameters:\n"); if (cross_carrier_indicator >= 0) { printf("\t\t-a carrier-indicator [Default %d]\n", cross_carrier_indicator); @@ -85,7 +87,7 @@ void parse_args(int argc, char** argv) nof_rx_ant = 2; } - while ((opt = getopt(argc, argv, "cfapndvqstmE")) != -1) { + while ((opt = getopt(argc, argv, "cfapndvqstmES")) != -1) { switch (opt) { case 't': transmission_mode = (uint32_t)strtol(argv[optind], NULL, 10) - 1; @@ -112,6 +114,9 @@ void parse_args(int argc, char** argv) case 's': nof_subframes = (uint32_t)strtol(argv[optind], NULL, 10); break; + case 'S': + snr_db = strtof(argv[optind], NULL); + break; case 'E': cell.cp = ((uint32_t)strtol(argv[optind], NULL, 10)) ? SRSRAN_CP_EXT : SRSRAN_CP_NORM; break; @@ -316,6 +321,8 @@ int main(int argc, char** argv) uint32_t count_failures = 0, count_tbs = 0; size_t pdsch_decode_us = 0; size_t pdsch_encode_us = 0; + srsran_channel_awgn_t awgn = {}; + float snr_db_avg = 0.0; int ret = -1; @@ -334,6 +341,11 @@ int main(int argc, char** argv) } } + if (srsran_channel_awgn_init(&awgn, 0x1234) < SRSRAN_SUCCESS) { + ERROR("Error AWGN init"); + goto quit; + } + for (int i = 0; i < SRSRAN_MAX_TB; i++) { softbuffer_tx[i] = (srsran_softbuffer_tx_t*)calloc(sizeof(srsran_softbuffer_tx_t), 1); if (!softbuffer_tx[i]) { @@ -383,6 +395,17 @@ int main(int argc, char** argv) goto quit; } + /* + * Set AWGN N0 + */ + if (isnormal(snr_db)) { + if (srsran_channel_awgn_set_n0(&awgn, srsran_enb_dl_get_maximum_signal_power_dBfs(cell.nof_prb) - snr_db) < + SRSRAN_SUCCESS) { + ERROR("Error setting N0"); + goto quit; + } + } + /* * Initialise UE */ @@ -547,7 +570,10 @@ int main(int argc, char** argv) signal_buffer[0][i] = y0; signal_buffer[1][i] = y1; } + + srsran_channel_awgn_run_c(&awgn, signal_buffer[1], signal_buffer[1], SRSRAN_SF_LEN_PRB(cell.nof_prb)); } + srsran_channel_awgn_run_c(&awgn, signal_buffer[0], signal_buffer[0], SRSRAN_SF_LEN_PRB(cell.nof_prb)); /* * Run UE @@ -592,11 +618,13 @@ int main(int argc, char** argv) get_time_interval(t); pdsch_decode_us += (size_t)(t[0].tv_sec * 1e6 + t[0].tv_usec); + snr_db_avg += ue_dl->chest_res.snr_db; + for (int i = 0; i < SRSRAN_MAX_TB; i++) { if (ue_dl_cfg.cfg.pdsch.grant.tb[i].enabled) { - if (check_evm(enb_dl, ue_dl, &ue_dl_cfg, i)) { + if (!isnormal(snr_db) && check_evm(enb_dl, ue_dl, &ue_dl_cfg, i)) { count_failures++; - } else if (check_softbits(enb_dl, ue_dl, &ue_dl_cfg, sf_idx, i) != SRSRAN_SUCCESS) { + } else if (!isnormal(snr_db) && check_softbits(enb_dl, ue_dl, &ue_dl_cfg, sf_idx, i) != SRSRAN_SUCCESS) { printf("TB%d: The received softbits in subframe %d DO NOT match the encoded bits (crc=%d)\n", i, sf_idx, @@ -636,6 +664,10 @@ int main(int argc, char** argv) printf("BLER: %5.1f%%\n", (float)count_failures / (float)count_tbs * 100.0f); + if (isnormal(snr_db)) { + printf("SNR Real: %+.2f; estimated: %+.2f\n", snr_db, snr_db_avg / nof_subframes); + } + quit: srsran_enb_dl_free(enb_dl); srsran_ue_dl_free(ue_dl); @@ -672,6 +704,7 @@ quit: if (ue_dl) { free(ue_dl); } + srsran_channel_awgn_free(&awgn); if (ret) { printf("Error\n"); From 2ca0932d9ba2946210f611a331ceed9fa469c261 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 3 May 2021 15:23:38 +0200 Subject: [PATCH 084/156] Reviewed LTE noise estimation --- lib/src/phy/ch_estimation/chest_dl.c | 47 ++++++++++++++-------------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/lib/src/phy/ch_estimation/chest_dl.c b/lib/src/phy/ch_estimation/chest_dl.c index 92ee5f92e..7bfa06c76 100644 --- a/lib/src/phy/ch_estimation/chest_dl.c +++ b/lib/src/phy/ch_estimation/chest_dl.c @@ -323,15 +323,18 @@ static float estimate_noise_pilots(srsran_chest_dl_t* q, srsran_dl_sf_cfg_t* sf, : srsran_refsignal_cs_nof_re(&q->csr_refs, sf, port_id); uint32_t nsymbols = (ch_mode == SRSRAN_SF_MBSFN) ? srsran_refsignal_mbsfn_nof_symbols() : srsran_refsignal_cs_nof_symbols(&q->csr_refs, sf, port_id); + if (nsymbols == 0) { + ERROR("Invalid number of CRS symbols\n"); + return SRSRAN_ERROR; + } + uint32_t nref = npilots / nsymbols; uint32_t fidx = (ch_mode == SRSRAN_SF_MBSFN) ? srsran_refsignal_mbsfn_fidx(1) : srsran_refsignal_cs_fidx(q->cell, 0, port_id, 0); - - cf_t* input2d[nsymbols + 2]; cf_t* tmp_noise = q->tmp_noise; - // Special case for 1 symbol - if (nsymbols == 1) { + // Special case for 1 or 2 symbol + if (nsymbols < 3) { srsran_vec_sc_prod_cfc(q->pilot_estimates + 1, weight, tmp_noise, nref - 2); srsran_vec_sum_ccc(q->pilot_estimates + 0, tmp_noise, tmp_noise, nref - 2); srsran_vec_sum_ccc(q->pilot_estimates + 2, tmp_noise, tmp_noise, nref - 2); @@ -341,30 +344,21 @@ static float estimate_noise_pilots(srsran_chest_dl_t* q, srsran_dl_sf_cfg_t* sf, return sum_power; } + // Convert pilots to 2D to ease access + cf_t* input2d[4]; // The maximum number of symbols is 4 for (int i = 0; i < nsymbols; i++) { - input2d[i + 1] = &q->pilot_estimates[i * nref]; - } - - input2d[0] = &q->tmp_noise[nref]; - if (nsymbols > 3) { - srsran_vec_sc_prod_cfc(input2d[2], 2.0f, input2d[0], nref); - srsran_vec_sub_ccc(input2d[0], input2d[4], input2d[0], nref); - } else { - srsran_vec_sc_prod_cfc(input2d[2], 1.0f, input2d[0], nref); + input2d[i] = &q->pilot_estimates[i * nref]; } - input2d[nsymbols + 1] = &q->tmp_noise[nref * 2]; - if (nsymbols > 3) { - srsran_vec_sc_prod_cfc(input2d[nsymbols - 1], 2.0f, input2d[nsymbols + 1], nref); - srsran_vec_sub_ccc(input2d[nsymbols + 1], input2d[nsymbols - 3], input2d[nsymbols + 1], nref); - } else { - srsran_vec_sc_prod_cfc(input2d[nsymbols - 1], 1.0f, input2d[nsymbols + 1], nref); - } - - for (int i = 1; i < nsymbols + 1; i++) { + // Compares surrounding pilots in time/frequency. It requires at least 3 symbols with pilots. + for (int i = 1; i < nsymbols - 1; i++) { + // Calculate previous and next symbol indexes offset uint32_t offset = ((fidx < 3) ^ (i & 1)) ? 0 : 1; + + // Write estimates from this symbols srsran_vec_sc_prod_cfc(input2d[i], weight, tmp_noise, nref); + // Add the previous symbol estimates and extrapolate first/last element srsran_vec_sum_ccc(&input2d[i - 1][0], &tmp_noise[offset], &tmp_noise[offset], nref - offset); srsran_vec_sum_ccc(&input2d[i - 1][1 - offset], &tmp_noise[0], &tmp_noise[0], nref + offset - 1); if (offset) { @@ -373,6 +367,7 @@ static float estimate_noise_pilots(srsran_chest_dl_t* q, srsran_dl_sf_cfg_t* sf, tmp_noise[nref - 1] += 2.0f * input2d[i - 1][nref - 2] - input2d[i - 1][nref - 1]; } + // Add the next symbol estimates and extrapolate first/last element srsran_vec_sum_ccc(&input2d[i + 1][0], &tmp_noise[offset], &tmp_noise[offset], nref - offset); srsran_vec_sum_ccc(&input2d[i + 1][1 - offset], &tmp_noise[0], &tmp_noise[0], nref + offset - 1); if (offset) { @@ -381,14 +376,18 @@ static float estimate_noise_pilots(srsran_chest_dl_t* q, srsran_dl_sf_cfg_t* sf, tmp_noise[nref - 1] += 2.0f * input2d[i + 1][nref - 2] - input2d[i + 1][nref - 1]; } + // Scale to normalise to this symbol srsran_vec_sc_prod_cfc(tmp_noise, 1.0f / (weight + 4.0f), tmp_noise, nref); + // Subtract this symbol srsran_vec_sub_ccc(input2d[i], tmp_noise, tmp_noise, nref); - sum_power = srsran_vec_avg_power_cf(tmp_noise, nref); + + // The left signal after the subtraction can be considered noise + sum_power += srsran_vec_avg_power_cf(tmp_noise, nref); count++; } - return sum_power / (float)count * sqrtf(weight + 4.0f); + return sum_power / (float)count; } static float estimate_noise_pss(srsran_chest_dl_t* q, cf_t* input, cf_t* ce) From ce3c808a169ce12bff362e85c6a2f2dbcec4be4a Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Wed, 26 May 2021 12:50:16 +0200 Subject: [PATCH 085/156] Reviewed SRSENB PHY unused variables and log messages --- srsenb/hdr/phy/lte/sf_worker.h | 4 +--- srsenb/hdr/phy/txrx.h | 2 -- srsenb/src/phy/lte/cc_worker.cc | 9 ++++----- srsenb/src/phy/lte/sf_worker.cc | 18 ++++++------------ srsenb/src/phy/phy.cc | 5 +++-- srsenb/src/phy/phy_ue_db.cc | 6 ++++-- srsenb/src/phy/txrx.cc | 9 ++------- 7 files changed, 20 insertions(+), 33 deletions(-) diff --git a/srsenb/hdr/phy/lte/sf_worker.h b/srsenb/hdr/phy/lte/sf_worker.h index 4830fea55..b350f4939 100644 --- a/srsenb/hdr/phy/lte/sf_worker.h +++ b/srsenb/hdr/phy/lte/sf_worker.h @@ -32,7 +32,7 @@ public: void init(phy_common* phy); cf_t* get_buffer_rx(uint32_t cc_idx, uint32_t antenna_idx); - void set_time(uint32_t tti_, uint32_t tx_worker_cnt_, const srsran::rf_timestamp_t& tx_time_); + void set_time(uint32_t tti_, const srsran::rf_timestamp_t& tx_time_); int add_rnti(uint16_t rnti, uint32_t cc_idx); void rem_rnti(uint16_t rnti); @@ -60,8 +60,6 @@ private: std::mutex work_mutex; uint32_t tti_rx = 0, tti_tx_dl = 0, tti_tx_ul = 0; - uint32_t t_rx = 0, t_tx_dl = 0, t_tx_ul = 0; - uint32_t tx_worker_cnt = 0; srsran::rf_timestamp_t tx_time = {}; std::vector > cc_workers; diff --git a/srsenb/hdr/phy/txrx.h b/srsenb/hdr/phy/txrx.h index 18d4e8400..4b305c184 100644 --- a/srsenb/hdr/phy/txrx.h +++ b/srsenb/hdr/phy/txrx.h @@ -52,8 +52,6 @@ private: // Main system TTI counter uint32_t tti = 0; - uint32_t tx_worker_cnt = 0; - uint32_t nof_workers = 0; std::atomic running; }; diff --git a/srsenb/src/phy/lte/cc_worker.cc b/srsenb/src/phy/lte/cc_worker.cc index 2b5227f97..25a93fffe 100644 --- a/srsenb/src/phy/lte/cc_worker.cc +++ b/srsenb/src/phy/lte/cc_worker.cc @@ -187,8 +187,6 @@ void cc_worker::rem_rnti(uint16_t rnti) if (ue_db.count(rnti)) { delete ue_db[rnti]; ue_db.erase(rnti); - } else { - Error("Removing user: rnti=0x%x does not exist\n", rnti); } } @@ -273,7 +271,8 @@ void cc_worker::decode_pusch_rnti(stack_interface_phy_lte::ul_sched_grant_t& ul_ // Get UE configuration if (phy->ue_db.get_ul_config(rnti, cc_idx, ul_cfg) < SRSRAN_SUCCESS) { - Error("Error retrieving UL configuration for RNTI %x and CC %d", rnti, cc_idx); + // It could happen that the UL configuration is missing due to intra-enb HO which is not an error + Info("Failed retrieving UL configuration for cc=%d rnti=0x%x", cc_idx, rnti); return; } @@ -458,7 +457,7 @@ int cc_worker::encode_pdcch_ul(stack_interface_phy_lte::ul_sched_grant_t* grants srsran_dci_cfg_t dci_cfg = {}; if (phy->ue_db.get_dci_ul_config(grants[i].dci.rnti, cc_idx, dci_cfg) < SRSRAN_SUCCESS) { - Error("Error retrieving DCI UL configuration for RNTI %x, CC %d", grants[i].dci.rnti, cc_idx); + Error("Error retrieving DCI UL configuration for cc=%d rnti=0x%x", grants[i].dci.rnti, cc_idx); continue; } @@ -479,7 +478,7 @@ int cc_worker::encode_pdcch_ul(stack_interface_phy_lte::ul_sched_grant_t* grants if (logger.info.enabled()) { char str[512]; srsran_dci_ul_info(&grants[i].dci, str, 512); - logger.info("PDCCH: cc=%d, %s, tti_tx_dl=%d", cc_idx, str, tti_tx_dl); + logger.info("PDCCH: cc=%d, rnti=0x%x, %s, tti_tx_dl=%d", cc_idx, grants[i].dci.rnti, str, tti_tx_dl); } } } diff --git a/srsenb/src/phy/lte/sf_worker.cc b/srsenb/src/phy/lte/sf_worker.cc index 6ab897427..d95c43d9d 100644 --- a/srsenb/src/phy/lte/sf_worker.cc +++ b/srsenb/src/phy/lte/sf_worker.cc @@ -101,17 +101,12 @@ cf_t* sf_worker::get_buffer_rx(uint32_t cc_idx, uint32_t antenna_idx) return cc_workers[cc_idx]->get_buffer_rx(antenna_idx); } -void sf_worker::set_time(uint32_t tti_, uint32_t tx_worker_cnt_, const srsran::rf_timestamp_t& tx_time_) +void sf_worker::set_time(uint32_t tti_, const srsran::rf_timestamp_t& tx_time_) { tti_rx = tti_; tti_tx_dl = TTI_ADD(tti_rx, FDD_HARQ_DELAY_UL_MS); tti_tx_ul = TTI_RX_ACK(tti_rx); - t_tx_dl = TTIMOD(tti_tx_dl); - t_rx = TTIMOD(tti_rx); - t_tx_ul = TTIMOD(tti_tx_ul); - - tx_worker_cnt = tx_worker_cnt_; tx_time.copy(tx_time_); for (auto& w : cc_workers) { @@ -167,9 +162,9 @@ void sf_worker::work_imp() srsran_sf_t sf_type = phy->is_mbsfn_sf(&mbsfn_cfg, tti_tx_dl) ? SRSRAN_SF_MBSFN : SRSRAN_SF_NORM; // Uplink grants to receive this TTI - stack_interface_phy_lte::ul_sched_list_t ul_grants = phy->get_ul_grants(t_rx); + stack_interface_phy_lte::ul_sched_list_t ul_grants = phy->get_ul_grants(tti_rx); // Uplink grants to transmit this tti and receive in the future - stack_interface_phy_lte::ul_sched_list_t ul_grants_tx = phy->get_ul_grants(t_tx_ul); + stack_interface_phy_lte::ul_sched_list_t ul_grants_tx = phy->get_ul_grants(tti_tx_ul); // Downlink grants to transmit this TTI stack_interface_phy_lte::dl_sched_list_t dl_grants(phy->get_nof_carriers_lte()); @@ -184,8 +179,8 @@ void sf_worker::work_imp() ul_sf.tti = tti_rx; // Set UL grant availability prior to any UL processing - if (phy->ue_db.set_ul_grant_available(tti_rx, ul_grants)) { - Error("Error setting UL grants. Some grant's RNTI does not exist."); + if (phy->ue_db.set_ul_grant_available(tti_rx, ul_grants) < SRSRAN_SUCCESS) { + Info("Failed setting UL grants. Some grant's RNTI does not exist."); } // Process UL @@ -235,8 +230,7 @@ void sf_worker::work_imp() } // Save grants - phy->set_ul_grants(t_tx_ul, ul_grants_tx); - phy->set_ul_grants(t_rx, ul_grants); + phy->set_ul_grants(tti_tx_ul, ul_grants_tx); Debug("Sending to radio"); tx_buffer.set_nof_samples(SRSRAN_SF_LEN_PRB(phy->get_nof_prb(0))); diff --git a/srsenb/src/phy/phy.cc b/srsenb/src/phy/phy.cc index 8bbe4f712..1db96641c 100644 --- a/srsenb/src/phy/phy.cc +++ b/srsenb/src/phy/phy.cc @@ -105,9 +105,10 @@ int phy::init(const phy_args_t& args, } // Add PHY lib log. - srslog::basic_levels log_lvl = srslog::str_to_basic_level(args.log.phy_lib_level); + srslog::basic_levels lib_log_lvl = srslog::str_to_basic_level(args.log.phy_lib_level); + srslog::basic_levels log_lvl = srslog::str_to_basic_level(args.log.phy_level); - phy_lib_log.set_level(log_lvl); + phy_lib_log.set_level(lib_log_lvl); phy_lib_log.set_hex_dump_max_size(args.log.phy_hex_limit); if (log_lvl != srslog::basic_levels::none) { srsran_phy_log_register_handler(this, srsran_phy_handler); diff --git a/srsenb/src/phy/phy_ue_db.cc b/srsenb/src/phy/phy_ue_db.cc index 5988f164e..0932edb33 100644 --- a/srsenb/src/phy/phy_ue_db.cc +++ b/srsenb/src/phy/phy_ue_db.cc @@ -740,6 +740,7 @@ int phy_ue_db::get_last_ul_tb(uint16_t rnti, uint32_t enb_cc_idx, uint32_t pid, int phy_ue_db::set_ul_grant_available(uint32_t tti, const stack_interface_phy_lte::ul_sched_list_t& ul_sched_list) { + int ret = SRSRAN_SUCCESS; std::lock_guard lock(mutex); // Reset all available grants flags for the given TTI @@ -757,12 +758,13 @@ int phy_ue_db::set_ul_grant_available(uint32_t tti, const stack_interface_phy_lt uint16_t rnti = ul_sched_grant.dci.rnti; // Check that eNb Cell/Carrier is active for the given RNTI if (_assert_active_enb_cc(rnti, enb_cc_idx) != SRSRAN_SUCCESS) { - return SRSRAN_ERROR; + ret = SRSRAN_ERROR; + continue; } // Rise Grant available flag ue_db[rnti].cell_info[_get_ue_cc_idx(rnti, enb_cc_idx)].is_grant_available[tti] = true; } } - return SRSRAN_SUCCESS; + return ret; } diff --git a/srsenb/src/phy/txrx.cc b/srsenb/src/phy/txrx.cc index 03f1f0935..d78393550 100644 --- a/srsenb/src/phy/txrx.cc +++ b/srsenb/src/phy/txrx.cc @@ -53,11 +53,8 @@ bool txrx::init(stack_interface_phy_lte* stack_, nr_workers = nr_workers_; worker_com = worker_com_; prach = prach_; - tx_worker_cnt = 0; running = true; - nof_workers = lte_workers->get_nof_workers(); - // Instantiate UL channel emulator if (worker_com->params.ul_channel_args.enable) { ul_channel = srsran::channel_ptr( @@ -167,15 +164,13 @@ void txrx::run_thread() // Compute TX time: Any transmission happens in TTI+4 thus advance 4 ms the reception time timestamp.add(FDD_HARQ_DELAY_UL_MS * 1e-3); - Debug("Setting TTI=%d, tx_mutex=%d, tx_time=%ld:%f to worker %d", + Debug("Setting TTI=%d, tx_time=%ld:%f to worker %d", tti, - tx_worker_cnt, timestamp.get(0).full_secs, timestamp.get(0).frac_secs, lte_worker->get_id()); - lte_worker->set_time(tti, tx_worker_cnt, timestamp); - tx_worker_cnt = (tx_worker_cnt + 1) % nof_workers; + lte_worker->set_time(tti, timestamp); // Trigger prach worker execution for (uint32_t cc = 0; cc < worker_com->get_nof_carriers_lte(); cc++) { From 6de34524e2c3dababa8e3f7aed816dcae7f530a4 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Wed, 26 May 2021 13:58:58 +0200 Subject: [PATCH 086/156] Fix SRSENB PHY log line --- srsenb/src/phy/lte/cc_worker.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/srsenb/src/phy/lte/cc_worker.cc b/srsenb/src/phy/lte/cc_worker.cc index 25a93fffe..fe4b2e2bd 100644 --- a/srsenb/src/phy/lte/cc_worker.cc +++ b/srsenb/src/phy/lte/cc_worker.cc @@ -457,7 +457,7 @@ int cc_worker::encode_pdcch_ul(stack_interface_phy_lte::ul_sched_grant_t* grants srsran_dci_cfg_t dci_cfg = {}; if (phy->ue_db.get_dci_ul_config(grants[i].dci.rnti, cc_idx, dci_cfg) < SRSRAN_SUCCESS) { - Error("Error retrieving DCI UL configuration for cc=%d rnti=0x%x", grants[i].dci.rnti, cc_idx); + Error("Error retrieving DCI UL configuration for RNTI %x, CC %d", grants[i].dci.rnti, cc_idx); continue; } From bbab2cd9ba2bec4c306026720950e5733c124954 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Tue, 1 Jun 2021 13:13:45 +0200 Subject: [PATCH 087/156] Make PDCCH LLR mean amplitude in function of maximum --- lib/src/phy/phch/pdcch.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/lib/src/phy/phch/pdcch.c b/lib/src/phy/phch/pdcch.c index badcba244..3d2e79d48 100644 --- a/lib/src/phy/phch/pdcch.c +++ b/lib/src/phy/phch/pdcch.c @@ -36,7 +36,7 @@ float srsran_pdcch_coderate(uint32_t nof_bits, uint32_t l) { - static const int nof_bits_x_symbol = 2; //QPSK + static const int nof_bits_x_symbol = 2; // QPSK return (float)(nof_bits + 16) / (nof_bits_x_symbol * PDCCH_FORMAT_NOF_REGS(l)); } @@ -377,12 +377,23 @@ int srsran_pdcch_decode_msg(srsran_pdcch_t* q, srsran_dl_sf_cfg_t* sf, srsran_dc uint32_t nof_bits = srsran_dci_format_sizeof(&q->cell, sf, dci_cfg, msg->format); uint32_t e_bits = PDCCH_FORMAT_NOF_BITS(msg->location.L); + // Set threshold to 2/3 of absolute LLRs maximum for this candidate if bigger than 0.3. Otherwise set the + // threshold to 0.3. + uint32_t max_i = srsran_vec_max_abs_fi(&q->llr[msg->location.ncce * 72], e_bits); + if (max_i >= e_bits) { + ERROR("The impossible happened %d>=%d", max_i, e_bits); + return SRSRAN_ERROR; + } + double threshold = SRSRAN_MAX(0.3f, (2.0 / 3.0) * fabsf(q->llr[msg->location.ncce * 72 + max_i])); + + // Compute Root mean square of the LLRs double mean = 0; for (int i = 0; i < e_bits; i++) { mean += fabsf(q->llr[msg->location.ncce * 72 + i]); } mean /= e_bits; - if (mean > 0.3) { + + if (mean > threshold) { ret = srsran_pdcch_dci_decode(q, &q->llr[msg->location.ncce * 72], msg->payload, e_bits, nof_bits, &msg->rnti); if (ret == SRSRAN_SUCCESS) { msg->nof_bits = nof_bits; @@ -401,7 +412,12 @@ int srsran_pdcch_decode_msg(srsran_pdcch_t* q, srsran_dl_sf_cfg_t* sf, srsran_dc mean, msg->rnti); } else { - INFO("Skipping DCI: nCCE=%d, L=%d, msg_len=%d, mean=%f", msg->location.ncce, msg->location.L, nof_bits, mean); + INFO("Skipping DCI: nCCE=%d, L=%d, msg_len=%d, mean=%f, thr=%f", + msg->location.ncce, + msg->location.L, + nof_bits, + mean, + threshold); } } } else if (msg != NULL) { From 50b7d3937f39d37e5c889ceaab9deaf0880535c3 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Tue, 1 Jun 2021 13:14:27 +0200 Subject: [PATCH 088/156] Added RNTI in SRSENB PDCCH log line --- srsenb/src/phy/lte/cc_worker.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/srsenb/src/phy/lte/cc_worker.cc b/srsenb/src/phy/lte/cc_worker.cc index fe4b2e2bd..196e158cc 100644 --- a/srsenb/src/phy/lte/cc_worker.cc +++ b/srsenb/src/phy/lte/cc_worker.cc @@ -513,7 +513,7 @@ int cc_worker::encode_pdcch_dl(stack_interface_phy_lte::dl_sched_grant_t* grants // Logging char str[512]; srsran_dci_dl_info(&grants[i].dci, str, 512); - logger.info("PDCCH: cc=%d, %s, tti_tx_dl=%d", cc_idx, str, tti_tx_dl); + logger.info("PDCCH: cc=%d, rnti=0x%x, %s, tti_tx_dl=%d", cc_idx, grants[i].dci.rnti, str, tti_tx_dl); } } } From 2ace2b47b85de8be5fb1774f815b92814dcc7532 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Mon, 31 May 2021 13:05:13 +0200 Subject: [PATCH 089/156] pssch: fix uninitialized value --- lib/src/phy/phch/pssch.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/src/phy/phch/pssch.c b/lib/src/phy/phch/pssch.c index 759e36561..f2fa6cf0d 100644 --- a/lib/src/phy/phch/pssch.c +++ b/lib/src/phy/phch/pssch.c @@ -201,6 +201,8 @@ int srsran_pssch_init(srsran_pssch_t* q, ERROR("Error allocating memory"); return SRSRAN_ERROR; } + srsran_vec_cf_zero(q->scfdma_symbols, q->nof_data_symbols * SRSRAN_NRE * SRSRAN_MAX_PRB); + if (srsran_dft_precoding_init(&q->dft_precoder, SRSRAN_MAX_PRB, true)) { ERROR("Error DFT precoder init"); return SRSRAN_ERROR; From 3966065bff8d9289527ffb610651e8764480b329 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Mon, 31 May 2021 13:06:42 +0200 Subject: [PATCH 090/156] pssch_test: fix newlines in printf --- lib/src/phy/phch/test/pscch_test.c | 2 +- lib/src/phy/phch/test/pssch_pscch_file_test.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/src/phy/phch/test/pscch_test.c b/lib/src/phy/phch/test/pscch_test.c index 7d9b15990..b82b5fb1c 100644 --- a/lib/src/phy/phch/test/pscch_test.c +++ b/lib/src/phy/phch/test/pscch_test.c @@ -155,7 +155,7 @@ int main(int argc, char** argv) } srsran_sci_info(&sci, sci_msg, sizeof(sci_msg)); - fprintf(stdout, "%s", sci_msg); + fprintf(stdout, "%s\n", sci_msg); if (sci.riv == riv_txed) { ret = SRSRAN_SUCCESS; } diff --git a/lib/src/phy/phch/test/pssch_pscch_file_test.c b/lib/src/phy/phch/test/pssch_pscch_file_test.c index 9aef5eb66..47113978b 100644 --- a/lib/src/phy/phch/test/pssch_pscch_file_test.c +++ b/lib/src/phy/phch/test/pssch_pscch_file_test.c @@ -287,7 +287,7 @@ int main(int argc, char** argv) if (srsran_pscch_decode(&pscch, equalized_sf_buffer, sci_rx, pscch_prb_start_idx) == SRSRAN_SUCCESS) { if (srsran_sci_format0_unpack(&sci, sci_rx) == SRSRAN_SUCCESS) { srsran_sci_info(&sci, sci_msg, sizeof(sci_msg)); - fprintf(stdout, "%s", sci_msg); + fprintf(stdout, "%s\n", sci_msg); sci_decoded = true; num_decoded_sci++; @@ -348,7 +348,7 @@ int main(int argc, char** argv) if (srsran_pscch_decode(&pscch, equalized_sf_buffer, sci_rx, pscch_prb_start_idx) == SRSRAN_SUCCESS) { if (srsran_sci_format1_unpack(&sci, sci_rx) == SRSRAN_SUCCESS) { srsran_sci_info(&sci, sci_msg, sizeof(sci_msg)); - fprintf(stdout, "%s", sci_msg); + fprintf(stdout, "%s\n", sci_msg); num_decoded_sci++; From d329297151cd7916356b72d72f4d448fa34d76c9 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Tue, 1 Jun 2021 09:03:44 +0200 Subject: [PATCH 091/156] Implement radio invalid mapping countermeasure --- lib/src/radio/radio.cc | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/lib/src/radio/radio.cc b/lib/src/radio/radio.cc index f9b77dc82..e84dc6e0d 100644 --- a/lib/src/radio/radio.cc +++ b/lib/src/radio/radio.cc @@ -625,6 +625,14 @@ void radio::set_rx_freq(const uint32_t& carrier_idx, const double& freq) // Map carrier index to physical channel if (rx_channel_mapping.allocate_freq(carrier_idx, freq)) { channel_mapping::device_mapping_t device_mapping = rx_channel_mapping.get_device_mapping(carrier_idx); + if (device_mapping.carrier_idx >= nof_channels_x_dev) { + logger.error("Invalid mapping RF channel %d to logical carrier %d on f_rx=%.1f MHz", + device_mapping.carrier_idx, + carrier_idx, + freq / 1e6); + return; + } + logger.info("Mapping RF channel %d (device=%d, channel=%d) to logical carrier %d on f_rx=%.1f MHz", device_mapping.carrier_idx, device_mapping.device_idx, @@ -636,6 +644,12 @@ void radio::set_rx_freq(const uint32_t& carrier_idx, const double& freq) cur_rx_freqs[device_mapping.carrier_idx] = freq; for (uint32_t i = 0; i < nof_antennas; i++) { channel_mapping::device_mapping_t dm = rx_channel_mapping.get_device_mapping(carrier_idx, i); + if (dm.device_idx >= rf_devices.size() or dm.carrier_idx >= nof_channels_x_dev) { + logger.error( + "Invalid port mapping %d:%d to logical carrier %d on f_rx=%.1f MHz", carrier_idx, i, freq / 1e6); + return; + } + srsran_rf_set_rx_freq(&rf_devices[dm.device_idx], dm.channel_idx, freq + freq_offset); } } else { @@ -740,6 +754,14 @@ void radio::set_tx_freq(const uint32_t& carrier_idx, const double& freq) // Map carrier index to physical channel if (tx_channel_mapping.allocate_freq(carrier_idx, freq)) { channel_mapping::device_mapping_t device_mapping = tx_channel_mapping.get_device_mapping(carrier_idx); + if (device_mapping.carrier_idx >= nof_channels_x_dev) { + logger.error("Invalid mapping RF channel %d to logical carrier %d on f_tx=%.1f MHz", + device_mapping.carrier_idx, + carrier_idx, + freq / 1e6); + return; + } + logger.info("Mapping RF channel %d (device=%d, channel=%d) to logical carrier %d on f_tx=%.1f MHz", device_mapping.carrier_idx, device_mapping.device_idx, @@ -751,6 +773,11 @@ void radio::set_tx_freq(const uint32_t& carrier_idx, const double& freq) cur_tx_freqs[device_mapping.carrier_idx] = freq; for (uint32_t i = 0; i < nof_antennas; i++) { device_mapping = tx_channel_mapping.get_device_mapping(carrier_idx, i); + if (device_mapping.device_idx >= rf_devices.size() or device_mapping.carrier_idx >= nof_channels_x_dev) { + logger.error( + "Invalid port mapping %d:%d to logical carrier %d on f_rx=%.1f MHz", carrier_idx, i, freq / 1e6); + return; + } srsran_rf_set_tx_freq(&rf_devices[device_mapping.device_idx], device_mapping.channel_idx, freq + freq_offset); } From 2d0a21f779ee70a47101e69d86c119aa8ae963ee Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Tue, 1 Jun 2021 09:29:28 +0200 Subject: [PATCH 092/156] Move radio frequency mapping out of the PHY common into the PHY reset method --- srsue/src/phy/phy.cc | 7 +++++++ srsue/src/phy/phy_common.cc | 7 ------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/srsue/src/phy/phy.cc b/srsue/src/phy/phy.cc index e8df18a33..ada8d8083 100644 --- a/srsue/src/phy/phy.cc +++ b/srsue/src/phy/phy.cc @@ -389,6 +389,13 @@ void phy::reset() Info("Resetting PHY..."); common.ta.set_base_sec(0); common.reset(); + + // Release mapping of secondary cells + if (radio != nullptr) { + for (uint32_t i = 1; i < args.nof_lte_carriers; i++) { + radio->release_freq(i); + } + } } uint32_t phy::get_current_tti() diff --git a/srsue/src/phy/phy_common.cc b/srsue/src/phy/phy_common.cc index 6e0c350fe..836c7859d 100644 --- a/srsue/src/phy/phy_common.cc +++ b/srsue/src/phy/phy_common.cc @@ -906,13 +906,6 @@ void phy_common::reset() i = {}; } } - - // Release mapping of secondary cells - if (args != nullptr && radio_h != nullptr) { - for (uint32_t i = 1; i < args->nof_lte_carriers; i++) { - radio_h->release_freq(i); - } - } } /* Convert 6-bit maps to 10-element subframe tables From 4f7a94acb6251f1ac0d7f3a0587fbaf5140e3a0f Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Tue, 1 Jun 2021 15:06:48 +0200 Subject: [PATCH 093/156] Fix comment --- lib/src/phy/phch/pdcch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/phy/phch/pdcch.c b/lib/src/phy/phch/pdcch.c index 3d2e79d48..533a713fa 100644 --- a/lib/src/phy/phch/pdcch.c +++ b/lib/src/phy/phch/pdcch.c @@ -386,7 +386,7 @@ int srsran_pdcch_decode_msg(srsran_pdcch_t* q, srsran_dl_sf_cfg_t* sf, srsran_dc } double threshold = SRSRAN_MAX(0.3f, (2.0 / 3.0) * fabsf(q->llr[msg->location.ncce * 72 + max_i])); - // Compute Root mean square of the LLRs + // Compute absolute mean of the LLRs double mean = 0; for (int i = 0; i < e_bits; i++) { mean += fabsf(q->llr[msg->location.ncce * 72 + i]); From 18e2149d6879f4188d0309047d6a7cfa4b003326 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Mon, 10 May 2021 18:57:44 +0100 Subject: [PATCH 094/156] Sending Initial Context Setup Response after RRC reconfiguration. --- .../srsran/interfaces/enb_s1ap_interfaces.h | 5 +++-- srsenb/hdr/stack/s1ap/s1ap.h | 7 ++++-- srsenb/src/stack/rrc/rrc_ue.cc | 6 ++--- srsenb/src/stack/s1ap/s1ap.cc | 22 ++++++++++++++++++- srsenb/test/common/dummy_classes.h | 2 +- srsenb/test/s1ap/s1ap_test.cc | 4 ++-- 6 files changed, 35 insertions(+), 11 deletions(-) diff --git a/lib/include/srsran/interfaces/enb_s1ap_interfaces.h b/lib/include/srsran/interfaces/enb_s1ap_interfaces.h index 299f1fe4f..6bb07f353 100644 --- a/lib/include/srsran/interfaces/enb_s1ap_interfaces.h +++ b/lib/include/srsran/interfaces/enb_s1ap_interfaces.h @@ -59,8 +59,9 @@ public: virtual bool user_release(uint16_t rnti, asn1::s1ap::cause_radio_network_e cause_radio) = 0; virtual bool is_mme_connected() = 0; - /// TS 36.413, 8.3.1 - Initial Context Setup - virtual void ue_ctxt_setup_complete(uint16_t rnti) = 0; + // Notify S1AP of RRC reconfiguration successful finish. + // Many S1AP procedures use this notification to indicate successful end (e.g InitialContextSetupRequest) + virtual void notify_rrc_reconf_complete(uint16_t rnti) = 0; /** * Command the s1ap to transmit a HandoverRequired message to MME. diff --git a/srsenb/hdr/stack/s1ap/s1ap.h b/srsenb/hdr/stack/s1ap/s1ap.h index 73e214b93..57b330f4e 100644 --- a/srsenb/hdr/stack/s1ap/s1ap.h +++ b/srsenb/hdr/stack/s1ap/s1ap.h @@ -80,7 +80,7 @@ public: bool user_exists(uint16_t rnti) override; void user_mod(uint16_t old_rnti, uint16_t new_rnti) override; bool user_release(uint16_t rnti, asn1::s1ap::cause_radio_network_e cause_radio) override; - void ue_ctxt_setup_complete(uint16_t rnti) override; + void notify_rrc_reconf_complete(uint16_t rnti) override; bool is_mme_connected() override; bool send_ho_required(uint16_t rnti, uint32_t target_eci, @@ -110,7 +110,7 @@ public: // Stack interface bool - handle_mme_rx_msg(srsran::unique_byte_buffer_t pdu, const sockaddr_in& from, const sctp_sndrcvinfo& sri, int flags); + handle_mme_rx_msg(srsran::unique_byte_buffer_t pdu, const sockaddr_in& from, const sctp_sndrcvinfo& sri, int flags); void start_pcap(srsran::s1ap_pcap* pcap_); private: @@ -168,6 +168,8 @@ private: bool handle_erabreleasecommand(const asn1::s1ap::erab_release_cmd_s& msg); bool handle_uecontextmodifyrequest(const asn1::s1ap::ue_context_mod_request_s& msg); + void ue_ctxt_setup_complete(uint16_t rnti); + // handover /** * Source eNB Handler for S1AP "HANDOVER PREPARATION FAILURE" Message @@ -247,6 +249,7 @@ private: uint32_t m_tmsi = 0, uint8_t mmec = 0); void ue_ctxt_setup_complete(); + void notify_rrc_reconf_complete(); bool send_erab_setup_response(const erab_id_list& erabs_setup, const erab_item_list& erabs_failed); bool send_erab_release_response(const erab_id_list& erabs_released, const erab_item_list& erabs_failed); bool send_erab_modify_response(const erab_id_list& erabs_modified, const erab_item_list& erabs_failed); diff --git a/srsenb/src/stack/rrc/rrc_ue.cc b/srsenb/src/stack/rrc/rrc_ue.cc index 4181a6579..deaea1afc 100644 --- a/srsenb/src/stack/rrc/rrc_ue.cc +++ b/srsenb/src/stack/rrc/rrc_ue.cc @@ -332,9 +332,7 @@ void rrc::ue::parse_ul_dcch(uint32_t lcid, srsran::unique_byte_buffer_t pdu) break; case ul_dcch_msg_type_c::c1_c_::types::ue_cap_info: if (handle_ue_cap_info(&ul_dcch_msg.msg.c1().ue_cap_info())) { - parent->s1ap->ue_ctxt_setup_complete(rnti); send_connection_reconf(std::move(pdu)); - state = RRC_STATE_WAIT_FOR_CON_RECONF_COMPLETE; } else { send_connection_reject(procedure_result_code::none); state = RRC_STATE_IDLE; @@ -475,7 +473,6 @@ void rrc::ue::handle_rrc_con_setup_complete(rrc_conn_setup_complete_s* msg, srsr } else { parent->s1ap->initial_ue(rnti, enb_cc_idx, s1ap_cause, std::move(pdu)); } - state = RRC_STATE_WAIT_FOR_CON_RECONF_COMPLETE; // 2> if the UE has radio link failure or handover failure information available if (msg->crit_exts.type().value == c1_or_crit_ext_opts::c1 and @@ -828,6 +825,9 @@ void rrc::ue::handle_rrc_reconf_complete(rrc_conn_recfg_complete_s* msg, srsran: rlf_info_pending = false; send_ue_info_req(); } + + // Many S1AP procedures end with RRC Reconfiguration. Notify S1AP accordingly. + parent->s1ap->notify_rrc_reconf_complete(rnti); } void rrc::ue::send_ue_info_req() diff --git a/srsenb/src/stack/s1ap/s1ap.cc b/srsenb/src/stack/s1ap/s1ap.cc index 8f408627c..6fb0d8e8e 100644 --- a/srsenb/src/stack/s1ap/s1ap.cc +++ b/srsenb/src/stack/s1ap/s1ap.cc @@ -452,6 +452,15 @@ void s1ap::ue_ctxt_setup_complete(uint16_t rnti) u->ue_ctxt_setup_complete(); } +void s1ap::notify_rrc_reconf_complete(uint16_t rnti) +{ + ue* u = users.find_ue_rnti(rnti); + if (u == nullptr) { + return; + } + u->notify_rrc_reconf_complete(); +} + bool s1ap::is_mme_connected() { return mme_connected; @@ -1461,6 +1470,17 @@ bool s1ap::ue::send_uectxtreleasecomplete() return s1ap_ptr->sctp_send_s1ap_pdu(tx_pdu, ctxt.rnti, "UEContextReleaseComplete"); } +void s1ap::ue::notify_rrc_reconf_complete() +{ + if (current_state == s1ap_elem_procs_o::init_msg_c::types_opts::init_context_setup_request) { + logger.info("Procedure %s,rnti=0x%x - Received RRC reconf complete. Finishing UE context setup.", + s1ap_elem_procs_o::init_msg_c::types_opts{current_state}.to_string(), + ctxt.rnti); + ue_ctxt_setup_complete(); + return; + } +} + void s1ap::ue::ue_ctxt_setup_complete() { if (current_state != s1ap_elem_procs_o::init_msg_c::types_opts::init_context_setup_request) { @@ -1510,7 +1530,7 @@ void s1ap::ue::ue_ctxt_setup_complete() // Log event. event_logger::get().log_s1_ctx_create(ctxt.enb_cc_idx, ctxt.mme_ue_s1ap_id.value(), ctxt.enb_ue_s1ap_id, ctxt.rnti); - s1ap_ptr->sctp_send_s1ap_pdu(tx_pdu, ctxt.rnti, "E-RABSetupResponse"); + s1ap_ptr->sctp_send_s1ap_pdu(tx_pdu, ctxt.rnti, "InitialContextSetupResponse"); } bool s1ap::ue::send_erab_setup_response(const erab_id_list& erabs_setup, const erab_item_list& erabs_failed) diff --git a/srsenb/test/common/dummy_classes.h b/srsenb/test/common/dummy_classes.h index f4aff5085..6887b6546 100644 --- a/srsenb/test/common/dummy_classes.h +++ b/srsenb/test/common/dummy_classes.h @@ -104,7 +104,7 @@ public: void write_pdu(uint16_t rnti, srsran::unique_byte_buffer_t pdu) override {} bool user_exists(uint16_t rnti) override { return true; } bool user_release(uint16_t rnti, asn1::s1ap::cause_radio_network_e cause_radio) override { return true; } - void ue_ctxt_setup_complete(uint16_t rnti) override {} + void notify_rrc_reconf_complete(uint16_t rnti) override {} bool is_mme_connected() override { return true; } bool send_ho_required(uint16_t rnti, uint32_t target_eci, diff --git a/srsenb/test/s1ap/s1ap_test.cc b/srsenb/test/s1ap/s1ap_test.cc index c0641b6e4..5cc888e94 100644 --- a/srsenb/test/s1ap/s1ap_test.cc +++ b/srsenb/test/s1ap/s1ap_test.cc @@ -185,7 +185,7 @@ void add_rnti(s1ap& s1ap_obj, mme_dummy& mme) 0x40, 0x0a, 0x0a, 0x1f, 0x7f, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01}; cbref = asn1::cbit_ref(icsresp, sizeof(icsresp)); TESTASSERT(s1ap_pdu.unpack(cbref) == SRSRAN_SUCCESS); - s1ap_obj.ue_ctxt_setup_complete(0x46); + s1ap_obj.notify_rrc_reconf_complete(0x46); sdu = mme.read_msg(); TESTASSERT(sdu->N_bytes > 0); cbref = asn1::cbit_ref{sdu->msg, sdu->N_bytes}; @@ -329,4 +329,4 @@ int main(int argc, char** argv) test_s1ap_erab_setup(test_event::wrong_erabid_mod); test_s1ap_erab_setup(test_event::wrong_mme_s1ap_id); test_s1ap_erab_setup(test_event::repeated_erabid_mod); -} \ No newline at end of file +} From c23034e1a7d4f1388ea70fdc93dd1dbc62642188 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Thu, 27 May 2021 14:18:36 +0100 Subject: [PATCH 095/156] Make sure the S1AP state is reset after sending a successful/unsuccessful message --- srsenb/src/stack/s1ap/s1ap.cc | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/srsenb/src/stack/s1ap/s1ap.cc b/srsenb/src/stack/s1ap/s1ap.cc index 6fb0d8e8e..82cd36707 100644 --- a/srsenb/src/stack/s1ap/s1ap.cc +++ b/srsenb/src/stack/s1ap/s1ap.cc @@ -1499,7 +1499,14 @@ void s1ap::ue::ue_ctxt_setup_complete() container.enb_ue_s1ap_id.value = ctxt.enb_ue_s1ap_id; container.mme_ue_s1ap_id.value = ctxt.mme_ue_s1ap_id.value(); - container.cause.value = failed_cfg_erabs.front().cause; + if (not failed_cfg_erabs.empty()) { + container.cause.value = failed_cfg_erabs.front().cause; + } else { + logger.warning("Procedure %s,rnti=0x%x - no specified cause for failed configuration", + s1ap_elem_procs_o::init_msg_c::types_opts{current_state}.to_string(), + ctxt.rnti); + container.cause.value.set_misc().value = cause_misc_opts::unspecified; + } s1ap_ptr->sctp_send_s1ap_pdu(tx_pdu, ctxt.rnti, "UEContextModificationFailure"); return; } @@ -1836,7 +1843,6 @@ void s1ap::user_list::erase(ue* ue_ptr) /******************************************************************************* /* General helpers ********************************************************************************/ - bool s1ap::sctp_send_s1ap_pdu(const asn1::s1ap::s1ap_pdu_c& tx_pdu, uint32_t rnti, const char* procedure_name) { if (not mme_connected and rnti != SRSRAN_INVALID_RNTI) { @@ -1844,6 +1850,19 @@ bool s1ap::sctp_send_s1ap_pdu(const asn1::s1ap::s1ap_pdu_c& tx_pdu, uint32_t rnt return false; } + // Reset the state if it is a successful or unsucessfull message + if (tx_pdu.type() == s1ap_pdu_c::types_opts::successful_outcome || + tx_pdu.type() == s1ap_pdu_c::types_opts::unsuccessful_outcome) { + if (rnti != SRSRAN_INVALID_RNTI) { + s1ap::ue* u = users.find_ue_rnti(rnti); + if (u == nullptr) { + logger.warning("Could not find user for %s. RNTI=%x", procedure_name, rnti); + } else { + u->set_state(s1ap_proc_id_t::nulltype, {}, {}); + } + } + } + srsran::unique_byte_buffer_t buf = srsran::make_byte_buffer(); if (buf == nullptr) { logger.error("Fatal Error: Couldn't allocate buffer for %s.", procedure_name); From 8ab512c2bef0e750929c0165e194a3c87d2abd0a Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Thu, 27 May 2021 17:43:19 +0200 Subject: [PATCH 096/156] nas_test: fix TSAN warnings remove mutex and cvar again that we used to circumvent the startup. we now use a atomic variable to sync the main thread and the stack. --- srsue/test/upper/nas_test.cc | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/srsue/test/upper/nas_test.cc b/srsue/test/upper/nas_test.cc index a2ff89452..845690bc1 100644 --- a/srsue/test/upper/nas_test.cc +++ b/srsue/test/upper/nas_test.cc @@ -12,6 +12,7 @@ #include "srsran/common/bcd_helpers.h" #include "srsran/common/test_common.h" +#include "srsran/common/tsan_options.h" #include "srsran/interfaces/ue_pdcp_interfaces.h" #include "srsran/srslog/srslog.h" #include "srsran/test/ue_test_interfaces.h" @@ -145,10 +146,7 @@ public: void run_thread() { - std::unique_lock lk(init_mutex); running = true; - init_cv.notify_all(); - lk.unlock(); while (running) { task_sched.tic(); task_sched.run_pending_tasks(); @@ -157,18 +155,15 @@ public: } void stop() { - std::unique_lock lk(init_mutex); while (not running) { - init_cv.wait(lk); + usleep(1000); } running = false; wait_thread_finish(); } pdcp_interface_gw* pdcp = nullptr; srsue::nas* nas = nullptr; - bool running = false; - std::mutex init_mutex; - std::condition_variable init_cv; + std::atomic running = {false}; }; class gw_dummy : public gw_interface_nas, public gw_interface_pdcp From 1d34aa280f94fac9e1e1880d4be9157fc9ab1d9d Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Thu, 27 May 2021 17:59:37 +0200 Subject: [PATCH 097/156] byte_buffer_queue: make class thread-safe by using atomics --- lib/include/srsran/upper/byte_buffer_queue.h | 28 +++++++++++--------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/lib/include/srsran/upper/byte_buffer_queue.h b/lib/include/srsran/upper/byte_buffer_queue.h index 4c8a0aa14..0bddfb296 100644 --- a/lib/include/srsran/upper/byte_buffer_queue.h +++ b/lib/include/srsran/upper/byte_buffer_queue.h @@ -80,33 +80,37 @@ public: private: struct push_callback { - explicit push_callback(uint32_t& unread_bytes_, uint32_t& n_sdus_) : unread_bytes(&unread_bytes_), n_sdus(&n_sdus_) + explicit push_callback(std::atomic& unread_bytes_, std::atomic& n_sdus_) : + unread_bytes(unread_bytes_), n_sdus(n_sdus_) {} void operator()(const unique_byte_buffer_t& msg) { - *unread_bytes += msg->N_bytes; - (*n_sdus)++; + unread_bytes.fetch_add(msg->N_bytes, std::memory_order_relaxed); + n_sdus.fetch_add(1, std::memory_order_relaxed); } - uint32_t* unread_bytes; - uint32_t* n_sdus; + std::atomic& unread_bytes; + std::atomic& n_sdus; }; struct pop_callback { - explicit pop_callback(uint32_t& unread_bytes_, uint32_t& n_sdus_) : unread_bytes(&unread_bytes_), n_sdus(&n_sdus_) + explicit pop_callback(std::atomic& unread_bytes_, std::atomic& n_sdus_) : + unread_bytes(unread_bytes_), n_sdus(n_sdus_) {} void operator()(const unique_byte_buffer_t& msg) { if (msg == nullptr) { return; } - *unread_bytes -= std::min(msg->N_bytes, *unread_bytes); - *n_sdus = std::max(0, (int32_t)(*n_sdus) - 1); + // non-atomic update of both state variables + unread_bytes.fetch_sub(std::min(msg->N_bytes, unread_bytes.load(std::memory_order_relaxed)), + std::memory_order_relaxed); + n_sdus.store(std::max(0, (int32_t)(n_sdus.load(std::memory_order_relaxed)) - 1), std::memory_order_relaxed); } - uint32_t* unread_bytes; - uint32_t* n_sdus; + std::atomic& unread_bytes; + std::atomic& n_sdus; }; - uint32_t unread_bytes = 0; - uint32_t n_sdus = 0; + std::atomic unread_bytes = {0}; + std::atomic n_sdus = {0}; public: dyn_blocking_queue queue; From c434aac526a39e6bd76a60cde149566985142a28 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Thu, 27 May 2021 18:00:01 +0200 Subject: [PATCH 098/156] rlc_stress_test: include tsan options header --- lib/test/upper/rlc_stress_test.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/test/upper/rlc_stress_test.cc b/lib/test/upper/rlc_stress_test.cc index 54cd64eb1..5b2db1d91 100644 --- a/lib/test/upper/rlc_stress_test.cc +++ b/lib/test/upper/rlc_stress_test.cc @@ -15,6 +15,7 @@ #include "srsran/common/rlc_pcap.h" #include "srsran/common/test_common.h" #include "srsran/common/threads.h" +#include "srsran/common/tsan_options.h" #include "srsran/upper/rlc.h" #include #include From 312b5a241ceed4ecb0397ed2945a7881da94544f Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Thu, 27 May 2021 21:07:47 +0200 Subject: [PATCH 099/156] mac_pcap_base: fix race detected with TSAN --- lib/include/srsran/common/mac_pcap_base.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/include/srsran/common/mac_pcap_base.h b/lib/include/srsran/common/mac_pcap_base.h index 8eed68c9e..f80167853 100644 --- a/lib/include/srsran/common/mac_pcap_base.h +++ b/lib/include/srsran/common/mac_pcap_base.h @@ -95,7 +95,7 @@ protected: std::mutex mutex; srslog::basic_logger& logger; - bool running = false; + std::atomic running = {false}; static_blocking_queue queue; uint16_t ue_id = 0; From 1ef3cb7e5d0d8c52e31fb0aaa3adceb4923c634c Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Thu, 27 May 2021 21:15:20 +0200 Subject: [PATCH 100/156] threads: fix race in stopping periodic thread --- lib/include/srsran/common/threads.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/include/srsran/common/threads.h b/lib/include/srsran/common/threads.h index bbf8972d0..8f39f787f 100644 --- a/lib/include/srsran/common/threads.h +++ b/lib/include/srsran/common/threads.h @@ -35,6 +35,7 @@ void threads_print_self(); #ifdef __cplusplus } +#include #include namespace srsran { @@ -129,10 +130,10 @@ protected: virtual void run_period() = 0; private: - int wakeups_missed; - int timer_fd; - int period_us; - bool run_enable; + int wakeups_missed = 0; + int timer_fd = 0; + int period_us = 0; + std::atomic run_enable = {false}; void run_thread() { From 2c975732dc16f5fef5ba8e959877c6d2c02e6c6b Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Thu, 27 May 2021 21:15:43 +0200 Subject: [PATCH 101/156] metrics_stdout: fix race detected by TSAN --- srsenb/hdr/metrics_stdout.h | 6 +++--- srsue/hdr/metrics_stdout.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/srsenb/hdr/metrics_stdout.h b/srsenb/hdr/metrics_stdout.h index 494dcc08c..99fd1e009 100644 --- a/srsenb/hdr/metrics_stdout.h +++ b/srsenb/hdr/metrics_stdout.h @@ -41,9 +41,9 @@ private: std::string int_to_hex_string(int value, int field_width); std::string float_to_eng_string(float f, int digits); - bool do_print; - uint8_t n_reports; - enb_metrics_interface* enb; + std::atomic do_print = {false}; + uint8_t n_reports = 0; + enb_metrics_interface* enb = nullptr; }; } // namespace srsenb diff --git a/srsue/hdr/metrics_stdout.h b/srsue/hdr/metrics_stdout.h index 727461587..626a5f74a 100644 --- a/srsue/hdr/metrics_stdout.h +++ b/srsue/hdr/metrics_stdout.h @@ -50,7 +50,7 @@ private: std::string float_to_eng_string(float f, int digits); void print_table(const bool display_neighbours, const bool is_nr); - bool do_print = false; + std::atomic do_print = {false}; bool table_has_neighbours = false; ///< state of last table head uint8_t n_reports = 10; ue_metrics_interface* ue = nullptr; From 716caafd6c17eacc94a439910bb43eff8a8bad08 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Thu, 27 May 2021 21:38:17 +0200 Subject: [PATCH 102/156] multiqueue_test: fix race reported by TSAN --- lib/test/common/multiqueue_test.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/test/common/multiqueue_test.cc b/lib/test/common/multiqueue_test.cc index a82c6b45c..7ef198076 100644 --- a/lib/test/common/multiqueue_test.cc +++ b/lib/test/common/multiqueue_test.cc @@ -118,17 +118,17 @@ int test_multiqueue_threading() int capacity = 4, number = 0, start_number = 2, nof_pushes = capacity + 1; multiqueue_handler multiqueue(capacity); auto qid1 = multiqueue.add_queue(); - auto push_blocking_func = [](queue_handle* qid, int start_value, int nof_pushes, bool* is_running) { + std::atomic t1_running = {true}; + auto push_blocking_func = [&t1_running](queue_handle* qid, int start_value, int nof_pushes) { for (int i = 0; i < nof_pushes; ++i) { qid->push(start_value + i); std::cout << "t1: pushed item " << i << std::endl; } std::cout << "t1: pushed all items\n"; - *is_running = false; + t1_running = false; }; - bool t1_running = true; - std::thread t1(push_blocking_func, &qid1, start_number, nof_pushes, &t1_running); + std::thread t1(push_blocking_func, &qid1, start_number, nof_pushes); // Wait for queue to fill while ((int)qid1.size() != capacity) { From f823340a95cdbb3462d2015f4ed26a6058ffab60 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Thu, 27 May 2021 21:47:39 +0200 Subject: [PATCH 103/156] rf_imp: fix race when stopping gain thread detected with TSAN using benchmark_radio test --- lib/src/phy/rf/rf_imp.c | 2 ++ lib/src/radio/test/benchmark_radio.cc | 1 + 2 files changed, 3 insertions(+) diff --git a/lib/src/phy/rf/rf_imp.c b/lib/src/phy/rf/rf_imp.c index 8ed99f0c0..eb0cac1ad 100644 --- a/lib/src/phy/rf/rf_imp.c +++ b/lib/src/phy/rf/rf_imp.c @@ -175,7 +175,9 @@ int srsran_rf_close(srsran_rf_t* rf) { // Stop gain thread if (rf->thread_gain_run) { + pthread_mutex_lock(&rf->mutex); rf->thread_gain_run = false; + pthread_mutex_unlock(&rf->mutex); pthread_cond_signal(&rf->cond); pthread_join(rf->thread_gain, NULL); } diff --git a/lib/src/radio/test/benchmark_radio.cc b/lib/src/radio/test/benchmark_radio.cc index 26c9f3f23..ab88adcfd 100644 --- a/lib/src/radio/test/benchmark_radio.cc +++ b/lib/src/radio/test/benchmark_radio.cc @@ -25,6 +25,7 @@ extern "C" { //#undef I // Fix complex.h #define I nastiness when using C++ #endif +#include "srsran/common/tsan_options.h" #include "srsran/phy/utils/debug.h" #include "srsran/radio/radio.h" From b88f22b9fe899c0f906970399757f1c62a250db9 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Thu, 27 May 2021 21:49:54 +0200 Subject: [PATCH 104/156] network_utils_test: fix race detected with TSAN --- lib/test/common/network_utils_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/test/common/network_utils_test.cc b/lib/test/common/network_utils_test.cc index 2a9290777..5701e1d89 100644 --- a/lib/test/common/network_utils_test.cc +++ b/lib/test/common/network_utils_test.cc @@ -44,7 +44,7 @@ int test_socket_handler() { auto& logger = srslog::fetch_basic_logger("S1AP", false); - int counter = 0; + std::atomic counter = {0}; srsran::unique_socket server_socket, client_socket, client_socket2; srsran::socket_manager sockhandler; From 7ee38e6255cbe7789491e32ce48fb85b500934c9 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Thu, 27 May 2021 15:20:48 +0200 Subject: [PATCH 105/156] threads: disable thread attributes when compiled with TSAN TSAN doesn't work well then threads are created with attributes thar require root rights but the process is run as normal user. this patch avoid the thread attributes in this case. TSAN isn't going to be used for production builds. --- CMakeLists.txt | 2 +- lib/src/common/threads.c | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3b9e86333..a5682e077 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -486,7 +486,7 @@ if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang") endif (ENABLE_ASAN) if (ENABLE_TSAN) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=thread") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=thread -DHAVE_TSAN") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread") endif (ENABLE_TSAN) diff --git a/lib/src/common/threads.c b/lib/src/common/threads.c index a53aebfa8..bad3d05d7 100644 --- a/lib/src/common/threads.c +++ b/lib/src/common/threads.c @@ -136,6 +136,11 @@ bool threads_new_rt_cpu(pthread_t* thread, void* (*start_routine)(void*), void* } } +// TSAN seems to have issues with thread attributes when running as normal user, disable them in that case +#if HAVE_TSAN + attr_enable = false; +#endif + int err = pthread_create(thread, attr_enable ? &attr : NULL, start_routine, arg); if (err) { if (EPERM == err) { From 1529379e9ece4edf40a68c44df0d365afcae701d Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Thu, 27 May 2021 15:22:29 +0200 Subject: [PATCH 106/156] fec,pbch: remove unused variables unused code that moreover was causing TSAN to complain, e.g. in the ue_phy_test --- lib/src/phy/fec/convolutional/viterbi37_avx2_16bit.c | 2 -- lib/src/phy/phch/pbch.c | 4 ---- 2 files changed, 6 deletions(-) diff --git a/lib/src/phy/fec/convolutional/viterbi37_avx2_16bit.c b/lib/src/phy/fec/convolutional/viterbi37_avx2_16bit.c index 9f0aaabaa..6d143dbb1 100644 --- a/lib/src/phy/fec/convolutional/viterbi37_avx2_16bit.c +++ b/lib/src/phy/fec/convolutional/viterbi37_avx2_16bit.c @@ -43,7 +43,6 @@ union branchtab27 { } Branchtab37_sse2[3]; -int firstGo_16bit; /* State info for instance of Viterbi decoder */ struct v37 { metric_t metrics1; /* path metric buffer 1 */ @@ -85,7 +84,6 @@ int init_viterbi37_avx2_16bit(void* p, int starting_state) vp->metrics1.c[i] = 63; clear_v37_avx2_16bit(vp); - firstGo_16bit = 1; vp->old_metrics = &vp->metrics1; vp->new_metrics = &vp->metrics2; vp->dp = vp->decisions; diff --git a/lib/src/phy/phch/pbch.c b/lib/src/phy/phch/pbch.c index 4b2b5bcf9..eb51efa94 100644 --- a/lib/src/phy/phch/pbch.c +++ b/lib/src/phy/phch/pbch.c @@ -40,15 +40,11 @@ bool srsran_pbch_exists(int nframe, int nslot) return (!(nframe % 5) && nslot == 1); } -cf_t* offset_original; - int srsran_pbch_cp(cf_t* input, cf_t* output, srsran_cell_t cell, bool put) { int i; cf_t* ptr; - offset_original = input; - if (put) { ptr = input; output += cell.nof_prb * SRSRAN_NRE / 2 - 36; From 98a91a20579999f1717dc58ba929faeaccdc592a Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Thu, 27 May 2021 15:25:55 +0200 Subject: [PATCH 107/156] sync: protect sync_state, access ue_sync object only from one thread races detected with TSAN, primarily the ue_sync object which isn't thread-safe is accessed by all workers to set the CFO and by the sync thread to receive samples (which read the CFO). The patch introduces shadow variables that are updates from the main thread before/after the sync is executed. The atomic shadow variables can then be read from otherthreads without holding a mutex, i.e. blocking the sync. --- srsue/hdr/phy/sync.h | 9 ++++++--- srsue/hdr/phy/sync_state.h | 29 +++++++++++++---------------- srsue/src/phy/sync.cc | 30 ++++++++++++++++++++---------- 3 files changed, 39 insertions(+), 29 deletions(-) diff --git a/srsue/hdr/phy/sync.h b/srsue/hdr/phy/sync.h index 793abed94..09b177770 100644 --- a/srsue/hdr/phy/sync.h +++ b/srsue/hdr/phy/sync.h @@ -189,7 +189,7 @@ private: bool set_frequency(); bool set_cell(float cfo); - bool running = false; + std::atomic running = {false}; bool is_overflow = false; srsran::rf_timestamp_t last_rx_time; @@ -229,11 +229,14 @@ private: srsran::rf_buffer_t dummy_buffer; // Sync metrics + std::atomic sfo = {}; // SFO estimate updated after each sync-cycle + std::atomic cfo = {}; // CFO estimate updated after each sync-cycle + std::atomic ref_cfo = {}; // provided adjustment value applied before sync sync_metrics_t metrics = {}; // in-sync / out-of-sync counters - uint32_t out_of_sync_cnt = 0; - uint32_t in_sync_cnt = 0; + std::atomic out_of_sync_cnt = {0}; + std::atomic in_sync_cnt = {0}; std::mutex rrc_mutex; enum { diff --git a/srsue/hdr/phy/sync_state.h b/srsue/hdr/phy/sync_state.h index 2c10ebb6c..aa3338bf1 100644 --- a/srsue/hdr/phy/sync_state.h +++ b/srsue/hdr/phy/sync_state.h @@ -30,7 +30,7 @@ public: */ state_t run_state() { - std::lock_guard lock(inside); + std::lock_guard lock(mutex); cur_state = next_state; if (state_setting) { state_setting = false; @@ -43,7 +43,7 @@ public: // Called by the main thread at the end of each state to indicate it has finished. void state_exit(bool exit_ok = true) { - std::lock_guard lock(inside); + std::lock_guard lock(mutex); if (cur_state == SFN_SYNC && exit_ok == true) { next_state = CAMPING; } else { @@ -54,7 +54,7 @@ public: } void force_sfn_sync() { - std::lock_guard lock(inside); + std::lock_guard lock(mutex); next_state = SFN_SYNC; } @@ -65,20 +65,17 @@ public: */ void go_idle() { - std::lock_guard lock(outside); // Do not wait when transitioning to IDLE to avoid blocking - go_state_nowait(IDLE); + next_state = IDLE; } void run_cell_search() { - std::lock_guard lock(outside); go_state(CELL_SEARCH); wait_state_run(); wait_state_next(); } void run_sfn_sync() { - std::lock_guard lock(outside); go_state(SFN_SYNC); wait_state_run(); wait_state_next(); @@ -89,7 +86,7 @@ public: bool is_camping() { return cur_state == CAMPING; } bool wait_idle(uint32_t timeout_ms) { - std::unique_lock lock(outside); + std::unique_lock lock(mutex); // Avoid wasting time if the next state will not be IDLE if (next_state != IDLE) { @@ -116,6 +113,7 @@ public: const char* to_string() { + std::lock_guard lock(mutex); switch (cur_state) { case IDLE: return "IDLE"; @@ -135,7 +133,7 @@ public: private: void go_state(state_t s) { - std::unique_lock ul(inside); + std::unique_lock ul(mutex); next_state = s; state_setting = true; while (state_setting) { @@ -145,7 +143,7 @@ private: void go_state_nowait(state_t s) { - std::unique_lock ul(inside); + std::unique_lock ul(mutex); next_state = s; state_setting = true; } @@ -153,14 +151,14 @@ private: /* Waits until there is a call to set_state() and then run_state(). Returns when run_state() returns */ void wait_state_run() { - std::unique_lock ul(inside); + std::unique_lock ul(mutex); while (state_running) { cvar.wait(ul); } } void wait_state_next() { - std::unique_lock ul(inside); + std::unique_lock ul(mutex); while (cur_state != next_state) { cvar.wait(ul); } @@ -168,10 +166,9 @@ private: bool state_running = false; bool state_setting = false; - state_t cur_state = IDLE; - state_t next_state = IDLE; - std::mutex inside; - std::mutex outside; + std::atomic next_state = {IDLE}; // can be updated from outside (i.e. other thread) + state_t cur_state = IDLE; // will only be accessed when holding the mutex + std::mutex mutex; std::condition_variable cvar; }; diff --git a/srsue/src/phy/sync.cc b/srsue/src/phy/sync.cc index 76a8649bb..945bdc2fd 100644 --- a/srsue/src/phy/sync.cc +++ b/srsue/src/phy/sync.cc @@ -482,8 +482,9 @@ void sync::run_camping_in_sync_state(lte::sf_worker* lte_worker, Debug("SYNC: Worker %d synchronized", lte_worker->get_id()); - metrics.sfo = srsran_ue_sync_get_sfo(&ue_sync); - metrics.cfo = srsran_ue_sync_get_cfo(&ue_sync); + // Collect and provide metrics from last successful sync + metrics.sfo = sfo; + metrics.cfo = cfo; metrics.ta_us = worker_com->ta.get_usec(); for (uint32_t i = 0; i < worker_com->args->nof_lte_carriers; i++) { worker_com->set_sync_metrics(i, metrics); @@ -505,7 +506,7 @@ void sync::run_camping_in_sync_state(lte::sf_worker* lte_worker, // Set CFO for all Carriers for (uint32_t cc = 0; cc < worker_com->args->nof_lte_carriers; cc++) { lte_worker->set_cfo_unlocked(cc, get_tx_cfo()); - worker_com->update_cfo_measurement(cc, srsran_ue_sync_get_cfo(&ue_sync)); + worker_com->update_cfo_measurement(cc, cfo); } lte_worker->set_tti(tti); @@ -568,8 +569,18 @@ void sync::run_camping_state() } } + // Apply CFO adjustment if available + if (ref_cfo != 0.0) { + srsran_ue_sync_set_cfo_ref(&ue_sync, ref_cfo); + ref_cfo = 0.0; // reset until value changes again + } + // Primary Cell (PCell) Synchronization - switch (srsran_ue_sync_zerocopy(&ue_sync, sync_buffer.to_cf_t(), lte_worker->get_buffer_len())) { + int sync_result = srsran_ue_sync_zerocopy(&ue_sync, sync_buffer.to_cf_t(), lte_worker->get_buffer_len()); + cfo = srsran_ue_sync_get_cfo(&ue_sync); + sfo = srsran_ue_sync_get_sfo(&ue_sync); + + switch (sync_result) { case 1: run_camping_in_sync_state(lte_worker, nr_worker, sync_buffer); break; @@ -621,7 +632,7 @@ void sync::run_idle_state() void sync::run_thread() { - while (running) { + while (running.load(std::memory_order_relaxed)) { phy_lib_logger.set_context(tti); Debug("SYNC: state=%s, tti=%d", phy_state.to_string(), tti); @@ -683,7 +694,7 @@ void sync::in_sync() void sync::out_of_sync() { // Send RRC out-of-sync signal after NOF_OUT_OF_SYNC_SF consecutive subframes - Info("Out-of-sync %d/%d", out_of_sync_cnt, worker_com->args->nof_out_of_sync_events); + Info("Out-of-sync %d/%d", out_of_sync_cnt.load(std::memory_order_relaxed), worker_com->args->nof_out_of_sync_events); out_of_sync_cnt++; if (out_of_sync_cnt == worker_com->args->nof_out_of_sync_events) { Info("Sending to RRC"); @@ -695,7 +706,7 @@ void sync::out_of_sync() void sync::set_cfo(float cfo) { - srsran_ue_sync_set_cfo_ref(&ue_sync, cfo); + ref_cfo = cfo; } void sync::set_agc_enable(bool enable) @@ -724,7 +735,7 @@ void sync::set_agc_enable(bool enable) return; } - // Enable AGC + // Enable AGC (unprotected call to ue_sync must not happen outside of thread calling recv) srsran_ue_sync_start_agc( &ue_sync, callback_set_rx_gain, rf_info->min_rx_gain, rf_info->max_rx_gain, radio_h->get_rx_gain()); search_p.set_agc_enable(true); @@ -732,8 +743,7 @@ void sync::set_agc_enable(bool enable) float sync::get_tx_cfo() { - float cfo = srsran_ue_sync_get_cfo(&ue_sync); - + // Use CFO estimate from last successful sync float ret = cfo * ul_dl_factor; if (worker_com->args->cfo_is_doppler) { From f43e82a8a695f011c92c89c3daa8917734cc6228 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Thu, 27 May 2021 15:27:48 +0200 Subject: [PATCH 108/156] ue_phy_test: fix test --- srsue/test/phy/ue_phy_test.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/srsue/test/phy/ue_phy_test.cc b/srsue/test/phy/ue_phy_test.cc index 83f3e98f3..b2e4881c6 100644 --- a/srsue/test/phy/ue_phy_test.cc +++ b/srsue/test/phy/ue_phy_test.cc @@ -12,10 +12,10 @@ #include #include +#include #include #include #include -#include #include #define CALLBACK(NAME, ...) \ @@ -375,6 +375,9 @@ public: phy = std::unique_ptr(new srsue::phy); phy->init(phy_args, &stack, &radio); + // Wait PHY init to end + phy->wait_initialize(); + // Initialise DL baseband buffers for (uint32_t i = 0; i < cell.nof_ports; i++) { enb_dl_buffer[i] = srsran_vec_cf_malloc(sf_len); @@ -386,9 +389,6 @@ public: // Initialise eNb DL srsran_enb_dl_init(&enb_dl, enb_dl_buffer, SRSRAN_MAX_PRB); srsran_enb_dl_set_cell(&enb_dl, cell); - - // Wait PHY init to end - phy->wait_initialize(); } ~phy_test_bench() From d2ec3ca5e1dbeb0636640e2fce7c80e8b6ba192e Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Fri, 28 May 2021 09:48:19 +0200 Subject: [PATCH 109/156] intra_measure_base: fix race detected with TSAN use mutex to protect state getters --- srsue/hdr/phy/scell/intra_measure_base.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/srsue/hdr/phy/scell/intra_measure_base.h b/srsue/hdr/phy/scell/intra_measure_base.h index df6cd2a0e..e4836d71b 100644 --- a/srsue/hdr/phy/scell/intra_measure_base.h +++ b/srsue/hdr/phy/scell/intra_measure_base.h @@ -188,7 +188,11 @@ private: * @brief Get the internal state * @return protected state */ - state_t get_state() const { return state; } + state_t get_state() + { + std::lock_guard lock(mutex); + return state; + } /** * @brief Transitions to a different state, all transitions are allowed except from quit @@ -221,7 +225,7 @@ private: /** * @brief Computes the measurement trigger based on TTI and the last TTI trigger */ - bool receive_tti_trigger(uint32_t tti) const + bool receive_tti_trigger(uint32_t tti) { // If the elapsed time does not satisfy with the minimum time, do not trigger uint32_t elapsed_tti = TTI_SUB(tti, last_measure_tti); From b0a2f31478c70080f393b5b179f8292e23795a68 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Fri, 28 May 2021 09:55:32 +0200 Subject: [PATCH 110/156] prach: protect configuration and state getters with mutex purely TSAN with unit-test based approach that protects the state getters and configuration routines with a mutex --- srsue/hdr/phy/prach.h | 2 ++ srsue/src/phy/prach.cc | 9 ++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/srsue/hdr/phy/prach.h b/srsue/hdr/phy/prach.h index 3e2941b81..cfe9a272d 100644 --- a/srsue/hdr/phy/prach.h +++ b/srsue/hdr/phy/prach.h @@ -18,6 +18,7 @@ #include "srsran/srslog/srslog.h" #include "srsran/srsran.h" #include +#include namespace srsue { @@ -70,6 +71,7 @@ private: bool mem_initiated = false; bool cell_initiated = false; std::bitset buffer_bitmask; + mutable std::mutex mutex; }; } // namespace srsue diff --git a/srsue/src/phy/prach.cc b/srsue/src/phy/prach.cc index 3d4013bdb..86021bd95 100644 --- a/srsue/src/phy/prach.cc +++ b/srsue/src/phy/prach.cc @@ -83,6 +83,8 @@ void prach::stop() bool prach::set_cell(srsran_cell_t cell_, srsran_prach_cfg_t prach_cfg) { + std::lock_guard lock(mutex); + if (!mem_initiated) { ERROR("PRACH: Error must call init() first"); return false; @@ -147,6 +149,7 @@ bool prach::generate_buffer(uint32_t f_idx) bool prach::prepare_to_send(uint32_t preamble_idx_, int allowed_subframe_, float target_power_dbm_) { + std::lock_guard lock(mutex); if (preamble_idx_ >= max_preambles) { Error("PRACH: Invalid preamble %d", preamble_idx_); return false; @@ -162,7 +165,11 @@ bool prach::prepare_to_send(uint32_t preamble_idx_, int allowed_subframe_, float bool prach::is_pending() const { - return cell_initiated && preamble_idx >= 0 && unsigned(preamble_idx) < max_preambles; + std::unique_lock lock(mutex, std::try_to_lock); + if (lock.owns_lock()) { + return cell_initiated && preamble_idx >= 0 && unsigned(preamble_idx) < max_preambles; + } + return false; } bool prach::is_ready_to_send(uint32_t current_tti_, uint32_t current_pci) From 19af55b63d4dc9e655357ef86b3d40b01723c046 Mon Sep 17 00:00:00 2001 From: Francisco Date: Tue, 25 May 2021 11:03:05 +0100 Subject: [PATCH 111/156] bugfix, handover: Avoid sending UEContextReleaseRequest from Target eNB during S1 Handover due to UL KOs --- srsenb/src/stack/rrc/rrc_ue.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/srsenb/src/stack/rrc/rrc_ue.cc b/srsenb/src/stack/rrc/rrc_ue.cc index deaea1afc..e335f79d7 100644 --- a/srsenb/src/stack/rrc/rrc_ue.cc +++ b/srsenb/src/stack/rrc/rrc_ue.cc @@ -159,6 +159,13 @@ void rrc::ue::set_radiolink_ul_state(bool crc_res) return; } + if (mobility_handler->is_ho_running()) { + // Do not count UL KOs if handover is on-going. + // Source eNB should only rely in relocation timer + // Target eNB should either wait for UE to handover or explicit release by the MME + return; + } + // Count KOs in MAC and trigger release if it goes above a certain value. // This is done to detect out-of-coverage UEs if (phy_ul_rlf_timer.is_running()) { From 0349949ccec2a938f95db51cac9e43de4043ee6f Mon Sep 17 00:00:00 2001 From: Francisco Date: Tue, 25 May 2021 11:37:11 +0100 Subject: [PATCH 112/156] bugfix, handover: disable inactivity timer during s1 handover in target enb --- srsenb/hdr/stack/rrc/rrc_ue.h | 15 +++++++-------- srsenb/src/stack/rrc/rrc_mobility.cc | 1 + srsenb/src/stack/rrc/rrc_ue.cc | 22 +++++++++++++--------- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/srsenb/hdr/stack/rrc/rrc_ue.h b/srsenb/hdr/stack/rrc/rrc_ue.h index 236dc0cb7..4386caa03 100644 --- a/srsenb/hdr/stack/rrc/rrc_ue.h +++ b/srsenb/hdr/stack/rrc/rrc_ue.h @@ -25,6 +25,11 @@ class rrc::ue { public: class rrc_mobility; + enum activity_timeout_type_t { + MSG3_RX_TIMEOUT = 0, ///< Msg3 has its own timeout to quickly remove fake UEs from random PRACHs + UE_INACTIVITY_TIMEOUT, ///< UE inactivity timeout (usually bigger than reestablishment timeout) + nulltype + }; ue(rrc* outer_rrc, uint16_t rnti, const sched_interface::ue_cfg_t& ue_cfg); ~ue(); @@ -32,15 +37,9 @@ public: bool is_connected(); bool is_idle(); - typedef enum { - MSG3_RX_TIMEOUT = 0, ///< Msg3 has its own timeout to quickly remove fake UEs from random PRACHs - UE_INACTIVITY_TIMEOUT, ///< UE inactivity timeout (usually bigger than reestablishment timeout) - nulltype - } activity_timeout_type_t; - std::string to_string(const activity_timeout_type_t& type); - void set_activity_timeout(const activity_timeout_type_t type); - void set_activity(); + void set_activity_timeout(activity_timeout_type_t type); + void set_activity(bool enabled = true); void set_radiolink_dl_state(bool crc_res); void set_radiolink_ul_state(bool crc_res); void activity_timer_expired(const activity_timeout_type_t type); diff --git a/srsenb/src/stack/rrc/rrc_mobility.cc b/srsenb/src/stack/rrc/rrc_mobility.cc index 797def2b9..475396540 100644 --- a/srsenb/src/stack/rrc/rrc_mobility.cc +++ b/srsenb/src/stack/rrc/rrc_mobility.cc @@ -176,6 +176,7 @@ uint16_t rrc::start_ho_ue_resource_alloc(const asn1::s1ap::ho_request_s& ue* ue_ptr = it->second.get(); // Reset activity timer (Response is not expected) ue_ptr->set_activity_timeout(ue::UE_INACTIVITY_TIMEOUT); + ue_ptr->set_activity(false); // /* Setup e-RABs & DRBs / establish an UL/DL S1 bearer to the S-GW */ // if (not setup_ue_erabs(rnti, msg)) { diff --git a/srsenb/src/stack/rrc/rrc_ue.cc b/srsenb/src/stack/rrc/rrc_ue.cc index e335f79d7..1d7040873 100644 --- a/srsenb/src/stack/rrc/rrc_ue.cc +++ b/srsenb/src/stack/rrc/rrc_ue.cc @@ -100,11 +100,19 @@ void rrc::ue::get_metrics(rrc_ue_metrics_t& ue_metrics) const } } -void rrc::ue::set_activity() +void rrc::ue::set_activity(bool enabled) { if (rnti == SRSRAN_MRNTI) { return; } + if (not enabled) { + if (activity_timer.is_running()) { + parent->logger.debug("Inactivity timer interrupted for rnti=0x%x", rnti); + } + activity_timer.stop(); + return; + } + // re-start activity timer with current timeout value activity_timer.run(); parent->logger.debug("Activity registered for rnti=0x%x (timeout_value=%dms)", rnti, activity_timer.duration()); @@ -236,28 +244,24 @@ void rrc::ue::max_rlc_retx_reached() rlc_rlf_timer.run(); } -void rrc::ue::set_activity_timeout(const activity_timeout_type_t type) +void rrc::ue::set_activity_timeout(activity_timeout_type_t type) { - uint32_t deadline_s = 0; uint32_t deadline_ms = 0; switch (type) { case MSG3_RX_TIMEOUT: - deadline_s = 0; deadline_ms = static_cast( (get_ue_cc_cfg(UE_PCELL_CC_IDX)->sib2.rr_cfg_common.rach_cfg_common.max_harq_msg3_tx + 1) * 16); break; case UE_INACTIVITY_TIMEOUT: - deadline_s = parent->cfg.inactivity_timeout_ms / 1000; - deadline_ms = parent->cfg.inactivity_timeout_ms % 1000; + deadline_ms = parent->cfg.inactivity_timeout_ms; break; default: parent->logger.error("Unknown timeout type %d", type); } - uint32_t deadline = deadline_s * 1e3 + deadline_ms; - activity_timer.set(deadline, [this, type](uint32_t tid) { activity_timer_expired(type); }); - parent->logger.debug("Setting timer for %s for rnti=0x%x to %dms", to_string(type).c_str(), rnti, deadline); + activity_timer.set(deadline_ms, [this, type](uint32_t tid) { activity_timer_expired(type); }); + parent->logger.debug("Setting timer for %s for rnti=0x%x to %dms", to_string(type).c_str(), rnti, deadline_ms); set_activity(); } From 3f7553866072da819fd4ddb2addbb9dde845d9f4 Mon Sep 17 00:00:00 2001 From: Francisco Date: Fri, 28 May 2021 16:26:45 +0100 Subject: [PATCH 113/156] rrc,feature: Use t301 to set time that the enb waits for the UE RRCConnectionSetupComplete or ReestablishmentComplete --- srsenb/hdr/stack/rrc/rrc_ue.h | 1 + srsenb/src/stack/rrc/rrc_ue.cc | 43 ++++++++++++++++++++++------------ 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/srsenb/hdr/stack/rrc/rrc_ue.h b/srsenb/hdr/stack/rrc/rrc_ue.h index 4386caa03..b46302d62 100644 --- a/srsenb/hdr/stack/rrc/rrc_ue.h +++ b/srsenb/hdr/stack/rrc/rrc_ue.h @@ -28,6 +28,7 @@ public: enum activity_timeout_type_t { MSG3_RX_TIMEOUT = 0, ///< Msg3 has its own timeout to quickly remove fake UEs from random PRACHs UE_INACTIVITY_TIMEOUT, ///< UE inactivity timeout (usually bigger than reestablishment timeout) + MSG5_RX_TIMEOUT, ///< UE timeout for receiving RRCConnectionSetupComplete / RRCReestablishmentComplete nulltype }; diff --git a/srsenb/src/stack/rrc/rrc_ue.cc b/srsenb/src/stack/rrc/rrc_ue.cc index 1d7040873..bbb0791f4 100644 --- a/srsenb/src/stack/rrc/rrc_ue.cc +++ b/srsenb/src/stack/rrc/rrc_ue.cc @@ -43,7 +43,12 @@ rrc::ue::ue(rrc* outer_rrc, uint16_t rnti_, const sched_interface::ue_cfg_t& sch mac_ctrl(rnti, ue_cell_list, bearer_list, parent->cfg, parent->mac, *parent->cell_common_list, sched_ue_cfg) {} -rrc::ue::~ue() {} +rrc::ue::~ue() +{ + if (old_reest_rnti != SRSRAN_INVALID_RNTI and parent->users.count(old_reest_rnti) > 0) { + parent->rem_user(old_reest_rnti); + } +} int rrc::ue::init() { @@ -194,19 +199,23 @@ void rrc::ue::activity_timer_expired(const activity_timeout_type_t type) parent->logger.info("Activity timer for rnti=0x%x expired after %d ms", rnti, activity_timer.time_elapsed()); if (parent->s1ap->user_exists(rnti)) { - if (type == UE_INACTIVITY_TIMEOUT) { - parent->s1ap->user_release(rnti, asn1::s1ap::cause_radio_network_opts::user_inactivity); - con_release_result = procedure_result_code::activity_timeout; - } else if (type == MSG3_RX_TIMEOUT) { - // MSG3 timeout, no need to notify S1AP, just remove UE - parent->rem_user_thread(rnti); - con_release_result = procedure_result_code::msg3_timeout; - } else { - // Unhandled activity timeout, just remove UE and log an error - parent->rem_user_thread(rnti); - con_release_result = procedure_result_code::activity_timeout; - parent->logger.error( - "Unhandled reason for activity timer expiration. rnti=0x%x, cause %d", rnti, static_cast(type)); + switch (type) { + case UE_INACTIVITY_TIMEOUT: + parent->s1ap->user_release(rnti, asn1::s1ap::cause_radio_network_opts::user_inactivity); + con_release_result = procedure_result_code::activity_timeout; + break; + case MSG3_RX_TIMEOUT: + case MSG5_RX_TIMEOUT: + // MSG3 timeout, no need to notify S1AP, just remove UE + parent->rem_user_thread(rnti); + con_release_result = procedure_result_code::msg3_timeout; + break; + default: + // Unhandled activity timeout, just remove UE and log an error + parent->rem_user_thread(rnti); + con_release_result = procedure_result_code::activity_timeout; + parent->logger.error( + "Unhandled reason for activity timer expiration. rnti=0x%x, cause %d", rnti, static_cast(type)); } } else { parent->rem_user_thread(rnti); @@ -256,6 +265,9 @@ void rrc::ue::set_activity_timeout(activity_timeout_type_t type) case UE_INACTIVITY_TIMEOUT: deadline_ms = parent->cfg.inactivity_timeout_ms; break; + case MSG5_RX_TIMEOUT: + deadline_ms = get_ue_cc_cfg(UE_PCELL_CC_IDX)->sib2.ue_timers_and_consts.t301.to_number(); + break; default: parent->logger.error("Unknown timeout type %d", type); } @@ -617,7 +629,7 @@ void rrc::ue::handle_rrc_con_reest_req(rrc_conn_reest_request_s* msg) old_reest_rnti = old_rnti; state = RRC_STATE_WAIT_FOR_CON_REEST_COMPLETE; - set_activity_timeout(UE_INACTIVITY_TIMEOUT); + set_activity_timeout(MSG5_RX_TIMEOUT); } void rrc::ue::send_connection_reest(uint8_t ncc) @@ -700,6 +712,7 @@ void rrc::ue::handle_rrc_con_reest_complete(rrc_conn_reest_complete_s* msg, srsr // remove old RNTI parent->rem_user(old_reest_rnti); + old_reest_rnti = SRSRAN_INVALID_RNTI; state = RRC_STATE_REESTABLISHMENT_COMPLETE; From 47494a668dc53a679c928586f12d6c6dee730cfd Mon Sep 17 00:00:00 2001 From: Francisco Date: Mon, 31 May 2021 17:58:23 +0100 Subject: [PATCH 114/156] rrc,bugfix: fix reestablishment crash due to pointer invalidation --- srsenb/src/stack/rrc/rrc_ue.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/srsenb/src/stack/rrc/rrc_ue.cc b/srsenb/src/stack/rrc/rrc_ue.cc index bbb0791f4..01d1d7cba 100644 --- a/srsenb/src/stack/rrc/rrc_ue.cc +++ b/srsenb/src/stack/rrc/rrc_ue.cc @@ -46,7 +46,7 @@ rrc::ue::ue(rrc* outer_rrc, uint16_t rnti_, const sched_interface::ue_cfg_t& sch rrc::ue::~ue() { if (old_reest_rnti != SRSRAN_INVALID_RNTI and parent->users.count(old_reest_rnti) > 0) { - parent->rem_user(old_reest_rnti); + parent->rem_user_thread(old_reest_rnti); } } From dda52afe61b42692586b5a1205b24811b53522f8 Mon Sep 17 00:00:00 2001 From: Francisco Date: Wed, 26 May 2021 15:04:04 +0100 Subject: [PATCH 115/156] move rrc unit tests to rrc/ folder --- srsenb/test/rrc/CMakeLists.txt | 15 +++++++++++++++ srsenb/test/{upper => rrc}/erab_setup_test.cc | 2 +- srsenb/test/{upper => rrc}/rrc_meascfg_test.cc | 0 srsenb/test/{upper => rrc}/rrc_mobility_test.cc | 0 srsenb/test/{upper => rrc}/test_helpers.cc | 0 srsenb/test/{upper => rrc}/test_helpers.h | 0 srsenb/test/upper/CMakeLists.txt | 15 --------------- 7 files changed, 16 insertions(+), 16 deletions(-) rename srsenb/test/{upper => rrc}/erab_setup_test.cc (99%) rename srsenb/test/{upper => rrc}/rrc_meascfg_test.cc (100%) rename srsenb/test/{upper => rrc}/rrc_mobility_test.cc (100%) rename srsenb/test/{upper => rrc}/test_helpers.cc (100%) rename srsenb/test/{upper => rrc}/test_helpers.h (100%) diff --git a/srsenb/test/rrc/CMakeLists.txt b/srsenb/test/rrc/CMakeLists.txt index 800e2d088..c6e86a03d 100644 --- a/srsenb/test/rrc/CMakeLists.txt +++ b/srsenb/test/rrc/CMakeLists.txt @@ -6,7 +6,22 @@ # the distribution. # +add_library(test_helpers test_helpers.cc) +target_link_libraries(test_helpers srsenb_rrc srsenb_common rrc_asn1 s1ap_asn1 srsran_common enb_cfg_parser ${LIBCONFIGPP_LIBRARIES}) + add_executable(rrc_nr_test rrc_nr_test.cc) target_link_libraries(rrc_nr_test srsgnb_rrc srsran_common rrc_nr_asn1) add_test(rrc_nr_test rrc_nr_test) +add_executable(rrc_meascfg_test rrc_meascfg_test.cc) +target_link_libraries(rrc_meascfg_test test_helpers) + +add_executable(erab_setup_test erab_setup_test.cc) +target_link_libraries(erab_setup_test test_helpers ${LIBCONFIGPP_LIBRARIES}) + +add_executable(rrc_mobility_test rrc_mobility_test.cc) +target_link_libraries(rrc_mobility_test srsran_asn1 test_helpers) + +add_test(rrc_mobility_test rrc_mobility_test -i ${CMAKE_CURRENT_SOURCE_DIR}/../..) +add_test(erab_setup_test erab_setup_test -i ${CMAKE_CURRENT_SOURCE_DIR}/../..) +add_test(rrc_meascfg_test rrc_meascfg_test -i ${CMAKE_CURRENT_SOURCE_DIR}/../..) diff --git a/srsenb/test/upper/erab_setup_test.cc b/srsenb/test/rrc/erab_setup_test.cc similarity index 99% rename from srsenb/test/upper/erab_setup_test.cc rename to srsenb/test/rrc/erab_setup_test.cc index fdd07990b..1c96eac72 100644 --- a/srsenb/test/upper/erab_setup_test.cc +++ b/srsenb/test/rrc/erab_setup_test.cc @@ -12,9 +12,9 @@ #include "srsenb/hdr/enb.h" #include "srsenb/src/enb_cfg_parser.h" +#include "srsenb/test/rrc/test_helpers.h" #include "srsran/asn1/rrc_utils.h" #include "srsran/common/test_common.h" -#include "test_helpers.h" #include int test_erab_setup(srsran::log_sink_spy& spy, bool qci_exists) diff --git a/srsenb/test/upper/rrc_meascfg_test.cc b/srsenb/test/rrc/rrc_meascfg_test.cc similarity index 100% rename from srsenb/test/upper/rrc_meascfg_test.cc rename to srsenb/test/rrc/rrc_meascfg_test.cc diff --git a/srsenb/test/upper/rrc_mobility_test.cc b/srsenb/test/rrc/rrc_mobility_test.cc similarity index 100% rename from srsenb/test/upper/rrc_mobility_test.cc rename to srsenb/test/rrc/rrc_mobility_test.cc diff --git a/srsenb/test/upper/test_helpers.cc b/srsenb/test/rrc/test_helpers.cc similarity index 100% rename from srsenb/test/upper/test_helpers.cc rename to srsenb/test/rrc/test_helpers.cc diff --git a/srsenb/test/upper/test_helpers.h b/srsenb/test/rrc/test_helpers.h similarity index 100% rename from srsenb/test/upper/test_helpers.h rename to srsenb/test/rrc/test_helpers.h diff --git a/srsenb/test/upper/CMakeLists.txt b/srsenb/test/upper/CMakeLists.txt index d3eb8ac8d..73cd6eab0 100644 --- a/srsenb/test/upper/CMakeLists.txt +++ b/srsenb/test/upper/CMakeLists.txt @@ -6,28 +6,13 @@ # the distribution. # -add_library(test_helpers test_helpers.cc) -target_link_libraries(test_helpers srsenb_rrc srsenb_common rrc_asn1 s1ap_asn1 srsran_common enb_cfg_parser ${LIBCONFIGPP_LIBRARIES}) - # Simple PLMN -> MCC/MNC test add_executable(plmn_test plmn_test.cc) target_link_libraries(plmn_test rrc_asn1) -add_executable(rrc_mobility_test rrc_mobility_test.cc) -target_link_libraries(rrc_mobility_test srsran_asn1 test_helpers) - -add_executable(erab_setup_test erab_setup_test.cc) -target_link_libraries(erab_setup_test test_helpers ${LIBCONFIGPP_LIBRARIES}) - -add_executable(rrc_meascfg_test rrc_meascfg_test.cc) -target_link_libraries(rrc_meascfg_test test_helpers) - add_executable(gtpu_test gtpu_test.cc) target_link_libraries(gtpu_test srsran_common s1ap_asn1 srsenb_upper srsran_upper ${SCTP_LIBRARIES}) -add_test(rrc_mobility_test rrc_mobility_test -i ${CMAKE_CURRENT_SOURCE_DIR}/../..) -add_test(erab_setup_test erab_setup_test -i ${CMAKE_CURRENT_SOURCE_DIR}/../..) -add_test(rrc_meascfg_test rrc_meascfg_test -i ${CMAKE_CURRENT_SOURCE_DIR}/../..) add_test(plmn_test plmn_test) add_test(gtpu_test gtpu_test) From 2a2c56391ca20190f3d7d5da97de1b51b0915e69 Mon Sep 17 00:00:00 2001 From: Francisco Date: Fri, 28 May 2021 16:52:21 +0100 Subject: [PATCH 116/156] sched,refactor: Improve DL/UL grant log lines in the scheduler to print CFI as well --- srsenb/src/stack/mac/sched_grid.cc | 37 ++++++++++--------- .../stack/mac/sched_ue_ctrl/sched_ue_cell.cc | 10 +++-- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/srsenb/src/stack/mac/sched_grid.cc b/srsenb/src/stack/mac/sched_grid.cc index 755feb496..0f2fcff0c 100644 --- a/srsenb/src/stack/mac/sched_grid.cc +++ b/srsenb/src/stack/mac/sched_grid.cc @@ -699,8 +699,8 @@ void sf_sched::set_dl_data_sched_result(const sf_cch_allocator::alloc_result_t& // Print Resulting DL Allocation fmt::memory_buffer str_buffer; fmt::format_to(str_buffer, - "SCHED: DL {} rnti=0x{:x}, cc={}, pid={}, mask=0x{:x}, dci=({}, {}), n_rtx={}, tbs={}, " - "buffer={}/{}, tti_tx_dl={}", + "SCHED: DL {} rnti=0x{:x}, cc={}, pid={}, mask=0x{:x}, dci=({}, {}), n_rtx={}, cfi={}, " + "tbs={}, buffer={}/{}, tti_tx_dl={}", is_newtx ? "tx" : "retx", user->get_rnti(), cc_cfg->enb_cc_idx, @@ -709,6 +709,7 @@ void sf_sched::set_dl_data_sched_result(const sf_cch_allocator::alloc_result_t& data->dci.location.L, data->dci.location.ncce, dl_harq.nof_retx(0) + dl_harq.nof_retx(1), + tti_alloc.get_cfi(), tbs, data_before, user->get_pending_dl_bytes(cc_cfg->enb_cc_idx), @@ -860,21 +861,23 @@ void sf_sched::set_ul_sched_result(const sf_cch_allocator::alloc_result_t& dci_r uint32_t old_pending_bytes = user->get_pending_ul_old_data(); if (logger.info.enabled()) { fmt::memory_buffer str_buffer; - fmt::format_to(str_buffer, - "SCHED: {} {} rnti=0x{:x}, cc={}, pid={}, dci=({},{}), prb={}, n_rtx={}, tbs={}, bsr={} ({}-{})", - ul_alloc.is_msg3 ? "Msg3" : "UL", - ul_alloc.is_retx() ? "retx" : "tx", - user->get_rnti(), - cc_cfg->enb_cc_idx, - h->get_id(), - pusch.dci.location.L, - pusch.dci.location.ncce, - ul_alloc.alloc, - h->nof_retx(0), - tbs, - new_pending_bytes, - total_data_before, - old_pending_bytes); + fmt::format_to( + str_buffer, + "SCHED: {} {} rnti=0x{:x}, cc={}, pid={}, dci=({},{}), prb={}, n_rtx={}, cfi={}, tbs={}, bsr={} ({}-{})", + ul_alloc.is_msg3 ? "Msg3" : "UL", + ul_alloc.is_retx() ? "retx" : "tx", + user->get_rnti(), + cc_cfg->enb_cc_idx, + h->get_id(), + pusch.dci.location.L, + pusch.dci.location.ncce, + ul_alloc.alloc, + h->nof_retx(0), + tti_alloc.get_cfi(), + tbs, + new_pending_bytes, + total_data_before, + old_pending_bytes); logger.info("%s", srsran::to_c_str(str_buffer)); } diff --git a/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc b/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc index 01e9d7efd..a70d57856 100644 --- a/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc +++ b/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc @@ -189,7 +189,8 @@ int sched_ue_cell::set_ul_crc(tti_point tti_rx, bool crc_res) float delta_inc_eff = mcs >= (int)max_mcs_ul ? 0 : delta_inc; ul_snr_coeff += crc_res ? delta_inc_eff : -delta_dec_eff; ul_snr_coeff = std::min(std::max(-max_snr_coeff, ul_snr_coeff), max_snr_coeff); - logger.info("SCHED: UL adaptive link: snr_estim=%.2f, last_mcs=%d, snr_offset=%f", + logger.info("SCHED: UL adaptive link: rnti=0x%x, snr_estim=%.2f, last_mcs=%d, snr_offset=%f", + rnti, tpc_fsm.get_ul_snr_estim(), mcs, ul_snr_coeff); @@ -225,8 +226,11 @@ int sched_ue_cell::set_ack_info(tti_point tti_rx, uint32_t tb_idx, bool ack) float delta_inc_eff = mcs >= (int)max_mcs_dl ? 0 : delta_inc; dl_cqi_coeff += ack ? delta_inc_eff : -delta_dec_eff; dl_cqi_coeff = std::min(std::max(-max_cqi_coeff, dl_cqi_coeff), max_cqi_coeff); - logger.info( - "SCHED: DL adaptive link: cqi=%d, last_mcs=%d, cqi_offset=%f", dl_cqi_ctxt.get_avg_cqi(), mcs, dl_cqi_coeff); + logger.info("SCHED: DL adaptive link: rnti=0x%x, cqi=%d, last_mcs=%d, cqi_offset=%f", + rnti, + dl_cqi_ctxt.get_avg_cqi(), + mcs, + dl_cqi_coeff); } return tbs_acked; } From 89406b07d6122dd165eb1e7b40bd247220600854 Mon Sep 17 00:00:00 2001 From: Francisco Date: Fri, 28 May 2021 15:24:34 +0100 Subject: [PATCH 117/156] make eNB UL SNR initial value an exponential average alpha configurable --- lib/include/srsran/interfaces/sched_interface.h | 2 ++ srsenb/enb.conf.example | 4 ++++ srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h | 11 +++++++---- srsenb/src/main.cc | 2 ++ srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc | 4 +++- 5 files changed, 18 insertions(+), 5 deletions(-) diff --git a/lib/include/srsran/interfaces/sched_interface.h b/lib/include/srsran/interfaces/sched_interface.h index f2b53188d..aa946772f 100644 --- a/lib/include/srsran/interfaces/sched_interface.h +++ b/lib/include/srsran/interfaces/sched_interface.h @@ -62,6 +62,8 @@ public: float max_delta_ul_snr = 5; float adaptive_link_step_size = 0.001; uint32_t min_tpc_tti_interval = 1; + float ul_snr_avg_alpha = 0.05; + int init_ul_snr_value = 5; }; struct cell_cfg_t { diff --git a/srsenb/enb.conf.example b/srsenb/enb.conf.example index 1672bfcdb..c656f6a55 100644 --- a/srsenb/enb.conf.example +++ b/srsenb/enb.conf.example @@ -174,6 +174,8 @@ enable = false # max_delta_ul_snr: Maximum shift in UL SNR for adaptive UL link # adaptive_link_step_size: Step size or learning rate used in adaptive link # min_tpc_tti_interval: Minimum TTI interval between TPCs different than 1 +# ul_snr_avg_alpha: Exponential Average alpha coefficient used in estimation of UL SNR +# init_ul_snr_value: Initial UL SNR value used for computing MCS in the first UL grant # ##################################################################### [scheduler] @@ -194,6 +196,8 @@ enable = false #max_delta_ul_snr = 5 #adaptive_link_step_size = 0.001 #min_tpc_tti_interval = 1 +#ul_snr_avg_alpha=0.05 +#init_ul_snr_value=5 ##################################################################### # eMBMS configuration options diff --git a/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h b/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h index 4844f1bc3..b7ee39c4b 100644 --- a/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h +++ b/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h @@ -39,11 +39,14 @@ public: float target_pucch_snr_dB_ = -1.0, float target_pusch_sn_dB_ = -1.0, bool phr_handling_flag_ = false, - uint32_t min_tpc_tti_interval_ = 1) : + uint32_t min_tpc_tti_interval_ = 1, + float ul_snr_avg_alpha = 0.05, + int init_ul_snr_value = 5) : nof_prb(cell_nof_prb), target_pucch_snr_dB(target_pucch_snr_dB_), target_pusch_snr_dB(target_pusch_sn_dB_), - snr_estim_list({ul_ch_snr_estim{target_pusch_snr_dB}, ul_ch_snr_estim{target_pucch_snr_dB}}), + snr_estim_list( + {ul_ch_snr_estim{ul_snr_avg_alpha, init_ul_snr_value}, ul_ch_snr_estim{ul_snr_avg_alpha, init_ul_snr_value}}), phr_handling_flag(phr_handling_flag_), max_prbs_cached(nof_prb), min_tpc_tti_interval(min_tpc_tti_interval_), @@ -206,8 +209,8 @@ private: int acc_tpc_values = 0; uint32_t last_tpc_tti_count = 0; - explicit ul_ch_snr_estim(float initial_snr) : - snr_avg(0.1, initial_snr < 0 ? 5 : initial_snr), win_tpc_values(FDD_HARQ_DELAY_UL_MS + FDD_HARQ_DELAY_DL_MS) + explicit ul_ch_snr_estim(float exp_avg_alpha, int initial_snr) : + snr_avg(exp_avg_alpha, initial_snr), win_tpc_values(FDD_HARQ_DELAY_UL_MS + FDD_HARQ_DELAY_DL_MS) {} }; std::array snr_estim_list; diff --git a/srsenb/src/main.cc b/srsenb/src/main.cc index d03812f52..e5a534518 100644 --- a/srsenb/src/main.cc +++ b/srsenb/src/main.cc @@ -156,6 +156,8 @@ void parse_args(all_args_t* args, int argc, char* argv[]) ("scheduler.max_delta_ul_snr", bpo::value(&args->stack.mac.sched.max_delta_ul_snr)->default_value(5.0), "Maximum shift in UL SNR for adaptive UL link") ("scheduler.adaptive_link_step_size", bpo::value(&args->stack.mac.sched.max_delta_ul_snr)->default_value(0.001), "Step size or learning rate used in adaptive link") ("scheduler.min_tpc_tti_interval", bpo::value(&args->stack.mac.sched.min_tpc_tti_interval)->default_value(1), "Minimum TTI interval between positive or negative TPCs") + ("scheduler.ul_snr_avg_alpha", bpo::value(&args->stack.mac.sched.ul_snr_avg_alpha)->default_value(0.05), "Exponential Average alpha coefficient used in estimation of UL SNR") + ("scheduler.init_ul_snr_value", bpo::value(&args->stack.mac.sched.init_ul_snr_value)->default_value(5), "Initial UL SNR value used for computing MCS in the first UL grant") /* Downlink Channel emulator section */ diff --git a/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc b/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc index a70d57856..f844aced3 100644 --- a/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc +++ b/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc @@ -39,7 +39,9 @@ sched_ue_cell::sched_ue_cell(uint16_t rnti_, const sched_cell_params_t& cell_cfg cell_cfg->cfg.target_pucch_ul_sinr, cell_cfg->cfg.target_pusch_ul_sinr, cell_cfg->cfg.enable_phr_handling, - cell_cfg->sched_cfg->min_tpc_tti_interval), + cell_cfg->sched_cfg->min_tpc_tti_interval, + cell_cfg->sched_cfg->ul_snr_avg_alpha, + cell_cfg->sched_cfg->init_ul_snr_value), fixed_mcs_dl(cell_cfg_.sched_cfg->pdsch_mcs), fixed_mcs_ul(cell_cfg_.sched_cfg->pusch_mcs), current_tti(current_tti_), From 3b61df4b64d8003be190b428fa7a70052c8be317 Mon Sep 17 00:00:00 2001 From: Francisco Date: Fri, 28 May 2021 16:03:28 +0100 Subject: [PATCH 118/156] test,sched: update TPC test to reflect changes in SNR estimatioN --- srsenb/test/mac/sched_tpc_test.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/srsenb/test/mac/sched_tpc_test.cc b/srsenb/test/mac/sched_tpc_test.cc index acfe07ea4..faffe4694 100644 --- a/srsenb/test/mac/sched_tpc_test.cc +++ b/srsenb/test/mac/sched_tpc_test.cc @@ -28,7 +28,12 @@ int test_finite_target_snr() tpc tpcfsm(nof_prbs, 15, 15, true); - // TEST: While no SNR info is provided, no TPC commands are sent + // 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); From 5db3030428efa2710e11f54003755821df7e2f14 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Tue, 11 May 2021 16:55:50 +0200 Subject: [PATCH 119/156] Tiny changes --- lib/src/mac/pdu.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/mac/pdu.cc b/lib/src/mac/pdu.cc index 844a32a5b..2f7565d54 100644 --- a/lib/src/mac/pdu.cc +++ b/lib/src/mac/pdu.cc @@ -550,7 +550,7 @@ bool sch_subh::is_var_len_ce() uint16_t sch_subh::get_c_rnti() { - return le16toh((uint16_t)payload[0] << 8 | payload[1]); + return (uint16_t)payload[0] << 8 | payload[1]; } uint64_t sch_subh::get_con_res_id() From 92e272ce3ecaf6df26e22e87d84015d4f2aec0fc Mon Sep 17 00:00:00 2001 From: Francisco Date: Fri, 30 Apr 2021 14:08:27 +0100 Subject: [PATCH 120/156] limit minimum UL grant size to accommodate both BSR and RLC headers --- srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc b/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc index f844aced3..c6876b008 100644 --- a/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc +++ b/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc @@ -439,7 +439,7 @@ int get_required_prb_dl(const sched_ue_cell& cell, uint32_t get_required_prb_ul(const sched_ue_cell& cell, uint32_t req_bytes) { - const static int MIN_ALLOC_BYTES = 10; + const static int MIN_ALLOC_BYTES = 10; /// There should be enough space for RLC header + BSR + some payload if (req_bytes == 0) { return 0; } @@ -458,9 +458,7 @@ uint32_t get_required_prb_ul(const sched_ue_cell& cell, uint32_t req_bytes) uint32_t final_tbs = std::get<3>(ret); while (final_tbs < MIN_ALLOC_BYTES and req_prbs < cell.cell_cfg->nof_prb()) { // Note: If PHR<0 is limiting the max nof PRBs per UL grant, the UL grant may become too small to fit any - // data other than headers + BSR. Besides, forcing unnecessary segmentation, it may additionally - // forbid the UE from fitting small RRC messages (e.g. RRCReconfComplete) in the UL grants. - // To avoid TBS<10, we force an increase the nof required PRBs. + // data other than headers + BSR. In this edge-case, force an increase the nof required PRBs. req_prbs++; final_tbs = compute_tbs_approx(req_prbs); } From 5cef78078953eadc3b6103f07b1e6b8bf025bf14 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Tue, 11 May 2021 17:19:41 +0200 Subject: [PATCH 121/156] Radio-link KO notification. Measgap fix --- srsenb/src/stack/enb_stack_lte.cc | 1 - srsenb/src/stack/mac/mac.cc | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/srsenb/src/stack/enb_stack_lte.cc b/srsenb/src/stack/enb_stack_lte.cc index 4f27efe0c..c98db892f 100644 --- a/srsenb/src/stack/enb_stack_lte.cc +++ b/srsenb/src/stack/enb_stack_lte.cc @@ -158,7 +158,6 @@ void enb_stack_lte::tti_clock() void enb_stack_lte::tti_clock_impl() { - trace_complete_event("enb_stack_lte::tti_clock_impl", "total_time"); task_sched.tic(); rrc.tti_clock(); } diff --git a/srsenb/src/stack/mac/mac.cc b/srsenb/src/stack/mac/mac.cc index 328ff1ae0..17e2dee7d 100644 --- a/srsenb/src/stack/mac/mac.cc +++ b/srsenb/src/stack/mac/mac.cc @@ -422,6 +422,8 @@ int mac::snr_info(uint32_t tti_rx, uint16_t rnti, uint32_t enb_cc_idx, float snr return SRSRAN_ERROR; } + rrc_h->set_radiolink_ul_state(rnti, snr > 0); + return scheduler.ul_snr_info(tti_rx, rnti, enb_cc_idx, snr, (uint32_t)ch); } @@ -607,7 +609,7 @@ int mac::get_dl_sched(uint32_t tti_tx_dl, dl_sched_list_t& dl_sched_res_list) return 0; } - trace_complete_event("mac::get_dl_sched", "total_time"); + trace_threshold_complete_event("mac::get_dl_sched", "total_time", std::chrono::microseconds(100)); logger.set_context(TTI_SUB(tti_tx_dl, FDD_HARQ_DELAY_UL_MS)); if (do_padding) { add_padding(); From d74f70289ea7d0b735cee0f338f1f064ace58b6a Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Wed, 2 Jun 2021 10:50:46 +0200 Subject: [PATCH 122/156] SRSUE: fix last reported RI state --- srsue/hdr/phy/phy_common.h | 3 +++ srsue/src/phy/lte/cc_worker.cc | 6 ++++++ srsue/src/phy/phy_common.cc | 1 + 3 files changed, 10 insertions(+) diff --git a/srsue/hdr/phy/phy_common.h b/srsue/hdr/phy/phy_common.h index 2a635912e..3acbd80df 100644 --- a/srsue/hdr/phy/phy_common.h +++ b/srsue/hdr/phy/phy_common.h @@ -69,6 +69,9 @@ public: // Time Aligment Controller, internal thread safe ta_control ta; + // Last reported RI + std::atomic last_ri = {0}; + phy_common(srslog::basic_logger& logger); ~phy_common(); diff --git a/srsue/src/phy/lte/cc_worker.cc b/srsue/src/phy/lte/cc_worker.cc index e25ec70e2..913e5beae 100644 --- a/srsue/src/phy/lte/cc_worker.cc +++ b/srsue/src/phy/lte/cc_worker.cc @@ -807,10 +807,16 @@ uint32_t cc_worker::get_wideband_cqi() void cc_worker::set_uci_periodic_cqi(srsran_uci_data_t* uci_data) { + // Load last reported RI + ue_dl_cfg.last_ri = phy->last_ri; + srsran_ue_dl_gen_cqi_periodic(&ue_dl, &ue_dl_cfg, get_wideband_cqi(), CURRENT_TTI_TX, uci_data); // Store serving cell index for logging purposes uci_data->cfg.cqi.scell_index = cc_idx; + + // Store the reported RI + phy->last_ri = ue_dl_cfg.last_ri; } void cc_worker::set_uci_aperiodic_cqi(srsran_uci_data_t* uci_data) diff --git a/srsue/src/phy/phy_common.cc b/srsue/src/phy/phy_common.cc index 836c7859d..062abd5a8 100644 --- a/srsue/src/phy/phy_common.cc +++ b/srsue/src/phy/phy_common.cc @@ -871,6 +871,7 @@ void phy_common::reset() cur_pusch_power = 0; sr_last_tx_tti = -1; pcell_report_period = 20; + last_ri = 0; ZERO_OBJECT(pathloss); ZERO_OBJECT(avg_sinr_db); From f7aef3ffc175fd0f0ec80df84520fa905291e040 Mon Sep 17 00:00:00 2001 From: Francisco Date: Tue, 1 Jun 2021 18:05:15 +0100 Subject: [PATCH 123/156] sched,bugfix: fix nof_retx update when UL HARQs are resumed --- lib/include/srsran/common/srsran_assert.h | 2 +- .../hdr/stack/mac/sched_ue_ctrl/sched_harq.h | 9 ++-- srsenb/src/stack/mac/sched_grid.cc | 41 ++++++++++++------- .../src/stack/mac/sched_ue_ctrl/sched_harq.cc | 36 ++++++++-------- srsenb/test/mac/sched_common_test_suite.cc | 4 +- srsenb/test/mac/sched_sim_ue.cc | 18 +++++--- srsenb/test/mac/sched_sim_ue.h | 2 +- srsenb/test/mac/sched_ue_ded_test_suite.cc | 27 +++++++----- 8 files changed, 84 insertions(+), 55 deletions(-) diff --git a/lib/include/srsran/common/srsran_assert.h b/lib/include/srsran/common/srsran_assert.h index aaad80874..45eaa4a6d 100644 --- a/lib/include/srsran/common/srsran_assert.h +++ b/lib/include/srsran/common/srsran_assert.h @@ -19,8 +19,8 @@ #define srsran_unlikely(expr) __builtin_expect(!!(expr), 0) #define srsran_terminate(fmt, ...) \ - std::fprintf(stderr, "%s:%d: " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__); \ srslog::flush(); \ + std::fprintf(stderr, "%s:%d: " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__); \ std::abort() #ifdef ASSERTS_ENABLED diff --git a/srsenb/hdr/stack/mac/sched_ue_ctrl/sched_harq.h b/srsenb/hdr/stack/mac/sched_ue_ctrl/sched_harq.h index 7805a8b87..5bd5278ca 100644 --- a/srsenb/hdr/stack/mac/sched_ue_ctrl/sched_harq.h +++ b/srsenb/hdr/stack/mac/sched_ue_ctrl/sched_harq.h @@ -106,14 +106,15 @@ public: uint32_t get_pending_data() const; bool has_pending_phich() const; bool pop_pending_phich(); - void phich_alloc_failed(); + void request_pdcch(); + void retx_skipped(); private: prb_interval allocation; int pending_data; - bool pending_phich = false; - bool is_msg3_ = false; - bool pdcch_required = false; + bool pending_phich = false; + bool is_msg3_ = false; + bool pdcch_requested = false; }; class harq_entity diff --git a/srsenb/src/stack/mac/sched_grid.cc b/srsenb/src/stack/mac/sched_grid.cc index 0f2fcff0c..c68df774f 100644 --- a/srsenb/src/stack/mac/sched_grid.cc +++ b/srsenb/src/stack/mac/sched_grid.cc @@ -637,17 +637,20 @@ alloc_result sf_sched::alloc_phich(sched_ue* user) auto* ul_sf_result = &cc_results->get_cc(cc_cfg->enb_cc_idx)->ul_sched_result; if (ul_sf_result->phich.full()) { - logger.warning("SCHED: Maximum number of PHICH allocations has been reached"); - h->phich_alloc_failed(); + logger.warning( + "SCHED: UL skipped retx rnti=0x%x, pid=%d. Cause: No PHICH space left", user->get_rnti(), h->get_id()); + h->pop_pending_phich(); return alloc_result::no_grant_space; } if (not user->phich_enabled(get_tti_rx(), cc_cfg->enb_cc_idx)) { // PHICH falls in measGap. PHICH hi=1 is assumed by UE. In case of NACK, the HARQ is going to be resumed later on. - logger.debug("SCHED: HARQ pid=%d for rnti=0x%x is being resumed due to PHICH - MeasGap collision", - h->get_id(), - user->get_rnti()); - h->phich_alloc_failed(); + logger.info( + "SCHED: UL skipped retx rnti=0x%x, pid=%d. Cause: PHICH-measGap collision", user->get_rnti(), h->get_id()); + h->pop_pending_phich(); // empty pending PHICH + // Note: Given that the UE assumes PHICH hi=1, it is not expecting PUSCH grants for tti_tx_ul. Requesting PDCCH + // for the UL Harq has the effect of forbidding PUSCH grants, since phich_tti == pdcch_tti. + h->request_pdcch(); return alloc_result::no_cch_space; } @@ -906,15 +909,23 @@ void sf_sched::generate_sched_results(sched_ue_list& ue_db) /* Resume UL HARQs with pending retxs that did not get allocated */ using phich_t = sched_interface::ul_sched_phich_t; auto& phich_list = cc_result->ul_sched_result.phich; - for (uint32_t i = 0; i < cc_result->ul_sched_result.phich.size(); ++i) { - auto& phich = phich_list[i]; - if (phich.phich == phich_t::NACK) { - auto& ue = *ue_db[phich.rnti]; - ul_harq_proc* h = ue.get_ul_harq(get_tti_tx_ul(), cc_cfg->enb_cc_idx); - if (not is_ul_alloc(ue.get_rnti()) and h != nullptr and not h->is_empty()) { - // There was a missed UL harq retx. Halt+Resume the HARQ - phich.phich = phich_t::ACK; - logger.debug("SCHED: rnti=0x%x UL harq pid=%d is being resumed", ue.get_rnti(), h->get_id()); + for (auto& ue_pair : ue_db) { + auto& ue = *ue_pair.second; + uint16_t rnti = ue.get_rnti(); + ul_harq_proc* h = ue.get_ul_harq(get_tti_tx_ul(), cc_cfg->enb_cc_idx); + if (h != nullptr and not h->is_empty() and not is_ul_alloc(rnti)) { + // There was a missed UL harq retx. Halt+Resume the HARQ + h->retx_skipped(); + auto same_rnti = [rnti](const phich_t& p) { return p.rnti == rnti; }; + phich_t* phich = std::find_if(phich_list.begin(), phich_list.end(), same_rnti); + if (phich != phich_list.end()) { + srsran_assert(phich->phich == phich_t::NACK, "Expected hi=0 in case of active UL HARQ that was not retx"); + logger.info("SCHED: UL skipped retx rnti=0x%x, pid=%d. Cause: %s", + ue.get_rnti(), + h->get_id(), + ue.pusch_enabled(get_tti_rx(), cc_cfg->enb_cc_idx, false) ? "lack of PHY resources" + : "PUSCH-measGap collision"); + phich->phich = phich_t::ACK; } } } diff --git a/srsenb/src/stack/mac/sched_ue_ctrl/sched_harq.cc b/srsenb/src/stack/mac/sched_ue_ctrl/sched_harq.cc index fc7ab9c8d..23826d26c 100644 --- a/srsenb/src/stack/mac/sched_ue_ctrl/sched_harq.cc +++ b/srsenb/src/stack/mac/sched_ue_ctrl/sched_harq.cc @@ -247,10 +247,10 @@ void ul_harq_proc::new_tx(tti_point tti_, int mcs, int tbs, prb_interval alloc, { allocation = alloc; new_tx_common(0, tti_point{tti_}, mcs, tbs, max_retx_); - pending_data = tbs; - pending_phich = true; - is_msg3_ = is_msg3; - pdcch_required = false; + pending_data = tbs; + pending_phich = true; + is_msg3_ = is_msg3; + pdcch_requested = false; } void ul_harq_proc::new_retx(tti_point tti_, int* mcs, int* tbs, prb_interval alloc) @@ -258,15 +258,15 @@ void ul_harq_proc::new_retx(tti_point tti_, int* mcs, int* tbs, prb_interval all // If PRBs changed, or there was no tx in last oportunity (e.g. HARQ is being resumed) allocation = alloc; new_retx_common(0, tti_point{tti_}, mcs, tbs); - pending_phich = true; - pdcch_required = false; + pending_phich = true; + pdcch_requested = false; } bool ul_harq_proc::retx_requires_pdcch(tti_point tti_, prb_interval alloc) const { // Adaptive retx if: (1) PRBs changed, (2) HARQ resumed due to last PUSCH retx being skipped (3) HARQ resumed due to // last PHICH alloc being skipped (e.g. due to measGaps) - return alloc != allocation or tti_ != to_tx_ul(tti) or pdcch_required; + return alloc != allocation or pdcch_requested; } bool ul_harq_proc::set_ack(uint32_t tb_idx, bool ack_) @@ -283,13 +283,17 @@ bool ul_harq_proc::has_pending_phich() const return pending_phich; } -void ul_harq_proc::phich_alloc_failed() +void ul_harq_proc::request_pdcch() { - pop_pending_phich(); - if (not is_empty(0)) { - // HARQ needs to be resumed. This is signalled by pending_phich flag - pdcch_required = true; - } + pdcch_requested = true; +} + +void ul_harq_proc::retx_skipped() +{ + // Note: This function should be called in case of PHICH allocation is successful + // Flagging "PDCCH required" for next retx, as HARQ is being resumed + pdcch_requested = true; + n_rtx[0]++; } bool ul_harq_proc::pop_pending_phich() @@ -307,9 +311,9 @@ bool ul_harq_proc::pop_pending_phich() void ul_harq_proc::reset_pending_data() { reset_pending_data_common(); - pending_data = 0; - is_msg3_ = false; - pdcch_required = false; + pending_data = 0; + is_msg3_ = false; + pdcch_requested = false; } uint32_t ul_harq_proc::get_pending_data() const diff --git a/srsenb/test/mac/sched_common_test_suite.cc b/srsenb/test/mac/sched_common_test_suite.cc index d04999f9a..71cc82213 100644 --- a/srsenb/test/mac/sched_common_test_suite.cc +++ b/srsenb/test/mac/sched_common_test_suite.cc @@ -266,7 +266,9 @@ int test_dci_content_common(const sf_output_res_t& sf_out, uint32_t enb_cc_idx) CONDERROR(pusch.tbs == 0, "Allocated PUSCH with invalid TBS=%d", pusch.tbs); CONDERROR(alloc_rntis.count(rnti) > 0, "The user rnti=0x%x got allocated multiple times in UL", rnti); alloc_rntis.insert(pusch.dci.rnti); - CONDERROR(not((pusch.current_tx_nb == 0) xor (pusch.dci.tb.rv != 0)), "Number of txs incorrectly set"); + CONDERROR(not(((pusch.current_tx_nb % 4) == 0) xor (pusch.dci.tb.rv != 0)), + "[rnti=0x%x] Number of txs incorrectly set", + rnti); if (not pusch.needs_pdcch) { // In case of non-adaptive retx or Msg3 continue; diff --git a/srsenb/test/mac/sched_sim_ue.cc b/srsenb/test/mac/sched_sim_ue.cc index 4ce4dc4ac..4606ba400 100644 --- a/srsenb/test/mac/sched_sim_ue.cc +++ b/srsenb/test/mac/sched_sim_ue.cc @@ -116,6 +116,9 @@ void ue_sim::update_ul_harqs(const sf_output_res_t& sf_out) // Update UL harqs with PHICH info bool found_phich = false; + bool is_msg3 = h.nof_txs == h.nof_retxs + 1 and ctxt.msg3_tti_rx.is_valid() and h.first_tti_rx == ctxt.msg3_tti_rx; + uint32_t max_retxs = is_msg3 ? sf_out.cc_params[0].cfg.maxharq_msg3tx : ctxt.ue_cfg.maxharq_tx; + bool last_retx = h.nof_retxs + 1 >= max_retxs; for (uint32_t i = 0; i < sf_out.ul_cc_result[cc].phich.size(); ++i) { const auto& phich = sf_out.ul_cc_result[cc].phich[i]; if (phich.rnti != ctxt.rnti) { @@ -124,25 +127,23 @@ void ue_sim::update_ul_harqs(const sf_output_res_t& sf_out) found_phich = true; bool is_ack = phich.phich == phich_t::ACK; - bool is_msg3 = - h.nof_txs == h.nof_retxs + 1 and ctxt.msg3_tti_rx.is_valid() and h.first_tti_rx == ctxt.msg3_tti_rx; - bool last_retx = h.nof_retxs + 1 >= (is_msg3 ? sf_out.cc_params[0].cfg.maxharq_msg3tx : ctxt.ue_cfg.maxharq_tx); if (is_ack or last_retx) { h.active = false; } } - if (h.active and not found_phich) { - // HARQ being resumed. Possibly due to measGap, PHICH may not be allocated. - logger.info("TESTER: rnti=0x%x, HARQ pid=%d being resumed.", ctxt.rnti, pid); + if (not found_phich and h.active) { + // There can be missing PHICH due to measGap collisions. In such case, we deactivate the harq and assume hi=1 h.active = false; } // Update UL harqs with PUSCH grants + bool pusch_found = false; for (uint32_t i = 0; i < sf_out.ul_cc_result[cc].pusch.size(); ++i) { const auto& data = sf_out.ul_cc_result[cc].pusch[i]; if (data.dci.rnti != ctxt.rnti) { continue; } + pusch_found = true; if (h.nof_txs == 0 or h.ndi != data.dci.tb.ndi) { // newtx @@ -158,6 +159,11 @@ void ue_sim::update_ul_harqs(const sf_output_res_t& sf_out) h.riv = data.dci.type2_alloc.riv; h.nof_txs++; } + if (not pusch_found and h.nof_retxs < max_retxs) { + // PUSCH *may* be skipped due to measGap. nof_retxs keeps getting incremented + h.nof_retxs++; + h.nof_txs++; + } } } diff --git a/srsenb/test/mac/sched_sim_ue.h b/srsenb/test/mac/sched_sim_ue.h index 34a84b88f..8a39426f5 100644 --- a/srsenb/test/mac/sched_sim_ue.h +++ b/srsenb/test/mac/sched_sim_ue.h @@ -26,7 +26,7 @@ struct ue_harq_ctxt_t { bool ndi = false; uint32_t pid = 0; uint32_t nof_txs = 0; - uint32_t nof_retxs = 0; + uint32_t nof_retxs = std::numeric_limits::max(); uint32_t riv = 0; srsran_dci_location_t dci_loc = {}; uint32_t tbs = 0; diff --git a/srsenb/test/mac/sched_ue_ded_test_suite.cc b/srsenb/test/mac/sched_ue_ded_test_suite.cc index 63fc56b87..dad865ebe 100644 --- a/srsenb/test/mac/sched_ue_ded_test_suite.cc +++ b/srsenb/test/mac/sched_ue_ded_test_suite.cc @@ -189,13 +189,16 @@ int test_ul_sched_result(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& continue; } - const auto& h = ue.cc_list[ue_cc_idx].ul_harqs[pid]; - bool phich_ack = phich_ptr != nullptr and phich_ptr->phich == phich_t::ACK; - bool is_msg3 = h.first_tti_rx == ue.msg3_tti_rx and h.nof_txs == h.nof_retxs + 1; - bool last_retx = h.nof_retxs + 1 >= (is_msg3 ? sf_out.cc_params[0].cfg.maxharq_msg3tx : ue.ue_cfg.maxharq_tx); - tti_point tti_tx_phich = to_tx_dl(sf_out.tti_rx); - bool phich_in_meas_gap = is_in_measgap(tti_tx_phich, ue.ue_cfg.measgap_period, ue.ue_cfg.measgap_offset); - bool h_inactive_now = (not h.active) or (phich_ack or last_retx or phich_in_meas_gap); + const auto& h = ue.cc_list[ue_cc_idx].ul_harqs[pid]; + bool phich_ack = phich_ptr != nullptr and phich_ptr->phich == phich_t::ACK; + bool is_msg3 = h.first_tti_rx == ue.msg3_tti_rx and h.nof_txs == h.nof_retxs + 1; + uint32_t max_nof_retxs = is_msg3 ? sf_out.cc_params[0].cfg.maxharq_msg3tx : ue.ue_cfg.maxharq_tx; + bool last_retx = h.nof_retxs + 1 >= max_nof_retxs; + tti_point tti_tx_phich = to_tx_dl(sf_out.tti_rx); + bool phich_in_meas_gap = is_in_measgap(tti_tx_phich, ue.ue_cfg.measgap_period, ue.ue_cfg.measgap_offset); + bool pusch_in_meas_gap = + is_in_measgap(to_tx_ul(sf_out.tti_rx), ue.ue_cfg.measgap_period, ue.ue_cfg.measgap_offset); + bool h_cleared = (not h.active) or (phich_ack or last_retx); // TEST: Already active UL HARQs have to receive PHICH (unless MeasGap collision) CONDERROR(h.active and phich_ptr == nullptr and not phich_in_meas_gap, @@ -209,7 +212,7 @@ int test_ul_sched_result(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& // TEST: absent PUSCH grants for active UL HARQs must be either ACKs, last retx, or interrupted HARQs if (phich_ptr != nullptr) { - CONDERROR(not h_inactive_now and pusch_ptr == nullptr, + CONDERROR(not h_cleared and pusch_ptr == nullptr and not pusch_in_meas_gap, "PHICH NACK received for rnti=0x%x but no PUSCH retx reallocated", rnti); } @@ -224,11 +227,13 @@ int test_ul_sched_result(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& // newtx CONDERROR(nof_retx != 0, "Invalid rv index for new UL tx"); CONDERROR(pusch_ptr->current_tx_nb != 0, "UL HARQ retxs need to have been previously transmitted"); - CONDERROR(not h_inactive_now, "New tx for already active UL HARQ"); + CONDERROR(not h_cleared, "New tx for already active UL HARQ"); CONDERROR(not pusch_ptr->needs_pdcch and ue.msg3_tti_rx.is_valid() and sf_out.tti_rx > ue.msg3_tti_rx, "In case of newtx, PDCCH allocation is required, unless it is Msg3"); } else { CONDERROR(pusch_ptr->current_tx_nb == 0, "UL retx has to have nof tx > 0"); + CONDERROR(h.nof_retxs >= max_nof_retxs, "UL max nof retxs exceeded"); + CONDERROR(pusch_ptr->current_tx_nb != h.nof_retxs + 1, "UL HARQ nof_retx mismatch"); if (not h.active) { // the HARQ is being resumed. PDCCH must be active with the exception of Msg3 CONDERROR(ue.msg4_tti_rx.is_valid() and not pusch_ptr->needs_pdcch, @@ -239,11 +244,11 @@ int test_ul_sched_result(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& } else { // non-adaptive retx CONDERROR(pusch_ptr->dci.type2_alloc.riv != h.riv, "Non-adaptive retx must keep the same riv"); - CONDERROR(to_tx_ul(h.last_tti_rx) > sf_out.tti_rx, "UL harq pid=%d was reused too soon", h.pid); } } - CONDERROR(get_rvidx(h.nof_retxs + 1) != (uint32_t)pusch_ptr->dci.tb.rv, "Invalid rv index for retx"); + CONDERROR(get_rvidx(h.nof_retxs + 1) != (uint32_t)pusch_ptr->dci.tb.rv, "Invalid rv index for UL retx"); CONDERROR(h.tbs != pusch_ptr->tbs, "TBS changed during HARQ retx"); + CONDERROR(to_tx_ul(h.last_tti_rx) > sf_out.tti_rx, "UL harq pid=%d was reused too soon", h.pid); } } } From 486823e5dec3ffbc6e45e370152c186757d50221 Mon Sep 17 00:00:00 2001 From: Francisco Date: Wed, 2 Jun 2021 16:31:17 +0100 Subject: [PATCH 124/156] sched,bugfix: The PHR handling scheme now considers the number of PRBs of the UL grant that carried the PHR. Before, it was assuming the most conservative scenario of Nprb=1 --- .../srsran/interfaces/enb_mac_interfaces.h | 8 +++++++- lib/include/srsran/interfaces/sched_interface.h | 2 +- lib/include/srsran/mac/pdu_queue.h | 5 +++-- lib/src/mac/pdu_queue.cc | 11 ++++++----- srsenb/hdr/stack/enb_stack_lte.h | 9 +++++++-- srsenb/hdr/stack/mac/mac.h | 3 ++- srsenb/hdr/stack/mac/sched.h | 2 +- srsenb/hdr/stack/mac/sched_ue.h | 2 +- srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h | 15 ++++++++++++--- srsenb/hdr/stack/mac/ue.h | 12 ++++++------ srsenb/src/phy/lte/cc_worker.cc | 3 ++- srsenb/src/stack/mac/mac.cc | 9 +++++++-- srsenb/src/stack/mac/sched.cc | 4 ++-- srsenb/src/stack/mac/sched_ue.cc | 4 ++-- .../stack/mac/sched_ue_ctrl/sched_ue_cell.cc | 3 ++- srsenb/src/stack/mac/ue.cc | 17 +++++++++-------- srsenb/test/mac/sched_tpc_test.cc | 10 +++++----- srsenb/test/mac/sched_ue_cell_test.cc | 4 ++-- srsenb/test/phy/enb_phy_test.cc | 3 ++- srsue/hdr/stack/mac/demux.h | 2 +- srsue/src/stack/mac/demux.cc | 2 +- srsue/test/ttcn3/hdr/ttcn3_syssim.h | 2 +- srsue/test/ttcn3/src/ttcn3_syssim.cc | 2 +- 23 files changed, 83 insertions(+), 51 deletions(-) diff --git a/lib/include/srsran/interfaces/enb_mac_interfaces.h b/lib/include/srsran/interfaces/enb_mac_interfaces.h index 19c2b7fc0..0b33584ed 100644 --- a/lib/include/srsran/interfaces/enb_mac_interfaces.h +++ b/lib/include/srsran/interfaces/enb_mac_interfaces.h @@ -183,9 +183,15 @@ public: * @param enb_cc_idx the eNb Cell/Carrier identifier * @param nof_bytes the number of grants carrierd by the PUSCH message * @param crc_res the CRC check, set to true if the message was decoded succesfully + * @param ul_nof_prbs Number of PRBs allocated to grant * @return SRSRAN_SUCCESS if no error occurs, SRSRAN_ERROR* if an error occurs */ - virtual int push_pdu(uint32_t tti_rx, uint16_t rnti, uint32_t enb_cc_idx, uint32_t nof_bytes, bool crc_res) = 0; + virtual int push_pdu(uint32_t tti_rx, + uint16_t rnti, + uint32_t enb_cc_idx, + uint32_t nof_bytes, + bool crc_res, + uint32_t ul_nof_prbs) = 0; virtual int get_dl_sched(uint32_t tti, dl_sched_list_t& dl_sched_res) = 0; virtual int get_mch_sched(uint32_t tti, bool is_mcch, dl_sched_list_t& dl_sched_res) = 0; diff --git a/lib/include/srsran/interfaces/sched_interface.h b/lib/include/srsran/interfaces/sched_interface.h index aa946772f..3ae3ac340 100644 --- a/lib/include/srsran/interfaces/sched_interface.h +++ b/lib/include/srsran/interfaces/sched_interface.h @@ -295,7 +295,7 @@ public: virtual int ul_crc_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, bool crc) = 0; virtual int ul_sr_info(uint32_t tti, uint16_t rnti) = 0; virtual int ul_bsr(uint16_t rnti, uint32_t lcg_id, uint32_t bsr) = 0; - virtual int ul_phr(uint16_t rnti, int phr) = 0; + virtual int ul_phr(uint16_t rnti, int phr, uint32_t ul_nof_prb) = 0; virtual int ul_snr_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, float snr, uint32_t ul_ch_code) = 0; /* Run Scheduler for this tti */ diff --git a/lib/include/srsran/mac/pdu_queue.h b/lib/include/srsran/mac/pdu_queue.h index 74e60a09f..424c505b0 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) = 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) {} @@ -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); + void push(const uint8_t* ptr, uint32_t len, channel_t channel = DCH, int ul_nof_prbs = -1); bool process_pdus(); @@ -52,6 +52,7 @@ private: uint8_t ptr[MAX_PDU_LEN]; uint32_t len; channel_t channel; + int grant_nof_prbs; #ifdef SRSRAN_BUFFER_POOL_LOG_ENABLED char debug_name[128]; #endif diff --git a/lib/src/mac/pdu_queue.cc b/lib/src/mac/pdu_queue.cc index 43c858326..cc4481234 100644 --- a/lib/src/mac/pdu_queue.cc +++ b/lib/src/mac/pdu_queue.cc @@ -53,12 +53,13 @@ void pdu_queue::deallocate(const uint8_t* pdu) * This function enqueues the packet and returns quicly because ACK * deadline is important here. */ -void pdu_queue::push(const uint8_t* ptr, uint32_t len, channel_t channel) +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_t* pdu = (pdu_t*)ptr; + pdu->len = len; + pdu->channel = channel; + pdu->grant_nof_prbs = grant_nof_prbs; if (!pdu_q.try_push(pdu)) { logger.warning("Error pushing pdu: queue is full"); } @@ -74,7 +75,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); + callback->process_pdu(pdu->ptr, pdu->len, pdu->channel, pdu->grant_nof_prbs); } cnt++; have_data = true; diff --git a/srsenb/hdr/stack/enb_stack_lte.h b/srsenb/hdr/stack/enb_stack_lte.h index 14d99279b..6e0ef91ec 100644 --- a/srsenb/hdr/stack/enb_stack_lte.h +++ b/srsenb/hdr/stack/enb_stack_lte.h @@ -77,9 +77,14 @@ public: { return mac.crc_info(tti, rnti, enb_cc_idx, nof_bytes, crc_res); } - int push_pdu(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, uint32_t nof_bytes, bool crc_res) final + int push_pdu(uint32_t tti, + uint16_t rnti, + uint32_t enb_cc_idx, + uint32_t nof_bytes, + bool crc_res, + uint32_t grant_nof_prbs) final { - return mac.push_pdu(tti, rnti, enb_cc_idx, nof_bytes, crc_res); + return mac.push_pdu(tti, rnti, enb_cc_idx, nof_bytes, crc_res, grant_nof_prbs); } int get_dl_sched(uint32_t tti, dl_sched_list_t& dl_sched_res) final { return mac.get_dl_sched(tti, dl_sched_res); } int get_mch_sched(uint32_t tti, bool is_mcch, dl_sched_list_t& dl_sched_res) final diff --git a/srsenb/hdr/stack/mac/mac.h b/srsenb/hdr/stack/mac/mac.h index 585b2c6aa..2755335cb 100644 --- a/srsenb/hdr/stack/mac/mac.h +++ b/srsenb/hdr/stack/mac/mac.h @@ -59,7 +59,8 @@ public: int ta_info(uint32_t tti, uint16_t rnti, float ta_us) override; int ack_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, uint32_t tb_idx, bool ack) override; int crc_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, uint32_t nof_bytes, bool crc_res) override; - int push_pdu(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, uint32_t nof_bytes, bool crc_res) override; + int push_pdu(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, uint32_t nof_bytes, bool crc_res, uint32_t ul_nof_prbs) + override; int get_dl_sched(uint32_t tti_tx_dl, dl_sched_list_t& dl_sched_res) override; int get_ul_sched(uint32_t tti_tx_ul, ul_sched_list_t& ul_sched_res) override; diff --git a/srsenb/hdr/stack/mac/sched.h b/srsenb/hdr/stack/mac/sched.h index 16cc2541f..b67d9b9a1 100644 --- a/srsenb/hdr/stack/mac/sched.h +++ b/srsenb/hdr/stack/mac/sched.h @@ -64,7 +64,7 @@ public: int ul_crc_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, bool crc) final; int ul_sr_info(uint32_t tti, uint16_t rnti) override; int ul_bsr(uint16_t rnti, uint32_t lcg_id, uint32_t bsr) final; - int ul_phr(uint16_t rnti, int phr) final; + int ul_phr(uint16_t rnti, int phr, uint32_t ul_nof_prb) final; int ul_snr_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, float snr, uint32_t ul_ch_code) final; int dl_sched(uint32_t tti, uint32_t enb_cc_idx, dl_sched_res_t& sched_result) final; diff --git a/srsenb/hdr/stack/mac/sched_ue.h b/srsenb/hdr/stack/mac/sched_ue.h index 24b120cb4..5f831ca13 100644 --- a/srsenb/hdr/stack/mac/sched_ue.h +++ b/srsenb/hdr/stack/mac/sched_ue.h @@ -53,7 +53,7 @@ public: void dl_buffer_state(uint8_t lc_id, uint32_t tx_queue, uint32_t retx_queue); void ul_buffer_state(uint8_t lcg_id, uint32_t bsr); - void ul_phr(int phr); + void ul_phr(int phr, uint32_t grant_nof_prb); void mac_buffer_state(uint32_t ce_code, uint32_t nof_cmds); void set_ul_snr(tti_point tti_rx, uint32_t enb_cc_idx, float snr, uint32_t ul_ch_code); diff --git a/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h b/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h index b7ee39c4b..4a3f37a1d 100644 --- a/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h +++ b/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h @@ -35,13 +35,15 @@ public: static constexpr uint32_t PUSCH_CODE = 0, PUCCH_CODE = 1; static constexpr int PHR_NEG_NOF_PRB = 1; - explicit tpc(uint32_t cell_nof_prb, + explicit tpc(uint16_t rnti_, + uint32_t cell_nof_prb, float target_pucch_snr_dB_ = -1.0, float target_pusch_sn_dB_ = -1.0, bool phr_handling_flag_ = false, uint32_t min_tpc_tti_interval_ = 1, float ul_snr_avg_alpha = 0.05, int init_ul_snr_value = 5) : + rnti(rnti_), nof_prb(cell_nof_prb), target_pucch_snr_dB(target_pucch_snr_dB_), target_pusch_snr_dB(target_pusch_sn_dB_), @@ -69,7 +71,7 @@ public: snr_estim_list[ul_ch_code].pending_snr = snr; } } - void set_phr(int phr_) + void set_phr(int phr_, uint32_t grant_nof_prbs) { last_phr = phr_; for (auto& ch_snr : snr_estim_list) { @@ -79,12 +81,18 @@ public: // compute and cache the max nof UL PRBs that avoids overflowing PHR if (phr_handling_flag) { max_prbs_cached = PHR_NEG_NOF_PRB; + int phr_x_prb = std::roundf(last_phr + 10.0F * log10f(grant_nof_prbs)); // get what the PHR would be if Nprb=1 for (int n = nof_prb; n > PHR_NEG_NOF_PRB; --n) { - if (last_phr >= 10 * log10(n)) { + if (phr_x_prb >= 10 * log10f(n)) { max_prbs_cached = n; break; } } + logger.info("SCHED: rnti=0x%x received PHR=%d for UL Nprb=%d. Max UL Nprb is now=%d", + rnti, + phr_, + grant_nof_prbs, + max_prbs_cached); } } @@ -181,6 +189,7 @@ private: return encode_tpc_delta(ch_snr.pending_delta); } + uint16_t rnti; uint32_t nof_prb; uint32_t min_tpc_tti_interval = 1; float target_pucch_snr_dB, target_pusch_snr_dB; diff --git a/srsenb/hdr/stack/mac/ue.h b/srsenb/hdr/stack/mac/ue.h index d7e201794..abd30bee2 100644 --- a/srsenb/hdr/stack/mac/ue.h +++ b/srsenb/hdr/stack/mac/ue.h @@ -67,7 +67,7 @@ public: uint8_t* request_pdu(tti_point tti, uint32_t len); - bool push_pdu(tti_point tti, uint32_t len); + bool push_pdu(tti_point tti, uint32_t len, uint32_t grant_nof_prbs); void clear_old_pdus(tti_point current_tti); @@ -161,10 +161,10 @@ public: bool process_pdus(); uint8_t* request_buffer(uint32_t tti, uint32_t ue_cc_idx, const uint32_t len); - void process_pdu(uint8_t* pdu, uint32_t nof_bytes, srsran::pdu_queue::channel_t channel) override; - void push_pdu(uint32_t tti, uint32_t ue_cc_idx, uint32_t len); - void deallocate_pdu(uint32_t tti, uint32_t ue_cc_idx); - void clear_old_buffers(uint32_t tti); + void process_pdu(uint8_t* pdu, uint32_t nof_bytes, srsran::pdu_queue::channel_t channel, int grant_nof_prbs) override; + void push_pdu(uint32_t tti, uint32_t ue_cc_idx, uint32_t len, uint32_t grant_nof_prbs); + void deallocate_pdu(uint32_t tti, uint32_t ue_cc_idx); + void clear_old_buffers(uint32_t tti); void metrics_read(mac_ue_metrics_t* metrics_); void metrics_rx(bool crc, uint32_t tbs); @@ -179,7 +179,7 @@ public: private: void allocate_sdu(srsran::sch_pdu* pdu, uint32_t lcid, uint32_t sdu_len); - bool process_ce(srsran::sch_subh* subh); + bool process_ce(srsran::sch_subh* subh, int grant_nof_prbs); void allocate_ce(srsran::sch_pdu* pdu, uint32_t lcid); rlc_interface_mac* rlc = nullptr; diff --git a/srsenb/src/phy/lte/cc_worker.cc b/srsenb/src/phy/lte/cc_worker.cc index 196e158cc..e424d9c53 100644 --- a/srsenb/src/phy/lte/cc_worker.cc +++ b/srsenb/src/phy/lte/cc_worker.cc @@ -365,7 +365,8 @@ void cc_worker::decode_pusch(stack_interface_phy_lte::ul_sched_grant_t* grants, // Inform MAC about the CRC result phy->stack->crc_info(tti_rx, rnti, cc_idx, ul_cfg.pusch.grant.tb.tbs / 8, pusch_res.crc); // Push PDU buffer - phy->stack->push_pdu(tti_rx, rnti, cc_idx, ul_cfg.pusch.grant.tb.tbs / 8, pusch_res.crc); + phy->stack->push_pdu( + tti_rx, rnti, cc_idx, ul_cfg.pusch.grant.tb.tbs / 8, pusch_res.crc, ul_cfg.pusch.grant.L_prb); // Logging if (logger.info.enabled()) { char str[512]; diff --git a/srsenb/src/stack/mac/mac.cc b/srsenb/src/stack/mac/mac.cc index 17e2dee7d..7663df6b1 100644 --- a/srsenb/src/stack/mac/mac.cc +++ b/srsenb/src/stack/mac/mac.cc @@ -341,7 +341,12 @@ int mac::crc_info(uint32_t tti_rx, uint16_t rnti, uint32_t enb_cc_idx, uint32_t return scheduler.ul_crc_info(tti_rx, rnti, enb_cc_idx, crc); } -int mac::push_pdu(uint32_t tti_rx, uint16_t rnti, uint32_t enb_cc_idx, uint32_t nof_bytes, bool crc) +int mac::push_pdu(uint32_t tti_rx, + uint16_t rnti, + uint32_t enb_cc_idx, + uint32_t nof_bytes, + bool crc, + uint32_t ul_nof_prbs) { srsran::rwlock_read_guard lock(rwlock); @@ -359,7 +364,7 @@ int mac::push_pdu(uint32_t tti_rx, uint16_t rnti, uint32_t enb_cc_idx, uint32_t // push the pdu through the queue if received correctly if (crc) { logger.info("Pushing PDU rnti=0x%x, tti_rx=%d, nof_bytes=%d", rnti, tti_rx, nof_bytes); - ue_db[rnti]->push_pdu(tti_rx, ue_cc_idx, nof_bytes); + ue_db[rnti]->push_pdu(tti_rx, ue_cc_idx, nof_bytes, ul_nof_prbs); stack_task_queue.push([this]() { process_pdus(); }); } else { logger.debug("Discarting PDU rnti=0x%x, tti_rx=%d, nof_bytes=%d", rnti, tti_rx, nof_bytes); diff --git a/srsenb/src/stack/mac/sched.cc b/srsenb/src/stack/mac/sched.cc index 8156adfab..833b0c389 100644 --- a/srsenb/src/stack/mac/sched.cc +++ b/srsenb/src/stack/mac/sched.cc @@ -231,10 +231,10 @@ int sched::ul_buffer_add(uint16_t rnti, uint32_t lcid, uint32_t bytes) return ue_db_access_locked(rnti, [lcid, bytes](sched_ue& ue) { ue.ul_buffer_add(lcid, bytes); }); } -int sched::ul_phr(uint16_t rnti, int phr) +int sched::ul_phr(uint16_t rnti, int phr, uint32_t ul_nof_prb) { return ue_db_access_locked( - rnti, [phr](sched_ue& ue) { ue.ul_phr(phr); }, __PRETTY_FUNCTION__); + rnti, [phr, ul_nof_prb](sched_ue& ue) { ue.ul_phr(phr, ul_nof_prb); }, __PRETTY_FUNCTION__); } int sched::ul_sr_info(uint32_t tti, uint16_t rnti) diff --git a/srsenb/src/stack/mac/sched_ue.cc b/srsenb/src/stack/mac/sched_ue.cc index 7f56d6b99..2f269d5b6 100644 --- a/srsenb/src/stack/mac/sched_ue.cc +++ b/srsenb/src/stack/mac/sched_ue.cc @@ -131,9 +131,9 @@ void sched_ue::ul_buffer_add(uint8_t lcid, uint32_t bytes) lch_handler.ul_buffer_add(lcid, bytes); } -void sched_ue::ul_phr(int phr) +void sched_ue::ul_phr(int phr, uint32_t grant_nof_prb) { - cells[cfg.supported_cc_list[0].enb_cc_idx].tpc_fsm.set_phr(phr); + cells[cfg.supported_cc_list[0].enb_cc_idx].tpc_fsm.set_phr(phr, grant_nof_prb); } void sched_ue::dl_buffer_state(uint8_t lc_id, uint32_t tx_queue, uint32_t retx_queue) diff --git a/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc b/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc index c6876b008..b793bdad9 100644 --- a/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc +++ b/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc @@ -35,7 +35,8 @@ sched_ue_cell::sched_ue_cell(uint16_t rnti_, const sched_cell_params_t& cell_cfg cell_cfg(&cell_cfg_), dci_locations(generate_cce_location_table(rnti_, cell_cfg_)), harq_ent(SCHED_MAX_HARQ_PROC, SCHED_MAX_HARQ_PROC), - tpc_fsm(cell_cfg->nof_prb(), + tpc_fsm(rnti_, + cell_cfg->nof_prb(), cell_cfg->cfg.target_pucch_ul_sinr, cell_cfg->cfg.target_pusch_ul_sinr, cell_cfg->cfg.enable_phr_handling, diff --git a/srsenb/src/stack/mac/ue.cc b/srsenb/src/stack/mac/ue.cc index 9e5153a1a..20435213a 100644 --- a/srsenb/src/stack/mac/ue.cc +++ b/srsenb/src/stack/mac/ue.cc @@ -71,14 +71,14 @@ cc_used_buffers_map::~cc_used_buffers_map() clear(); } -bool cc_used_buffers_map::push_pdu(tti_point tti, uint32_t len) +bool cc_used_buffers_map::push_pdu(tti_point tti, uint32_t len, uint32_t grant_nof_prbs) { if (not has_tti(tti)) { return false; } uint8_t* buffer = pdu_map[tti.to_uint()]; if (len > 0) { - shared_pdu_queue->push(buffer, len); + shared_pdu_queue->push(buffer, len, srsran::pdu_queue::DCH, grant_nof_prbs); } else { shared_pdu_queue->deallocate(buffer); logger->error("Error pushing PDU: null length"); @@ -329,7 +329,7 @@ uint32_t ue::set_ta(int ta_) return nof_cmd; } -void ue::process_pdu(uint8_t* pdu, uint32_t nof_bytes, srsran::pdu_queue::channel_t channel) +void ue::process_pdu(uint8_t* pdu, uint32_t nof_bytes, srsran::pdu_queue::channel_t channel, int grant_nof_prbs) { // Unpack ULSCH MAC PDU mac_msg_ul.init_rx(nof_bytes, true); @@ -417,7 +417,7 @@ void ue::process_pdu(uint8_t* pdu, uint32_t nof_bytes, srsran::pdu_queue::channe assert(mac_msg_ul.get()); if (!mac_msg_ul.get()->is_sdu()) { // Process MAC Control Element - bsr_received |= process_ce(mac_msg_ul.get()); + bsr_received |= process_ce(mac_msg_ul.get(), grant_nof_prbs); } } @@ -440,15 +440,15 @@ void ue::deallocate_pdu(uint32_t tti, uint32_t ue_cc_idx) } } -void ue::push_pdu(uint32_t tti, uint32_t ue_cc_idx, uint32_t len) +void ue::push_pdu(uint32_t tti, uint32_t ue_cc_idx, uint32_t len, uint32_t grant_nof_prbs) { std::unique_lock lock(rx_buffers_mutex); - if (not cc_buffers[ue_cc_idx].get_rx_used_buffers().push_pdu(tti_point(tti), len)) { + if (not cc_buffers[ue_cc_idx].get_rx_used_buffers().push_pdu(tti_point(tti), len, grant_nof_prbs)) { logger.warning("UE buffers: Failed to push RX PDU for rnti=0x%x tti=%d cc_idx=%d", rnti, tti, ue_cc_idx); } } -bool ue::process_ce(srsran::sch_subh* subh) +bool ue::process_ce(srsran::sch_subh* subh, int grant_nof_prbs) { uint32_t buff_size_idx[4] = {}; uint32_t buff_size_bytes[4] = {}; @@ -459,7 +459,8 @@ bool ue::process_ce(srsran::sch_subh* subh) switch (subh->ul_sch_ce_type()) { case srsran::ul_sch_lcid::PHR_REPORT: phr = subh->get_phr(); - sched->ul_phr(rnti, (int)phr); + srsran_assert(grant_nof_prbs > 0, "Invalid nof prbs=%d provided for PHR handling", grant_nof_prbs); + sched->ul_phr(rnti, (int)phr, grant_nof_prbs); metrics_phr(phr); break; case srsran::ul_sch_lcid::CRNTI: diff --git a/srsenb/test/mac/sched_tpc_test.cc b/srsenb/test/mac/sched_tpc_test.cc index faffe4694..1bd28d559 100644 --- a/srsenb/test/mac/sched_tpc_test.cc +++ b/srsenb/test/mac/sched_tpc_test.cc @@ -26,7 +26,7 @@ int test_finite_target_snr() const uint32_t nof_prbs = 50; const int target_snr = 15; - tpc tpcfsm(nof_prbs, 15, 15, true); + tpc tpcfsm(0x46, nof_prbs, 15, 15, true); // 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) { @@ -78,7 +78,7 @@ int test_undefined_target_snr() { const uint32_t nof_prbs = 50; - tpc tpcfsm(nof_prbs, -1, -1, true); + tpc tpcfsm(0x46, nof_prbs, -1, -1, true); TESTASSERT(tpcfsm.max_ul_prbs() == 50); // TEST: While the PHR is not updated, a limited number of TPC commands should be sent @@ -107,7 +107,7 @@ int test_undefined_target_snr() // TEST: Check that high PHR allows full utilization of available PRBs, TPC remains at zero (no target SINR) int phr = 30; - tpcfsm.set_phr(phr); + tpcfsm.set_phr(phr, 1); TESTASSERT(tpcfsm.max_ul_prbs() == 50); sum_pusch = 0; sum_pucch = 0; @@ -120,7 +120,7 @@ int test_undefined_target_snr() // TEST: PHR is too low to allow all PRBs to be allocated. This event should not affect TPC commands phr = 5; - tpcfsm.set_phr(phr); + tpcfsm.set_phr(phr, 1); TESTASSERT(tpcfsm.max_ul_prbs() < 50); for (uint32_t i = 0; i < 100; ++i) { tpcfsm.new_tti(); @@ -130,7 +130,7 @@ int test_undefined_target_snr() // TEST: PHR is negative. The TPC should slightly decrease Tx UL power until next PHR phr = -1; - tpcfsm.set_phr(phr); + tpcfsm.set_phr(phr, 1); TESTASSERT(tpcfsm.max_ul_prbs() == tpc::PHR_NEG_NOF_PRB); sum_pusch = 0; sum_pucch = 0; diff --git a/srsenb/test/mac/sched_ue_cell_test.cc b/srsenb/test/mac/sched_ue_cell_test.cc index 44ff63269..2a1e70484 100644 --- a/srsenb/test/mac/sched_ue_cell_test.cc +++ b/srsenb/test/mac/sched_ue_cell_test.cc @@ -40,12 +40,12 @@ void test_neg_phr_scenario() float snr = 0; ue_cc.set_ul_snr(tti_point(0), snr, 0); ue_cc.set_ul_snr(tti_point(0), snr, 1); - ue_cc.tpc_fsm.set_phr(-5); + ue_cc.tpc_fsm.set_phr(-5, 1); ue_cc.new_tti(tti_point(0)); uint32_t req_bytes = 10000; uint32_t pending_prbs = get_required_prb_ul(ue_cc, req_bytes); - TESTASSERT(pending_prbs < 10); // The PHR<0 is limiting the number of allocated PRBs + TESTASSERT(pending_prbs == 1); // The PHR<0 is limiting the number of allocated PRBs uint32_t N_srs = 0; uint32_t prb_grant_size = pending_prbs; diff --git a/srsenb/test/phy/enb_phy_test.cc b/srsenb/test/phy/enb_phy_test.cc index ede958091..f2014e637 100644 --- a/srsenb/test/phy/enb_phy_test.cc +++ b/srsenb/test/phy/enb_phy_test.cc @@ -505,7 +505,8 @@ public: return 0; } - int push_pdu(uint32_t tti, uint16_t rnti, uint32_t cc_idx, uint32_t nof_bytes, bool crc_res) override + int push_pdu(uint32_t tti, uint16_t rnti, uint32_t cc_idx, uint32_t nof_bytes, bool crc_res, uint32_t grant_nof_prbs) + override { logger.info("Received push_pdu tti=%d; rnti=0x%x; ack=%d;", tti, rnti, crc_res); notify_push_pdu(); diff --git a/srsue/hdr/stack/mac/demux.h b/srsue/hdr/stack/mac/demux.h index 313e8d9fa..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, srsran::pdu_queue::channel_t channel); + 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 e601af618..eeff692b0 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, srsran::pdu_queue::channel_t channel) +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/test/ttcn3/hdr/ttcn3_syssim.h b/srsue/test/ttcn3/hdr/ttcn3_syssim.h index 827563841..1869b85dd 100644 --- a/srsue/test/ttcn3/hdr/ttcn3_syssim.h +++ b/srsue/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); + 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/test/ttcn3/src/ttcn3_syssim.cc b/srsue/test/ttcn3/src/ttcn3_syssim.cc index 8978e861b..c195dcd32 100644 --- a/srsue/test/ttcn3/src/ttcn3_syssim.cc +++ b/srsue/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) {} +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 ceaef3523fd0cbef26105a45d9947fdb50e74b08 Mon Sep 17 00:00:00 2001 From: Francisco Date: Wed, 2 Jun 2021 17:47:59 +0100 Subject: [PATCH 125/156] sched,feature: Enable setting the target PHR below which the maximum UL grant size starts decreasing --- .../srsran/interfaces/enb_rrc_interface_types.h | 1 + lib/include/srsran/interfaces/sched_interface.h | 1 + srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h | 5 ++++- srsenb/rr.conf.example | 2 ++ srsenb/src/enb_cfg_parser.cc | 1 + .../src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc | 1 + srsenb/src/stack/rrc/rrc.cc | 1 + srsenb/test/mac/sched_test_rand.cc | 1 + srsenb/test/mac/sched_test_utils.h | 2 ++ srsenb/test/mac/sched_ue_cell_test.cc | 14 +++++++++----- 10 files changed, 23 insertions(+), 6 deletions(-) diff --git a/lib/include/srsran/interfaces/enb_rrc_interface_types.h b/lib/include/srsran/interfaces/enb_rrc_interface_types.h index 6674fc43b..f5d6f4497 100644 --- a/lib/include/srsran/interfaces/enb_rrc_interface_types.h +++ b/lib/include/srsran/interfaces/enb_rrc_interface_types.h @@ -61,6 +61,7 @@ struct cell_cfg_t { int target_pusch_sinr_db; uint32_t initial_dl_cqi; bool enable_phr_handling; + int min_phr_thres; asn1::rrc::mob_ctrl_info_s::t304_e_ t304; std::vector scell_list; rrc_meas_cfg_t meas_cfg; diff --git a/lib/include/srsran/interfaces/sched_interface.h b/lib/include/srsran/interfaces/sched_interface.h index 3ae3ac340..f526fe56b 100644 --- a/lib/include/srsran/interfaces/sched_interface.h +++ b/lib/include/srsran/interfaces/sched_interface.h @@ -80,6 +80,7 @@ public: /* pusch configuration */ srsran_pusch_hopping_cfg_t pusch_hopping_cfg; float target_pusch_ul_sinr; + int min_phr_thres; bool enable_phr_handling; bool enable_64qam; diff --git a/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h b/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h index 4a3f37a1d..1ea15067b 100644 --- a/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h +++ b/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h @@ -40,6 +40,7 @@ public: float target_pucch_snr_dB_ = -1.0, float target_pusch_sn_dB_ = -1.0, bool phr_handling_flag_ = false, + int min_phr_thres_ = 0, uint32_t min_tpc_tti_interval_ = 1, float ul_snr_avg_alpha = 0.05, int init_ul_snr_value = 5) : @@ -47,6 +48,7 @@ public: nof_prb(cell_nof_prb), target_pucch_snr_dB(target_pucch_snr_dB_), target_pusch_snr_dB(target_pusch_sn_dB_), + min_phr_thres(min_phr_thres_), snr_estim_list( {ul_ch_snr_estim{ul_snr_avg_alpha, init_ul_snr_value}, ul_ch_snr_estim{ul_snr_avg_alpha, init_ul_snr_value}}), phr_handling_flag(phr_handling_flag_), @@ -83,7 +85,7 @@ public: max_prbs_cached = PHR_NEG_NOF_PRB; int phr_x_prb = std::roundf(last_phr + 10.0F * log10f(grant_nof_prbs)); // get what the PHR would be if Nprb=1 for (int n = nof_prb; n > PHR_NEG_NOF_PRB; --n) { - if (phr_x_prb >= 10 * log10f(n)) { + if (phr_x_prb >= 10 * log10f(n) + min_phr_thres) { max_prbs_cached = n; break; } @@ -193,6 +195,7 @@ private: uint32_t nof_prb; uint32_t min_tpc_tti_interval = 1; float target_pucch_snr_dB, target_pusch_snr_dB; + int min_phr_thres; bool phr_handling_flag; srslog::basic_logger& logger; diff --git a/srsenb/rr.conf.example b/srsenb/rr.conf.example index bdf62cc9a..ee1b285a9 100644 --- a/srsenb/rr.conf.example +++ b/srsenb/rr.conf.example @@ -65,6 +65,8 @@ cell_list = //meas_gap_offset_subframe = [6, 12, 18, 24, 30]; // target_pusch_sinr = -1; // target_pucch_sinr = -1; + // enable_phr_handling = false; + // min_phr_thres = 0; // allowed_meas_bw = 6; // t304 = 2000; // in msec. possible values: 50, 100, 150, 200, 500, 1000, 2000 diff --git a/srsenb/src/enb_cfg_parser.cc b/srsenb/src/enb_cfg_parser.cc index 3149f0360..cd48cc887 100644 --- a/srsenb/src/enb_cfg_parser.cc +++ b/srsenb/src/enb_cfg_parser.cc @@ -771,6 +771,7 @@ static int parse_cell_list(all_args_t* args, rrc_cfg_t* rrc_cfg, Setting& root) HANDLEPARSERCODE(parse_default_field(cell_cfg.target_pusch_sinr_db, cellroot, "target_pusch_sinr", -1)); HANDLEPARSERCODE(parse_default_field(cell_cfg.target_pucch_sinr_db, cellroot, "target_pucch_sinr", -1)); HANDLEPARSERCODE(parse_default_field(cell_cfg.enable_phr_handling, cellroot, "enable_phr_handling", false)); + HANDLEPARSERCODE(parse_default_field(cell_cfg.min_phr_thres, cellroot, "min_phr_thres", 0)); parse_default_field(cell_cfg.meas_cfg.allowed_meas_bw, cellroot, "allowed_meas_bw", 6u); srsran_assert(srsran::is_lte_cell_nof_prb(cell_cfg.meas_cfg.allowed_meas_bw), "Invalid measurement Bandwidth"); HANDLEPARSERCODE(asn1_parsers::default_number_to_enum( diff --git a/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc b/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc index b793bdad9..afecd674d 100644 --- a/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc +++ b/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc @@ -40,6 +40,7 @@ sched_ue_cell::sched_ue_cell(uint16_t rnti_, const sched_cell_params_t& cell_cfg cell_cfg->cfg.target_pucch_ul_sinr, cell_cfg->cfg.target_pusch_ul_sinr, cell_cfg->cfg.enable_phr_handling, + cell_cfg->cfg.min_phr_thres, cell_cfg->sched_cfg->min_tpc_tti_interval, cell_cfg->sched_cfg->ul_snr_avg_alpha, cell_cfg->sched_cfg->init_ul_snr_value), diff --git a/srsenb/src/stack/rrc/rrc.cc b/srsenb/src/stack/rrc/rrc.cc index 77cd7aecf..f9079443b 100644 --- a/srsenb/src/stack/rrc/rrc.cc +++ b/srsenb/src/stack/rrc/rrc.cc @@ -635,6 +635,7 @@ void rrc::config_mac() item.target_pucch_ul_sinr = cfg.cell_list[ccidx].target_pucch_sinr_db; item.target_pusch_ul_sinr = cfg.cell_list[ccidx].target_pusch_sinr_db; item.enable_phr_handling = cfg.cell_list[ccidx].enable_phr_handling; + item.min_phr_thres = cfg.cell_list[ccidx].min_phr_thres; item.delta_pucch_shift = cfg.sibs[1].sib2().rr_cfg_common.pucch_cfg_common.delta_pucch_shift.to_number(); item.ncs_an = cfg.sibs[1].sib2().rr_cfg_common.pucch_cfg_common.ncs_an; item.n1pucch_an = cfg.sibs[1].sib2().rr_cfg_common.pucch_cfg_common.n1_pucch_an; diff --git a/srsenb/test/mac/sched_test_rand.cc b/srsenb/test/mac/sched_test_rand.cc index 76f56cc87..f26a05566 100644 --- a/srsenb/test/mac/sched_test_rand.cc +++ b/srsenb/test/mac/sched_test_rand.cc @@ -274,6 +274,7 @@ sched_sim_events rand_sim_params(uint32_t nof_ttis) sim_gen.sim_args.cell_cfg[0].target_pucch_ul_sinr = pick_random_uniform({10, 15, 20, -1}); sim_gen.sim_args.cell_cfg[0].target_pusch_ul_sinr = pick_random_uniform({10, 15, 20, -1}); sim_gen.sim_args.cell_cfg[0].enable_phr_handling = false; + sim_gen.sim_args.cell_cfg[0].min_phr_thres = 0; sim_gen.sim_args.default_ue_sim_cfg.ue_cfg = generate_default_ue_cfg(); sim_gen.sim_args.default_ue_sim_cfg.periodic_cqi = true; sim_gen.sim_args.default_ue_sim_cfg.ue_cfg.maxharq_tx = std::uniform_int_distribution<>{1, 5}(srsenb::get_rand_gen()); diff --git a/srsenb/test/mac/sched_test_utils.h b/srsenb/test/mac/sched_test_utils.h index 003724629..f21734ce0 100644 --- a/srsenb/test/mac/sched_test_utils.h +++ b/srsenb/test/mac/sched_test_utils.h @@ -52,6 +52,8 @@ inline srsenb::sched_interface::cell_cfg_t generate_default_cell_cfg(uint32_t no cell_cfg.initial_dl_cqi = 6; cell_cfg.target_pusch_ul_sinr = -1; cell_cfg.target_pucch_ul_sinr = -1; + cell_cfg.enable_phr_handling = false; + cell_cfg.min_phr_thres = 0; cell_cfg.nrb_cqi = 1; cell_cfg.n1pucch_an = 12; cell_cfg.delta_pucch_shift = 1; diff --git a/srsenb/test/mac/sched_ue_cell_test.cc b/srsenb/test/mac/sched_ue_cell_test.cc index 2a1e70484..5a3f29d65 100644 --- a/srsenb/test/mac/sched_ue_cell_test.cc +++ b/srsenb/test/mac/sched_ue_cell_test.cc @@ -28,6 +28,7 @@ void test_neg_phr_scenario() sched_interface::cell_cfg_t cell_cfg = generate_default_cell_cfg(50); cell_cfg.target_pucch_ul_sinr = 20; cell_cfg.target_pusch_ul_sinr = 20; + cell_cfg.min_phr_thres = 0; cell_cfg.enable_phr_handling = true; sched_interface::sched_args_t sched_cfg = {}; sched_cell_params_t cell_params; @@ -37,11 +38,14 @@ void test_neg_phr_scenario() sched_ue_cell ue_cc(0x46, cell_params, tti_point(0)); ue_cc.set_ue_cfg(ue_cfg); - float snr = 0; - ue_cc.set_ul_snr(tti_point(0), snr, 0); - ue_cc.set_ul_snr(tti_point(0), snr, 1); - ue_cc.tpc_fsm.set_phr(-5, 1); - ue_cc.new_tti(tti_point(0)); + float snr = 20; + tti_point tti{0}; + for (; ue_cc.tpc_fsm.get_ul_snr_estim(0) < snr - 2; ++tti) { + ue_cc.set_ul_snr(tti, snr, 0); + ue_cc.set_ul_snr(tti, snr, 1); + ue_cc.tpc_fsm.set_phr(-5, 1); + ue_cc.new_tti(tti); + } uint32_t req_bytes = 10000; uint32_t pending_prbs = get_required_prb_ul(ue_cc, req_bytes); From 3df72cb6ab8a5aa471436aebe3671bac492ced32 Mon Sep 17 00:00:00 2001 From: faluco Date: Fri, 28 May 2021 12:58:55 +0200 Subject: [PATCH 126/156] Move out a free call in a RT thread when doing lots of rachs. --- srsenb/src/stack/mac/mac.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/srsenb/src/stack/mac/mac.cc b/srsenb/src/stack/mac/mac.cc index 7663df6b1..25772a3a0 100644 --- a/srsenb/src/stack/mac/mac.cc +++ b/srsenb/src/stack/mac/mac.cc @@ -545,12 +545,12 @@ void mac::rach_detected(uint32_t tti, uint32_t enb_cc_idx, uint32_t preamble_idx logger.set_context(tti); auto rach_tprof_meas = rach_tprof.start(); - uint16_t rnti = allocate_ue(); - if (rnti == SRSRAN_INVALID_RNTI) { - return; - } + stack_task_queue.push([this, tti, enb_cc_idx, preamble_idx, time_adv, rach_tprof_meas]() mutable { + uint16_t rnti = allocate_ue(); + if (rnti == SRSRAN_INVALID_RNTI) { + return; + } - stack_task_queue.push([this, rnti, tti, enb_cc_idx, preamble_idx, time_adv, rach_tprof_meas]() mutable { rach_tprof_meas.defer_stop(); // Generate RAR data sched_interface::dl_sched_rar_info_t rar_info = {}; From 80a89ec4bfe1235f199c3f1b833c832b8e040255 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Thu, 3 Jun 2021 17:18:28 +0200 Subject: [PATCH 127/156] enb,mac: protect concurrent access to ue_db from different threads race condition between PHY worker(s) and Stack thread when accessing ue_db member. RWlock needs to be hold. partly fixes #2932 --- srsenb/src/stack/mac/mac.cc | 80 +++++++++++++++++++------------------ 1 file changed, 41 insertions(+), 39 deletions(-) diff --git a/srsenb/src/stack/mac/mac.cc b/srsenb/src/stack/mac/mac.cc index 25772a3a0..f8f4a2185 100644 --- a/srsenb/src/stack/mac/mac.cc +++ b/srsenb/src/stack/mac/mac.cc @@ -126,6 +126,7 @@ void mac::reset() void mac::start_pcap(srsran::mac_pcap* pcap_) { + srsran::rwlock_read_guard lock(rwlock); pcap = pcap_; // Set pcap in all UEs for UL messages for (auto& u : ue_db) { @@ -135,6 +136,7 @@ void mac::start_pcap(srsran::mac_pcap* pcap_) void mac::start_pcap_net(srsran::mac_pcap_net* pcap_net_) { + srsran::rwlock_read_guard lock(rwlock); pcap_net = pcap_net_; // Set pcap in all UEs for UL messages for (auto& u : ue_db) { @@ -292,6 +294,7 @@ void mac::toggle_padding() void mac::add_padding() { + srsran::rwlock_read_guard lock(rwlock); for (auto it = ue_db.begin(); it != ue_db.end(); ++it) { uint16_t cur_rnti = it->first; auto ue = it; @@ -817,6 +820,7 @@ void mac::build_mch_sched(uint32_t tbs) int mac::get_mch_sched(uint32_t tti, bool is_mcch, dl_sched_list_t& dl_sched_res_list) { + srsran::rwlock_read_guard lock(rwlock); dl_sched_t* dl_sched_res = &dl_sched_res_list[0]; logger.set_context(tti); srsran_ra_tb_t mcs = {}; @@ -930,6 +934,8 @@ int mac::get_ul_sched(uint32_t tti_tx_ul, ul_sched_list_t& ul_sched_res_list) logger.set_context(TTI_SUB(tti_tx_ul, FDD_HARQ_DELAY_UL_MS + FDD_HARQ_DELAY_DL_MS)); + srsran::rwlock_read_guard lock(rwlock); + // Execute UE FSMs (e.g. TA) for (auto& ue : ue_db) { ue.second->tic(); @@ -945,52 +951,46 @@ int mac::get_ul_sched(uint32_t tti_tx_ul, ul_sched_list_t& ul_sched_res_list) return SRSRAN_ERROR; } - { - srsran::rwlock_read_guard lock(rwlock); + // Copy DCI grants + phy_ul_sched_res->nof_grants = 0; + int n = 0; + for (uint32_t i = 0; i < sched_result.pusch.size(); i++) { + if (sched_result.pusch[i].tbs > 0) { + // Get UE + uint16_t rnti = sched_result.pusch[i].dci.rnti; - // Copy DCI grants - phy_ul_sched_res->nof_grants = 0; - int n = 0; - for (uint32_t i = 0; i < sched_result.pusch.size(); i++) { - if (sched_result.pusch[i].tbs > 0) { - // Get UE - uint16_t rnti = sched_result.pusch[i].dci.rnti; - - if (ue_db.contains(rnti)) { - // Copy grant info - phy_ul_sched_res->pusch[n].current_tx_nb = sched_result.pusch[i].current_tx_nb; - phy_ul_sched_res->pusch[n].pid = TTI_RX(tti_tx_ul) % SRSRAN_FDD_NOF_HARQ; - phy_ul_sched_res->pusch[n].needs_pdcch = sched_result.pusch[i].needs_pdcch; - phy_ul_sched_res->pusch[n].dci = sched_result.pusch[i].dci; - phy_ul_sched_res->pusch[n].softbuffer_rx = - ue_db[rnti]->get_rx_softbuffer(sched_result.pusch[i].dci.ue_cc_idx, tti_tx_ul); - - // If the Rx soft-buffer is not given, abort reception - if (phy_ul_sched_res->pusch[n].softbuffer_rx == nullptr) { - continue; - } + if (ue_db.contains(rnti)) { + // Copy grant info + phy_ul_sched_res->pusch[n].current_tx_nb = sched_result.pusch[i].current_tx_nb; + phy_ul_sched_res->pusch[n].pid = TTI_RX(tti_tx_ul) % SRSRAN_FDD_NOF_HARQ; + phy_ul_sched_res->pusch[n].needs_pdcch = sched_result.pusch[i].needs_pdcch; + phy_ul_sched_res->pusch[n].dci = sched_result.pusch[i].dci; + phy_ul_sched_res->pusch[n].softbuffer_rx = + ue_db[rnti]->get_rx_softbuffer(sched_result.pusch[i].dci.ue_cc_idx, tti_tx_ul); + + // If the Rx soft-buffer is not given, abort reception + if (phy_ul_sched_res->pusch[n].softbuffer_rx == nullptr) { + continue; + } - if (sched_result.pusch[n].current_tx_nb == 0) { - srsran_softbuffer_rx_reset_tbs(phy_ul_sched_res->pusch[n].softbuffer_rx, sched_result.pusch[i].tbs * 8); - } - phy_ul_sched_res->pusch[n].data = - ue_db[rnti]->request_buffer(tti_tx_ul, sched_result.pusch[i].dci.ue_cc_idx, sched_result.pusch[i].tbs); - if (phy_ul_sched_res->pusch[n].data) { - phy_ul_sched_res->nof_grants++; - } else { - logger.error("Grant for rnti=0x%x could not be allocated due to lack of buffers", rnti); - } - n++; + if (sched_result.pusch[n].current_tx_nb == 0) { + srsran_softbuffer_rx_reset_tbs(phy_ul_sched_res->pusch[n].softbuffer_rx, sched_result.pusch[i].tbs * 8); + } + phy_ul_sched_res->pusch[n].data = + ue_db[rnti]->request_buffer(tti_tx_ul, sched_result.pusch[i].dci.ue_cc_idx, sched_result.pusch[i].tbs); + if (phy_ul_sched_res->pusch[n].data) { + phy_ul_sched_res->nof_grants++; } else { - logger.warning("Invalid UL scheduling result. User 0x%x does not exist", rnti); + logger.error("Grant for rnti=0x%x could not be allocated due to lack of buffers", rnti); } - + n++; } else { - logger.warning("Grant %d for rnti=0x%x has zero TBS", i, sched_result.pusch[i].dci.rnti); + logger.warning("Invalid UL scheduling result. User 0x%x does not exist", rnti); } - } - // No more uses of ue_db beyond here + } else { + logger.warning("Grant %d for rnti=0x%x has zero TBS", i, sched_result.pusch[i].dci.rnti); + } } // Copy PHICH actions @@ -1023,6 +1023,7 @@ void mac::write_mcch(const srsran::sib2_mbms_t* sib2_, const uint8_t* mcch_payload, const uint8_t mcch_payload_length) { + srsran::rwlock_write_guard lock(rwlock); mcch = *mcch_; mch.num_mtch_sched = this->mcch.pmch_info_list[0].nof_mbms_session_info; for (uint32_t i = 0; i < mch.num_mtch_sched; ++i) { @@ -1038,6 +1039,7 @@ void mac::write_mcch(const srsran::sib2_mbms_t* sib2_, rrc_h->add_user(SRSRAN_MRNTI, {}); } +// Internal helper function, caller must hold UE DB rwlock bool mac::check_ue_exists(uint16_t rnti) { if (not ue_db.contains(rnti)) { From 5d238a6d80f730ba57f05c216cdec6cc62c50c55 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Thu, 3 Jun 2021 17:20:02 +0200 Subject: [PATCH 128/156] cmake: fix compilation with MSAN and enable origin tracking --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a5682e077..4109dd73e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -491,8 +491,8 @@ if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang") endif (ENABLE_TSAN) if (ENABLE_MSAN AND CMAKE_C_COMPILER_ID MATCHES "Clang") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=memory -fno-omit-frame-pointer -fPIE -pie") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=memory -fno-omit-frame-pointer -fPIE -pie") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=memory -fno-omit-frame-pointer -fsanitize-memory-track-origins -fPIE") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=memory -fno-omit-frame-pointer -fsanitize-memory-track-origins -fPIE") endif (ENABLE_MSAN AND CMAKE_C_COMPILER_ID MATCHES "Clang") if (ENABLE_GCOV) From 107f6334dd625f8e7ea26ce95630cc54ebbec9f8 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Wed, 2 Jun 2021 14:44:32 +0200 Subject: [PATCH 129/156] compile: fix compilation on 32bit systems that require -latomic --- lib/src/upper/CMakeLists.txt | 2 +- lib/test/common/CMakeLists.txt | 4 ++-- lib/test/upper/CMakeLists.txt | 4 ++-- srsenb/test/rrc/CMakeLists.txt | 8 ++++---- srsue/src/CMakeLists.txt | 3 ++- srsue/src/stack/mac_nr/test/CMakeLists.txt | 6 +++--- srsue/test/upper/CMakeLists.txt | 2 +- 7 files changed, 15 insertions(+), 14 deletions(-) diff --git a/lib/src/upper/CMakeLists.txt b/lib/src/upper/CMakeLists.txt index 9d70b93ad..c6b65ba10 100644 --- a/lib/src/upper/CMakeLists.txt +++ b/lib/src/upper/CMakeLists.txt @@ -22,5 +22,5 @@ set(SOURCES gtpu.cc bearer_mem_pool.cc) add_library(srsran_upper STATIC ${SOURCES}) -target_link_libraries(srsran_upper srsran_common srsran_asn1) +target_link_libraries(srsran_upper srsran_common srsran_asn1 ${ATOMIC_LIBS}) INSTALL(TARGETS srsran_upper DESTINATION ${LIBRARY_DIR}) diff --git a/lib/test/common/CMakeLists.txt b/lib/test/common/CMakeLists.txt index 4ea720a21..1b731e167 100644 --- a/lib/test/common/CMakeLists.txt +++ b/lib/test/common/CMakeLists.txt @@ -54,7 +54,7 @@ target_link_libraries(queue_test srsran_common ${CMAKE_THREAD_LIBS_INIT}) add_test(queue_test queue_test) add_executable(timer_test timer_test.cc) -target_link_libraries(timer_test srsran_common) +target_link_libraries(timer_test srsran_common ${ATOMIC_LIBS}) add_test(timer_test timer_test) add_executable(network_utils_test network_utils_test.cc) @@ -70,7 +70,7 @@ target_link_libraries(choice_type_test srsran_common) add_test(choice_type_test choice_type_test) add_executable(task_scheduler_test task_scheduler_test.cc) -target_link_libraries(task_scheduler_test srsran_common) +target_link_libraries(task_scheduler_test srsran_common ${ATOMIC_LIBS}) add_test(task_scheduler_test task_scheduler_test) add_executable(pnf_dummy pnf_dummy.cc) diff --git a/lib/test/upper/CMakeLists.txt b/lib/test/upper/CMakeLists.txt index e17961e96..b17495db8 100644 --- a/lib/test/upper/CMakeLists.txt +++ b/lib/test/upper/CMakeLists.txt @@ -25,7 +25,7 @@ target_link_libraries(rlc_am_nr_pdu_test srsran_upper srsran_phy) add_nr_test(rlc_am_nr_pdu_test rlc_am_nr_pdu_test) add_executable(rlc_stress_test rlc_stress_test.cc) -target_link_libraries(rlc_stress_test srsran_upper srsran_mac srsran_phy srsran_common ${Boost_LIBRARIES}) +target_link_libraries(rlc_stress_test srsran_upper srsran_mac srsran_phy srsran_common ${Boost_LIBRARIES} ${ATOMIC_LIBS}) add_lte_test(rlc_am_stress_test rlc_stress_test --mode=AM --loglevel 1 --sdu_gen_delay 250) add_lte_test(rlc_um_stress_test rlc_stress_test --mode=UM --loglevel 1) add_lte_test(rlc_tm_stress_test rlc_stress_test --mode=TM --loglevel 1 --random_opp=false) @@ -62,7 +62,7 @@ target_link_libraries(pdcp_nr_test_rx srsran_upper srsran_common) add_nr_test(pdcp_nr_test_rx pdcp_nr_test_rx) add_executable(pdcp_nr_test_discard_sdu pdcp_nr_test_discard_sdu.cc) -target_link_libraries(pdcp_nr_test_discard_sdu srsran_upper srsran_common) +target_link_libraries(pdcp_nr_test_discard_sdu srsran_upper srsran_common ${ATOMIC_LIBS}) add_nr_test(pdcp_nr_test_discard_sdu pdcp_nr_test_discard_sdu) add_executable(pdcp_lte_test_rx pdcp_lte_test_rx.cc) diff --git a/srsenb/test/rrc/CMakeLists.txt b/srsenb/test/rrc/CMakeLists.txt index c6e86a03d..2a57744b2 100644 --- a/srsenb/test/rrc/CMakeLists.txt +++ b/srsenb/test/rrc/CMakeLists.txt @@ -10,17 +10,17 @@ add_library(test_helpers test_helpers.cc) target_link_libraries(test_helpers srsenb_rrc srsenb_common rrc_asn1 s1ap_asn1 srsran_common enb_cfg_parser ${LIBCONFIGPP_LIBRARIES}) add_executable(rrc_nr_test rrc_nr_test.cc) -target_link_libraries(rrc_nr_test srsgnb_rrc srsran_common rrc_nr_asn1) +target_link_libraries(rrc_nr_test srsgnb_rrc srsran_common rrc_nr_asn1 ${ATOMIC_LIBS}) add_test(rrc_nr_test rrc_nr_test) add_executable(rrc_meascfg_test rrc_meascfg_test.cc) -target_link_libraries(rrc_meascfg_test test_helpers) +target_link_libraries(rrc_meascfg_test test_helpers ${ATOMIC_LIBS}) add_executable(erab_setup_test erab_setup_test.cc) -target_link_libraries(erab_setup_test test_helpers ${LIBCONFIGPP_LIBRARIES}) +target_link_libraries(erab_setup_test test_helpers ${LIBCONFIGPP_LIBRARIES} ${ATOMIC_LIBS}) add_executable(rrc_mobility_test rrc_mobility_test.cc) -target_link_libraries(rrc_mobility_test srsran_asn1 test_helpers) +target_link_libraries(rrc_mobility_test srsran_asn1 test_helpers ${ATOMIC_LIBS}) add_test(rrc_mobility_test rrc_mobility_test -i ${CMAKE_CURRENT_SOURCE_DIR}/../..) add_test(erab_setup_test erab_setup_test -i ${CMAKE_CURRENT_SOURCE_DIR}/../..) diff --git a/srsue/src/CMakeLists.txt b/srsue/src/CMakeLists.txt index 6b8d0e653..aa6809c9f 100644 --- a/srsue/src/CMakeLists.txt +++ b/srsue/src/CMakeLists.txt @@ -29,7 +29,8 @@ set(SRSRAN_SOURCES ${SRSRAN_SOURCES} rrc_nr_asn1 ngap_nr_asn1) target_link_libraries(srsue ${SRSUE_SOURCES} ${SRSRAN_SOURCES} ${CMAKE_THREAD_LIBS_INIT} - ${Boost_LIBRARIES}) + ${Boost_LIBRARIES} + ${ATOMIC_LIBS}) if (RPATH) set_target_properties(srsue PROPERTIES INSTALL_RPATH ".") diff --git a/srsue/src/stack/mac_nr/test/CMakeLists.txt b/srsue/src/stack/mac_nr/test/CMakeLists.txt index d9039c278..76ad50743 100644 --- a/srsue/src/stack/mac_nr/test/CMakeLists.txt +++ b/srsue/src/stack/mac_nr/test/CMakeLists.txt @@ -7,11 +7,11 @@ # add_executable(proc_ra_nr_test proc_ra_nr_test.cc) -target_link_libraries(proc_ra_nr_test srsue_mac_nr srsran_common) +target_link_libraries(proc_ra_nr_test srsue_mac_nr srsran_common ${ATOMIC_LIBS}) add_test(proc_ra_nr_test proc_ra_nr_test) add_executable(proc_bsr_nr_test proc_bsr_nr_test.cc) -target_link_libraries(proc_bsr_nr_test srsue_mac_nr srsran_common) +target_link_libraries(proc_bsr_nr_test srsue_mac_nr srsran_common ${ATOMIC_LIBS}) add_test(proc_bsr_nr_test proc_bsr_nr_test) add_executable(proc_sr_nr_test proc_sr_nr_test.cc) @@ -19,5 +19,5 @@ target_link_libraries(proc_sr_nr_test srsue_mac_nr srsran_common) add_test(proc_sr_nr_test proc_sr_nr_test) add_executable(mac_nr_test mac_nr_test.cc) -target_link_libraries(mac_nr_test srsue_mac_nr srsran_common) +target_link_libraries(mac_nr_test srsue_mac_nr srsran_common ${ATOMIC_LIBS}) add_test(mac_nr_test mac_nr_test) \ No newline at end of file diff --git a/srsue/test/upper/CMakeLists.txt b/srsue/test/upper/CMakeLists.txt index 959712a34..f3e3cc3db 100644 --- a/srsue/test/upper/CMakeLists.txt +++ b/srsue/test/upper/CMakeLists.txt @@ -36,7 +36,7 @@ target_link_libraries(tft_test srsue_upper srsran_upper srsran_phy) add_test(tft_test tft_test) add_executable(rrc_phy_ctrl_test rrc_phy_ctrl_test.cc) -target_link_libraries(rrc_phy_ctrl_test srsran_common srsue_rrc) +target_link_libraries(rrc_phy_ctrl_test srsran_common srsue_rrc ${ATOMIC_LIBS}) add_test(rrc_phy_ctrl_test rrc_phy_ctrl_test) add_executable(rrc_cell_test rrc_cell_test.cc) From aaffdeb326bba1c72ffe991627184706245a9394 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Thu, 3 Jun 2021 11:36:45 +0200 Subject: [PATCH 130/156] rrc,rlc: add method to signal protocol failure to RRC general-purpose method for lower layers to signal protocol failures to higher layers, i.e. RRC. In the current case, implement a direct release of the UE (enb) or a reestablishment (UE). --- lib/include/srsran/interfaces/enb_rrc_interfaces.h | 1 + lib/include/srsran/interfaces/gnb_interfaces.h | 1 + lib/include/srsran/interfaces/ue_rrc_interfaces.h | 1 + lib/test/upper/rlc_am_test.cc | 2 ++ lib/test/upper/rlc_common_test.cc | 1 + lib/test/upper/rlc_stress_test.cc | 6 ++++++ lib/test/upper/rlc_test_common.h | 1 + srsenb/hdr/stack/rrc/rrc.h | 2 ++ srsenb/hdr/stack/rrc/rrc_nr.h | 1 + srsenb/hdr/stack/rrc/rrc_ue.h | 2 ++ srsenb/hdr/stack/upper/rlc.h | 1 + srsenb/hdr/stack/upper/rlc_nr.h | 1 + srsenb/src/stack/rrc/rrc.cc | 11 +++++++++++ srsenb/src/stack/rrc/rrc_ue.cc | 11 +++++++++++ srsenb/src/stack/upper/rlc.cc | 5 +++++ srsenb/src/stack/upper/rlc_nr.cc | 5 +++++ srsue/hdr/stack/rrc/rrc.h | 1 + srsue/hdr/stack/rrc/rrc_nr.h | 1 + srsue/src/stack/rrc/rrc.cc | 5 +++++ srsue/src/stack/rrc/rrc_nr.cc | 1 + srsue/test/ttcn3/hdr/ttcn3_syssim.h | 1 + srsue/test/ttcn3/src/ttcn3_syssim.cc | 4 ++++ 22 files changed, 65 insertions(+) diff --git a/lib/include/srsran/interfaces/enb_rrc_interfaces.h b/lib/include/srsran/interfaces/enb_rrc_interfaces.h index 967426f50..961bd1a50 100644 --- a/lib/include/srsran/interfaces/enb_rrc_interfaces.h +++ b/lib/include/srsran/interfaces/enb_rrc_interfaces.h @@ -91,6 +91,7 @@ class rrc_interface_rlc { public: virtual void max_retx_attempted(uint16_t rnti) = 0; + virtual void protocol_failure(uint16_t rnti) = 0; virtual void write_pdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t sdu) = 0; }; diff --git a/lib/include/srsran/interfaces/gnb_interfaces.h b/lib/include/srsran/interfaces/gnb_interfaces.h index 35f19d651..50a3a5f0d 100644 --- a/lib/include/srsran/interfaces/gnb_interfaces.h +++ b/lib/include/srsran/interfaces/gnb_interfaces.h @@ -151,6 +151,7 @@ class rrc_interface_rlc_nr public: virtual void read_pdu_pcch(uint8_t* payload, uint32_t payload_size) = 0; virtual void max_retx_attempted(uint16_t rnti) = 0; + virtual void protocol_failure(uint16_t rnti) = 0; virtual void write_pdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t sdu) = 0; virtual const char* get_rb_name(uint32_t lcid) = 0; }; diff --git a/lib/include/srsran/interfaces/ue_rrc_interfaces.h b/lib/include/srsran/interfaces/ue_rrc_interfaces.h index b72e59fdd..7b40ab483 100644 --- a/lib/include/srsran/interfaces/ue_rrc_interfaces.h +++ b/lib/include/srsran/interfaces/ue_rrc_interfaces.h @@ -91,6 +91,7 @@ class rrc_interface_rlc { public: virtual void max_retx_attempted() = 0; + virtual void protocol_failure() = 0; virtual const char* get_rb_name(uint32_t lcid) = 0; virtual void write_pdu(uint32_t lcid, srsran::unique_byte_buffer_t pdu) = 0; }; diff --git a/lib/test/upper/rlc_am_test.cc b/lib/test/upper/rlc_am_test.cc index 89e163e60..5baa7907b 100644 --- a/lib/test/upper/rlc_am_test.cc +++ b/lib/test/upper/rlc_am_test.cc @@ -70,12 +70,14 @@ public: // RRC interface void max_retx_attempted() { max_retx_triggered = true; } + void protocol_failure() { protocol_failure_triggered = true; } const char* get_rb_name(uint32_t lcid) { return ""; } std::vector sdus; rlc_pcap* pcap = nullptr; bool max_retx_triggered = false; + bool protocol_failure_triggered = false; std::map notified_counts; // Map of PDCP SNs to number of notifications }; diff --git a/lib/test/upper/rlc_common_test.cc b/lib/test/upper/rlc_common_test.cc index 8437b5103..cdcf198c1 100644 --- a/lib/test/upper/rlc_common_test.cc +++ b/lib/test/upper/rlc_common_test.cc @@ -54,6 +54,7 @@ public: // RRC interface void max_retx_attempted() {} + void protocol_failure() {} const char* get_rb_name(uint32_t lcid) { return "TestRB"; } void set_expected_sdu_len(uint32_t len) { expected_sdu_len = len; } diff --git a/lib/test/upper/rlc_stress_test.cc b/lib/test/upper/rlc_stress_test.cc index 5b2db1d91..bf7ed78f0 100644 --- a/lib/test/upper/rlc_stress_test.cc +++ b/lib/test/upper/rlc_stress_test.cc @@ -381,6 +381,12 @@ public: std::this_thread::sleep_for(std::chrono::seconds(1)); exit(1); } + void protocol_failure() + { + logger.error("RLC protocol error detected."); + std::this_thread::sleep_for(std::chrono::seconds(1)); + exit(1); + } const char* get_rb_name(uint32_t rx_lcid) { return "DRB1"; } int get_nof_rx_pdus() { return rx_pdus; } diff --git a/lib/test/upper/rlc_test_common.h b/lib/test/upper/rlc_test_common.h index 0278bac39..494a09a60 100644 --- a/lib/test/upper/rlc_test_common.h +++ b/lib/test/upper/rlc_test_common.h @@ -56,6 +56,7 @@ public: // RRC interface void max_retx_attempted() {} + void protocol_failure() {} const char* get_rb_name(uint32_t lcid) { return ""; } void set_expected_sdu_len(uint32_t len) { expected_sdu_len = len; } diff --git a/srsenb/hdr/stack/rrc/rrc.h b/srsenb/hdr/stack/rrc/rrc.h index 4e0b0c44b..274ae5d75 100644 --- a/srsenb/hdr/stack/rrc/rrc.h +++ b/srsenb/hdr/stack/rrc/rrc.h @@ -79,6 +79,7 @@ public: // rrc_interface_rlc void read_pdu_pcch(uint32_t tti_tx_dl, uint8_t* payload, uint32_t buffer_size) override; void max_retx_attempted(uint16_t rnti) override; + void protocol_failure(uint16_t rnti) override; // rrc_interface_s1ap void write_dl_info(uint16_t rnti, srsran::unique_byte_buffer_t sdu) override; @@ -193,6 +194,7 @@ private: const static uint32_t LCID_RLC_RTX = 0xffff0005; const static uint32_t LCID_RADLINK_DL = 0xffff0006; const static uint32_t LCID_RADLINK_UL = 0xffff0007; + const static uint32_t LCID_PROT_FAIL = 0xffff0008; bool running = false; srsran::dyn_blocking_queue rx_pdu_queue; diff --git a/srsenb/hdr/stack/rrc/rrc_nr.h b/srsenb/hdr/stack/rrc/rrc_nr.h index b8fbf1622..70eebdecd 100644 --- a/srsenb/hdr/stack/rrc/rrc_nr.h +++ b/srsenb/hdr/stack/rrc/rrc_nr.h @@ -88,6 +88,7 @@ public: // TODO void read_pdu_pcch(uint8_t* payload, uint32_t payload_size) {} void max_retx_attempted(uint16_t rnti) {} + void protocol_failure(uint16_t rnti) {} const char* get_rb_name(uint32_t lcid) { return "invalid"; } // PDCP interface void write_pdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t pdu) final; diff --git a/srsenb/hdr/stack/rrc/rrc_ue.h b/srsenb/hdr/stack/rrc/rrc_ue.h index b46302d62..2d1e0f171 100644 --- a/srsenb/hdr/stack/rrc/rrc_ue.h +++ b/srsenb/hdr/stack/rrc/rrc_ue.h @@ -46,6 +46,7 @@ public: void activity_timer_expired(const activity_timeout_type_t type); void rlf_timer_expired(uint32_t timeout_id); void max_rlc_retx_reached(); + void protocol_failure(); void deactivate_bearers() { mac_ctrl.set_radio_bearer_state(sched_interface::ue_bearer_cfg_t::IDLE); } rrc_state_t get_state(); @@ -62,6 +63,7 @@ public: error_unknown_rnti, radio_conn_with_ue_lost, msg3_timeout, + fail_in_radio_interface_proc, unspecified }; diff --git a/srsenb/hdr/stack/upper/rlc.h b/srsenb/hdr/stack/upper/rlc.h index a4a08ecfe..30fdc2875 100644 --- a/srsenb/hdr/stack/upper/rlc.h +++ b/srsenb/hdr/stack/upper/rlc.h @@ -78,6 +78,7 @@ private: void write_pdu_pcch(srsran::unique_byte_buffer_t sdu); void write_pdu_mch(uint32_t lcid, srsran::unique_byte_buffer_t sdu) {} void max_retx_attempted(); + void protocol_failure(); const char* get_rb_name(uint32_t lcid); uint16_t rnti; diff --git a/srsenb/hdr/stack/upper/rlc_nr.h b/srsenb/hdr/stack/upper/rlc_nr.h index f655673e3..5e72e6382 100644 --- a/srsenb/hdr/stack/upper/rlc_nr.h +++ b/srsenb/hdr/stack/upper/rlc_nr.h @@ -67,6 +67,7 @@ private: void write_pdu_pcch(srsran::unique_byte_buffer_t sdu); void write_pdu_mch(uint32_t lcid, srsran::unique_byte_buffer_t sdu) {} void max_retx_attempted() final; + void protocol_failure() final; const char* get_rb_name(uint32_t lcid) final; uint16_t rnti; diff --git a/srsenb/src/stack/rrc/rrc.cc b/srsenb/src/stack/rrc/rrc.cc index f9079443b..3d6992eb1 100644 --- a/srsenb/src/stack/rrc/rrc.cc +++ b/srsenb/src/stack/rrc/rrc.cc @@ -181,6 +181,14 @@ void rrc::max_retx_attempted(uint16_t rnti) } } +void rrc::protocol_failure(uint16_t rnti) +{ + rrc_pdu p = {rnti, LCID_PROT_FAIL, false, nullptr}; + if (not rx_pdu_queue.try_push(std::move(p))) { + logger.error("Failed to push protocol failure to RRC queue"); + } +} + // This function is called from PRACH worker (can wait) int rrc::add_user(uint16_t rnti, const sched_interface::ue_cfg_t& sched_ue_cfg) { @@ -944,6 +952,9 @@ void rrc::tti_clock() case LCID_RLC_RTX: user_it->second->max_rlc_retx_reached(); break; + case LCID_PROT_FAIL: + user_it->second->protocol_failure(); + break; case LCID_EXIT: logger.info("Exiting thread"); break; diff --git a/srsenb/src/stack/rrc/rrc_ue.cc b/srsenb/src/stack/rrc/rrc_ue.cc index 01d1d7cba..f1ad7d9a0 100644 --- a/srsenb/src/stack/rrc/rrc_ue.cc +++ b/srsenb/src/stack/rrc/rrc_ue.cc @@ -253,6 +253,17 @@ void rrc::ue::max_rlc_retx_reached() rlc_rlf_timer.run(); } +void rrc::ue::protocol_failure() +{ + parent->logger.info("RLC protocol failure for rnti=0x%x", rnti); + + // Release UE immediately with appropiate cause + state = RRC_STATE_RELEASE_REQUEST; + + parent->s1ap->user_release(rnti, asn1::s1ap::cause_radio_network_opts::fail_in_radio_interface_proc); + con_release_result = procedure_result_code::fail_in_radio_interface_proc; +} + void rrc::ue::set_activity_timeout(activity_timeout_type_t type) { uint32_t deadline_ms = 0; diff --git a/srsenb/src/stack/upper/rlc.cc b/srsenb/src/stack/upper/rlc.cc index 6c43421aa..5f44dd2b7 100644 --- a/srsenb/src/stack/upper/rlc.cc +++ b/srsenb/src/stack/upper/rlc.cc @@ -255,6 +255,11 @@ void rlc::user_interface::max_retx_attempted() rrc->max_retx_attempted(rnti); } +void rlc::user_interface::protocol_failure() +{ + rrc->protocol_failure(rnti); +} + void rlc::user_interface::write_pdu(uint32_t lcid, srsran::unique_byte_buffer_t sdu) { if (lcid == srb_to_lcid(lte_srb::srb0)) { diff --git a/srsenb/src/stack/upper/rlc_nr.cc b/srsenb/src/stack/upper/rlc_nr.cc index 67d079457..b441c83df 100644 --- a/srsenb/src/stack/upper/rlc_nr.cc +++ b/srsenb/src/stack/upper/rlc_nr.cc @@ -177,6 +177,11 @@ void rlc_nr::user_interface::max_retx_attempted() m_rrc->max_retx_attempted(rnti); } +void rlc_nr::user_interface::protocol_failure() +{ + m_rrc->protocol_failure(rnti); +} + void rlc_nr::user_interface::write_pdu(uint32_t lcid, srsran::unique_byte_buffer_t sdu) { if (lcid == (int)srsran::nr_srb::srb0) { diff --git a/srsue/hdr/stack/rrc/rrc.h b/srsue/hdr/stack/rrc/rrc.h index 003c6cb70..3125eaf2f 100644 --- a/srsue/hdr/stack/rrc/rrc.h +++ b/srsue/hdr/stack/rrc/rrc.h @@ -318,6 +318,7 @@ private: // RLC interface void max_retx_attempted(); + void protocol_failure(); // RRC NR interface void nr_scg_failure_information(const srsran::scg_failure_cause_t cause); diff --git a/srsue/hdr/stack/rrc/rrc_nr.h b/srsue/hdr/stack/rrc/rrc_nr.h index 605be42fe..80aee18b8 100644 --- a/srsue/hdr/stack/rrc/rrc_nr.h +++ b/srsue/hdr/stack/rrc/rrc_nr.h @@ -101,6 +101,7 @@ public: // RLC interface void max_retx_attempted() final; + void protocol_failure() final; // MAC interface void run_tti(uint32_t tti) final; diff --git a/srsue/src/stack/rrc/rrc.cc b/srsue/src/stack/rrc/rrc.cc index 928547935..eca1a141f 100644 --- a/srsue/src/stack/rrc/rrc.cc +++ b/srsue/src/stack/rrc/rrc.cc @@ -719,6 +719,11 @@ void rrc::max_retx_attempted() radio_link_failure_push_cmd(); } +void rrc::protocol_failure() +{ + logger.warning("RLC protocol failure detected"); +} + void rrc::timer_expired(uint32_t timeout_id) { if (timeout_id == t310.id()) { diff --git a/srsue/src/stack/rrc/rrc_nr.cc b/srsue/src/stack/rrc/rrc_nr.cc index 0ca80f752..7d0236aa2 100644 --- a/srsue/src/stack/rrc/rrc_nr.cc +++ b/srsue/src/stack/rrc/rrc_nr.cc @@ -1461,6 +1461,7 @@ bool rrc_nr::apply_radio_bearer_cfg(const radio_bearer_cfg_s& radio_bearer_cfg) } // RLC interface void rrc_nr::max_retx_attempted() {} +void rrc_nr::protocol_failure() {} // MAC interface void rrc_nr::ra_completed() {} diff --git a/srsue/test/ttcn3/hdr/ttcn3_syssim.h b/srsue/test/ttcn3/hdr/ttcn3_syssim.h index 1869b85dd..ffcfec54f 100644 --- a/srsue/test/ttcn3/hdr/ttcn3_syssim.h +++ b/srsue/test/ttcn3/hdr/ttcn3_syssim.h @@ -157,6 +157,7 @@ public: void write_pdu_pcch(unique_byte_buffer_t pdu); void write_pdu_mch(uint32_t lcid, unique_byte_buffer_t pdu); void max_retx_attempted(); + void protocol_failure(); const char* get_rb_name(uint32_t lcid); diff --git a/srsue/test/ttcn3/src/ttcn3_syssim.cc b/srsue/test/ttcn3/src/ttcn3_syssim.cc index c195dcd32..6ee227cba 100644 --- a/srsue/test/ttcn3/src/ttcn3_syssim.cc +++ b/srsue/test/ttcn3/src/ttcn3_syssim.cc @@ -1134,6 +1134,10 @@ void ttcn3_syssim::max_retx_attempted() { logger.error("%s not implemented.", __FUNCTION__); } +void ttcn3_syssim::protocol_failure() +{ + logger.error("%s not implemented.", __FUNCTION__); +} const char* ttcn3_syssim::get_rb_name(uint32_t lcid) { From 9612bb0e140c79649b940c8df2630997f4c72d60 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Wed, 26 May 2021 21:33:51 +0200 Subject: [PATCH 131/156] rlc_am_test: fix status PDU test and add extra test for failure signaling --- lib/test/upper/rlc_am_test.cc | 76 ++++++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 2 deletions(-) diff --git a/lib/test/upper/rlc_am_test.cc b/lib/test/upper/rlc_am_test.cc index 5baa7907b..d86502df5 100644 --- a/lib/test/upper/rlc_am_test.cc +++ b/lib/test/upper/rlc_am_test.cc @@ -3226,9 +3226,9 @@ bool status_pdu_test() TESTASSERT(0 == rlc1.get_buffer_state()); - // Only pass 2nd and last PDUs to RLC2 + // Only pass 1st and last PDUs to RLC2 for (uint32_t i = 0; i < n_pdus; ++i) { - if (i == 0 || i == 2 || i == n_pdus - 1) { + if (i == 0 || i == n_pdus - 1) { rlc2.write_pdu(pdu_bufs[i].msg, pdu_bufs[i].N_bytes); } } @@ -3295,6 +3295,73 @@ bool status_pdu_test() return SRSRAN_SUCCESS; } +// This test checks the correct handling of a sending RLC entity when an incorrect status PDU is injected. +// In this test, the receiver requests the retransmission of a SN that he has acknowledeged before. +// The incidence is reported to the upper layers. +bool incorrect_status_pdu_test() +{ + rlc_am_tester tester; + srsran::timer_handler timers(8); + int len = 0; + + rlc_am_lte rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); + rlc_am_lte rlc2(srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers); + + if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) { + return -1; + } + + // Push 5 SDUs into RLC1 + const uint32_t n_sdus = 10; + unique_byte_buffer_t sdu_bufs[n_sdus]; + for (uint32_t i = 0; i < n_sdus; i++) { + sdu_bufs[i] = srsran::make_byte_buffer(); + sdu_bufs[i]->N_bytes = 1; // Give each buffer a size of 1 byte + sdu_bufs[i]->msg[0] = i; // Write the index into the buffer + rlc1.write_sdu(std::move(sdu_bufs[i])); + } + + // Read 5 PDUs from RLC1 (1 byte each) + const uint32_t n_pdus = n_sdus; + byte_buffer_t pdu_bufs[n_pdus]; + for (uint32_t i = 0; i < n_pdus; i++) { + len = rlc1.read_pdu(pdu_bufs[i].msg, 3); // 2 byte header + 1 byte payload + pdu_bufs[i].N_bytes = len; + } + + TESTASSERT(0 == rlc1.get_buffer_state()); + + // Construct a status PDU that ACKs SN 1 + rlc_status_pdu_t status_pdu = {}; + status_pdu.ack_sn = 4; + status_pdu.N_nack = 3; + status_pdu.nacks[0].nack_sn = 0; + status_pdu.nacks[1].nack_sn = 2; + TESTASSERT(rlc_am_is_valid_status_pdu(status_pdu)); + + // pack PDU and write to RLC + byte_buffer_t status_buf; + rlc_am_write_status_pdu(&status_pdu, &status_buf); + rlc1.write_pdu(status_buf.msg, status_buf.N_bytes); + + // This will remove SN=1 from the Tx window + + TESTASSERT(tester.protocol_failure_triggered == false); + + // construct a valid but conflicting status PDU that request SN=1 for retx + status_pdu.N_nack = 1; + status_pdu.nacks[0].nack_sn = 1; + TESTASSERT(rlc_am_is_valid_status_pdu(status_pdu)); + + // pack and write to RLC again + rlc_am_write_status_pdu(&status_pdu, &status_buf); + rlc1.write_pdu(status_buf.msg, status_buf.N_bytes); + + TESTASSERT(tester.protocol_failure_triggered == true); + + return SRSRAN_SUCCESS; +} + // This test checks the correct functioning of RLC reestablishment // after maxRetx attempt. bool reestablish_test() @@ -3685,6 +3752,11 @@ int main(int argc, char** argv) exit(-1); }; + if (incorrect_status_pdu_test()) { + printf("incorrect_status_pdu_test failed\n"); + exit(-1); + }; + if (discard_test()) { printf("discard_test failed\n"); exit(-1); From f22f4b4fbde27b2aa3626b89180007cf2d63bcea Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Wed, 26 May 2021 21:34:40 +0200 Subject: [PATCH 132/156] rlc_am: fix potential stalling in RLC transmitter it turned out that a certain order of events can lead to a RLC transmitter stalling because even though unacknowledged PDUs are queued, none of them was actually considered for retx. This can happen if a pollRetxTimer expires for a SN that, meanwhile, has already been acknowledged. The positive lead to the deletion of the SN from the Tx window. The fix makes sure that when a retx for a unexisting SN is requested, the sender will consider the next unacknowledged SN instead. --- lib/src/upper/rlc_am_lte.cc | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/src/upper/rlc_am_lte.cc b/lib/src/upper/rlc_am_lte.cc index 1fa934fa1..795e2be83 100644 --- a/lib/src/upper/rlc_am_lte.cc +++ b/lib/src/upper/rlc_am_lte.cc @@ -701,8 +701,15 @@ int rlc_am_lte::rlc_am_lte_tx::build_retx_pdu(uint8_t* payload, uint32_t nof_byt if (!retx_queue.empty()) { retx = retx_queue.front(); } else { - logger.info("In build_retx_pdu(): retx_queue is empty during sanity check, sn=%d", retx.sn); - return 0; + logger.info("%s SN=%d not in Tx window. Ignoring retx.", RB_NAME, retx.sn); + if (tx_window.has_sn(vt_a)) { + // schedule next SN for retx + retransmit_pdu(vt_a); + retx = retx_queue.front(); + } else { + // empty tx window, can't provide retx PDU + return 0; + } } } From 5838ec499986447c76e4d6a01f5f86f28099b223 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Wed, 26 May 2021 21:39:34 +0200 Subject: [PATCH 133/156] rlc_am: revert expect macro back to error log and inform higher layers the incidence really must be handled by the higher layers, i.e. the bearer needs to be reestablished. --- lib/src/upper/rlc_am_lte.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/src/upper/rlc_am_lte.cc b/lib/src/upper/rlc_am_lte.cc index 795e2be83..df8274166 100644 --- a/lib/src/upper/rlc_am_lte.cc +++ b/lib/src/upper/rlc_am_lte.cc @@ -1241,7 +1241,7 @@ void rlc_am_lte::rlc_am_lte_tx::handle_control_pdu(uint8_t* payload, uint32_t no logger.info("%s NACKed SN=%d already considered for retransmission", RB_NAME, i); } } else { - logger.warning("%s NACKed SN=%d already removed from Tx window", RB_NAME, i); + logger.error("%s NACKed SN=%d already removed from Tx window", RB_NAME, i); } } } @@ -1263,8 +1263,9 @@ void rlc_am_lte::rlc_am_lte_tx::handle_control_pdu(uint8_t* payload, uint32_t no } // Make sure vt_a points to valid SN - if (not tx_window.empty()) { - srsran_expect(tx_window.has_sn(vt_a), "%s vt_a=%d points to invalid position in Tx window", RB_NAME, vt_a); + 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(); From a36e0477b8a94acf46c17d53003d89d4fa6cd7ba Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Wed, 26 May 2021 21:42:34 +0200 Subject: [PATCH 134/156] rlc_am: fix status PDU packing when grant size isn't enough to send full report when a small grant is provided it might not be possible to fit a full status PDU. This is currently detected while packing the PDU. In order to avoid sending potentiall contradicting status info to the sending entity, the fix makes sure to only transmit a small PDU acking what really has been received so far. This might not be optimal in terms for retx but will not corrupt any state. --- lib/src/upper/rlc_am_lte.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/src/upper/rlc_am_lte.cc b/lib/src/upper/rlc_am_lte.cc index df8274166..8590d0b91 100644 --- a/lib/src/upper/rlc_am_lte.cc +++ b/lib/src/upper/rlc_am_lte.cc @@ -1925,8 +1925,9 @@ int rlc_am_lte::rlc_am_lte_rx::get_status_pdu(rlc_status_pdu_t* status, const ui status->N_nack--; // make sure we don't have the current ACK_SN in the NACK list if (rlc_am_is_valid_status_pdu(*status) == false) { - // No space to send any NACKs - logger.debug("Resetting N_nack to zero"); + // No space to send any NACKs, play safe and just ack lower edge + logger.debug("Resetting ACK_SN and N_nack to initial state"); + status->ack_sn = vr_r; status->N_nack = 0; } } else { From 090022568e17a378ca09b2a0e0ebbe08e5c0b06c Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Wed, 2 Jun 2021 18:20:48 +0200 Subject: [PATCH 135/156] DCI NCCE find considers L and NCCE --- lib/include/srsran/phy/enb/enb_dl.h | 2 +- lib/include/srsran/phy/phch/dci.h | 5 +++-- lib/src/phy/enb/enb_dl.c | 6 +++--- lib/src/phy/phch/dci.c | 6 ++++-- lib/src/phy/ue/ue_dl.c | 4 ++-- srsenb/src/phy/lte/cc_worker.cc | 6 ++++-- 6 files changed, 17 insertions(+), 12 deletions(-) diff --git a/lib/include/srsran/phy/enb/enb_dl.h b/lib/include/srsran/phy/enb/enb_dl.h index 76c7a20c4..5c1c03010 100644 --- a/lib/include/srsran/phy/enb/enb_dl.h +++ b/lib/include/srsran/phy/enb/enb_dl.h @@ -93,7 +93,7 @@ SRSRAN_API void srsran_enb_dl_free(srsran_enb_dl_t* q); SRSRAN_API int srsran_enb_dl_set_cell(srsran_enb_dl_t* q, srsran_cell_t cell); -SRSRAN_API bool srsran_enb_dl_location_is_common_ncce(srsran_enb_dl_t* q, uint32_t ncce); +SRSRAN_API bool srsran_enb_dl_location_is_common_ncce(srsran_enb_dl_t* q, const srsran_dci_location_t* loc); SRSRAN_API void srsran_enb_dl_put_base(srsran_enb_dl_t* q, srsran_dl_sf_cfg_t* dl_sf); diff --git a/lib/include/srsran/phy/phch/dci.h b/lib/include/srsran/phy/phch/dci.h index 96f86a6ea..4469b5607 100644 --- a/lib/include/srsran/phy/phch/dci.h +++ b/lib/include/srsran/phy/phch/dci.h @@ -229,8 +229,9 @@ SRSRAN_API char* srsran_dci_format_string_short(srsran_dci_format_t format); SRSRAN_API bool srsran_location_find(const srsran_dci_location_t* locations, uint32_t nof_locations, srsran_dci_location_t x); -SRSRAN_API bool -srsran_location_find_ncce(const srsran_dci_location_t* locations, uint32_t nof_locations, uint32_t ncce); +SRSRAN_API bool srsran_location_find_location(const srsran_dci_location_t* locations, + uint32_t nof_locations, + const srsran_dci_location_t* location); SRSRAN_API int srsran_dci_location_set(srsran_dci_location_t* c, uint32_t L, uint32_t nCCE); diff --git a/lib/src/phy/enb/enb_dl.c b/lib/src/phy/enb/enb_dl.c index 91eb8b0b2..c9b240b2f 100644 --- a/lib/src/phy/enb/enb_dl.c +++ b/lib/src/phy/enb/enb_dl.c @@ -356,11 +356,11 @@ void srsran_enb_dl_put_phich(srsran_enb_dl_t* q, srsran_phich_grant_t* grant, bo srsran_phich_encode(&q->phich, &q->dl_sf, resource, ack, q->sf_symbols); } -bool srsran_enb_dl_location_is_common_ncce(srsran_enb_dl_t* q, uint32_t ncce) +bool srsran_enb_dl_location_is_common_ncce(srsran_enb_dl_t* q, const srsran_dci_location_t* loc) { if (SRSRAN_CFI_ISVALID(q->dl_sf.cfi)) { - return srsran_location_find_ncce( - q->common_locations[SRSRAN_CFI_IDX(q->dl_sf.cfi)], q->nof_common_locations[SRSRAN_CFI_IDX(q->dl_sf.cfi)], ncce); + return srsran_location_find_location( + q->common_locations[SRSRAN_CFI_IDX(q->dl_sf.cfi)], q->nof_common_locations[SRSRAN_CFI_IDX(q->dl_sf.cfi)], loc); } else { return false; } diff --git a/lib/src/phy/phch/dci.c b/lib/src/phy/phch/dci.c index 6c1cfd3d7..5db625ced 100644 --- a/lib/src/phy/phch/dci.c +++ b/lib/src/phy/phch/dci.c @@ -1380,10 +1380,12 @@ bool srsran_location_find(const srsran_dci_location_t* locations, uint32_t nof_l return false; } -bool srsran_location_find_ncce(const srsran_dci_location_t* locations, uint32_t nof_locations, uint32_t ncce) +bool srsran_location_find_location(const srsran_dci_location_t* locations, + uint32_t nof_locations, + const srsran_dci_location_t* location) { for (uint32_t i = 0; i < nof_locations; i++) { - if (locations[i].ncce == ncce) { + if (locations[i].ncce == location->ncce && locations[i].L == location->L) { return true; } } diff --git a/lib/src/phy/ue/ue_dl.c b/lib/src/phy/ue/ue_dl.c index 8159e4267..b60ebc661 100644 --- a/lib/src/phy/ue/ue_dl.c +++ b/lib/src/phy/ue/ue_dl.c @@ -452,8 +452,8 @@ static int dci_blind_search(srsran_ue_dl_t* q, * that only the PDCCH in the common search space is transmitted by the primary cell. */ // Find a matching ncce in the common SS - if (srsran_location_find_ncce( - q->current_ss_common.loc, q->current_ss_common.nof_locations, dci_msg[nof_dci].location.ncce)) { + if (srsran_location_find_location( + q->current_ss_common.loc, q->current_ss_common.nof_locations, &dci_msg[nof_dci].location)) { srsran_dci_cfg_t cfg = *dci_cfg; srsran_dci_cfg_set_common_ss(&cfg); // if the payload size is the same that it would have in the common SS (only Format0/1A is allowed there) diff --git a/srsenb/src/phy/lte/cc_worker.cc b/srsenb/src/phy/lte/cc_worker.cc index e424d9c53..1f817fe4e 100644 --- a/srsenb/src/phy/lte/cc_worker.cc +++ b/srsenb/src/phy/lte/cc_worker.cc @@ -463,7 +463,7 @@ int cc_worker::encode_pdcch_ul(stack_interface_phy_lte::ul_sched_grant_t* grants } if (SRSRAN_RNTI_ISUSER(grants[i].dci.rnti)) { - if (srsran_enb_dl_location_is_common_ncce(&enb_dl, grants[i].dci.location.ncce) && + if (srsran_enb_dl_location_is_common_ncce(&enb_dl, &grants[i].dci.location) && phy->ue_db.is_pcell(grants[i].dci.rnti, cc_idx)) { // Disable extended CSI request and SRS request in common SS srsran_dci_cfg_set_common_ss(&dci_cfg); @@ -498,8 +498,10 @@ int cc_worker::encode_pdcch_dl(stack_interface_phy_lte::dl_sched_grant_t* grants continue; } + // Detect if the DCI location is in common SS, if that is the case, flag it as common SS + // This makes possible UE specific DCI fields to be disabled, so it uses a fallback DCI size if (SRSRAN_RNTI_ISUSER(grants[i].dci.rnti) && grants[i].dci.format == SRSRAN_DCI_FORMAT1A) { - if (srsran_enb_dl_location_is_common_ncce(&enb_dl, grants[i].dci.location.ncce) && + if (srsran_enb_dl_location_is_common_ncce(&enb_dl, &grants[i].dci.location) && phy->ue_db.is_pcell(grants[i].dci.rnti, cc_idx)) { srsran_dci_cfg_set_common_ss(&dci_cfg); } From d46be09663def81aaf05f9eefb5a8aa23c5bd12b Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Thu, 3 Jun 2021 16:50:48 +0200 Subject: [PATCH 136/156] Increase viterbi default number of iterations --- lib/src/phy/fec/convolutional/viterbi.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/src/phy/fec/convolutional/viterbi.c b/lib/src/phy/fec/convolutional/viterbi.c index a346ebc7e..f89e9c3fb 100644 --- a/lib/src/phy/fec/convolutional/viterbi.c +++ b/lib/src/phy/fec/convolutional/viterbi.c @@ -25,11 +25,11 @@ #define DEB 0 -#define TB_ITER 3 +#define TB_ITER 5 #define DEFAULT_GAIN 100 -#define DEFAULT_GAIN_16 1000 +#define DEFAULT_GAIN_16 500 #define VITERBI_16 #ifndef LV_HAVE_AVX2 @@ -549,11 +549,10 @@ int srsran_viterbi_decode_f(srsran_viterbi_t* q, float* symbols, uint8_t* data, len = 3 * (frame_length + q->K - 1); } if (!q->decode_f) { - float max = 1e-9; - for (int i = 0; i < len; i++) { - if (fabs(symbols[i]) > max) { - max = fabs(symbols[i]); - } + float max = 1e-9; + uint32_t max_i = srsran_vec_max_abs_fi(symbols, len); + if (max_i < len && isnormal(symbols[max_i])) { + max = fabsf(symbols[max_i]); } #ifdef VITERBI_16 srsran_vec_quant_fus(symbols, q->symbols_us, q->gain_quant / max, 32767.5, 65535, len); From 5ddc974beb4d889c108ab15f88c8f4b19583a29f Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Thu, 3 Jun 2021 16:55:17 +0200 Subject: [PATCH 137/156] Reverted PDCCH threshold --- lib/src/phy/phch/pdcch.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/lib/src/phy/phch/pdcch.c b/lib/src/phy/phch/pdcch.c index 533a713fa..edeaf3b81 100644 --- a/lib/src/phy/phch/pdcch.c +++ b/lib/src/phy/phch/pdcch.c @@ -377,15 +377,6 @@ int srsran_pdcch_decode_msg(srsran_pdcch_t* q, srsran_dl_sf_cfg_t* sf, srsran_dc uint32_t nof_bits = srsran_dci_format_sizeof(&q->cell, sf, dci_cfg, msg->format); uint32_t e_bits = PDCCH_FORMAT_NOF_BITS(msg->location.L); - // Set threshold to 2/3 of absolute LLRs maximum for this candidate if bigger than 0.3. Otherwise set the - // threshold to 0.3. - uint32_t max_i = srsran_vec_max_abs_fi(&q->llr[msg->location.ncce * 72], e_bits); - if (max_i >= e_bits) { - ERROR("The impossible happened %d>=%d", max_i, e_bits); - return SRSRAN_ERROR; - } - double threshold = SRSRAN_MAX(0.3f, (2.0 / 3.0) * fabsf(q->llr[msg->location.ncce * 72 + max_i])); - // Compute absolute mean of the LLRs double mean = 0; for (int i = 0; i < e_bits; i++) { @@ -393,7 +384,7 @@ int srsran_pdcch_decode_msg(srsran_pdcch_t* q, srsran_dl_sf_cfg_t* sf, srsran_dc } mean /= e_bits; - if (mean > threshold) { + if (mean > 0.3f) { ret = srsran_pdcch_dci_decode(q, &q->llr[msg->location.ncce * 72], msg->payload, e_bits, nof_bits, &msg->rnti); if (ret == SRSRAN_SUCCESS) { msg->nof_bits = nof_bits; @@ -412,12 +403,7 @@ int srsran_pdcch_decode_msg(srsran_pdcch_t* q, srsran_dl_sf_cfg_t* sf, srsran_dc mean, msg->rnti); } else { - INFO("Skipping DCI: nCCE=%d, L=%d, msg_len=%d, mean=%f, thr=%f", - msg->location.ncce, - msg->location.L, - nof_bits, - mean, - threshold); + INFO("Skipping DCI: nCCE=%d, L=%d, msg_len=%d, mean=%f", msg->location.ncce, msg->location.L, nof_bits, mean); } } } else if (msg != NULL) { From 60f294a6a1316818711490c915961ca9a66e6e25 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Thu, 3 Jun 2021 16:55:57 +0200 Subject: [PATCH 138/156] Refactor PDCCH encode/decode unit test --- lib/src/phy/phch/test/pdcch_test.c | 478 +++++++++++++---------------- 1 file changed, 217 insertions(+), 261 deletions(-) diff --git a/lib/src/phy/phch/test/pdcch_test.c b/lib/src/phy/phch/test/pdcch_test.c index a6f030417..a455227ba 100644 --- a/lib/src/phy/phch/test/pdcch_test.c +++ b/lib/src/phy/phch/test/pdcch_test.c @@ -15,28 +15,36 @@ #include #include +#include "srsran/common/test_common.h" #include "srsran/srsran.h" -srsran_cell_t cell = {.nof_prb = 6, - .nof_ports = 1, - .id = 1, - .cp = SRSRAN_CP_NORM, - .phich_resources = SRSRAN_PHICH_R_1, - .phich_length = SRSRAN_PHICH_NORM}; - -uint32_t cfi = 1; -uint32_t nof_rx_ant = 1; -bool print_dci_table; -srsran_dci_cfg_t dci_cfg = {}; +// Test parameters +static uint32_t pci = 1; +static uint16_t rnti = 0x46; +static uint32_t cfi = 1; +static uint32_t nof_ports = 1; +static bool print_dci_table; +static srsran_dci_cfg_t dci_cfg = {}; +static uint32_t nof_prb = 100; +static float snr_dB = 20.0f; +static uint32_t repetitions = 1; +static bool false_check = false; + +// Test objects +static srsran_random_t random_gen = NULL; +static srsran_pdcch_t pdcch_tx = {}; +static srsran_pdcch_t pdcch_rx = {}; +static srsran_chest_dl_res_t chest_dl_res = {}; +static srsran_channel_awgn_t awgn = {}; +static cf_t* slot_symbols[SRSRAN_MAX_PORTS]; void usage(char* prog) { printf("Usage: %s [cfpndxv]\n", prog); - printf("\t-c cell id [Default %d]\n", cell.id); + printf("\t-c cell id [Default %d]\n", pci); printf("\t-f cfi [Default %d]\n", cfi); - printf("\t-p cell.nof_ports [Default %d]\n", cell.nof_ports); - printf("\t-n cell.nof_prb [Default %d]\n", cell.nof_prb); - printf("\t-A nof_rx_ant [Default %d]\n", nof_rx_ant); + printf("\t-p cell.nof_ports [Default %d]\n", nof_ports); + printf("\t-n cell.nof_prb [Default %d]\n", nof_prb); printf("\t-d Print DCI table [Default %s]\n", print_dci_table ? "yes" : "no"); printf("\t-x Enable/Disable Cross-scheduling [Default %s]\n", dci_cfg.cif_enabled ? "enabled" : "disabled"); printf("\t-v [set srsran_verbose to debug, default none]\n"); @@ -48,19 +56,16 @@ void parse_args(int argc, char** argv) while ((opt = getopt(argc, argv, "cfpndvAx")) != -1) { switch (opt) { case 'p': - cell.nof_ports = (uint32_t)strtol(argv[optind], NULL, 10); + nof_ports = (uint32_t)strtol(argv[optind], NULL, 10); break; case 'f': cfi = (uint32_t)strtol(argv[optind], NULL, 10); break; case 'n': - cell.nof_prb = (uint32_t)strtol(argv[optind], NULL, 10); + nof_prb = (uint32_t)strtol(argv[optind], NULL, 10); break; case 'c': - cell.id = (uint32_t)strtol(argv[optind], NULL, 10); - break; - case 'A': - nof_rx_ant = (uint32_t)strtol(argv[optind], NULL, 10); + pci = (uint32_t)strtol(argv[optind], NULL, 10); break; case 'd': print_dci_table = true; @@ -78,10 +83,19 @@ void parse_args(int argc, char** argv) } } -int test_dci_payload_size() +static void print_dci_msg(const char* desc, const srsran_dci_msg_t* dci_msg) +{ + printf("%srnti=0x%04x; format=%s; L=%d; ncce=%d; payload=", + desc, + rnti, + srsran_dci_format_string(dci_msg->format), + dci_msg->location.L, + dci_msg->location.ncce); + srsran_vec_fprint_byte(stdout, dci_msg->payload, dci_msg->nof_bits); +} + +static int assert_payload_size(const srsran_cell_t* cell, srsran_dl_sf_cfg_t* dl_sf) { - int i, j; - int x[5]; const srsran_dci_format_t formats[] = { SRSRAN_DCI_FORMAT0, SRSRAN_DCI_FORMAT1, SRSRAN_DCI_FORMAT1A, SRSRAN_DCI_FORMAT1C, SRSRAN_DCI_FORMAT2A}; const int prb[6] = {6, 15, 25, 50, 75, 100}; @@ -92,297 +106,236 @@ int test_dci_payload_size() {27, 33, 27, 14, 42}, {28, 39, 28, 15, 48}}; - srsran_dl_sf_cfg_t dl_sf; - ZERO_OBJECT(dl_sf); - - srsran_cell_t cell_test; - ZERO_OBJECT(cell_test); - cell_test.nof_ports = 1; + // Skip if special options are requested + if (dci_cfg.cif_enabled || dci_cfg.multiple_csi_request_enabled) { + return SRSRAN_SUCCESS; + } - ZERO_OBJECT(dci_cfg); + // Skip if MIMO is enabled + if (cell->nof_ports > 1) { + return SRSRAN_SUCCESS; + } - printf("Testing DCI payload sizes...\n"); - printf(" PRB\t0\t1\t1A\t1C\t2A\n"); - for (i = 0; i < 6; i++) { - int n = prb[i]; - cell_test.nof_prb = n; + for (uint32_t i = 0; i < 6; i++) { + if (prb[i] != cell->nof_prb) { + continue; + } + int n = prb[i]; - for (j = 0; j < 5; j++) { - x[j] = srsran_dci_format_sizeof(&cell_test, &dl_sf, &dci_cfg, formats[j]); + uint32_t x[5]; + for (uint32_t j = 0; j < 5; j++) { + x[j] = srsran_dci_format_sizeof(cell, dl_sf, &dci_cfg, formats[j]); if (x[j] != dci_sz[i][j]) { ERROR("Invalid DCI payload size for %s and %d PRB. Is %d and should be %d", srsran_dci_format_string(formats[j]), n, x[j], dci_sz[i][j]); - return -1; + return SRSRAN_ERROR; } } - printf(" %2d:\t%2d\t%2d\t%2d\t%2d\t%2d\n", n, x[0], x[1], x[2], x[3], x[4]); - } - printf("Ok\n"); - - if (print_dci_table) { - printf("dci_sz_table[101][4] = {\n"); - for (i = 0; i <= 100; i++) { - printf(" {"); - for (j = 0; j < 4; j++) { - cell_test.nof_prb = i; - printf("%d", srsran_dci_format_sizeof(&cell, &dl_sf, &dci_cfg, formats[j])); - if (j < 3) { - printf(", "); - } - } - if (i < 100) { - printf("},\n"); - } else { - printf("}\n"); - } - } - printf("};\n"); + return SRSRAN_SUCCESS; } + return 0; } -typedef struct { - srsran_dci_msg_t dci_tx, dci_rx; - srsran_dci_location_t dci_location; - srsran_dci_format_t dci_format; - srsran_dci_dl_t ra_dl_tx; - srsran_dci_dl_t ra_dl_rx; -} testcase_dci_t; +static const srsran_dci_format_t formats[] = {SRSRAN_DCI_FORMAT0, + SRSRAN_DCI_FORMAT1A, + SRSRAN_DCI_FORMAT1, + SRSRAN_DCI_FORMAT2A, + SRSRAN_DCI_FORMAT2, + SRSRAN_DCI_NOF_FORMATS}; -int main(int argc, char** argv) +static int test_case1() { - srsran_chest_dl_res_t chest_dl_res; - srsran_pdcch_t pdcch_tx, pdcch_rx; - testcase_dci_t testcases[10]; - srsran_regs_t regs; - int i; - int nof_re; - cf_t* slot_symbols[SRSRAN_MAX_PORTS]; - int nof_dcis; + uint32_t nof_re = SRSRAN_NOF_RE(pdcch_tx.cell); + struct timeval t[3] = {}; + uint64_t t_encode_us = 0; + uint64_t t_encode_count = 0; + uint64_t t_llr_us = 0; + uint64_t t_decode_us = 0; + uint64_t t_decode_count = 0; + + // Iterate all possible subframes + for (uint32_t f_idx = 0; formats[f_idx] != SRSRAN_DCI_NOF_FORMATS; f_idx++) { + srsran_dci_format_t format = formats[f_idx]; + + for (uint32_t sf_idx = 0; sf_idx < repetitions * SRSRAN_NOF_SF_X_FRAME; sf_idx++) { + srsran_dl_sf_cfg_t dl_sf_cfg = {}; + dl_sf_cfg.cfi = cfi; + dl_sf_cfg.tti = sf_idx % 10240; + + // Generate PDCCH locations + srsran_dci_location_t locations[SRSRAN_MAX_CANDIDATES] = {}; + uint32_t locations_count = 0; + locations_count += + srsran_pdcch_common_locations(&pdcch_tx, &locations[locations_count], SRSRAN_MAX_CANDIDATES_COM, cfi); + locations_count += + srsran_pdcch_ue_locations(&pdcch_tx, &dl_sf_cfg, &locations[locations_count], SRSRAN_MAX_CANDIDATES_UE, rnti); + + // Iterate all possible locations + for (uint32_t loc = 0; loc < locations_count; loc++) { + srsran_dci_msg_t dci_tx = {}; + dci_tx.nof_bits = srsran_dci_format_sizeof(&pdcch_tx.cell, &dl_sf_cfg, &dci_cfg, format); + dci_tx.location = locations[loc]; + dci_tx.format = format; + dci_tx.rnti = rnti; + + // Assert DCI size + TESTASSERT(assert_payload_size(&pdcch_tx.cell, &dl_sf_cfg) == SRSRAN_SUCCESS); + + // Initialise resource grid for each Tx port + for (uint32_t p = 0; p < nof_ports; p++) { + srsran_vec_cf_zero(slot_symbols[p], nof_re); + } - bzero(&testcases, sizeof(testcase_dci_t) * 10); - srsran_random_t random_gen = srsran_random_init(0x1234); + // Generate Tx DCI + srsran_random_bit_vector(random_gen, dci_tx.payload, dci_tx.nof_bits); - int ret = -1; + // Encode + gettimeofday(&t[1], NULL); + TESTASSERT(srsran_pdcch_encode(&pdcch_tx, &dl_sf_cfg, &dci_tx, slot_symbols) == SRSRAN_SUCCESS); + gettimeofday(&t[2], NULL); + get_time_interval(t); + t_encode_us += (size_t)(t[0].tv_sec * 1e6 + t[0].tv_usec); + t_encode_count++; - parse_args(argc, argv); + // Apply AWGN + for (uint32_t p = 0; p < nof_ports; p++) { + srsran_channel_awgn_run_c(&awgn, slot_symbols[p], slot_symbols[p], nof_re); + } - nof_re = SRSRAN_CP_NORM_NSYMB * cell.nof_prb * SRSRAN_NRE; + // Extract LLR + gettimeofday(&t[1], NULL); + TESTASSERT(srsran_pdcch_extract_llr(&pdcch_rx, &dl_sf_cfg, &chest_dl_res, slot_symbols) == SRSRAN_SUCCESS); + gettimeofday(&t[2], NULL); + get_time_interval(t); + t_llr_us += (size_t)(t[0].tv_sec * 1e6 + t[0].tv_usec); + + // Try decoding the PDCCH in all possible locations + for (uint32_t loc_rx = 0; loc_rx < locations_count; loc_rx++) { + if (!false_check && loc_rx != loc) { + continue; + } - if (test_dci_payload_size()) { - exit(-1); + // Prepare DCI message context + srsran_dci_msg_t dci_rx = {}; + dci_rx.location = locations[loc_rx]; + dci_rx.format = format; + + // Try to decode PDCCH message + gettimeofday(&t[1], NULL); + TESTASSERT(srsran_pdcch_decode_msg(&pdcch_rx, &dl_sf_cfg, &dci_cfg, &dci_rx) == SRSRAN_SUCCESS); + gettimeofday(&t[2], NULL); + get_time_interval(t); + t_decode_us += (size_t)(t[0].tv_sec * 1e6 + t[0].tv_usec); + t_decode_count++; + + bool rnti_match = (dci_tx.rnti == dci_rx.rnti); + bool location_match = (loc == loc_rx); + bool payload_match = (memcmp(dci_tx.payload, dci_rx.payload, dci_tx.nof_bits) == 0); + + // Skip location if the decoding is not successful in a different location than transmitted + if (!location_match && !rnti_match) { + continue; + } + + if (srsran_verbose >= SRSRAN_VERBOSE_INFO || !payload_match) { + print_dci_msg("Tx: ", &dci_tx); + print_dci_msg("Rx: ", &dci_rx); + } + + // Assert received message + TESTASSERT(payload_match); + } + } + } } - /* init memory */ + printf("test_case_1 - %.1f usec/encode; %.1f usec/llr; %.1f usec/decode;\n", + (double)t_encode_us / (double)(t_encode_count), + (double)t_llr_us / (double)(t_encode_count), + (double)t_decode_us / (double)(t_decode_count)); - srsran_chest_dl_res_init(&chest_dl_res, cell.nof_prb); + return SRSRAN_SUCCESS; +} + +int main(int argc, char** argv) +{ + srsran_regs_t regs; + int i; + int ret = SRSRAN_ERROR; + + parse_args(argc, argv); + random_gen = srsran_random_init(0x1234); + + // Create cell + srsran_cell_t cell = {}; + cell.nof_prb = nof_prb; + cell.nof_ports = nof_ports; + cell.cp = SRSRAN_CP_NORM; + cell.phich_resources = SRSRAN_PHICH_R_1; + cell.phich_length = SRSRAN_PHICH_NORM; + + // Initialise channel estimates with identity matrix + if (srsran_chest_dl_res_init(&chest_dl_res, cell.nof_prb) < SRSRAN_SUCCESS) { + ERROR("Error channel estimates"); + goto quit; + } srsran_chest_dl_res_set_identity(&chest_dl_res); + // Allocate grid + uint32_t nof_re = SRSRAN_NOF_RE(cell); for (i = 0; i < SRSRAN_MAX_PORTS; i++) { slot_symbols[i] = srsran_vec_cf_malloc(nof_re); - if (!slot_symbols[i]) { - perror("malloc"); - exit(-1); + if (slot_symbols[i] == NULL) { + ERROR("malloc"); + goto quit; } - srsran_vec_cf_zero(slot_symbols[i], nof_re); } if (srsran_regs_init(®s, cell)) { ERROR("Error initiating regs"); - exit(-1); + goto quit; } if (srsran_pdcch_init_enb(&pdcch_tx, cell.nof_prb)) { ERROR("Error creating PDCCH object"); - exit(-1); + goto quit; } if (srsran_pdcch_set_cell(&pdcch_tx, ®s, cell)) { ERROR("Error setting cell in PDCCH object"); - exit(-1); + goto quit; } - if (srsran_pdcch_init_ue(&pdcch_rx, cell.nof_prb, nof_rx_ant)) { + if (srsran_pdcch_init_ue(&pdcch_rx, cell.nof_prb, nof_ports)) { ERROR("Error creating PDCCH object"); - exit(-1); + goto quit; } + if (srsran_pdcch_set_cell(&pdcch_rx, ®s, cell)) { ERROR("Error setting cell in PDCCH object"); - exit(-1); + goto quit; } - /* Resource allocate init */ - nof_dcis = 0; - srsran_dci_dl_t dci; - ZERO_OBJECT(dci); - dci.pid = 5; - dci.tb[0].mcs_idx = 5; - dci.tb[0].ndi = 0; - dci.tb[0].rv = 1; - dci.alloc_type = SRSRAN_RA_ALLOC_TYPE0; - dci.type0_alloc.rbg_bitmask = 0x5; - dci.cif_present = dci_cfg.cif_enabled; - if (dci_cfg.cif_enabled) { - dci.cif = (uint32_t)srsran_random_uniform_int_dist(random_gen, 0, 7); + if (srsran_channel_awgn_init(&awgn, 0x1234) < SRSRAN_SUCCESS) { + ERROR("Error init AWGN"); + goto quit; } - /* Format 1 Test case */ - if (cell.nof_ports == 1) { - testcases[nof_dcis].dci_format = SRSRAN_DCI_FORMAT1; - if (dci_cfg.cif_enabled) { - dci.cif = (uint32_t)srsran_random_uniform_int_dist(random_gen, 0, 7); - } - testcases[nof_dcis].ra_dl_tx = dci; - nof_dcis++; - - /* Format 1 Test case */ - dci.tb[0].mcs_idx = 15; - testcases[nof_dcis].dci_format = SRSRAN_DCI_FORMAT1; - if (dci_cfg.cif_enabled) { - dci.cif = (uint32_t)srsran_random_uniform_int_dist(random_gen, 0, 7); - } - testcases[nof_dcis].ra_dl_tx = dci; - nof_dcis++; + if (srsran_channel_awgn_set_n0(&awgn, -snr_dB) < SRSRAN_SUCCESS) { + ERROR("Error setting n0"); + goto quit; } - /* Tx Diversity Test case */ - if (cell.nof_ports > 1) { - dci.tb[1].mcs_idx = 13; - dci.tb[1].rv = 3; - dci.tb[1].ndi = true; - testcases[nof_dcis].dci_format = SRSRAN_DCI_FORMAT2A; - if (dci_cfg.cif_enabled) { - dci.cif = (uint32_t)srsran_random_uniform_int_dist(random_gen, 0, 7); - } - testcases[nof_dcis].ra_dl_tx = dci; - nof_dcis++; + // Execute actual test cases + if (test_case1() < SRSRAN_SUCCESS) { + ERROR("Test case 1 failed"); + goto quit; } - /* CDD Spatial Multiplexing Test case */ - if (cell.nof_ports > 1) { - dci.tb[1].mcs_idx = 28; - dci.tb[1].rv = 1; - dci.tb[1].ndi = false; - testcases[nof_dcis].dci_format = SRSRAN_DCI_FORMAT2; - if (dci_cfg.cif_enabled) { - dci.cif = (uint32_t)srsran_random_uniform_int_dist(random_gen, 0, 7); - } - testcases[nof_dcis].ra_dl_tx = dci; - nof_dcis++; - } - - srsran_dl_sf_cfg_t dl_sf; - ZERO_OBJECT(dl_sf); - dl_sf.cfi = cfi; - - for (int s = 0; s < 10; s++) { - dl_sf.tti = s; - printf("Encoding %d DCIs for sf_idx=%d\n", nof_dcis, s); - /* Execute Rx */ - for (i = 0; i < nof_dcis; i++) { - testcases[i].ra_dl_tx.rnti = (uint16_t)(1234 + i); - testcases[i].ra_dl_tx.format = testcases[i].dci_format; - - srsran_dci_msg_pack_pdsch(&cell, &dl_sf, &dci_cfg, &testcases[i].ra_dl_tx, &testcases[i].dci_tx); - srsran_dci_location_set(&testcases[i].dci_location, 0, (uint32_t)i); - - testcases[i].dci_tx.format = testcases[i].dci_format; - testcases[i].dci_tx.location = testcases[i].dci_location; - - // Enable just 1 TB per default - if (testcases[i].dci_format < SRSRAN_DCI_FORMAT2) { - for (int j = 1; j < SRSRAN_MAX_CODEWORDS; j++) { - SRSRAN_DCI_TB_DISABLE(testcases[i].ra_dl_tx.tb[j]); - } - } - - if (srsran_pdcch_encode(&pdcch_tx, &dl_sf, &testcases[i].dci_tx, slot_symbols)) { - ERROR("Error encoding DCI message"); - goto quit; - } - } - - /* Execute 'Rx' */ - if (srsran_pdcch_extract_llr(&pdcch_rx, &dl_sf, &chest_dl_res, slot_symbols)) { - ERROR("Error extracting LLRs"); - goto quit; - } - - /* Decode DCIs */ - for (i = 0; i < nof_dcis; i++) { - testcases[i].dci_rx.format = testcases[i].dci_format; - testcases[i].dci_rx.location = testcases[i].dci_location; - if (srsran_pdcch_decode_msg(&pdcch_rx, &dl_sf, &dci_cfg, &testcases[i].dci_rx)) { - ERROR("Error decoding DCI message"); - goto quit; - } - if (srsran_dci_msg_unpack_pdsch(&cell, &dl_sf, &dci_cfg, &testcases[i].dci_rx, &testcases[i].ra_dl_rx)) { - ERROR("Error unpacking DCI message"); - goto quit; - } - if (testcases[i].dci_rx.rnti >= 1234 && testcases[i].dci_rx.rnti < 1234 + nof_dcis) { - testcases[i].dci_rx.rnti -= 1234; - } else { - printf("Received invalid DCI CRC %d\n", testcases[i].dci_rx.rnti); - goto quit; - } - } - - /* Compare Tx and Rx */ - for (i = 0; i < nof_dcis; i++) { - if (memcmp(testcases[i].dci_tx.payload, testcases[i].dci_rx.payload, testcases[i].dci_tx.nof_bits)) { - printf("Error in DCI %d: Received data does not match\n", i); - goto quit; - } -#if SRSRAN_DCI_HEXDEBUG - // Ignore Hex str - bzero(testcases[i].ra_dl_rx.hex_str, sizeof(testcases[i].ra_dl_rx.hex_str)); - testcases[i].ra_dl_rx.nof_bits = 0; -#endif - // Ignore DCI location - testcases[i].ra_dl_rx.location = testcases[i].ra_dl_tx.location; - // Ignore cw_idx - for (int j = 0; j < SRSRAN_MAX_CODEWORDS; j++) { - testcases[i].ra_dl_rx.tb[j].cw_idx = testcases[i].ra_dl_tx.tb[j].cw_idx; - } - if (memcmp(&testcases[i].ra_dl_tx, &testcases[i].ra_dl_rx, sizeof(srsran_dci_dl_t))) { - uint8_t* x = (uint8_t*)&testcases[i].ra_dl_rx; - uint8_t* y = (uint8_t*)&testcases[i].ra_dl_tx; - for (int j = 0; j < sizeof(srsran_dci_dl_t); j++) { - if (x[j] != y[j]) { - printf("error in byte %d, rx=%d, tx=%d\n", j, x[j], y[j]); - } - } - printf("tx: "); - srsran_vec_fprint_byte(stdout, (uint8_t*)&testcases[i].ra_dl_tx, sizeof(srsran_dci_dl_t)); - printf("rx: "); - srsran_vec_fprint_byte(stdout, (uint8_t*)&testcases[i].ra_dl_rx, sizeof(srsran_dci_dl_t)); - printf("Error in RA %d: Received data does not match\n", i); - printf(" Field | Tx | Rx \n"); - printf("--------------+----------+----------\n"); - if (testcases[i].ra_dl_tx.cif) { - printf(" cif | %8d | %8d\n", testcases[i].ra_dl_tx.cif, testcases[i].ra_dl_rx.cif); - } - printf(" harq_process | %8d | %8d\n", testcases[i].ra_dl_tx.pid, testcases[i].ra_dl_rx.pid); - printf(" mcs_idx | %8d | %8d\n", testcases[i].ra_dl_tx.tb[0].mcs_idx, testcases[i].ra_dl_rx.tb[0].mcs_idx); - printf(" rv_idx | %8d | %8d\n", testcases[i].ra_dl_tx.tb[0].rv, testcases[i].ra_dl_rx.tb[0].rv); - printf(" ndi | %8d | %8d\n", testcases[i].ra_dl_tx.tb[0].ndi, testcases[i].ra_dl_rx.tb[0].ndi); - printf(" mcs_idx_1 | %8d | %8d\n", testcases[i].ra_dl_tx.tb[1].mcs_idx, testcases[i].ra_dl_rx.tb[1].mcs_idx); - printf(" rv_idx_1 | %8d | %8d\n", testcases[i].ra_dl_tx.tb[1].rv, testcases[i].ra_dl_rx.tb[1].rv); - printf(" ndi_1 | %8d | %8d\n", testcases[i].ra_dl_tx.tb[1].ndi, testcases[i].ra_dl_rx.tb[1].ndi); - printf(" tb_cw_swap | %8d | %8d\n", testcases[i].ra_dl_tx.tb_cw_swap, testcases[i].ra_dl_rx.tb_cw_swap); - printf(" sram_id | %8d | %8d\n", testcases[i].ra_dl_tx.sram_id, testcases[i].ra_dl_rx.sram_id); - printf(" pinfo | %8d | %8d\n", testcases[i].ra_dl_tx.pinfo, testcases[i].ra_dl_rx.pinfo); - printf(" pconf | %8d | %8d\n", testcases[i].ra_dl_tx.pconf, testcases[i].ra_dl_rx.pconf); - printf(" power_offset | %8d | %8d\n", testcases[i].ra_dl_tx.power_offset, testcases[i].ra_dl_rx.power_offset); - printf(" tpc_pucch | %8d | %8d\n", testcases[i].ra_dl_tx.tpc_pucch, testcases[i].ra_dl_rx.tpc_pucch); - goto quit; - } - } - } - ret = 0; + ret = SRSRAN_SUCCESS; quit: srsran_pdcch_free(&pdcch_tx); @@ -390,9 +343,12 @@ quit: srsran_chest_dl_res_free(&chest_dl_res); srsran_regs_free(®s); srsran_random_free(random_gen); + srsran_channel_awgn_free(&awgn); for (i = 0; i < SRSRAN_MAX_PORTS; i++) { - free(slot_symbols[i]); + if (slot_symbols[i]) { + free(slot_symbols[i]); + } } if (ret) { printf("Error\n"); From 539ca47fe2d1316f81133fee96bfb9cce3ae4059 Mon Sep 17 00:00:00 2001 From: Francisco Date: Tue, 1 Jun 2021 19:45:28 +0100 Subject: [PATCH 139/156] lib,bugfix: fix blocking queue unit test. Dtor cannot destroy object while a thread is still pushing data --- lib/test/adt/circular_buffer_test.cc | 29 ++++++++++++---------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/lib/test/adt/circular_buffer_test.cc b/lib/test/adt/circular_buffer_test.cc index a1f78a8b1..efd5c561e 100644 --- a/lib/test/adt/circular_buffer_test.cc +++ b/lib/test/adt/circular_buffer_test.cc @@ -207,7 +207,7 @@ void test_dyn_circular_buffer() TESTASSERT(C::count == 0); } -int test_queue_block_api() +void test_queue_block_api() { dyn_blocking_queue queue(100); @@ -229,31 +229,26 @@ int test_queue_block_api() queue.stop(); t.join(); - return SRSRAN_SUCCESS; } -int test_queue_block_api_2() +void test_queue_block_api_2() { std::thread t; - { - dyn_blocking_queue queue(100); - - t = std::thread([&queue]() { - int count = 0; - while (queue.push_blocking(count++)) { - } - }); + dyn_blocking_queue queue(100); - for (int i = 0; i < 10000; ++i) { - TESTASSERT(queue.pop_blocking() == i); + t = std::thread([&queue]() { + int count = 0; + while (queue.push_blocking(count++)) { } + }); - // queue dtor called + for (int i = 0; i < 10000; ++i) { + TESTASSERT(queue.pop_blocking() == i); } + queue.stop(); t.join(); - return SRSRAN_SUCCESS; } } // namespace srsran @@ -267,8 +262,8 @@ int main(int argc, char** argv) TESTASSERT(srsran::test_static_circular_buffer() == SRSRAN_SUCCESS); srsran::test_dyn_circular_buffer(); - TESTASSERT(srsran::test_queue_block_api() == SRSRAN_SUCCESS); - TESTASSERT(srsran::test_queue_block_api_2() == SRSRAN_SUCCESS); + srsran::test_queue_block_api(); + srsran::test_queue_block_api_2(); srsran::console("Success\n"); return SRSRAN_SUCCESS; } \ No newline at end of file From c0be8187c8cc7cfd254d78281833eddb75bec540 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Thu, 3 Jun 2021 11:03:58 +0200 Subject: [PATCH 140/156] rlc interface: convert entire read_pdu() interface to return uint32_t we had it returning int but had a bug in using the return value properly, i.e. handling when -1 was returned in RLC TM. Thinking about it more, it doesn't make sense to have a negative return value here anyway. Either the RLC can return a PDU or not. If it can't the returned lenght is zero. --- lib/include/srsran/common/interfaces_common.h | 2 +- lib/include/srsran/interfaces/ue_rlc_interfaces.h | 2 +- lib/include/srsran/test/ue_test_interfaces.h | 2 +- lib/include/srsran/upper/rlc.h | 4 ++-- lib/include/srsran/upper/rlc_am_lte.h | 4 ++-- lib/include/srsran/upper/rlc_common.h | 3 ++- lib/include/srsran/upper/rlc_tm.h | 2 +- lib/include/srsran/upper/rlc_um_base.h | 6 +++--- lib/include/srsran/upper/rlc_um_lte.h | 2 +- lib/include/srsran/upper/rlc_um_nr.h | 2 +- lib/src/upper/rlc.cc | 4 ++-- lib/src/upper/rlc_am_lte.cc | 6 +++--- lib/src/upper/rlc_tm.cc | 6 +++--- lib/src/upper/rlc_um_base.cc | 4 ++-- lib/src/upper/rlc_um_lte.cc | 2 +- lib/src/upper/rlc_um_nr.cc | 2 +- lib/test/mac/pdu_test.cc | 2 +- srsenb/hdr/stack/mac/ue.h | 2 +- srsenb/src/stack/mac/ue.cc | 2 +- srsue/src/stack/mac_nr/test/mac_nr_test.cc | 2 +- srsue/test/mac_test.cc | 2 +- 21 files changed, 32 insertions(+), 31 deletions(-) diff --git a/lib/include/srsran/common/interfaces_common.h b/lib/include/srsran/common/interfaces_common.h index 5997e63b1..ce7996205 100644 --- a/lib/include/srsran/common/interfaces_common.h +++ b/lib/include/srsran/common/interfaces_common.h @@ -77,7 +77,7 @@ public: class read_pdu_interface { public: - virtual int read_pdu(uint32_t lcid, uint8_t* payload, uint32_t requested_bytes) = 0; + virtual uint32_t read_pdu(uint32_t lcid, uint8_t* payload, uint32_t requested_bytes) = 0; }; class stack_interface_phy_nr diff --git a/lib/include/srsran/interfaces/ue_rlc_interfaces.h b/lib/include/srsran/interfaces/ue_rlc_interfaces.h index c7f05dd42..4c6452138 100644 --- a/lib/include/srsran/interfaces/ue_rlc_interfaces.h +++ b/lib/include/srsran/interfaces/ue_rlc_interfaces.h @@ -67,7 +67,7 @@ public: /* MAC calls RLC to get RLC segment of nof_bytes length. * Segmentation happens in this function. RLC PDU is stored in payload. */ - virtual int read_pdu(uint32_t lcid, uint8_t* payload, uint32_t nof_bytes) = 0; + virtual uint32_t read_pdu(uint32_t lcid, uint8_t* payload, uint32_t nof_bytes) = 0; /* MAC calls RLC to push an RLC PDU. This function is called from an independent MAC thread. * PDU gets placed into the buffer and higher layer thread gets notified. */ diff --git a/lib/include/srsran/test/ue_test_interfaces.h b/lib/include/srsran/test/ue_test_interfaces.h index 4263eb6b8..0b7ad541f 100644 --- a/lib/include/srsran/test/ue_test_interfaces.h +++ b/lib/include/srsran/test/ue_test_interfaces.h @@ -50,7 +50,7 @@ class rlc_dummy_interface : public rlc_interface_mac public: bool has_data_locked(const uint32_t lcid) override { return false; } uint32_t get_buffer_state(const uint32_t lcid) override { return 0; } - int read_pdu(uint32_t lcid, uint8_t* payload, uint32_t nof_bytes) override { return 0; } + uint32_t read_pdu(uint32_t lcid, uint8_t* payload, uint32_t nof_bytes) override { return 0; } void write_pdu(uint32_t lcid, uint8_t* payload, uint32_t nof_bytes) override {} void write_pdu_bcch_bch(srsran::unique_byte_buffer_t payload) override {} void write_pdu_bcch_dlsch(uint8_t* payload, uint32_t nof_bytes) override {} diff --git a/lib/include/srsran/upper/rlc.h b/lib/include/srsran/upper/rlc.h index 75fff9a98..cb393a26e 100644 --- a/lib/include/srsran/upper/rlc.h +++ b/lib/include/srsran/upper/rlc.h @@ -66,8 +66,8 @@ public: bool has_data_locked(const uint32_t lcid); uint32_t get_buffer_state(const uint32_t lcid); uint32_t get_total_mch_buffer_state(uint32_t lcid); - int read_pdu(uint32_t lcid, uint8_t* payload, uint32_t nof_bytes); - int read_pdu_mch(uint32_t lcid, uint8_t* payload, uint32_t nof_bytes); + uint32_t read_pdu(uint32_t lcid, uint8_t* payload, uint32_t nof_bytes); + uint32_t read_pdu_mch(uint32_t lcid, uint8_t* payload, uint32_t nof_bytes); int get_increment_sequence_num(); void write_pdu(uint32_t lcid, uint8_t* payload, uint32_t nof_bytes); void write_pdu_bcch_bch(srsran::unique_byte_buffer_t pdu); diff --git a/lib/include/srsran/upper/rlc_am_lte.h b/lib/include/srsran/upper/rlc_am_lte.h index d5afc0aa4..e3f316b07 100644 --- a/lib/include/srsran/upper/rlc_am_lte.h +++ b/lib/include/srsran/upper/rlc_am_lte.h @@ -345,7 +345,7 @@ public: // MAC interface bool has_data(); uint32_t get_buffer_state(); - int read_pdu(uint8_t* payload, uint32_t nof_bytes); + uint32_t read_pdu(uint8_t* payload, uint32_t nof_bytes); void write_pdu(uint8_t* payload, uint32_t nof_bytes); rlc_bearer_metrics_t get_metrics(); @@ -368,7 +368,7 @@ private: void stop(); int write_sdu(unique_byte_buffer_t sdu); - int read_pdu(uint8_t* payload, uint32_t nof_bytes); + uint32_t read_pdu(uint8_t* payload, uint32_t nof_bytes); void discard_sdu(uint32_t discard_sn); bool sdu_queue_is_full(); diff --git a/lib/include/srsran/upper/rlc_common.h b/lib/include/srsran/upper/rlc_common.h index 44568cec7..fcbbf33e1 100644 --- a/lib/include/srsran/upper/rlc_common.h +++ b/lib/include/srsran/upper/rlc_common.h @@ -274,7 +274,7 @@ public: virtual bool has_data() = 0; bool is_suspended() { return suspended; }; virtual uint32_t get_buffer_state() = 0; - virtual int read_pdu(uint8_t* payload, uint32_t nof_bytes) = 0; + virtual uint32_t read_pdu(uint8_t* payload, uint32_t nof_bytes) = 0; virtual void write_pdu(uint8_t* payload, uint32_t nof_bytes) = 0; virtual void set_bsr_callback(bsr_callback_t callback) = 0; @@ -320,4 +320,5 @@ private: }; } // namespace srsran + #endif // SRSRAN_RLC_COMMON_H diff --git a/lib/include/srsran/upper/rlc_tm.h b/lib/include/srsran/upper/rlc_tm.h index d4890db70..b5db8fd67 100644 --- a/lib/include/srsran/upper/rlc_tm.h +++ b/lib/include/srsran/upper/rlc_tm.h @@ -54,7 +54,7 @@ public: // MAC interface bool has_data() override; uint32_t get_buffer_state() override; - int read_pdu(uint8_t* payload, uint32_t nof_bytes) override; + uint32_t read_pdu(uint8_t* payload, uint32_t nof_bytes) override; void write_pdu(uint8_t* payload, uint32_t nof_bytes) override; void set_bsr_callback(bsr_callback_t callback) override {} diff --git a/lib/include/srsran/upper/rlc_um_base.h b/lib/include/srsran/upper/rlc_um_base.h index 1094b7cff..b17357a38 100644 --- a/lib/include/srsran/upper/rlc_um_base.h +++ b/lib/include/srsran/upper/rlc_um_base.h @@ -58,7 +58,7 @@ public: // MAC interface bool has_data(); uint32_t get_buffer_state(); - int read_pdu(uint8_t* payload, uint32_t nof_bytes); + uint32_t read_pdu(uint8_t* payload, uint32_t nof_bytes); void write_pdu(uint8_t* payload, uint32_t nof_bytes); int get_increment_sequence_num(); @@ -75,7 +75,7 @@ protected: rlc_um_base_tx(rlc_um_base* parent_); virtual ~rlc_um_base_tx(); virtual bool configure(const rlc_config_t& cfg, std::string rb_name) = 0; - int build_data_pdu(uint8_t* payload, uint32_t nof_bytes); + uint32_t build_data_pdu(uint8_t* payload, uint32_t nof_bytes); void stop(); void reestablish(); void empty_queue(); @@ -107,7 +107,7 @@ protected: srsran::rolling_average mean_pdu_latency_us; #endif - virtual int build_data_pdu(unique_byte_buffer_t pdu, uint8_t* payload, uint32_t nof_bytes) = 0; + virtual uint32_t build_data_pdu(unique_byte_buffer_t pdu, uint8_t* payload, uint32_t nof_bytes) = 0; // helper functions virtual void debug_state() = 0; diff --git a/lib/include/srsran/upper/rlc_um_lte.h b/lib/include/srsran/upper/rlc_um_lte.h index f544c582e..17bf8ccb9 100644 --- a/lib/include/srsran/upper/rlc_um_lte.h +++ b/lib/include/srsran/upper/rlc_um_lte.h @@ -48,7 +48,7 @@ private: rlc_um_lte_tx(rlc_um_base* parent_); bool configure(const rlc_config_t& cfg, std::string rb_name); - int build_data_pdu(unique_byte_buffer_t pdu, uint8_t* payload, uint32_t nof_bytes); + uint32_t build_data_pdu(unique_byte_buffer_t pdu, uint8_t* payload, uint32_t nof_bytes); uint32_t get_buffer_state(); bool sdu_queue_is_full(); diff --git a/lib/include/srsran/upper/rlc_um_nr.h b/lib/include/srsran/upper/rlc_um_nr.h index 5d01b40d4..6c5e4936e 100644 --- a/lib/include/srsran/upper/rlc_um_nr.h +++ b/lib/include/srsran/upper/rlc_um_nr.h @@ -49,7 +49,7 @@ private: rlc_um_nr_tx(rlc_um_base* parent_); bool configure(const rlc_config_t& cfg, std::string rb_name); - int build_data_pdu(unique_byte_buffer_t pdu, uint8_t* payload, uint32_t nof_bytes); + uint32_t build_data_pdu(unique_byte_buffer_t pdu, uint8_t* payload, uint32_t nof_bytes); uint32_t get_buffer_state(); private: diff --git a/lib/src/upper/rlc.cc b/lib/src/upper/rlc.cc index 76836800e..d24dae789 100644 --- a/lib/src/upper/rlc.cc +++ b/lib/src/upper/rlc.cc @@ -292,7 +292,7 @@ uint32_t rlc::get_total_mch_buffer_state(uint32_t lcid) return ret; } -int rlc::read_pdu(uint32_t lcid, uint8_t* payload, uint32_t nof_bytes) +uint32_t rlc::read_pdu(uint32_t lcid, uint8_t* payload, uint32_t nof_bytes) { uint32_t ret = 0; @@ -309,7 +309,7 @@ int rlc::read_pdu(uint32_t lcid, uint8_t* payload, uint32_t nof_bytes) return ret; } -int rlc::read_pdu_mch(uint32_t lcid, uint8_t* payload, uint32_t nof_bytes) +uint32_t rlc::read_pdu_mch(uint32_t lcid, uint8_t* payload, uint32_t nof_bytes) { uint32_t ret = 0; diff --git a/lib/src/upper/rlc_am_lte.cc b/lib/src/upper/rlc_am_lte.cc index 8590d0b91..45079e826 100644 --- a/lib/src/upper/rlc_am_lte.cc +++ b/lib/src/upper/rlc_am_lte.cc @@ -248,9 +248,9 @@ uint32_t rlc_am_lte::get_buffer_state() return tx.get_buffer_state(); } -int rlc_am_lte::read_pdu(uint8_t* payload, uint32_t nof_bytes) +uint32_t rlc_am_lte::read_pdu(uint8_t* payload, uint32_t nof_bytes) { - int read_bytes = tx.read_pdu(payload, nof_bytes); + uint32_t read_bytes = tx.read_pdu(payload, nof_bytes); metrics.num_tx_pdus++; metrics.num_tx_pdu_bytes += read_bytes; return read_bytes; @@ -533,7 +533,7 @@ bool rlc_am_lte::rlc_am_lte_tx::sdu_queue_is_full() return tx_sdu_queue.is_full(); } -int rlc_am_lte::rlc_am_lte_tx::read_pdu(uint8_t* payload, uint32_t nof_bytes) +uint32_t rlc_am_lte::rlc_am_lte_tx::read_pdu(uint8_t* payload, uint32_t nof_bytes) { std::lock_guard lock(mutex); diff --git a/lib/src/upper/rlc_tm.cc b/lib/src/upper/rlc_tm.cc index e1da8b802..776d2b3cf 100644 --- a/lib/src/upper/rlc_tm.cc +++ b/lib/src/upper/rlc_tm.cc @@ -134,12 +134,12 @@ void rlc_tm::reset_metrics() metrics = {}; } -int rlc_tm::read_pdu(uint8_t* payload, uint32_t nof_bytes) +uint32_t rlc_tm::read_pdu(uint8_t* payload, uint32_t nof_bytes) { uint32_t pdu_size = ul_queue.size_tail_bytes(); if (pdu_size > nof_bytes) { logger.info("%s Tx PDU size larger than MAC opportunity (%d > %d)", rrc->get_rb_name(lcid), pdu_size, nof_bytes); - return -1; + return 0; } unique_byte_buffer_t buf; if (ul_queue.try_read(&buf)) { @@ -171,7 +171,7 @@ int rlc_tm::read_pdu(uint8_t* payload, uint32_t nof_bytes) void rlc_tm::write_pdu(uint8_t* payload, uint32_t nof_bytes) { unique_byte_buffer_t buf = make_byte_buffer(); - if (buf) { + if (buf != nullptr) { memcpy(buf->msg, payload, nof_bytes); buf->N_bytes = nof_bytes; buf->set_timestamp(); diff --git a/lib/src/upper/rlc_um_base.cc b/lib/src/upper/rlc_um_base.cc index 5155ca31e..1ac0d183b 100644 --- a/lib/src/upper/rlc_um_base.cc +++ b/lib/src/upper/rlc_um_base.cc @@ -130,7 +130,7 @@ uint32_t rlc_um_base::get_buffer_state() return 0; } -int rlc_um_base::read_pdu(uint8_t* payload, uint32_t nof_bytes) +uint32_t rlc_um_base::read_pdu(uint8_t* payload, uint32_t nof_bytes) { if (tx && tx_enabled) { uint32_t len = tx->build_data_pdu(payload, nof_bytes); @@ -283,7 +283,7 @@ bool rlc_um_base::rlc_um_base_tx::sdu_queue_is_full() return tx_sdu_queue.is_full(); } -int rlc_um_base::rlc_um_base_tx::build_data_pdu(uint8_t* payload, uint32_t nof_bytes) +uint32_t rlc_um_base::rlc_um_base_tx::build_data_pdu(uint8_t* payload, uint32_t nof_bytes) { unique_byte_buffer_t pdu; { diff --git a/lib/src/upper/rlc_um_lte.cc b/lib/src/upper/rlc_um_lte.cc index 004787c12..cbfe56e4c 100644 --- a/lib/src/upper/rlc_um_lte.cc +++ b/lib/src/upper/rlc_um_lte.cc @@ -109,7 +109,7 @@ bool rlc_um_lte::rlc_um_lte_tx::configure(const rlc_config_t& cnfg_, std::string return true; } -int rlc_um_lte::rlc_um_lte_tx::build_data_pdu(unique_byte_buffer_t pdu, uint8_t* payload, uint32_t nof_bytes) +uint32_t rlc_um_lte::rlc_um_lte_tx::build_data_pdu(unique_byte_buffer_t pdu, uint8_t* payload, uint32_t nof_bytes) { std::lock_guard lock(mutex); rlc_umd_pdu_header_t header; diff --git a/lib/src/upper/rlc_um_nr.cc b/lib/src/upper/rlc_um_nr.cc index 1c88f3aaa..1cf1aa4af 100644 --- a/lib/src/upper/rlc_um_nr.cc +++ b/lib/src/upper/rlc_um_nr.cc @@ -115,7 +115,7 @@ bool rlc_um_nr::rlc_um_nr_tx::configure(const rlc_config_t& cnfg_, std::string r return true; } -int rlc_um_nr::rlc_um_nr_tx::build_data_pdu(unique_byte_buffer_t pdu, uint8_t* payload, uint32_t nof_bytes) +uint32_t rlc_um_nr::rlc_um_nr_tx::build_data_pdu(unique_byte_buffer_t pdu, uint8_t* payload, uint32_t nof_bytes) { // Sanity check (we need at least 2B for a SDU) if (nof_bytes < 2) { diff --git a/lib/test/mac/pdu_test.cc b/lib/test/mac/pdu_test.cc index 13296205b..4f10332f5 100644 --- a/lib/test/mac/pdu_test.cc +++ b/lib/test/mac/pdu_test.cc @@ -169,7 +169,7 @@ int mac_rar_pdu_pack_test2() class rlc_dummy : public srsran::read_pdu_interface { public: - int read_pdu(uint32_t lcid, uint8_t* payload, uint32_t nof_bytes) + uint32_t read_pdu(uint32_t lcid, uint8_t* payload, uint32_t nof_bytes) { uint32_t len = std::min(ul_queues[lcid], nof_bytes); diff --git a/srsenb/hdr/stack/mac/ue.h b/srsenb/hdr/stack/mac/ue.h index abd30bee2..7e7a945d1 100644 --- a/srsenb/hdr/stack/mac/ue.h +++ b/srsenb/hdr/stack/mac/ue.h @@ -175,7 +175,7 @@ public: void metrics_dl_cqi(uint32_t dl_cqi); void metrics_cnt(); - int read_pdu(uint32_t lcid, uint8_t* payload, uint32_t requested_bytes) final; + uint32_t read_pdu(uint32_t lcid, uint8_t* payload, uint32_t requested_bytes) final; private: void allocate_sdu(srsran::sch_pdu* pdu, uint32_t lcid, uint32_t sdu_len); diff --git a/srsenb/src/stack/mac/ue.cc b/srsenb/src/stack/mac/ue.cc index 20435213a..0bc539178 100644 --- a/srsenb/src/stack/mac/ue.cc +++ b/srsenb/src/stack/mac/ue.cc @@ -503,7 +503,7 @@ bool ue::process_ce(srsran::sch_subh* subh, int grant_nof_prbs) return is_bsr; } -int ue::read_pdu(uint32_t lcid, uint8_t* payload, uint32_t requested_bytes) +uint32_t ue::read_pdu(uint32_t lcid, uint8_t* payload, uint32_t requested_bytes) { return rlc->read_pdu(rnti, lcid, payload, requested_bytes); } diff --git a/srsue/src/stack/mac_nr/test/mac_nr_test.cc b/srsue/src/stack/mac_nr/test/mac_nr_test.cc index ad685e63e..315581f92 100644 --- a/srsue/src/stack/mac_nr/test/mac_nr_test.cc +++ b/srsue/src/stack/mac_nr/test/mac_nr_test.cc @@ -92,7 +92,7 @@ public: rlc_dummy() : received_bytes(0) {} bool has_data_locked(const uint32_t lcid) final { return ul_queues[lcid] > 0; } uint32_t get_buffer_state(const uint32_t lcid) final { return ul_queues[lcid]; } - int read_pdu(uint32_t lcid, uint8_t* payload, uint32_t nof_bytes) final + uint32_t read_pdu(uint32_t lcid, uint8_t* payload, uint32_t nof_bytes) final { if (!read_enable || nof_bytes < read_min) { return 0; diff --git a/srsue/test/mac_test.cc b/srsue/test/mac_test.cc index 9d2b65b13..ba81533fe 100644 --- a/srsue/test/mac_test.cc +++ b/srsue/test/mac_test.cc @@ -37,7 +37,7 @@ public: rlc_dummy() : received_bytes(0) {} bool has_data_locked(const uint32_t lcid) final { return ul_queues[lcid] > 0; } uint32_t get_buffer_state(const uint32_t lcid) final { return ul_queues[lcid]; } - int read_pdu(uint32_t lcid, uint8_t* payload, uint32_t nof_bytes) final + uint32_t read_pdu(uint32_t lcid, uint8_t* payload, uint32_t nof_bytes) final { if (!read_enable || nof_bytes < read_min) { return 0; From a013a2fe059317c8edb0df21a085685bbeec6d20 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Thu, 3 Jun 2021 11:05:51 +0200 Subject: [PATCH 141/156] rlc_stress_test: fix bug when read_pdu was returning -1 --- lib/test/upper/rlc_stress_test.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/test/upper/rlc_stress_test.cc b/lib/test/upper/rlc_stress_test.cc index bf7ed78f0..d2530bfe2 100644 --- a/lib/test/upper/rlc_stress_test.cc +++ b/lib/test/upper/rlc_stress_test.cc @@ -197,8 +197,7 @@ private: // Request data to transmit uint32_t buf_state = tx_rlc->get_buffer_state(lcid); if (buf_state > 0) { - int read = tx_rlc->read_pdu(lcid, pdu->msg, opp_size); - pdu->N_bytes = read; + pdu->N_bytes = tx_rlc->read_pdu(lcid, pdu->msg, opp_size); // Push PDU in the list pdu_list.push_back(std::move(pdu)); From 295b5fe8fb24fa60048ce0bda146d7de27c02946 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Thu, 3 Jun 2021 11:06:27 +0200 Subject: [PATCH 142/156] rlc_tm: fix stopping of entity detected with TSAN --- lib/include/srsran/upper/rlc_tm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/include/srsran/upper/rlc_tm.h b/lib/include/srsran/upper/rlc_tm.h index b5db8fd67..858f9ff3b 100644 --- a/lib/include/srsran/upper/rlc_tm.h +++ b/lib/include/srsran/upper/rlc_tm.h @@ -66,7 +66,7 @@ private: srsue::pdcp_interface_rlc* pdcp = nullptr; srsue::rrc_interface_rlc* rrc = nullptr; - bool tx_enabled = true; + std::atomic tx_enabled = {true}; rlc_bearer_metrics_t metrics = {}; From 597f9937068104c073a2f84c582476926bd7bd68 Mon Sep 17 00:00:00 2001 From: Francisco Date: Wed, 2 Jun 2021 11:33:47 +0100 Subject: [PATCH 143/156] sched,improvement: filter out Msg3 UL SNR estimates from the TPC control loop --- srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc b/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc index afecd674d..ba600ed03 100644 --- a/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc +++ b/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc @@ -242,6 +242,10 @@ int sched_ue_cell::set_ack_info(tti_point tti_rx, uint32_t tb_idx, bool ack) int sched_ue_cell::set_ul_snr(tti_point tti_rx, float ul_snr, uint32_t ul_ch_code) { CHECK_VALID_CC("UL SNR estimate"); + if (ue_cfg->ue_bearers[1].direction == sched_interface::ue_bearer_cfg_t::IDLE) { + // Ignore Msg3 SNR samples as Msg3 uses a separate power control loop + return SRSRAN_SUCCESS; + } tpc_fsm.set_snr(ul_snr, ul_ch_code); if (ul_ch_code == tpc::PUSCH_CODE) { ul_cqi_tti_rx = tti_rx; From 75eebd6b5d8516cdd7aee485690f8bac06803942 Mon Sep 17 00:00:00 2001 From: Francisco Date: Fri, 4 Jun 2021 13:26:23 +0100 Subject: [PATCH 144/156] bugfix,gtpu: close forwarding tunnel during reestablishment due to handover failure --- srsenb/src/stack/upper/gtpu.cc | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/srsenb/src/stack/upper/gtpu.cc b/srsenb/src/stack/upper/gtpu.cc index 917dffd4f..1ef303105 100644 --- a/srsenb/src/stack/upper/gtpu.cc +++ b/srsenb/src/stack/upper/gtpu.cc @@ -134,9 +134,21 @@ bool gtpu_tunnel_manager::update_rnti(uint16_t old_rnti, uint16_t new_rnti) return false; } std::swap(ue_teidin_db[new_rnti], *old_rnti_ptr); - auto& new_rnti_obj = ue_teidin_db[new_rnti]; + ue_lcid_tunnel_list& new_rnti_obj = ue_teidin_db[new_rnti]; + srsran::bounded_vector to_remove; for (lcid_tunnel& bearer : new_rnti_obj) { tunnels[bearer.teid].rnti = new_rnti; + if (tunnels[bearer.teid].state == tunnel_state::forward_to) { + // Remove forwarding path + tunnels[bearer.teid].state = tunnel_state::pdcp_active; + tunnels[bearer.teid].fwd_tunnel = nullptr; + } else if (tunnels[bearer.teid].state == tunnel_state::forwarded_from) { + to_remove.push_back(bearer.teid); + } + } + while (not to_remove.empty()) { + remove_tunnel(to_remove.back()); + to_remove.pop_back(); } // Leave old_rnti as zombie to be removed later From e2c37ad5133a4fe886220acabdadffcb42e7b7ef Mon Sep 17 00:00:00 2001 From: Francisco Date: Fri, 4 Jun 2021 11:08:43 +0100 Subject: [PATCH 145/156] bugfix: missing early return in TPC derivation --- srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h b/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h index 1ea15067b..fa3a9424c 100644 --- a/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h +++ b/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h @@ -171,7 +171,9 @@ private: } if (last_phr < 0) { // negative PHR - encode_tpc_delta(-1); + logger.info( + "TPC: rnti=0x%x, %s command=-1 due to PHR=%d < 0", rnti, cc == PUSCH_CODE ? "PUSCH" : "PUCCH", last_phr); + return encode_tpc_delta(-1); } if ((tti_count - ch_snr.last_tpc_tti_count) < min_tpc_tti_interval) { // more time required before sending next TPC From 7badfb1c881ed254772bcd8321813405342ab6cf Mon Sep 17 00:00:00 2001 From: Francisco Date: Fri, 4 Jun 2021 11:41:35 +0100 Subject: [PATCH 146/156] bugfix: avoid multiple TPC=0 for a single PHR<0 --- srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h b/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h index fa3a9424c..379c87c5f 100644 --- a/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h +++ b/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h @@ -165,16 +165,17 @@ private: assert(ch_snr.pending_delta == 0); // ensure called once per {cc,tti} float target_snr_dB = cc == PUSCH_CODE ? target_pusch_snr_dB : target_pucch_snr_dB; - if (target_snr_dB < 0 or last_phr == 0) { - // undefined target sinr case, or no more PHR - return encode_tpc_delta(0); - } - if (last_phr < 0) { + if (last_phr < 0 and not ch_snr.phr_flag) { // negative PHR logger.info( "TPC: rnti=0x%x, %s command=-1 due to PHR=%d < 0", rnti, cc == PUSCH_CODE ? "PUSCH" : "PUCCH", last_phr); + ch_snr.phr_flag = true; return encode_tpc_delta(-1); } + if (target_snr_dB < 0 or last_phr <= 0) { + // undefined target sinr case, or no more PHR + 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); From bdc43624757acb49d26830850f371e030536afda Mon Sep 17 00:00:00 2001 From: Francisco Date: Fri, 4 Jun 2021 14:16:49 +0100 Subject: [PATCH 147/156] bugfix,tpc: place a cap on TPC due to PHR only when TPC is positive --- srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h b/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h index 379c87c5f..cadfe2aab 100644 --- a/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h +++ b/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h @@ -165,14 +165,7 @@ private: assert(ch_snr.pending_delta == 0); // ensure called once per {cc,tti} float target_snr_dB = cc == PUSCH_CODE ? target_pusch_snr_dB : target_pucch_snr_dB; - if (last_phr < 0 and not ch_snr.phr_flag) { - // negative PHR - logger.info( - "TPC: rnti=0x%x, %s command=-1 due to PHR=%d < 0", rnti, cc == PUSCH_CODE ? "PUSCH" : "PUCCH", last_phr); - ch_snr.phr_flag = true; - return encode_tpc_delta(-1); - } - if (target_snr_dB < 0 or last_phr <= 0) { + if (target_snr_dB < 0) { // undefined target sinr case, or no more PHR return encode_tpc_delta(0); } @@ -180,11 +173,19 @@ private: // more time required before sending next TPC return encode_tpc_delta(0); } + if (last_phr < 0 and not ch_snr.phr_flag) { + // negative PHR + logger.info( + "TPC: rnti=0x%x, %s command=-1 due to PHR=%d < 0", rnti, cc == PUSCH_CODE ? "PUSCH" : "PUCCH", last_phr); + ch_snr.phr_flag = true; + return encode_tpc_delta(-1); + } // target SINR is finite and there is power headroom float diff = target_snr_dB - ch_snr.snr_avg.value(); diff -= ch_snr.win_tpc_values.value() + ch_snr.acc_tpc_values; if (diff >= 1) { + diff = std::min(diff, (float)std::max(last_phr, 0)); // low PHR places a cap on TPC ch_snr.pending_delta = diff > 3 ? 3 : 1; ch_snr.last_tpc_tti_count = tti_count; } else if (diff <= -1) { From 9e2a7d45925ed7a751252f2b65dff201be1fb731 Mon Sep 17 00:00:00 2001 From: Francisco Date: Fri, 4 Jun 2021 14:38:40 +0100 Subject: [PATCH 148/156] bugfix,tpc: only cap PUSCH TPC when PHR is negative. I also extended TPC unit test --- srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h | 14 ++++++++------ srsenb/test/mac/sched_tpc_test.cc | 19 +++++++++++++++++++ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h b/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h index cadfe2aab..0c7df3634 100644 --- a/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h +++ b/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h @@ -173,10 +173,9 @@ private: // more time required before sending next TPC return encode_tpc_delta(0); } - if (last_phr < 0 and not ch_snr.phr_flag) { - // negative PHR - logger.info( - "TPC: rnti=0x%x, %s command=-1 due to PHR=%d < 0", rnti, cc == PUSCH_CODE ? "PUSCH" : "PUCCH", last_phr); + 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; return encode_tpc_delta(-1); } @@ -185,8 +184,11 @@ private: float diff = target_snr_dB - ch_snr.snr_avg.value(); diff -= ch_snr.win_tpc_values.value() + ch_snr.acc_tpc_values; if (diff >= 1) { - diff = std::min(diff, (float)std::max(last_phr, 0)); // low PHR places a cap on TPC - ch_snr.pending_delta = diff > 3 ? 3 : 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; + } ch_snr.last_tpc_tti_count = tti_count; } else if (diff <= -1) { ch_snr.pending_delta = -1; diff --git a/srsenb/test/mac/sched_tpc_test.cc b/srsenb/test/mac/sched_tpc_test.cc index 1bd28d559..914cd36e3 100644 --- a/srsenb/test/mac/sched_tpc_test.cc +++ b/srsenb/test/mac/sched_tpc_test.cc @@ -71,6 +71,25 @@ int test_finite_target_snr() TESTASSERT(sum_pucch > 0 and sum_pucch <= -snr_diff); } + // 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; + tpcfsm.set_snr(target_snr + snr_diff, tpc::PUSCH_CODE); + tpcfsm.set_snr(target_snr + snr_diff, tpc::PUCCH_CODE); + 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 + for (uint32_t j = 0; j < 100; ++j) { + tpcfsm.new_tti(); + TESTASSERT(decode_tpc(tpcfsm.encode_pusch_tpc()) == 0); + } + } + tpcfsm.set_phr(20, 1); + tpcfsm.new_tti(); + TESTASSERT(decode_tpc(tpcfsm.encode_pusch_tpc()) == 3); + return SRSRAN_SUCCESS; } From 76004a3054d511166b58b1eca2d4b55e0dfdcf3b Mon Sep 17 00:00:00 2001 From: Francisco Date: Thu, 3 Jun 2021 09:30:22 +0100 Subject: [PATCH 149/156] enb,mac,refactor: mac::ue now uses byte_buffer_pool for UL PDUs --- srsenb/hdr/stack/mac/mac.h | 2 - srsenb/hdr/stack/mac/ue.h | 47 ++++++------ srsenb/src/stack/mac/mac.cc | 31 ++++---- srsenb/src/stack/mac/ue.cc | 140 ++++++++++-------------------------- 4 files changed, 73 insertions(+), 147 deletions(-) diff --git a/srsenb/hdr/stack/mac/mac.h b/srsenb/hdr/stack/mac/mac.h index 2755335cb..a3b782603 100644 --- a/srsenb/hdr/stack/mac/mac.h +++ b/srsenb/hdr/stack/mac/mac.h @@ -92,8 +92,6 @@ public: /* Handover-related */ uint16_t reserve_new_crnti(const sched_interface::ue_cfg_t& ue_cfg) override; - bool process_pdus(); - void get_metrics(mac_metrics_t& metrics); void toggle_padding(); diff --git a/srsenb/hdr/stack/mac/ue.h b/srsenb/hdr/stack/mac/ue.h index 7e7a945d1..6e43597d6 100644 --- a/srsenb/hdr/stack/mac/ue.h +++ b/srsenb/hdr/stack/mac/ue.h @@ -36,6 +36,7 @@ class rrc_interface_mac; class rlc_interface_mac; class phy_interface_stack_lte; +/// Class to manage the allocation, deallocation & access to UE carrier DL + UL softbuffers struct ue_cc_softbuffers { // List of Tx softbuffers for all HARQ processes of one carrier using cc_softbuffer_tx_list_t = std::vector; @@ -59,39 +60,35 @@ struct ue_cc_softbuffers { srsran_softbuffer_rx_t& get_rx(uint32_t tti) { return softbuffer_rx_list.at(tti % nof_rx_harq_proc); } }; +/// Class to manage the allocation, deallocation & access to pending UL HARQ buffers class cc_used_buffers_map { public: - explicit cc_used_buffers_map(srsran::pdu_queue& shared_pdu_queue_); + explicit cc_used_buffers_map(); ~cc_used_buffers_map(); + void clear() { pdu_map.clear(); } + uint8_t* request_pdu(tti_point tti, uint32_t len); - bool push_pdu(tti_point tti, uint32_t len, uint32_t grant_nof_prbs); + srsran::unique_byte_buffer_t release_pdu(tti_point tti, uint32_t len); void clear_old_pdus(tti_point current_tti); - bool try_deallocate_pdu(tti_point tti); - - void clear(); - uint8_t*& operator[](tti_point tti); bool has_tti(tti_point tti) const; private: - void remove_pdu(tti_point tti); - srslog::basic_logger* logger; - srsran::pdu_queue* shared_pdu_queue; - srsran::static_circular_map pdu_map; + srsran::static_circular_map pdu_map; }; class cc_buffer_handler { public: - explicit cc_buffer_handler(srsran::pdu_queue& shared_pdu_queue_); + explicit cc_buffer_handler(); ~cc_buffer_handler(); void reset(); @@ -117,11 +114,11 @@ private: // buffers cc_used_buffers_map rx_used_buffers; - // One buffer per TB per HARQ process and per carrier is needed for each UE. + // One buffer per TB per DL HARQ process and per carrier is needed for each UE. std::array, SRSRAN_FDD_NOF_HARQ> tx_payload_buffer; }; -class ue : public srsran::read_pdu_interface, public srsran::pdu_queue::process_callback, public mac_ta_ue_interface +class ue : public srsran::read_pdu_interface, public mac_ta_ue_interface { public: ue(uint16_t rnti, @@ -139,7 +136,7 @@ public: void start_pcap(srsran::mac_pcap* pcap_); void start_pcap_net(srsran::mac_pcap_net* pcap_net_); void set_tti(uint32_t tti); - uint16_t get_rnti() { return rnti; } + uint16_t get_rnti() const { return rnti; } uint32_t set_ta(int ta) override; void start_ta() { ta_fsm.start(); }; uint32_t set_ta_us(float ta_us) { return ta_fsm.push_value(ta_us); }; @@ -155,16 +152,13 @@ public: uint8_t* generate_mch_pdu(uint32_t harq_pid, sched_interface::dl_pdu_mch_t sched, uint32_t nof_pdu_elems, uint32_t grant_size); - srsran_softbuffer_tx_t* - get_tx_softbuffer(const uint32_t ue_cc_idx, const uint32_t harq_process, const uint32_t tb_idx); - srsran_softbuffer_rx_t* get_rx_softbuffer(const uint32_t ue_cc_idx, const uint32_t tti); + srsran_softbuffer_tx_t* get_tx_softbuffer(uint32_t ue_cc_idx, uint32_t harq_process, uint32_t tb_idx); + srsran_softbuffer_rx_t* get_rx_softbuffer(uint32_t ue_cc_idx, uint32_t tti); - bool process_pdus(); - uint8_t* request_buffer(uint32_t tti, uint32_t ue_cc_idx, const uint32_t len); - void process_pdu(uint8_t* pdu, uint32_t nof_bytes, srsran::pdu_queue::channel_t channel, int grant_nof_prbs) override; - void push_pdu(uint32_t tti, uint32_t ue_cc_idx, uint32_t len, uint32_t grant_nof_prbs); - void deallocate_pdu(uint32_t tti, uint32_t ue_cc_idx); - void clear_old_buffers(uint32_t tti); + uint8_t* request_buffer(uint32_t tti, uint32_t ue_cc_idx, const uint32_t len); + void process_pdu(srsran::unique_byte_buffer_t pdu, uint32_t grant_nof_prbs); + srsran::unique_byte_buffer_t release_pdu(uint32_t tti, uint32_t ue_cc_idx, uint32_t len); + void clear_old_buffers(uint32_t tti); void metrics_read(mac_ue_metrics_t* metrics_); void metrics_rx(bool crc, uint32_t tbs); @@ -179,7 +173,7 @@ public: private: void allocate_sdu(srsran::sch_pdu* pdu, uint32_t lcid, uint32_t sdu_len); - bool process_ce(srsran::sch_subh* subh, int grant_nof_prbs); + bool process_ce(srsran::sch_subh* subh, uint32_t grant_nof_prbs); void allocate_ce(srsran::sch_pdu* pdu, uint32_t lcid); rlc_interface_mac* rlc = nullptr; @@ -207,9 +201,8 @@ private: ta ta_fsm; // For UL there are multiple buffers per PID and are managed by pdu_queue - srsran::pdu_queue pdus; - srsran::sch_pdu mac_msg_dl, mac_msg_ul; - srsran::mch_pdu mch_mac_msg_dl; + srsran::sch_pdu mac_msg_dl, mac_msg_ul; + srsran::mch_pdu mch_mac_msg_dl; srsran::bounded_vector cc_buffers; diff --git a/srsenb/src/stack/mac/mac.cc b/srsenb/src/stack/mac/mac.cc index f8f4a2185..4068af05c 100644 --- a/srsenb/src/stack/mac/mac.cc +++ b/srsenb/src/stack/mac/mac.cc @@ -32,6 +32,7 @@ mac::mac(srsran::ext_task_sched_handle task_sched_, srslog::basic_logger& logger logger(logger), rar_payload(), common_buffers(SRSRAN_MAX_CARRIERS), task_sched(task_sched_) { pthread_rwlock_init(&rwlock, nullptr); + stack_task_queue = task_sched.make_task_queue(); } mac::~mac() @@ -58,8 +59,6 @@ bool mac::init(const mac_args_t& args_, args = args_; cells = cells_; - stack_task_queue = task_sched.make_task_queue(); - scheduler.init(rrc, args.sched); // Init softbuffer for SI messages @@ -364,14 +363,24 @@ int mac::push_pdu(uint32_t tti_rx, } uint32_t ue_cc_idx = enb_ue_cc_map[enb_cc_idx]; + srsran::unique_byte_buffer_t pdu = ue_db[rnti]->release_pdu(tti_rx, ue_cc_idx, nof_bytes); + if (pdu == nullptr) { + logger.warning("Could not find MAC UL PDU for rnti=0x%x, cc=%d, tti=%d", rnti, enb_cc_idx, tti_rx); + return SRSRAN_ERROR; + } + // push the pdu through the queue if received correctly if (crc) { logger.info("Pushing PDU rnti=0x%x, tti_rx=%d, nof_bytes=%d", rnti, tti_rx, nof_bytes); - ue_db[rnti]->push_pdu(tti_rx, ue_cc_idx, nof_bytes, ul_nof_prbs); - stack_task_queue.push([this]() { process_pdus(); }); + auto process_pdu_task = [this, rnti, ul_nof_prbs](srsran::unique_byte_buffer_t& pdu) { + srsran::rwlock_read_guard lock(rwlock); + if (ue_db.contains(rnti)) { + ue_db[rnti]->process_pdu(std::move(pdu), ul_nof_prbs); + } + }; + auto ret = stack_task_queue.try_push(std::bind(process_pdu_task, std::move(pdu))); } else { - logger.debug("Discarting PDU rnti=0x%x, tti_rx=%d, nof_bytes=%d", rnti, tti_rx, nof_bytes); - ue_db[rnti]->deallocate_pdu(tti_rx, ue_cc_idx); + logger.debug("Discarding PDU rnti=0x%x, tti_rx=%d, nof_bytes=%d", rnti, tti_rx, nof_bytes); } return SRSRAN_SUCCESS; } @@ -1007,16 +1016,6 @@ int mac::get_ul_sched(uint32_t tti_tx_ul, ul_sched_list_t& ul_sched_res_list) return SRSRAN_SUCCESS; } -bool mac::process_pdus() -{ - srsran::rwlock_read_guard lock(rwlock); - bool ret = false; - for (auto& u : ue_db) { - ret |= u.second->process_pdus(); - } - return ret; -} - void mac::write_mcch(const srsran::sib2_mbms_t* sib2_, const srsran::sib13_t* sib13_, const srsran::mcch_msg_t* mcch_, diff --git a/srsenb/src/stack/mac/ue.cc b/srsenb/src/stack/mac/ue.cc index 0bc539178..ebbb03861 100644 --- a/srsenb/src/stack/mac/ue.cc +++ b/srsenb/src/stack/mac/ue.cc @@ -62,30 +62,26 @@ void ue_cc_softbuffers::clear() } } -cc_used_buffers_map::cc_used_buffers_map(srsran::pdu_queue& shared_pdu_queue_) : - shared_pdu_queue(&shared_pdu_queue_), logger(&srslog::fetch_basic_logger("MAC")) -{} +cc_used_buffers_map::cc_used_buffers_map() : logger(&srslog::fetch_basic_logger("MAC")) {} cc_used_buffers_map::~cc_used_buffers_map() { clear(); } -bool cc_used_buffers_map::push_pdu(tti_point tti, uint32_t len, uint32_t grant_nof_prbs) +srsran::unique_byte_buffer_t cc_used_buffers_map::release_pdu(tti_point tti, uint32_t len) { if (not has_tti(tti)) { - return false; - } - uint8_t* buffer = pdu_map[tti.to_uint()]; - if (len > 0) { - shared_pdu_queue->push(buffer, len, srsran::pdu_queue::DCH, grant_nof_prbs); - } else { - shared_pdu_queue->deallocate(buffer); - logger->error("Error pushing PDU: null length"); + return nullptr; } + + // Extract PDU from PDU map + srsran::unique_byte_buffer_t pdu = std::move(pdu_map[tti.to_uint()]); + srsran_expect(pdu->size() == len, "UL buffers: Inconsistent UL PDU length for tti=%d", tti.to_uint()); + // clear entry in map pdu_map.erase(tti.to_uint()); - return len > 0; + return pdu; } uint8_t* cc_used_buffers_map::request_pdu(tti_point tti, uint32_t len) @@ -95,15 +91,17 @@ uint8_t* cc_used_buffers_map::request_pdu(tti_point tti, uint32_t len) return nullptr; } - uint8_t* pdu = shared_pdu_queue->request(len); + srsran::unique_byte_buffer_t pdu = srsran::make_byte_buffer(); if (pdu == nullptr) { - logger->error("UE buffers: Requesting buffer from pool"); + logger->error("UE buffers: Requesting buffer from byte buffer pool"); return nullptr; } + srsran_assert(len < pdu->get_tailroom(), "Requested UL pdu doesn't fit in byte_buffer"); + pdu->N_bytes = len; - bool inserted = pdu_map.insert(tti.to_uint(), pdu); - srsran_assert(inserted, "Failure to allocate new buffer"); - return pdu; + auto inserted_elem = pdu_map.insert(tti.to_uint(), std::move(pdu)); + srsran_assert(inserted_elem.has_value(), "Failure to allocate new buffer in mac::ue"); + return inserted_elem.value()->second->data(); } void cc_used_buffers_map::clear_old_pdus(tti_point current_tti) @@ -115,40 +113,14 @@ void cc_used_buffers_map::clear_old_pdus(tti_point current_tti) tti_point t(pdu_pair.first); if (t < max_tti) { logger->warning("UE buffers: Removing old buffer tti=%d, interval=%d", t.to_uint(), current_tti - t); - remove_pdu(t); + pdu_map.erase(t.to_uint()); } } } -void cc_used_buffers_map::remove_pdu(tti_point tti) -{ - uint8_t* buffer = pdu_map[tti.to_uint()]; - // return pdus back to the queue - shared_pdu_queue->deallocate(buffer); - // clear entry in map - pdu_map.erase(tti.to_uint()); -} - -bool cc_used_buffers_map::try_deallocate_pdu(tti_point tti) -{ - if (has_tti(tti)) { - remove_pdu(tti); - return true; - } - return false; -} - -void cc_used_buffers_map::clear() -{ - for (auto& buffer : pdu_map) { - shared_pdu_queue->deallocate(buffer.second); - } - pdu_map.clear(); -} - uint8_t*& cc_used_buffers_map::operator[](tti_point tti) { - return pdu_map[tti.to_uint()]; + return pdu_map[tti.to_uint()]->msg; } bool cc_used_buffers_map::has_tti(tti_point tti) const @@ -158,7 +130,7 @@ bool cc_used_buffers_map::has_tti(tti_point tti) const //////////////// -cc_buffer_handler::cc_buffer_handler(srsran::pdu_queue& shared_pdu_queue_) : rx_used_buffers(shared_pdu_queue_) +cc_buffer_handler::cc_buffer_handler() { for (auto& harq_buffers : tx_payload_buffer) { for (srsran::unique_byte_buffer_t& tb_buffer : harq_buffers) { @@ -219,26 +191,15 @@ ue::ue(uint16_t rnti_, mac_msg_dl(20, logger_), mch_mac_msg_dl(10, logger_), mac_msg_ul(20, logger_), - pdus(logger_), ta_fsm(this), - softbuffer_pool(softbuffer_pool_) + softbuffer_pool(softbuffer_pool_), + cc_buffers(nof_cells_) { - for (size_t i = 0; i < nof_cells_; ++i) { - cc_buffers.emplace_back(pdus); - } - pdus.init(this); - // Allocate buffer for PCell cc_buffers[0].allocate_cc(softbuffer_pool->make()); } -ue::~ue() -{ - std::unique_lock lock(rx_buffers_mutex); - for (auto& cc : cc_buffers) { - cc.get_rx_used_buffers().clear(); - } -} +ue::~ue() {} void ue::reset() { @@ -260,7 +221,7 @@ void ue::start_pcap(srsran::mac_pcap* pcap_) pcap = pcap_; } -srsran_softbuffer_rx_t* ue::get_rx_softbuffer(const uint32_t ue_cc_idx, const uint32_t tti) +srsran_softbuffer_rx_t* ue::get_rx_softbuffer(uint32_t ue_cc_idx, uint32_t tti) { if ((size_t)ue_cc_idx >= cc_buffers.size()) { ERROR("UE CC Index (%d/%zd) out-of-range", ue_cc_idx, cc_buffers.size()); @@ -270,8 +231,7 @@ srsran_softbuffer_rx_t* ue::get_rx_softbuffer(const uint32_t ue_cc_idx, const ui return &cc_buffers[ue_cc_idx].get_rx_softbuffer(tti); } -srsran_softbuffer_tx_t* -ue::get_tx_softbuffer(const uint32_t ue_cc_idx, const uint32_t harq_process, const uint32_t tb_idx) +srsran_softbuffer_tx_t* ue::get_tx_softbuffer(uint32_t ue_cc_idx, uint32_t harq_process, uint32_t tb_idx) { if ((size_t)ue_cc_idx >= cc_buffers.size()) { ERROR("UE CC Index (%d/%zd) out-of-range", ue_cc_idx, cc_buffers.size()); @@ -283,31 +243,20 @@ ue::get_tx_softbuffer(const uint32_t ue_cc_idx, const uint32_t harq_process, con uint8_t* ue::request_buffer(uint32_t tti, uint32_t ue_cc_idx, const uint32_t len) { + srsran_assert(len > 0, "UE buffers: Requesting buffer for zero bytes"); std::unique_lock lock(rx_buffers_mutex); - uint8_t* pdu = nullptr; - if (len > 0) { - pdu = cc_buffers[ue_cc_idx].get_rx_used_buffers().request_pdu(tti_point(tti), len); - } else { - logger.error("UE buffers: Requesting buffer for zero bytes"); - } - return pdu; + return cc_buffers[ue_cc_idx].get_rx_used_buffers().request_pdu(tti_point(tti), len); } void ue::clear_old_buffers(uint32_t tti) { std::unique_lock lock(rx_buffers_mutex); - // remove old buffers for (auto& cc : cc_buffers) { cc.get_rx_used_buffers().clear_old_pdus(tti_point{tti}); } } -bool ue::process_pdus() -{ - return pdus.process_pdus(); -} - void ue::set_tti(uint32_t tti) { last_tti = tti; @@ -329,11 +278,11 @@ uint32_t ue::set_ta(int ta_) return nof_cmd; } -void ue::process_pdu(uint8_t* pdu, uint32_t nof_bytes, srsran::pdu_queue::channel_t channel, int grant_nof_prbs) +void ue::process_pdu(srsran::unique_byte_buffer_t pdu, uint32_t grant_nof_prbs) { // Unpack ULSCH MAC PDU - mac_msg_ul.init_rx(nof_bytes, true); - mac_msg_ul.parse_packet(pdu); + mac_msg_ul.init_rx(pdu->size(), true); + mac_msg_ul.parse_packet(pdu->data()); if (logger.info.enabled()) { fmt::memory_buffer str_buffer; @@ -341,16 +290,14 @@ void ue::process_pdu(uint8_t* pdu, uint32_t nof_bytes, srsran::pdu_queue::channe logger.info("0x%x %s", rnti, srsran::to_c_str(str_buffer)); } - if (pcap) { - pcap->write_ul_crnti(pdu, nof_bytes, rnti, true, last_tti, UL_CC_IDX); + if (pcap != nullptr) { + pcap->write_ul_crnti(pdu->data(), pdu->size(), rnti, true, last_tti, UL_CC_IDX); } - if (pcap_net) { - pcap_net->write_ul_crnti(pdu, nof_bytes, rnti, true, last_tti, UL_CC_IDX); + if (pcap_net != nullptr) { + pcap_net->write_ul_crnti(pdu->data(), pdu->size(), rnti, true, last_tti, UL_CC_IDX); } - pdus.deallocate(pdu); - uint32_t lcid_most_data = 0; int most_data = -99; @@ -386,7 +333,7 @@ void ue::process_pdu(uint8_t* pdu, uint32_t nof_bytes, srsran::pdu_queue::channe // Indicate DRB activity in UL to RRC if (mac_msg_ul.get()->get_sdu_lcid() > 2) { rrc->set_activity_user(rnti); - logger.debug("UL activity rnti=0x%x, n_bytes=%d", rnti, nof_bytes); + logger.debug("UL activity rnti=0x%x, n_bytes=%d", rnti, pdu->size()); } if ((int)mac_msg_ul.get()->get_payload_size() > most_data) { @@ -431,24 +378,13 @@ void ue::process_pdu(uint8_t* pdu, uint32_t nof_bytes, srsran::pdu_queue::channe logger.debug("MAC PDU processed"); } -void ue::deallocate_pdu(uint32_t tti, uint32_t ue_cc_idx) -{ - std::unique_lock lock(rx_buffers_mutex); - if (not cc_buffers[ue_cc_idx].get_rx_used_buffers().try_deallocate_pdu(tti_point(tti))) { - logger.warning( - "UE buffers: Null RX PDU pointer in deallocate_pdu for rnti=0x%x tti=%d cc_idx=%d", rnti, tti, ue_cc_idx); - } -} - -void ue::push_pdu(uint32_t tti, uint32_t ue_cc_idx, uint32_t len, uint32_t grant_nof_prbs) +srsran::unique_byte_buffer_t ue::release_pdu(uint32_t tti, uint32_t ue_cc_idx, uint32_t len) { - std::unique_lock lock(rx_buffers_mutex); - if (not cc_buffers[ue_cc_idx].get_rx_used_buffers().push_pdu(tti_point(tti), len, grant_nof_prbs)) { - logger.warning("UE buffers: Failed to push RX PDU for rnti=0x%x tti=%d cc_idx=%d", rnti, tti, ue_cc_idx); - } + std::lock_guard lock(rx_buffers_mutex); + return cc_buffers[ue_cc_idx].get_rx_used_buffers().release_pdu(tti_point(tti), len); } -bool ue::process_ce(srsran::sch_subh* subh, int grant_nof_prbs) +bool ue::process_ce(srsran::sch_subh* subh, uint32_t grant_nof_prbs) { uint32_t buff_size_idx[4] = {}; uint32_t buff_size_bytes[4] = {}; From fd1d73666c72d7d800f9b061d1bdf4d3a2949216 Mon Sep 17 00:00:00 2001 From: Francisco Date: Fri, 4 Jun 2021 17:37:58 +0100 Subject: [PATCH 150/156] bugfix,srsenb,mac: avoid sanity check for UL PDU length if CRC=KO --- srsenb/hdr/stack/mac/ue.h | 4 ++-- srsenb/src/stack/mac/mac.cc | 10 ++++++++-- srsenb/src/stack/mac/ue.cc | 7 +++---- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/srsenb/hdr/stack/mac/ue.h b/srsenb/hdr/stack/mac/ue.h index 6e43597d6..07f84955a 100644 --- a/srsenb/hdr/stack/mac/ue.h +++ b/srsenb/hdr/stack/mac/ue.h @@ -71,7 +71,7 @@ public: uint8_t* request_pdu(tti_point tti, uint32_t len); - srsran::unique_byte_buffer_t release_pdu(tti_point tti, uint32_t len); + srsran::unique_byte_buffer_t release_pdu(tti_point tti); void clear_old_pdus(tti_point current_tti); @@ -157,7 +157,7 @@ public: uint8_t* request_buffer(uint32_t tti, uint32_t ue_cc_idx, const uint32_t len); void process_pdu(srsran::unique_byte_buffer_t pdu, uint32_t grant_nof_prbs); - srsran::unique_byte_buffer_t release_pdu(uint32_t tti, uint32_t ue_cc_idx, uint32_t len); + srsran::unique_byte_buffer_t release_pdu(uint32_t tti, uint32_t ue_cc_idx); void clear_old_buffers(uint32_t tti); void metrics_read(mac_ue_metrics_t* metrics_); diff --git a/srsenb/src/stack/mac/mac.cc b/srsenb/src/stack/mac/mac.cc index 4068af05c..14fe50b55 100644 --- a/srsenb/src/stack/mac/mac.cc +++ b/srsenb/src/stack/mac/mac.cc @@ -363,7 +363,7 @@ int mac::push_pdu(uint32_t tti_rx, } uint32_t ue_cc_idx = enb_ue_cc_map[enb_cc_idx]; - srsran::unique_byte_buffer_t pdu = ue_db[rnti]->release_pdu(tti_rx, ue_cc_idx, nof_bytes); + srsran::unique_byte_buffer_t pdu = ue_db[rnti]->release_pdu(tti_rx, ue_cc_idx); if (pdu == nullptr) { logger.warning("Could not find MAC UL PDU for rnti=0x%x, cc=%d, tti=%d", rnti, enb_cc_idx, tti_rx); return SRSRAN_ERROR; @@ -372,6 +372,12 @@ int mac::push_pdu(uint32_t tti_rx, // push the pdu through the queue if received correctly if (crc) { logger.info("Pushing PDU rnti=0x%x, tti_rx=%d, nof_bytes=%d", rnti, tti_rx, nof_bytes); + srsran_expect(nof_bytes == pdu->size(), + "Inconsistent PDU length for rnti=0x%x, tti_rx=%d (%d!=%d)", + rnti, + tti_rx, + nof_bytes, + (int)pdu->size()); auto process_pdu_task = [this, rnti, ul_nof_prbs](srsran::unique_byte_buffer_t& pdu) { srsran::rwlock_read_guard lock(rwlock); if (ue_db.contains(rnti)) { @@ -830,7 +836,7 @@ void mac::build_mch_sched(uint32_t tbs) int mac::get_mch_sched(uint32_t tti, bool is_mcch, dl_sched_list_t& dl_sched_res_list) { srsran::rwlock_read_guard lock(rwlock); - dl_sched_t* dl_sched_res = &dl_sched_res_list[0]; + dl_sched_t* dl_sched_res = &dl_sched_res_list[0]; logger.set_context(tti); srsran_ra_tb_t mcs = {}; srsran_ra_tb_t mcs_data = {}; diff --git a/srsenb/src/stack/mac/ue.cc b/srsenb/src/stack/mac/ue.cc index ebbb03861..426e907ed 100644 --- a/srsenb/src/stack/mac/ue.cc +++ b/srsenb/src/stack/mac/ue.cc @@ -69,7 +69,7 @@ cc_used_buffers_map::~cc_used_buffers_map() clear(); } -srsran::unique_byte_buffer_t cc_used_buffers_map::release_pdu(tti_point tti, uint32_t len) +srsran::unique_byte_buffer_t cc_used_buffers_map::release_pdu(tti_point tti) { if (not has_tti(tti)) { return nullptr; @@ -77,7 +77,6 @@ srsran::unique_byte_buffer_t cc_used_buffers_map::release_pdu(tti_point tti, uin // Extract PDU from PDU map srsran::unique_byte_buffer_t pdu = std::move(pdu_map[tti.to_uint()]); - srsran_expect(pdu->size() == len, "UL buffers: Inconsistent UL PDU length for tti=%d", tti.to_uint()); // clear entry in map pdu_map.erase(tti.to_uint()); @@ -378,10 +377,10 @@ void ue::process_pdu(srsran::unique_byte_buffer_t pdu, uint32_t grant_nof_prbs) logger.debug("MAC PDU processed"); } -srsran::unique_byte_buffer_t ue::release_pdu(uint32_t tti, uint32_t ue_cc_idx, uint32_t len) +srsran::unique_byte_buffer_t ue::release_pdu(uint32_t tti, uint32_t ue_cc_idx) { std::lock_guard lock(rx_buffers_mutex); - return cc_buffers[ue_cc_idx].get_rx_used_buffers().release_pdu(tti_point(tti), len); + return cc_buffers[ue_cc_idx].get_rx_used_buffers().release_pdu(tti_point(tti)); } bool ue::process_ce(srsran::sch_subh* subh, uint32_t grant_nof_prbs) From 7e77da6a153d22e05310332126b62438d32b89ec Mon Sep 17 00:00:00 2001 From: Francisco Date: Fri, 4 Jun 2021 09:33:40 +0100 Subject: [PATCH 151/156] mac,optimization: use rnti memory pool to create mac::ue objects --- .../srsran/interfaces/enb_mac_interfaces.h | 3 +- srsenb/hdr/stack/mac/mac.h | 19 +- srsenb/hdr/stack/mac/ue.h | 4 + srsenb/src/stack/mac/mac.cc | 191 +++++++----------- srsenb/test/common/dummy_classes.h | 1 - 5 files changed, 80 insertions(+), 138 deletions(-) diff --git a/lib/include/srsran/interfaces/enb_mac_interfaces.h b/lib/include/srsran/interfaces/enb_mac_interfaces.h index 0b33584ed..4dd8fbf38 100644 --- a/lib/include/srsran/interfaces/enb_mac_interfaces.h +++ b/lib/include/srsran/interfaces/enb_mac_interfaces.h @@ -209,8 +209,7 @@ class mac_interface_rrc { public: /* Provides cell configuration including SIB periodicity, etc. */ - virtual int cell_cfg(const std::vector& cell_cfg) = 0; - virtual void reset() = 0; + virtual int cell_cfg(const std::vector& cell_cfg) = 0; /* Manages UE configuration context */ virtual int ue_cfg(uint16_t rnti, sched_interface::ue_cfg_t* cfg) = 0; diff --git a/srsenb/hdr/stack/mac/mac.h b/srsenb/hdr/stack/mac/mac.h index a3b782603..284b6db3c 100644 --- a/srsenb/hdr/stack/mac/mac.h +++ b/srsenb/hdr/stack/mac/mac.h @@ -14,6 +14,7 @@ #define SRSENB_MAC_H #include "sched.h" +#include "srsenb/hdr/common/rnti_pool.h" #include "srsenb/hdr/stack/mac/schedulers/sched_time_rr.h" #include "srsran/adt/circular_map.h" #include "srsran/adt/pool/batch_mem_pool.h" @@ -73,8 +74,7 @@ public: /******** Interface from RRC (RRC -> MAC) ****************/ /* Provides cell configuration including SIB periodicity, etc. */ - int cell_cfg(const std::vector& cell_cfg) override; - void reset() override; + int cell_cfg(const std::vector& cell_cfg) override; /* Manages UE scheduling context */ int ue_cfg(uint16_t rnti, sched_interface::ue_cfg_t* cfg) override; @@ -107,11 +107,9 @@ public: private: static const uint32_t cfi = 3; - bool check_ue_exists(uint16_t rnti); - uint16_t allocate_rnti(); + bool check_ue_active(uint16_t rnti); uint16_t allocate_ue(); - - std::mutex rnti_mutex; + bool is_valid_rnti_unprotected(uint16_t rnti); srslog::basic_logger& logger; @@ -140,12 +138,9 @@ private: sched_interface::dl_pdu_mch_t mch = {}; /* Map of active UEs */ - rnti_map_t > ue_db; - std::map > ues_to_rem; - uint16_t last_rnti = 70; - - srsran::static_blocking_queue, 32> ue_pool; ///< Pool of pre-allocated UE objects - void prealloc_ue(uint32_t nof_ue); + static const uint16_t FIRST_RNTI = 0x46; + rnti_map_t > ue_db; + std::atomic ue_counter; uint8_t* assemble_rar(sched_interface::dl_sched_rar_grant_t* grants, uint32_t enb_cc_idx, diff --git a/srsenb/hdr/stack/mac/ue.h b/srsenb/hdr/stack/mac/ue.h index 07f84955a..3cce3e59e 100644 --- a/srsenb/hdr/stack/mac/ue.h +++ b/srsenb/hdr/stack/mac/ue.h @@ -142,6 +142,8 @@ public: uint32_t set_ta_us(float ta_us) { return ta_fsm.push_value(ta_us); }; void tic(); void trigger_padding(int lcid); + void set_active(bool active) { active_state.store(active, std::memory_order_relaxed); } + bool is_active() const { return active_state.load(std::memory_order_relaxed); } uint8_t* generate_pdu(uint32_t ue_cc_idx, uint32_t harq_pid, @@ -189,6 +191,8 @@ private: uint32_t last_tti = 0; uint32_t nof_failures = 0; + std::atomic active_state{true}; + uint32_t phr_counter = 0; uint32_t dl_cqi_counter = 0; uint32_t dl_ri_counter = 0; diff --git a/srsenb/src/stack/mac/mac.cc b/srsenb/src/stack/mac/mac.cc index 14fe50b55..d71bd75ae 100644 --- a/srsenb/src/stack/mac/mac.cc +++ b/srsenb/src/stack/mac/mac.cc @@ -48,13 +48,9 @@ bool mac::init(const mac_args_t& args_, rrc_interface_mac* rrc) { started = false; - - if (not phy or not rlc) { - return false; - } - phy_h = phy; - rlc_h = rlc; - rrc_h = rrc; + phy_h = phy; + rlc_h = rlc; + rrc_h = rrc; args = args_; cells = cells_; @@ -74,8 +70,6 @@ bool mac::init(const mac_args_t& args_, srsran_softbuffer_tx_init(&cc.rar_softbuffer_tx, args.nof_prb); } - reset(); - // Initiate common pool of softbuffers uint32_t nof_prb = args.nof_prb; auto init_softbuffers = [nof_prb](void* ptr) { @@ -85,9 +79,6 @@ bool mac::init(const mac_args_t& args_, softbuffer_pool.reset(new srsran::background_obj_pool( 8, 8, args.nof_prealloc_ues, init_softbuffers, recycle_softbuffers)); - // Pre-alloc UE objects for first attaching users - prealloc_ue(10); - detected_rachs.resize(cells.size()); started = true; @@ -108,21 +99,9 @@ void mac::stop() srsran_softbuffer_tx_free(&cc.pcch_softbuffer_tx); srsran_softbuffer_tx_free(&cc.rar_softbuffer_tx); } - ue_pool.stop(); } } -// Implement Section 5.9 -void mac::reset() -{ - logger.info("Resetting MAC"); - - last_rnti = 70; - - /* Setup scheduler */ - scheduler.reset(); -} - void mac::start_pcap(srsran::mac_pcap* pcap_) { srsran::rwlock_read_guard lock(rwlock); @@ -148,11 +127,12 @@ void mac::start_pcap_net(srsran::mac_pcap_net* pcap_net_) * RLC interface * *******************************************************/ + int mac::rlc_buffer_state(uint16_t rnti, uint32_t lc_id, uint32_t tx_queue, uint32_t retx_queue) { srsran::rwlock_read_guard lock(rwlock); int ret = -1; - if (ue_db.contains(rnti)) { + if (check_ue_active(rnti)) { if (rnti != SRSRAN_MRNTI) { ret = scheduler.dl_rlc_buffer_state(rnti, lc_id, tx_queue, retx_queue); } else { @@ -163,34 +143,20 @@ int mac::rlc_buffer_state(uint16_t rnti, uint32_t lc_id, uint32_t tx_queue, uint } ret = 0; } - } else { - logger.error("User rnti=0x%x not found", rnti); } return ret; } int mac::bearer_ue_cfg(uint16_t rnti, uint32_t lc_id, sched_interface::ue_bearer_cfg_t* cfg) { - int ret = -1; srsran::rwlock_read_guard lock(rwlock); - if (ue_db.contains(rnti)) { - ret = scheduler.bearer_ue_cfg(rnti, lc_id, *cfg); - } else { - logger.error("User rnti=0x%x not found", rnti); - } - return ret; + return check_ue_active(rnti) ? scheduler.bearer_ue_cfg(rnti, lc_id, *cfg) : -1; } int mac::bearer_ue_rem(uint16_t rnti, uint32_t lc_id) { srsran::rwlock_read_guard lock(rwlock); - int ret = -1; - if (ue_db.contains(rnti)) { - ret = scheduler.bearer_ue_rem(rnti, lc_id); - } else { - logger.error("User rnti=0x%x not found", rnti); - } - return ret; + return check_ue_active(rnti) ? scheduler.bearer_ue_rem(rnti, lc_id) : -1; } void mac::phy_config_enabled(uint16_t rnti, bool enabled) @@ -202,14 +168,10 @@ void mac::phy_config_enabled(uint16_t rnti, bool enabled) int mac::ue_cfg(uint16_t rnti, sched_interface::ue_cfg_t* cfg) { srsran::rwlock_read_guard lock(rwlock); - - auto it = ue_db.find(rnti); - ue* ue_ptr = nullptr; - if (it == ue_db.end()) { - logger.error("User rnti=0x%x not found", rnti); + if (not check_ue_active(rnti)) { return SRSRAN_ERROR; } - ue_ptr = it->second.get(); + ue* ue_ptr = ue_db[rnti].get(); // Start TA FSM in UE entity ue_ptr->start_ta(); @@ -227,10 +189,9 @@ int mac::ue_rem(uint16_t rnti) { // Remove UE from the perspective of L2/L3 { - srsran::rwlock_write_guard lock(rwlock); - if (ue_db.contains(rnti)) { - ues_to_rem[rnti] = std::move(ue_db[rnti]); - ue_db.erase(rnti); + srsran::rwlock_read_guard lock(rwlock); + if (check_ue_active(rnti)) { + ue_db[rnti]->set_active(false); } else { logger.error("User rnti=0x%x not found", rnti); return SRSRAN_ERROR; @@ -242,7 +203,8 @@ int mac::ue_rem(uint16_t rnti) // Note: Let any pending retx ACK to arrive, so that PHY recognizes rnti task_sched.defer_callback(FDD_HARQ_DELAY_DL_MS + FDD_HARQ_DELAY_UL_MS, [this, rnti]() { phy_h->rem_rnti(rnti); - ues_to_rem.erase(rnti); + srsran::rwlock_write_guard lock(rwlock); + ue_db.erase(rnti); logger.info("User rnti=0x%x removed from MAC/PHY", rnti); }); return SRSRAN_SUCCESS; @@ -259,11 +221,7 @@ int mac::ue_set_crnti(uint16_t temp_crnti, uint16_t crnti, sched_interface::ue_c // Schedule ConRes Msg4 scheduler.dl_mac_buffer_state(crnti, (uint32_t)srsran::dl_sch_lcid::CON_RES_ID); } - int ret = ue_cfg(crnti, cfg); - if (ret != SRSRAN_SUCCESS) { - return ret; - } - return ret; + return ue_cfg(crnti, cfg); } int mac::cell_cfg(const std::vector& cell_cfg_) @@ -313,7 +271,7 @@ int mac::ack_info(uint32_t tti_rx, uint16_t rnti, uint32_t enb_cc_idx, uint32_t logger.set_context(tti_rx); srsran::rwlock_read_guard lock(rwlock); - if (not check_ue_exists(rnti)) { + if (not check_ue_active(rnti)) { return SRSRAN_ERROR; } @@ -330,7 +288,7 @@ int mac::crc_info(uint32_t tti_rx, uint16_t rnti, uint32_t enb_cc_idx, uint32_t logger.set_context(tti_rx); srsran::rwlock_read_guard lock(rwlock); - if (not check_ue_exists(rnti)) { + if (not check_ue_active(rnti)) { return SRSRAN_ERROR; } @@ -352,7 +310,7 @@ int mac::push_pdu(uint32_t tti_rx, { srsran::rwlock_read_guard lock(rwlock); - if (not check_ue_exists(rnti)) { + if (not check_ue_active(rnti)) { return SRSRAN_ERROR; } @@ -380,8 +338,10 @@ int mac::push_pdu(uint32_t tti_rx, (int)pdu->size()); auto process_pdu_task = [this, rnti, ul_nof_prbs](srsran::unique_byte_buffer_t& pdu) { srsran::rwlock_read_guard lock(rwlock); - if (ue_db.contains(rnti)) { + if (check_ue_active(rnti)) { ue_db[rnti]->process_pdu(std::move(pdu), ul_nof_prbs); + } else { + logger.debug("Discarding PDU rnti=0x%x", rnti); } }; auto ret = stack_task_queue.try_push(std::bind(process_pdu_task, std::move(pdu))); @@ -396,7 +356,7 @@ int mac::ri_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, uint32_t ri_v logger.set_context(tti); srsran::rwlock_read_guard lock(rwlock); - if (not check_ue_exists(rnti)) { + if (not check_ue_active(rnti)) { return SRSRAN_ERROR; } @@ -411,7 +371,7 @@ int mac::pmi_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, uint32_t pmi logger.set_context(tti); srsran::rwlock_read_guard lock(rwlock); - if (not check_ue_exists(rnti)) { + if (not check_ue_active(rnti)) { return SRSRAN_ERROR; } @@ -426,7 +386,7 @@ int mac::cqi_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, uint32_t cqi logger.set_context(tti); srsran::rwlock_read_guard lock(rwlock); - if (not check_ue_exists(rnti)) { + if (not check_ue_active(rnti)) { return SRSRAN_ERROR; } @@ -441,7 +401,7 @@ int mac::snr_info(uint32_t tti_rx, uint16_t rnti, uint32_t enb_cc_idx, float snr logger.set_context(tti_rx); srsran::rwlock_read_guard lock(rwlock); - if (not check_ue_exists(rnti)) { + if (not check_ue_active(rnti)) { return SRSRAN_ERROR; } @@ -454,13 +414,13 @@ int mac::ta_info(uint32_t tti, uint16_t rnti, float ta_us) { srsran::rwlock_read_guard lock(rwlock); - if (not check_ue_exists(rnti)) { + if (not check_ue_active(rnti)) { return SRSRAN_ERROR; } uint32_t nof_ta_count = ue_db[rnti]->set_ta_us(ta_us); - if (nof_ta_count) { - scheduler.dl_mac_buffer_state(rnti, (uint32_t)srsran::dl_sch_lcid::TA_CMD, nof_ta_count); + if (nof_ta_count > 0) { + return scheduler.dl_mac_buffer_state(rnti, (uint32_t)srsran::dl_sch_lcid::TA_CMD, nof_ta_count); } return SRSRAN_SUCCESS; } @@ -470,65 +430,64 @@ int mac::sr_detected(uint32_t tti, uint16_t rnti) logger.set_context(tti); srsran::rwlock_read_guard lock(rwlock); - if (not check_ue_exists(rnti)) { + if (not check_ue_active(rnti)) { return SRSRAN_ERROR; } return scheduler.ul_sr_info(tti, rnti); } -uint16_t mac::allocate_rnti() +bool mac::is_valid_rnti_unprotected(uint16_t rnti) { - std::lock_guard lock(rnti_mutex); - - // Assign a c-rnti - uint16_t rnti = last_rnti++; - if (last_rnti >= 60000) { - last_rnti = 70; + if (not started) { + logger.info("RACH ignored as eNB is being shutdown"); + return false; } - - return rnti; + if (ue_db.full()) { + logger.warning("Maximum number of connected UEs %zd connected to the eNB. Ignoring PRACH", SRSENB_MAX_UES); + return false; + } + if (not ue_db.has_space(rnti)) { + logger.info("Failed to allocate rnti=0x%x. Attempting a different rnti.", rnti); + return false; + } + return true; } uint16_t mac::allocate_ue() { - ue* inserted_ue = nullptr; + ue* inserted_ue = nullptr; + uint16_t rnti = SRSRAN_INVALID_RNTI; + do { - // Get pre-allocated UE object - std::unique_ptr ue_ptr; - if (not ue_pool.try_pop(ue_ptr)) { - logger.error("UE pool empty. Ignoring RACH attempt."); - return SRSRAN_INVALID_RNTI; - } - uint16_t rnti = ue_ptr->get_rnti(); + // Assign new RNTI + rnti = FIRST_RNTI + (ue_counter.fetch_add(1, std::memory_order_relaxed) % 60000); - // Add UE to map + // Pre-check if rnti is valid { - srsran::rwlock_write_guard lock(rwlock); - if (not started) { - logger.info("RACH ignored as eNB is being shutdown"); - return SRSRAN_INVALID_RNTI; - } - if (ue_db.size() >= SRSENB_MAX_UES) { - logger.warning("Maximum number of connected UEs %zd connected to the eNB. Ignoring PRACH", SRSENB_MAX_UES); - return SRSRAN_INVALID_RNTI; - } - auto ret = ue_db.insert(rnti, std::move(ue_ptr)); - if (ret) { - inserted_ue = ret.value()->second.get(); - } else { - logger.info("Failed to allocate rnti=0x%x. Attempting a different rnti.", rnti); + srsran::rwlock_read_guard read_lock(rwlock); + if (not is_valid_rnti_unprotected(rnti)) { + continue; } } - // Allocate one new UE object in advance - srsran::get_background_workers().push_task([this]() { prealloc_ue(1); }); + // Allocate and initialize UE object + unique_rnti_ptr ue_ptr = make_rnti_obj( + rnti, rnti, args.nof_prb, &scheduler, rrc_h, rlc_h, phy_h, logger, cells.size(), softbuffer_pool.get()); + // Add UE to rnti map + srsran::rwlock_write_guard rw_lock(rwlock); + if (not is_valid_rnti_unprotected(rnti)) { + continue; + } + auto ret = ue_db.insert(rnti, std::move(ue_ptr)); + if (ret.has_value()) { + inserted_ue = ret.value()->second.get(); + } else { + logger.info("Failed to allocate rnti=0x%x. Attempting a different rnti.", rnti); + } } while (inserted_ue == nullptr); - // RNTI allocation was successful - uint16_t rnti = inserted_ue->get_rnti(); - // Set PCAP if available if (pcap != nullptr) { inserted_ue->start_pcap(pcap); @@ -614,18 +573,6 @@ void mac::rach_detected(uint32_t tti, uint32_t enb_cc_idx, uint32_t preamble_idx }); } -void mac::prealloc_ue(uint32_t nof_ue) -{ - for (uint32_t i = 0; i < nof_ue; i++) { - std::unique_ptr ptr = std::unique_ptr(new ue( - allocate_rnti(), args.nof_prb, &scheduler, rrc_h, rlc_h, phy_h, logger, cells.size(), softbuffer_pool.get())); - if (not ue_pool.try_push(std::move(ptr))) { - logger.info("Cannot preallocate more UEs as pool is full"); - return; - } - } -} - int mac::get_dl_sched(uint32_t tti_tx_dl, dl_sched_list_t& dl_sched_res_list) { if (!started) { @@ -1045,15 +992,13 @@ void mac::write_mcch(const srsran::sib2_mbms_t* sib2_, } // Internal helper function, caller must hold UE DB rwlock -bool mac::check_ue_exists(uint16_t rnti) +bool mac::check_ue_active(uint16_t rnti) { if (not ue_db.contains(rnti)) { - if (not ues_to_rem.count(rnti)) { - logger.error("User rnti=0x%x not found", rnti); - } + logger.error("User rnti=0x%x not found", rnti); return false; } - return true; + return ue_db[rnti]->is_active(); } } // namespace srsenb diff --git a/srsenb/test/common/dummy_classes.h b/srsenb/test/common/dummy_classes.h index 6887b6546..68c50baa8 100644 --- a/srsenb/test/common/dummy_classes.h +++ b/srsenb/test/common/dummy_classes.h @@ -28,7 +28,6 @@ class mac_dummy : public mac_interface_rrc { public: int cell_cfg(const std::vector& cell_cfg) override { return 0; } - void reset() override {} int ue_cfg(uint16_t rnti, sched_interface::ue_cfg_t* cfg) override { return 0; } int ue_rem(uint16_t rnti) override { return 0; } int ue_set_crnti(uint16_t temp_crnti, uint16_t crnti, sched_interface::ue_cfg_t* cfg) override { return 0; } From 35cea3d104ca686c9df4047a3703b8f97b3488cd Mon Sep 17 00:00:00 2001 From: Francisco Date: Fri, 4 Jun 2021 09:49:38 +0100 Subject: [PATCH 152/156] enb,optimization: consider mac::ue object in rnti pool memory block size --- srsenb/hdr/stack/rrc/rrc.h | 3 ++- srsenb/src/common/rnti_pool.cc | 10 +++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/srsenb/hdr/stack/rrc/rrc.h b/srsenb/hdr/stack/rrc/rrc.h index 274ae5d75..5b559482b 100644 --- a/srsenb/hdr/stack/rrc/rrc.h +++ b/srsenb/hdr/stack/rrc/rrc.h @@ -143,8 +143,9 @@ public: log_rrc_message(Tx, rnti, -1, pdu, msg, msg_type); } -private: class ue; + +private: // args srsran::task_sched_handle task_sched; phy_interface_rrc_lte* phy = nullptr; diff --git a/srsenb/src/common/rnti_pool.cc b/srsenb/src/common/rnti_pool.cc index 27f6a9bfd..4c62932a9 100644 --- a/srsenb/src/common/rnti_pool.cc +++ b/srsenb/src/common/rnti_pool.cc @@ -12,14 +12,22 @@ #include "srsenb/hdr/common/rnti_pool.h" #include "srsenb/hdr/common/common_enb.h" +#include "srsenb/hdr/stack/mac/ue.h" +#include "srsenb/hdr/stack/rrc/rrc_mobility.h" +#include "srsenb/hdr/stack/rrc/rrc_ue.h" #include "srsran/adt/pool/circular_stack_pool.h" +#include "srsran/upper/pdcp.h" +#include "srsran/upper/rlc.h" namespace srsenb { +const static size_t UE_MEM_BLOCK_SIZE = + sizeof(ue) + sizeof(rrc::ue) + sizeof(rrc::ue::rrc_mobility) + sizeof(srsran::rlc) + sizeof(srsran::pdcp); + srsran::circular_stack_pool* get_rnti_pool() { static std::unique_ptr > pool( - new srsran::circular_stack_pool(8, 32768, 4)); + new srsran::circular_stack_pool(8, UE_MEM_BLOCK_SIZE, 4)); return pool.get(); } From f65faba7561ce182853b65900568b195568e456e Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Fri, 4 Jun 2021 10:05:37 +0200 Subject: [PATCH 153/156] sched_harq: fix uninitialized values in HARQ detected with Valgrind memcheck --- .../hdr/stack/mac/sched_ue_ctrl/sched_harq.h | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/srsenb/hdr/stack/mac/sched_ue_ctrl/sched_harq.h b/srsenb/hdr/stack/mac/sched_ue_ctrl/sched_harq.h index 5bd5278ca..50577374f 100644 --- a/srsenb/hdr/stack/mac/sched_ue_ctrl/sched_harq.h +++ b/srsenb/hdr/stack/mac/sched_ue_ctrl/sched_harq.h @@ -47,17 +47,17 @@ protected: enum ack_t { NACK, ACK }; - srslog::basic_logger* logger; - bool ack_state[SRSRAN_MAX_TB]; - bool active[SRSRAN_MAX_TB]; - std::array ndi = {}; - uint32_t id; - uint32_t max_retx = 5; - uint32_t n_rtx[SRSRAN_MAX_TB]; - uint32_t tx_cnt[SRSRAN_MAX_TB]; - srsran::tti_point tti; - int last_mcs[SRSRAN_MAX_TB]; - int last_tbs[SRSRAN_MAX_TB]; + srslog::basic_logger* logger = nullptr; + std::array ack_state = {}; + std::array active = {}; + std::array ndi = {}; + uint32_t id = 0; + uint32_t max_retx = 5; + std::array n_rtx = {}; + std::array tx_cnt = {}; + std::array last_mcs = {}; + std::array last_tbs = {}; + srsran::tti_point tti; }; class dl_harq_proc : public harq_proc From bcd2e59635166588608c7cde334eeff3a63e13b0 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Thu, 3 Jun 2021 17:05:44 +0200 Subject: [PATCH 154/156] PDCCH test global variable cleanup --- lib/src/phy/phch/test/pdcch_test.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/lib/src/phy/phch/test/pdcch_test.c b/lib/src/phy/phch/test/pdcch_test.c index a455227ba..2ba033317 100644 --- a/lib/src/phy/phch/test/pdcch_test.c +++ b/lib/src/phy/phch/test/pdcch_test.c @@ -23,7 +23,6 @@ static uint32_t pci = 1; static uint16_t rnti = 0x46; static uint32_t cfi = 1; static uint32_t nof_ports = 1; -static bool print_dci_table; static srsran_dci_cfg_t dci_cfg = {}; static uint32_t nof_prb = 100; static float snr_dB = 20.0f; @@ -40,12 +39,11 @@ static cf_t* slot_symbols[SRSRAN_MAX_PORTS]; void usage(char* prog) { - printf("Usage: %s [cfpndxv]\n", prog); + printf("Usage: %s [pfncxv]\n", prog); printf("\t-c cell id [Default %d]\n", pci); printf("\t-f cfi [Default %d]\n", cfi); printf("\t-p cell.nof_ports [Default %d]\n", nof_ports); printf("\t-n cell.nof_prb [Default %d]\n", nof_prb); - printf("\t-d Print DCI table [Default %s]\n", print_dci_table ? "yes" : "no"); printf("\t-x Enable/Disable Cross-scheduling [Default %s]\n", dci_cfg.cif_enabled ? "enabled" : "disabled"); printf("\t-v [set srsran_verbose to debug, default none]\n"); } @@ -53,7 +51,7 @@ void usage(char* prog) void parse_args(int argc, char** argv) { int opt; - while ((opt = getopt(argc, argv, "cfpndvAx")) != -1) { + while ((opt = getopt(argc, argv, "pfncxv")) != -1) { switch (opt) { case 'p': nof_ports = (uint32_t)strtol(argv[optind], NULL, 10); @@ -67,9 +65,6 @@ void parse_args(int argc, char** argv) case 'c': pci = (uint32_t)strtol(argv[optind], NULL, 10); break; - case 'd': - print_dci_table = true; - break; case 'x': dci_cfg.cif_enabled ^= true; break; From 7c78fd2050de27538050e0da1af85562a10130a3 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Fri, 4 Jun 2021 15:31:50 +0200 Subject: [PATCH 155/156] Implemented PDCCH DCI message correlation and updated test --- lib/include/srsran/phy/phch/pdcch.h | 8 ++ lib/src/phy/phch/pdcch.c | 22 +++++ lib/src/phy/phch/test/CMakeLists.txt | 27 +++--- lib/src/phy/phch/test/pdcch_test.c | 139 ++++++++++++++++++++------- 4 files changed, 148 insertions(+), 48 deletions(-) diff --git a/lib/include/srsran/phy/phch/pdcch.h b/lib/include/srsran/phy/phch/pdcch.h index 281c2ba9f..3caa5fbda 100644 --- a/lib/include/srsran/phy/phch/pdcch.h +++ b/lib/include/srsran/phy/phch/pdcch.h @@ -95,6 +95,14 @@ SRSRAN_API int srsran_pdcch_extract_llr(srsran_pdcch_t* q, SRSRAN_API int srsran_pdcch_decode_msg(srsran_pdcch_t* q, srsran_dl_sf_cfg_t* sf, srsran_dci_cfg_t* dci_cfg, srsran_dci_msg_t* msg); +/** + * @brief Computes decoded DCI correlation. It encodes the given DCI message and compares it with the received LLRs + * @param q PDCCH object + * @param msg Previously decoded DCI message + * @return The normalized correlation between the restored symbols and the received LLRs + */ +SRSRAN_API float srsran_pdcch_msg_corr(srsran_pdcch_t* q, srsran_dci_msg_t* msg); + SRSRAN_API int srsran_pdcch_dci_decode(srsran_pdcch_t* q, float* e, uint8_t* data, uint32_t E, uint32_t nof_bits, uint16_t* crc); diff --git a/lib/src/phy/phch/pdcch.c b/lib/src/phy/phch/pdcch.c index edeaf3b81..6b96b6d93 100644 --- a/lib/src/phy/phch/pdcch.c +++ b/lib/src/phy/phch/pdcch.c @@ -10,6 +10,7 @@ * */ +#include #include #include #include @@ -412,6 +413,27 @@ int srsran_pdcch_decode_msg(srsran_pdcch_t* q, srsran_dl_sf_cfg_t* sf, srsran_dc return ret; } +float srsran_pdcch_msg_corr(srsran_pdcch_t* q, srsran_dci_msg_t* msg) +{ + if (q == NULL || msg == NULL) { + return 0.0f; + } + + uint32_t E = PDCCH_FORMAT_NOF_BITS(msg->location.L); + uint32_t nof_llr = E / 2; + + // Encode same decoded message and compute correlation + srsran_pdcch_dci_encode(q, msg->payload, q->e, msg->nof_bits, E, msg->rnti); + + // Modulate + srsran_mod_modulate(&q->mod, q->e, q->d, E); + + // Correlate + cf_t corr = srsran_vec_dot_prod_conj_ccc((cf_t*)&q->llr[msg->location.ncce * 72], q->d, nof_llr); + + return cabsf(corr / nof_llr) * (float)M_SQRT1_2; +} + /** Performs PDCCH receiver processing to extract LLR for all control region. LLR bits are stored in srsran_pdcch_t * object. DCI can be decoded from given locations in successive calls to srsran_pdcch_decode_msg() */ diff --git a/lib/src/phy/phch/test/CMakeLists.txt b/lib/src/phy/phch/test/CMakeLists.txt index 98835024d..5e39926d1 100644 --- a/lib/src/phy/phch/test/CMakeLists.txt +++ b/lib/src/phy/phch/test/CMakeLists.txt @@ -198,19 +198,20 @@ add_lte_test(phich_test_104 phich_test -p 4 -n 10 -e -l -g 1/2) add_executable(pdcch_test pdcch_test.c) target_link_libraries(pdcch_test srsran_phy) -add_lte_test(pdcch_test_6 pdcch_test -n 6) -add_lte_test(pdcch_test_15 pdcch_test -n 15) -add_lte_test(pdcch_test_25 pdcch_test -n 25) -add_lte_test(pdcch_test_50 pdcch_test -n 50) -add_lte_test(pdcch_test_75 pdcch_test -n 75) -add_lte_test(pdcch_test_100 pdcch_test -n 100) -add_lte_test(pdcch_test_6_mimo pdcch_test -n 6 -p 2) -add_lte_test(pdcch_test_15_mimo pdcch_test -n 15 -p 2) -add_lte_test(pdcch_test_25_mimo pdcch_test -n 25 -p 2) -add_lte_test(pdcch_test_50_mimo pdcch_test -n 50 -p 2) -add_lte_test(pdcch_test_75_mimo pdcch_test -n 75 -p 2) -add_lte_test(pdcch_test_100_mimo pdcch_test -n 100 -p 2) -#add_lte_test(pdcch_test_crosscarrier pdcch_test -x) +foreach (nof_prb 6 15 25 50 75 100) + foreach (nof_ports 1 2) + foreach (cfi 1 2 3) + foreach (snr auto 15 300) + set(pdcch_test_args "") + set(pdcch_test_args -n ${nof_prb} -p ${nof_ports} -f ${cfi} -S ${snr} -R 1 -F) + + string(REGEX REPLACE "\ " "" test_name_args ${pdcch_test_args}) + + add_lte_test(pdcch_test${test_name_args} pdcch_test ${pdcch_test_args}) + endforeach () + endforeach () + endforeach () +endforeach () ######################################################################## # PDSCH TEST diff --git a/lib/src/phy/phch/test/pdcch_test.c b/lib/src/phy/phch/test/pdcch_test.c index 2ba033317..79c3dce55 100644 --- a/lib/src/phy/phch/test/pdcch_test.c +++ b/lib/src/phy/phch/test/pdcch_test.c @@ -19,25 +19,25 @@ #include "srsran/srsran.h" // Test parameters -static uint32_t pci = 1; -static uint16_t rnti = 0x46; -static uint32_t cfi = 1; -static uint32_t nof_ports = 1; +static uint32_t pci = 1; +static uint16_t rnti = 0x46; +static uint32_t cfi = 2; +static uint32_t nof_ports = 1; static srsran_dci_cfg_t dci_cfg = {}; static uint32_t nof_prb = 100; -static float snr_dB = 20.0f; +static float snr_dB = NAN; static uint32_t repetitions = 1; static bool false_check = false; // Test objects -static srsran_random_t random_gen = NULL; -static srsran_pdcch_t pdcch_tx = {}; -static srsran_pdcch_t pdcch_rx = {}; -static srsran_chest_dl_res_t chest_dl_res = {}; -static srsran_channel_awgn_t awgn = {}; -static cf_t* slot_symbols[SRSRAN_MAX_PORTS]; - -void usage(char* prog) +static srsran_random_t random_gen = NULL; +static srsran_pdcch_t pdcch_tx = {}; +static srsran_pdcch_t pdcch_rx = {}; +static srsran_chest_dl_res_t chest_dl_res = {}; +static srsran_channel_awgn_t awgn = {}; +static cf_t* slot_symbols[SRSRAN_MAX_PORTS] = {}; + +static void usage(char* prog) { printf("Usage: %s [pfncxv]\n", prog); printf("\t-c cell id [Default %d]\n", pci); @@ -45,13 +45,16 @@ void usage(char* prog) printf("\t-p cell.nof_ports [Default %d]\n", nof_ports); printf("\t-n cell.nof_prb [Default %d]\n", nof_prb); printf("\t-x Enable/Disable Cross-scheduling [Default %s]\n", dci_cfg.cif_enabled ? "enabled" : "disabled"); + printf("\t-F False detection check [Default %s]\n", false_check ? "enabled" : "disabled"); + printf("\t-R Repetitions [Default %d]\n", repetitions); + printf("\t-S SNR in dB [Default %+.1f]\n", snr_dB); printf("\t-v [set srsran_verbose to debug, default none]\n"); } -void parse_args(int argc, char** argv) +static void parse_args(int argc, char** argv) { int opt; - while ((opt = getopt(argc, argv, "pfncxv")) != -1) { + while ((opt = getopt(argc, argv, "pfncxvFRS")) != -1) { switch (opt) { case 'p': nof_ports = (uint32_t)strtol(argv[optind], NULL, 10); @@ -66,7 +69,16 @@ void parse_args(int argc, char** argv) pci = (uint32_t)strtol(argv[optind], NULL, 10); break; case 'x': - dci_cfg.cif_enabled ^= true; + dci_cfg.cif_enabled = !dci_cfg.cif_enabled; + break; + case 'F': + false_check = !false_check; + break; + case 'R': + repetitions = (uint32_t)strtol(argv[optind], NULL, 10); + break; + case 'S': + snr_dB = (float)strtof(argv[optind], NULL); break; case 'v': srsran_verbose++; @@ -76,6 +88,17 @@ void parse_args(int argc, char** argv) exit(-1); } } + printf("params - pci=%d; rnti=0x%04x; cfi=%d; nof_ports=%d; cif_enabled=%d; nof_prb=%d; snr_db=%+.1f; " + "repetitions=%d; false_check=%d;\n", + pci, + rnti, + cfi, + nof_ports, + dci_cfg.cif_enabled, + nof_prb, + snr_dB, + repetitions, + false_check); } static void print_dci_msg(const char* desc, const srsran_dci_msg_t* dci_msg) @@ -142,19 +165,32 @@ static const srsran_dci_format_t formats[] = {SRSRAN_DCI_FORMAT0, SRSRAN_DCI_FORMAT2, SRSRAN_DCI_NOF_FORMATS}; +static float get_snr_dB(uint32_t L) +{ + static const float snr_table_dB[4] = {15.0f, 6.0f, 5.0f, 0.0f}; + + if (isnormal(snr_dB) && L < 4) { + return snr_dB; + } + + return snr_table_dB[L]; +} + static int test_case1() { - uint32_t nof_re = SRSRAN_NOF_RE(pdcch_tx.cell); - struct timeval t[3] = {}; - uint64_t t_encode_us = 0; - uint64_t t_encode_count = 0; - uint64_t t_llr_us = 0; - uint64_t t_decode_us = 0; - uint64_t t_decode_count = 0; + uint32_t nof_re = SRSRAN_NOF_RE(pdcch_tx.cell); // Iterate all possible subframes for (uint32_t f_idx = 0; formats[f_idx] != SRSRAN_DCI_NOF_FORMATS; f_idx++) { - srsran_dci_format_t format = formats[f_idx]; + srsran_dci_format_t format = formats[f_idx]; + struct timeval t[3] = {}; + uint64_t t_encode_us = 0; + uint64_t t_encode_count = 0; + uint64_t t_llr_us = 0; + uint64_t t_decode_us = 0; + uint64_t t_decode_count = 0; + uint32_t false_alarm_corr_count = 0; + float min_corr = INFINITY; for (uint32_t sf_idx = 0; sf_idx < repetitions * SRSRAN_NOF_SF_X_FRAME; sf_idx++) { srsran_dl_sf_cfg_t dl_sf_cfg = {}; @@ -196,6 +232,11 @@ static int test_case1() t_encode_us += (size_t)(t[0].tv_sec * 1e6 + t[0].tv_usec); t_encode_count++; + // Set noise level according to aggregation level + float n0_dB = -get_snr_dB(locations[loc].L); + TESTASSERT(srsran_channel_awgn_set_n0(&awgn, n0_dB) == SRSRAN_SUCCESS); + chest_dl_res.noise_estimate = srsran_convert_dB_to_power(n0_dB); + // Apply AWGN for (uint32_t p = 0; p < nof_ports; p++) { srsran_channel_awgn_run_c(&awgn, slot_symbols[p], slot_symbols[p], nof_re); @@ -210,7 +251,10 @@ static int test_case1() // Try decoding the PDCCH in all possible locations for (uint32_t loc_rx = 0; loc_rx < locations_count; loc_rx++) { - if (!false_check && loc_rx != loc) { + // Skip location if: + // - False check is disabled and Tx/Rx dont match + // - Tx aggregation level is bigger than Rx aggregation level + if ((!false_check && loc_rx != loc) || locations[loc_rx].L < locations[loc].L) { continue; } @@ -227,16 +271,42 @@ static int test_case1() t_decode_us += (size_t)(t[0].tv_sec * 1e6 + t[0].tv_usec); t_decode_count++; + // Compute LLR correlation + float corr = srsran_pdcch_msg_corr(&pdcch_rx, &dci_rx); + bool rnti_match = (dci_tx.rnti == dci_rx.rnti); bool location_match = (loc == loc_rx); bool payload_match = (memcmp(dci_tx.payload, dci_rx.payload, dci_tx.nof_bits) == 0); + bool corr_thr = corr > 0.5f; // Skip location if the decoding is not successful in a different location than transmitted if (!location_match && !rnti_match) { continue; } + // Skip location if the correlation does not surpass the threshold + if (!location_match && !corr_thr) { + false_alarm_corr_count++; + continue; + } + + // Assert correlation only if location matches + if (location_match) { + TESTASSERT(corr_thr); + if (location_match && corr < min_corr) { + min_corr = corr; + } + } + if (srsran_verbose >= SRSRAN_VERBOSE_INFO || !payload_match) { + // If payload is not match and there is no logging, set logging to info and run the decoder again + if (srsran_verbose < SRSRAN_VERBOSE_INFO) { + printf("-- Detected payload was not matched, repeating decode with INFO logs (n0: %+.1f dB, corr: %f)\n", + n0_dB, + corr); + srsran_verbose = SRSRAN_VERBOSE_INFO; + srsran_pdcch_decode_msg(&pdcch_rx, &dl_sf_cfg, &dci_cfg, &dci_rx); + } print_dci_msg("Tx: ", &dci_tx); print_dci_msg("Rx: ", &dci_rx); } @@ -246,12 +316,16 @@ static int test_case1() } } } - } - printf("test_case_1 - %.1f usec/encode; %.1f usec/llr; %.1f usec/decode;\n", - (double)t_encode_us / (double)(t_encode_count), - (double)t_llr_us / (double)(t_encode_count), - (double)t_decode_us / (double)(t_decode_count)); + printf("test_case_1 - format %s - passed - %.1f usec/encode; %.1f usec/llr; %.1f usec/decode; min_corr=%f; " + "false_alarm_prob=%f;\n", + srsran_dci_format_string(format), + (double)t_encode_us / (double)(t_encode_count), + (double)t_llr_us / (double)(t_encode_count), + (double)t_decode_us / (double)(t_decode_count), + min_corr, + (double)false_alarm_corr_count / (double)t_decode_count); + } return SRSRAN_SUCCESS; } @@ -319,11 +393,6 @@ int main(int argc, char** argv) goto quit; } - if (srsran_channel_awgn_set_n0(&awgn, -snr_dB) < SRSRAN_SUCCESS) { - ERROR("Error setting n0"); - goto quit; - } - // Execute actual test cases if (test_case1() < SRSRAN_SUCCESS) { ERROR("Test case 1 failed"); From e8f2b3a74cdf57ac5e77aab3df2b7b5145d8d003 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Fri, 4 Jun 2021 15:32:28 +0200 Subject: [PATCH 156/156] Add PDCCH decoder correlation check in blind search --- lib/src/phy/ue/ue_dl.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/src/phy/ue/ue_dl.c b/lib/src/phy/ue/ue_dl.c index b60ebc661..32a3b77aa 100644 --- a/lib/src/phy/ue/ue_dl.c +++ b/lib/src/phy/ue/ue_dl.c @@ -440,8 +440,16 @@ static int dci_blind_search(srsran_ue_dl_t* q, return SRSRAN_ERROR; } + // Check if RNTI is matched if ((dci_msg[nof_dci].rnti == rnti) && (dci_msg[nof_dci].nof_bits > 0)) { - dci_msg[nof_dci].rnti = rnti; + // Compute decoded message correlation to drastically reduce false alarm probability + float corr = srsran_pdcch_msg_corr(&q->pdcch, &dci_msg[nof_dci]); + + // Skip candidate if the threshold is not reached + // 0.5 is set from pdcch_test + if (!isnormal(corr) || corr < 0.5f) { + continue; + } // Look for the messages found and apply the new format if the location is common if (search_in_common && (dci_cfg->multiple_csi_request_enabled || dci_cfg->srs_request_enabled)) {