diff --git a/srsue/hdr/stack/mac/mac_nr.h b/srsue/hdr/stack/mac/mac_nr.h index d6ce1d896..063c03858 100644 --- a/srsue/hdr/stack/mac/mac_nr.h +++ b/srsue/hdr/stack/mac/mac_nr.h @@ -34,10 +34,6 @@ namespace srsue { struct mac_nr_args_t { srsue::pcap_args_t pcap; - - // Add args - std::string log_level; - uint32_t log_hex_limit; }; class mac_nr : public mac_interface_phy_nr, public mac_interface_rrc_nr diff --git a/srsue/hdr/stack/ue_stack_nr.h b/srsue/hdr/stack/ue_stack_nr.h new file mode 100644 index 000000000..6710f3f1a --- /dev/null +++ b/srsue/hdr/stack/ue_stack_nr.h @@ -0,0 +1,147 @@ +/* + * Copyright 2013-2020 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * srsLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#ifndef SRSUE_UE_STACK_NR_H +#define SRSUE_UE_STACK_NR_H + +#include +#include +#include +#include + +#include "mac/mac_nr.h" +#include "rrc/rrc_nr.h" +#include "srslte/radio/radio.h" +#include "srslte/upper/pdcp.h" +#include "srslte/upper/rlc.h" +#include "upper/nas.h" +#include "upper/usim.h" + +#include "srslte/common/buffer_pool.h" +#include "srslte/common/log_filter.h" +#include "srslte/common/mac_nr_pcap.h" +#include "srslte/common/multiqueue.h" +#include "srslte/common/thread_pool.h" +#include "srslte/interfaces/ue_nr_interfaces.h" + +#include "srsue/hdr/ue_metrics_interface.h" +#include "ue_stack_base.h" + +namespace srsue { + +/** \brief L2/L3 stack class for 5G/NR UEs. + * + * This class wraps all L2/L3 blocks and provides a single interface towards the PHY. + */ + +class ue_stack_nr final : public ue_stack_base, + public stack_interface_phy_nr, + public stack_interface_gw, + public stack_interface_rrc, + public srslte::thread +{ +public: + ue_stack_nr(srslte::logger* logger_); + ~ue_stack_nr(); + + std::string get_type() final; + + int init(const stack_args_t& args_); + int init(const stack_args_t& args_, phy_interface_stack_nr* phy_, gw_interface_stack* gw_); + bool switch_on() final; + bool switch_off() final; + void stop(); + + bool get_metrics(stack_metrics_t* metrics); + bool is_rrc_connected(); + + // RRC interface for PHY + void in_sync() final; + void out_of_sync() final; + void run_tti(uint32_t tti) final; + + // MAC interface for PHY + int sf_indication(const uint32_t tti) + { + mac->sf_indication(tti); + return SRSLTE_SUCCESS; + } + void tb_decoded(const uint32_t cc_idx, mac_nr_grant_dl_t& grant) { mac->tb_decoded(cc_idx, grant); } + void new_grant_ul(const uint32_t cc_idx, const mac_nr_grant_ul_t& grant) { mac->new_grant_ul(cc_idx, grant); } + + // Interface for GW + void write_sdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu, bool blocking) final; + bool is_lcid_enabled(uint32_t lcid) final { return pdcp->is_lcid_enabled(lcid); } + + // Interface for RRC + void start_cell_search() final; + void start_cell_select(const phy_interface_rrc_lte::phy_cell_t* cell) final; + srslte::tti_point get_current_tti() { return srslte::tti_point{0}; }; + + // Task Handling interface + srslte::timer_handler::unique_timer get_unique_timer() final { return timers.get_unique_timer(); } + srslte::task_multiqueue::queue_handler make_task_queue() final { return pending_tasks.get_queue_handler(); } + void enqueue_background_task(std::function f) final; + void notify_background_task_result(srslte::move_task_t task) final; + void defer_callback(uint32_t duration_ms, std::function func) final; + void defer_task(srslte::move_task_t task) final; + +private: + void run_thread() final; + void run_tti_impl(uint32_t tti); + void stop_impl(); + + bool running = false; + srsue::stack_args_t args = {}; + + // timers + srslte::timer_handler timers; + + // UE stack logging + srslte::logger* logger = nullptr; + srslte::log_ref rlc_log; + srslte::log_ref pdcp_log; + srslte::log_ref pool_log; + + // stack components + std::unique_ptr mac; + std::unique_ptr rrc; + std::unique_ptr rlc; + std::unique_ptr pdcp; + + std::unique_ptr mac_pcap; + + // RAT-specific interfaces + phy_interface_stack_nr* phy = nullptr; + gw_interface_stack* gw = nullptr; + + // Thread + static const int STACK_MAIN_THREAD_PRIO = -1; // Use default high-priority below UHD + + srslte::task_multiqueue pending_tasks; + int sync_queue_id = -1, ue_queue_id = -1, gw_queue_id = -1, mac_queue_id = -1, background_queue_id = -1; + srslte::task_thread_pool background_tasks; ///< Thread pool used for long, low-priority tasks + std::vector deferred_stack_tasks; ///< enqueues stack tasks from within. Avoids locking +}; + +} // namespace srsue + +#endif // SRSUE_UE_STACK_NR_H \ No newline at end of file diff --git a/srsue/src/stack/CMakeLists.txt b/srsue/src/stack/CMakeLists.txt index e5e0b9ba4..460080a9c 100644 --- a/srsue/src/stack/CMakeLists.txt +++ b/srsue/src/stack/CMakeLists.txt @@ -23,4 +23,9 @@ add_subdirectory(rrc) add_subdirectory(upper) set(SOURCES ue_stack_lte.cc) -add_library(srsue_stack STATIC ${SOURCES}) \ No newline at end of file +add_library(srsue_stack STATIC ${SOURCES}) + +if(ENABLE_5GNR) + set(SOURCES ue_stack_nr.cc) + add_library(srsue_nr_stack STATIC ${SOURCES}) +endif() diff --git a/srsue/src/stack/mac/mac_nr.cc b/srsue/src/stack/mac/mac_nr.cc index 3ee774772..17571cca2 100644 --- a/srsue/src/stack/mac/mac_nr.cc +++ b/srsue/src/stack/mac/mac_nr.cc @@ -30,9 +30,6 @@ mac_nr::mac_nr() : pool(srslte::byte_buffer_pool::get_instance()), log_h("MAC") { tx_buffer = srslte::allocate_unique_buffer(*pool); rlc_buffer = srslte::allocate_unique_buffer(*pool); - - log_h->set_level(args.log_level); - log_h->set_hex_limit(args.log_hex_limit); } mac_nr::~mac_nr() diff --git a/srsue/src/stack/rrc/CMakeLists.txt b/srsue/src/stack/rrc/CMakeLists.txt index 52181fa4d..9a73c1600 100644 --- a/srsue/src/stack/rrc/CMakeLists.txt +++ b/srsue/src/stack/rrc/CMakeLists.txt @@ -23,5 +23,5 @@ add_library(srsue_rrc STATIC ${SOURCES}) if(ENABLE_5GNR) set(SOURCES rrc_nr.cc) - add_library(srsgnb_rrc STATIC ${SOURCES}) + add_library(srsue_nr_rrc STATIC ${SOURCES}) endif() diff --git a/srsue/src/stack/ue_stack_nr.cc b/srsue/src/stack/ue_stack_nr.cc new file mode 100644 index 000000000..f93359684 --- /dev/null +++ b/srsue/src/stack/ue_stack_nr.cc @@ -0,0 +1,268 @@ +/* + * Copyright 2013-2020 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * srsLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include "srsue/hdr/stack/ue_stack_nr.h" +#include "srslte/srslte.h" + +using namespace srslte; + +namespace srsue { + +ue_stack_nr::ue_stack_nr(srslte::logger* logger_) : + logger(logger_), + timers(64), + thread("STACK"), + pending_tasks(1024), + background_tasks(2), + rlc_log("RLC"), + pdcp_log("PDCP"), + pool_log("POOL") +{ + mac.reset(new mac_nr()); + pdcp.reset(new srslte::pdcp(this, "PDCP")); + rlc.reset(new srslte::rlc("RLC")); + rrc.reset(new rrc_nr()); + + // setup logging for pool, RLC and PDCP + pool_log->set_level(srslte::LOG_LEVEL_ERROR); + byte_buffer_pool::get_instance()->set_log(pool_log.get()); + + ue_queue_id = pending_tasks.add_queue(); + sync_queue_id = pending_tasks.add_queue(); + gw_queue_id = pending_tasks.add_queue(); + mac_queue_id = pending_tasks.add_queue(); + background_queue_id = pending_tasks.add_queue(); + + background_tasks.start(); +} + +ue_stack_nr::~ue_stack_nr() +{ + stop(); +} + +std::string ue_stack_nr::get_type() +{ + return "nr"; +} + +int ue_stack_nr::init(const stack_args_t& args_, phy_interface_stack_nr* phy_, gw_interface_stack* gw_) +{ + phy = phy_; + gw = gw_; + return init(args_); +} + +int ue_stack_nr::init(const stack_args_t& args_) +{ + args = args_; + + srslte::logmap::register_log(std::unique_ptr{new srslte::log_filter{"MAC", logger, true}}); + + srslte::log_ref mac_log{"MAC"}; + mac_log->set_level(args.log.mac_level); + mac_log->set_hex_limit(args.log.mac_hex_limit); + rlc_log->set_level(args.log.rlc_level); + rlc_log->set_hex_limit(args.log.rlc_hex_limit); + pdcp_log->set_level(args.log.pdcp_level); + pdcp_log->set_hex_limit(args.log.pdcp_hex_limit); + + mac_nr_args_t mac_args = {}; + mac_args.pcap = args.pcap; + mac->init(mac_args, phy, rlc.get(), &timers, this); + rlc->init(pdcp.get(), rrc.get(), &timers, 0 /* RB_ID_SRB0 */); + pdcp->init(rlc.get(), rrc.get(), gw); + + // TODO: where to put RRC args? + rrc_nr_args_t rrc_args = {}; + rrc_args.log_level = args.log.rrc_level; + rrc_args.log_hex_limit = args.log.rrc_hex_limit; + rrc_args.coreless.drb_lcid = 4; + rrc_args.coreless.ip_addr = "192.168.1.3"; + rrc->init(phy, mac.get(), rlc.get(), pdcp.get(), gw, &timers, this, rrc_args); + + // statically setup TUN (will be done through RRC later) + char* err_str = nullptr; + if (gw->setup_if_addr(rrc_args.coreless.drb_lcid, + LIBLTE_MME_PDN_TYPE_IPV4, + htonl(inet_addr(rrc_args.coreless.ip_addr.c_str())), + nullptr, + err_str)) { + printf("Error configuring TUN interface\n"); + } + + running = true; + start(STACK_MAIN_THREAD_PRIO); + + return SRSLTE_SUCCESS; +} + +void ue_stack_nr::stop() +{ + if (running) { + pending_tasks.try_push(ue_queue_id, [this]() { stop_impl(); }); + wait_thread_finish(); + } +} + +void ue_stack_nr::stop_impl() +{ + running = false; + + rrc->stop(); + + rlc->stop(); + pdcp->stop(); + mac->stop(); + + if (mac_pcap != nullptr) { + mac_pcap.reset(); + } +} + +bool ue_stack_nr::switch_on() +{ + return true; +} + +bool ue_stack_nr::switch_off() +{ + return true; +} + +bool ue_stack_nr::get_metrics(stack_metrics_t* metrics) +{ + // mac.get_metrics(metrics->mac); + rlc->get_metrics(metrics->rlc); + // rrc.get_metrics(metrics->rrc); + return true; +} + +void ue_stack_nr::run_thread() +{ + while (running) { + srslte::move_task_t task{}; + if (pending_tasks.wait_pop(&task) >= 0) { + task(); + } + } +} + +/*********************************************************************************************************************** + * Stack Interfaces + **********************************************************************************************************************/ + +/******************** + * GW Interface + *******************/ + +/** + * Push GW SDU to stack + * @param lcid + * @param sdu + * @param blocking + */ +void ue_stack_nr::write_sdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu, bool blocking) +{ + if (pdcp != nullptr) { + std::pair ret = pending_tasks.try_push( + gw_queue_id, + std::bind([this, lcid, blocking]( + srslte::unique_byte_buffer_t& sdu) { pdcp->write_sdu(lcid, std::move(sdu), blocking); }, + std::move(sdu))); + if (not ret.first) { + pdcp_log->warning("GW SDU with lcid=%d was discarded.\n", lcid); + } + } +} + +/******************** + * SYNC Interface + *******************/ + +/** + * Sync thread signal that it is in sync + */ +void ue_stack_nr::in_sync() +{ + // pending_tasks.push(sync_queue_id, task_t{[this](task_t*) { rrc.in_sync(); }}); +} + +void ue_stack_nr::out_of_sync() +{ + // pending_tasks.push(sync_queue_id, task_t{[this](task_t*) { rrc.out_of_sync(); }}); +} + +void ue_stack_nr::run_tti(uint32_t tti) +{ + // pending_tasks.push(sync_queue_id, task_t{[this, tti](task_t*) { run_tti_impl(tti); }}); +} + +void ue_stack_nr::run_tti_impl(uint32_t tti) +{ +#if 0 + mac->run_tti(tti); + rrc->run_tti(tti); + nas->run_tti(tti); + timers->step_all(); +#endif +} + +/******************** + * low MAC Interface + *******************/ + +void ue_stack_nr::start_cell_search() +{ + // not implemented +} + +void ue_stack_nr::start_cell_select(const phy_interface_rrc_lte::phy_cell_t* cell) +{ + // not implemented +} + +/*************************** + * Task Handling Interface + **************************/ + +void ue_stack_nr::enqueue_background_task(std::function f) +{ + background_tasks.push_task(std::move(f)); +} + +void ue_stack_nr::notify_background_task_result(srslte::move_task_t task) +{ + // run the notification in the stack thread + pending_tasks.push(background_queue_id, std::move(task)); +} + +void ue_stack_nr::defer_callback(uint32_t duration_ms, std::function func) +{ + timers.defer_callback(duration_ms, func); +} + +void ue_stack_nr::defer_task(srslte::move_task_t task) +{ + deferred_stack_tasks.push_back(std::move(task)); +} + +} // namespace srsue \ No newline at end of file