diff --git a/srsenb/hdr/phy/enb_phy_base.h b/srsenb/hdr/phy/enb_phy_base.h index ea2ef0ae3..794fbeee8 100644 --- a/srsenb/hdr/phy/enb_phy_base.h +++ b/srsenb/hdr/phy/enb_phy_base.h @@ -27,7 +27,7 @@ #ifndef SRSENB_PHY_BASE_H #define SRSENB_PHY_BASE_H -#include "srsue/hdr/phy/phy_metrics.h" +#include "srsenb/hdr/phy/phy_metrics.h" namespace srsenb { diff --git a/srsepc/hdr/mme/s1ap_nas_transport.h b/srsepc/hdr/mme/s1ap_nas_transport.h index 8f404cff8..8d689e759 100644 --- a/srsepc/hdr/mme/s1ap_nas_transport.h +++ b/srsepc/hdr/mme/s1ap_nas_transport.h @@ -52,7 +52,7 @@ private: srslte::log* m_s1ap_log; srslte::byte_buffer_pool* m_pool; - s1ap* m_s1ap; + s1ap* m_s1ap; nas_init_t m_nas_init; nas_if_t m_nas_if; diff --git a/srsue/hdr/stack/mac/mac_nr.h b/srsue/hdr/stack/mac/mac_nr.h new file mode 100644 index 000000000..e44492cf2 --- /dev/null +++ b/srsue/hdr/stack/mac/mac_nr.h @@ -0,0 +1,118 @@ +/* + * 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_MAC_NR_H +#define SRSUE_MAC_NR_H + +#include "srslte/common/block_queue.h" +#include "srslte/common/logmap.h" +#include "srslte/common/mac_nr_pcap.h" +#include "srslte/common/mac_nr_pdu.h" +#include "srslte/interfaces/ue_nr_interfaces.h" +#include "srsue/hdr/stack/mac/mux.h" +#include "srsue/hdr/stack/ue_stack_base.h" + +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 +{ +public: + mac_nr(); + ~mac_nr(); + + int init(const mac_nr_args_t& args_, + phy_interface_mac_nr* phy, + rlc_interface_mac* rlc, + srslte::timer_handler* timers_, + srslte::task_handler_interface* stack_); + void stop(); + + void reset(); + + void run_tti(const uint32_t tti); + + uint16_t get_dl_sched_rnti(uint32_t tti); + uint16_t get_ul_sched_rnti(uint32_t tti); + + void bch_decoded_ok(uint32_t tti, srslte::unique_byte_buffer_t payload); + + int sf_indication(const uint32_t tti); + + void tb_decoded(const uint32_t cc_idx, mac_nr_grant_dl_t& grant); + + void new_grant_ul(const uint32_t cc_idx, const mac_nr_grant_ul_t& grant); + + void timer_expired(uint32_t timer_id); + + void get_metrics(mac_metrics_t* metrics); + + /// stack interface + void process_pdus(); + +private: + void setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD); + void setup_lcid(const logical_channel_config_t& config); + + void handle_pdu(srslte::unique_byte_buffer_t pdu); + void get_ul_data(const mac_nr_grant_ul_t& grant, phy_interface_stack_nr::tx_request_t* tx_request); + + /// Interaction with rest of the stack + phy_interface_mac_nr* phy = nullptr; + rlc_interface_mac* rlc = nullptr; + srslte::task_handler_interface* stack = nullptr; + + std::unique_ptr pcap = nullptr; + srslte::log_ref log_h; + srslte::byte_buffer_pool* pool = nullptr; + srslte::timer_handler* timers = nullptr; + mac_nr_args_t args = {}; + + bool started = false; + + uint16_t crnti = 0xdead; + + static constexpr uint32_t MIN_RLC_PDU_LEN = + 5; ///< minimum bytes that need to be available in a MAC PDU for attempting to add another RLC SDU + + srslte::block_queue + pdu_queue; ///< currently only DCH PDUs supported (add BCH, PCH, etc) + + mac_metrics_t metrics[SRSLTE_MAX_CARRIERS] = {}; + + /// Tx buffer + srslte::mac_nr_sch_pdu tx_pdu; + srslte::unique_byte_buffer_t tx_buffer = nullptr; + srslte::unique_byte_buffer_t rlc_buffer = nullptr; + + srslte::task_multiqueue::queue_handler stack_task_dispatch_queue; +}; + +} // namespace srsue + +#endif // SRSUE_MAC_NR_H diff --git a/srsue/src/stack/mac/CMakeLists.txt b/srsue/src/stack/mac/CMakeLists.txt index eb2fca853..655abbf6a 100644 --- a/srsue/src/stack/mac/CMakeLists.txt +++ b/srsue/src/stack/mac/CMakeLists.txt @@ -19,4 +19,9 @@ # set(SOURCES demux.cc dl_harq.cc mac.cc mux.cc proc_bsr.cc proc_phr.cc proc_ra.cc proc_sr.cc ul_harq.cc) -add_library(srsue_mac STATIC ${SOURCES}) \ No newline at end of file +add_library(srsue_mac STATIC ${SOURCES}) + +if(ENABLE_5GNR) + set(SOURCES mac_nr.cc) + add_library(srsue_mac_nr STATIC ${SOURCES}) +endif() diff --git a/srsue/src/stack/mac/mac_nr.cc b/srsue/src/stack/mac/mac_nr.cc new file mode 100644 index 000000000..7972e0e37 --- /dev/null +++ b/srsue/src/stack/mac/mac_nr.cc @@ -0,0 +1,261 @@ +/* + * 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/. + * + */ + +#define Error(fmt, ...) log_h->error(fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) log_h->warning(fmt, ##__VA_ARGS__) +#define Info(fmt, ...) log_h->info(fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) log_h->debug(fmt, ##__VA_ARGS__) + +#include "srsue/hdr/stack/mac/mac_nr.h" + +using namespace asn1::rrc; + +namespace srsue { + +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() +{ + stop(); +} + +int mac_nr::init(const mac_nr_args_t& args_, + phy_interface_mac_nr* phy_, + rlc_interface_mac* rlc_, + srslte::timer_handler* timers_, + srslte::task_handler_interface* stack_) +{ + args = args_; + phy = phy_; + rlc = rlc_; + timers = timers_; + stack = stack_; + + // Create Stack task dispatch queue + stack_task_dispatch_queue = stack->make_task_queue(); + + // Set up pcap + if (args.pcap.enable) { + pcap.reset(new srslte::mac_nr_pcap()); + pcap->open(args.pcap.filename); + } + + started = true; + + return SRSLTE_SUCCESS; +} + +void mac_nr::stop() +{ + if (started) { + if (pcap != nullptr) { + pcap->close(); + } + + started = false; + } +} + +// Implement Section 5.9 +void mac_nr::reset() +{ + Info("Resetting MAC\n"); +} + +void mac_nr::run_tti(const uint32_t tti) +{ + log_h->step(tti); + + // Step all procedures + Debug("Running MAC tti=%d\n", tti); +} + +uint16_t mac_nr::get_ul_sched_rnti(uint32_t tti) +{ + return crnti; +} + +uint16_t mac_nr::get_dl_sched_rnti(uint32_t tti) +{ + return crnti; +} + +void mac_nr::bch_decoded_ok(uint32_t tti, srslte::unique_byte_buffer_t payload) +{ + // Send MIB to RLC + rlc->write_pdu_bcch_bch(std::move(payload)); + + if (pcap) { + // pcap->write_dl_bch(payload, len, true, tti); + } +} + +int mac_nr::sf_indication(const uint32_t tti) +{ + + return SRSLTE_SUCCESS; +} + +/** + * \brief Called from PHY after decoding a TB + * + * The TB can directly be used + * + * @param cc_idx + * @param grant structure + */ +void mac_nr::tb_decoded(const uint32_t cc_idx, mac_nr_grant_dl_t& grant) +{ + if (SRSLTE_RNTI_ISRAR(grant.rnti)) { + // TODO: deliver to RA procedure + } else if (grant.rnti == SRSLTE_PRNTI) { + // Send PCH payload to RLC + // rlc->write_pdu_pcch(pch_payload_buffer, grant.tb[0].tbs); + + if (pcap) { + // pcap->write_dl_pch(pch_payload_buffer, grant.tb[0].tbs, true, grant.tti); + } + } else { + for (uint32_t i = 0; i < SRSLTE_MAX_CODEWORDS; ++i) { + if (grant.tb[i] != nullptr) { + if (pcap) { + pcap->write_dl_crnti(grant.tb[i]->msg, grant.tb[i]->N_bytes, grant.rnti, true, grant.tti); + } + pdu_queue.push(std::move(grant.tb[i])); + + metrics[cc_idx].rx_pkts++; + } + } + + process_pdus(); + } +} + +void mac_nr::new_grant_ul(const uint32_t cc_idx, const mac_nr_grant_ul_t& grant) +{ + phy_interface_stack_nr::tx_request_t tx_request = {}; + + get_ul_data(grant, &tx_request); + + // send TX.request + phy->tx_request(tx_request); + + metrics[cc_idx].tx_pkts++; +} + +void mac_nr::get_ul_data(const mac_nr_grant_ul_t& grant, phy_interface_stack_nr::tx_request_t* tx_request) +{ + // Todo: delegate to mux class + tx_request->tb_len = grant.tbs; + + // initialize MAC PDU + tx_buffer->clear(); + tx_pdu.init_tx(tx_buffer.get(), grant.tbs, true); + + while (tx_pdu.get_remaing_len() >= MIN_RLC_PDU_LEN) { + // read RLC PDU + rlc_buffer->clear(); + int pdu_len = rlc->read_pdu(4, rlc_buffer->msg, tx_pdu.get_remaing_len() - 2); + + // Add SDU if RLC has something to tx + if (pdu_len > 0) { + rlc_buffer->N_bytes = pdu_len; + log_h->info_hex(rlc_buffer->msg, rlc_buffer->N_bytes, "Read %d B from RLC\n", rlc_buffer->N_bytes); + + // add to MAC PDU and pack + if (tx_pdu.add_sdu(4, rlc_buffer->msg, rlc_buffer->N_bytes) != SRSLTE_SUCCESS) { + log_h->error("Error packing MAC PDU\n"); + } + } + } + + // Pack PDU + tx_pdu.pack(); + + log_h->info_hex(tx_buffer->msg, tx_buffer->N_bytes, "Generated MAC PDU (%d B)\n", tx_buffer->N_bytes); + + tx_request->data = tx_buffer->msg; + tx_request->tb_len = tx_buffer->N_bytes; + + if (pcap) { + pcap->write_ul_crnti(tx_request->data, tx_request->tb_len, grant.rnti, grant.pid, grant.tti); + } +} + +void mac_nr::timer_expired(uint32_t timer_id) +{ + // not implemented +} + +void mac_nr::setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD) +{ + logical_channel_config_t config = {}; + config.lcid = lcid; + config.lcg = lcg; + config.priority = priority; + config.PBR = PBR_x_tti; + config.BSD = BSD; + config.bucket_size = config.PBR * config.BSD; + setup_lcid(config); +} + +void mac_nr::setup_lcid(const logical_channel_config_t& config) +{ + Info("Logical Channel Setup: LCID=%d, LCG=%d, priority=%d, PBR=%d, BSD=%dms, bucket_size=%d\n", + config.lcid, + config.lcg, + config.priority, + config.PBR, + config.BSD, + config.bucket_size); + // mux_unit.setup_lcid(config); + // bsr_procedure.setup_lcid(config.lcid, config.lcg, config.priority); +} + +void mac_nr::get_metrics(mac_metrics_t m[SRSLTE_MAX_CARRIERS]) {} + +/** + * Called from the main stack thread to process received PDUs + */ +void mac_nr::process_pdus() +{ + auto ret = stack_task_dispatch_queue.try_push([this]() { + while (started and not pdu_queue.empty()) { + srslte::unique_byte_buffer_t pdu = pdu_queue.wait_pop(); + // TODO: delegate to demux class + handle_pdu(std::move(pdu)); + } + }); +} + +void mac_nr::handle_pdu(srslte::unique_byte_buffer_t pdu) +{ + log_h->info_hex(pdu->msg, pdu->N_bytes, "Handling MAC PDU (%d B)\n", pdu->N_bytes); +} + +} // namespace srsue