diff --git a/lib/examples/pdsch_enodeb.c b/lib/examples/pdsch_enodeb.c index 0fcddf3ec..b0e57da37 100644 --- a/lib/examples/pdsch_enodeb.c +++ b/lib/examples/pdsch_enodeb.c @@ -371,8 +371,6 @@ static void base_init() exit(-1); } - srslte_pdsch_set_rnti(&pdsch, UE_CRNTI); - if (mbsfn_area_id > -1) { if (srslte_pmch_init(&pmch, cell.nof_prb, 1)) { ERROR("Error creating PMCH object"); diff --git a/lib/examples/pdsch_ue.c b/lib/examples/pdsch_ue.c index 44fc497d5..9a9c36405 100644 --- a/lib/examples/pdsch_ue.c +++ b/lib/examples/pdsch_ue.c @@ -633,9 +633,6 @@ int main(int argc, char** argv) pdsch_cfg.rnti = prog_args.rnti; - /* Configure downlink receiver for the SI-RNTI since will be the only one we'll use */ - srslte_ue_dl_set_rnti(&ue_dl, prog_args.rnti); - /* Configure MBSFN area id and non-MBSFN Region */ if (prog_args.mbsfn_area_id > -1) { srslte_ue_dl_set_mbsfn_area_id(&ue_dl, prog_args.mbsfn_area_id); diff --git a/lib/include/srslte/adt/circular_array.h b/lib/include/srslte/adt/circular_array.h index c47a3f23f..84f5178d7 100644 --- a/lib/include/srslte/adt/circular_array.h +++ b/lib/include/srslte/adt/circular_array.h @@ -23,6 +23,7 @@ #define SRSLTE_CIRCULAR_ARRAY_H #include +#include /** * diff --git a/lib/include/srslte/common/byte_buffer.h b/lib/include/srslte/common/byte_buffer.h index 45e7c460f..cb9873b23 100644 --- a/lib/include/srslte/common/byte_buffer.h +++ b/lib/include/srslte/common/byte_buffer.h @@ -141,7 +141,7 @@ public: } uint32_t get_headroom() { return msg - buffer; } // Returns the remaining space from what is reported to be the length of msg - uint32_t get_tailroom() { return (sizeof(buffer) - (msg - buffer) - N_bytes); } + uint32_t get_tailroom() const { return (sizeof(buffer) - (msg - buffer) - N_bytes); } std::chrono::microseconds get_latency_us() const { return md.tp.get_latency_us(); } std::chrono::high_resolution_clock::time_point get_timestamp() const { return md.tp.get_timestamp(); } @@ -156,6 +156,9 @@ public: N_bytes += size; } + // vector-like interface + void resize(size_t size) { N_bytes = size; } + size_t capacity() const { return get_tailroom(); } uint8_t* data() { return msg; } const uint8_t* data() const { return msg; } uint32_t size() const { return N_bytes; } diff --git a/lib/include/srslte/common/mac_pcap.h b/lib/include/srslte/common/mac_pcap.h index 2af747467..42a77e3d9 100644 --- a/lib/include/srslte/common/mac_pcap.h +++ b/lib/include/srslte/common/mac_pcap.h @@ -22,91 +22,26 @@ #ifndef SRSLTE_MAC_PCAP_H #define SRSLTE_MAC_PCAP_H -#include "srslte/common/block_queue.h" -#include "srslte/common/buffer_pool.h" #include "srslte/common/common.h" -#include "srslte/common/pcap.h" -#include "srslte/common/threads.h" -#include "srslte/srslog/srslog.h" -#include -#include -#include +#include "srslte/common/mac_pcap_base.h" +#include "srslte/srslte.h" namespace srslte { -class mac_pcap : srslte::thread +class mac_pcap : public mac_pcap_base { public: - mac_pcap(srslte_rat_t rat); + mac_pcap(); ~mac_pcap(); - void enable(bool enable); uint32_t open(std::string filename, uint32_t ue_id = 0); uint32_t close(); - void set_ue_id(uint16_t ue_id); - - // EUTRA - void - write_ul_crnti(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t crnti, uint32_t reTX, uint32_t tti, uint8_t cc_idx); - void write_dl_crnti(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t crnti, bool crc_ok, uint32_t tti, uint8_t cc_idx); - void write_dl_ranti(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t ranti, bool crc_ok, uint32_t tti, uint8_t cc_idx); - - // SI and BCH only for DL - void write_dl_sirnti(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti, uint8_t cc_idx); - void write_dl_bch(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti, uint8_t cc_idx); - void write_dl_pch(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti, uint8_t cc_idx); - void write_dl_mch(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti, uint8_t cc_idx); - - void write_ul_rrc_pdu(const uint8_t* input, const int32_t input_len); - - // Sidelink - void write_sl_crnti(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint32_t reTX, uint32_t tti, uint8_t cc_idx); - - // NR - void write_dl_crnti_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t crnti, uint8_t harqid, uint32_t tti); - void write_ul_crnti_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti); - void write_dl_ra_rnti_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti); - void write_dl_bch_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti); - void write_dl_pch_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti); - void write_dl_si_rnti_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti); - private: - srslog::basic_logger& logger; - bool running = false; - srslte_rat_t rat = srslte_rat_t::nulltype; - uint32_t dlt = 0; // The DLT used for the PCAP file - std::string filename; - FILE* pcap_file = nullptr; - uint32_t ue_id = 0; - void pack_and_queue(uint8_t* payload, - uint32_t payload_len, - uint32_t reTX, - bool crc_ok, - uint8_t cc_idx, - uint32_t tti, - uint16_t crnti_, - uint8_t direction, - uint8_t rnti_type); - void pack_and_queue_nr(uint8_t* payload, - uint32_t payload_len, - uint32_t tti, - uint16_t crnti, - uint8_t harqid, - uint8_t direction, - uint8_t rnti_type); + void write_pdu(srslte::mac_pcap_base::pcap_pdu_t& pdu); - typedef struct { - // Different PCAP context for both RATs - MAC_Context_Info_t context; - mac_nr_context_info_t context_nr; - unique_byte_buffer_t pdu; - } pcap_pdu_t; - block_queue queue; - std::mutex mutex; - - void write_pdu(pcap_pdu_t& pdu); - void run_thread() final; + FILE* pcap_file = nullptr; + uint32_t dlt = 0; // The DLT used for the PCAP file + std::string filename; }; - } // namespace srslte -#endif // SRSLTE_MAC_PCAP_H +#endif // SRSLTE_MAC_PCAP_H \ No newline at end of file diff --git a/lib/include/srslte/common/mac_pcap_base.h b/lib/include/srslte/common/mac_pcap_base.h new file mode 100644 index 000000000..67fd706b0 --- /dev/null +++ b/lib/include/srslte/common/mac_pcap_base.h @@ -0,0 +1,125 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2020 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 SRSLTE_MAC_PCAP_BASE_H +#define SRSLTE_MAC_PCAP_BASE_H + +#include "srslte/common/block_queue.h" +#include "srslte/common/buffer_pool.h" +#include "srslte/common/common.h" +#include "srslte/common/pcap.h" +#include "srslte/common/threads.h" +#include "srslte/srslog/srslog.h" +#include +#include +#include + +namespace srslte { +class mac_pcap_base : protected srslte::thread +{ +public: + mac_pcap_base(); + ~mac_pcap_base(); + void enable(bool enable); + virtual uint32_t close() = 0; + + void set_ue_id(uint16_t ue_id); + + // EUTRA + void + write_ul_crnti(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t crnti, uint32_t reTX, uint32_t tti, uint8_t cc_idx); + void write_dl_crnti(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t crnti, bool crc_ok, uint32_t tti, uint8_t cc_idx); + void write_dl_ranti(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t ranti, bool crc_ok, uint32_t tti, uint8_t cc_idx); + + void write_ul_crnti(uint8_t* pdu, + uint32_t pdu_len_bytes, + uint16_t crnti, + uint16_t ue_id, + uint32_t reTX, + uint32_t tti, + uint8_t cc_idx); + + void write_dl_crnti(uint8_t* pdu, + uint32_t pdu_len_bytes, + uint16_t crnti, + uint16_t ue_id, + bool crc_ok, + uint32_t tti, + uint8_t cc_idx); + + // SI and BCH only for DL + void write_dl_sirnti(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti, uint8_t cc_idx); + void write_dl_bch(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti, uint8_t cc_idx); + void write_dl_pch(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti, uint8_t cc_idx); + void write_dl_mch(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti, uint8_t cc_idx); + + void write_ul_rrc_pdu(const uint8_t* input, const int32_t input_len); + + // Sidelink + void write_sl_crnti(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint32_t reTX, uint32_t tti, uint8_t cc_idx); + + // NR + void write_dl_crnti_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t crnti, uint8_t harqid, uint32_t tti); + void write_ul_crnti_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti); + void write_dl_ra_rnti_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti); + void write_dl_bch_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti); + void write_dl_pch_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti); + void write_dl_si_rnti_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti); + + // NR for enb with different ue_id + // clang-format off + void write_dl_crnti_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t crnti, uint16_t ue_id, uint8_t harqid, uint32_t tti); + void write_ul_crnti_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint16_t ue_id, uint8_t harqid, uint32_t tti); + // clang-format on + +protected: + typedef struct { + // Different PCAP context for both RATs + srslte::srslte_rat_t rat; + MAC_Context_Info_t context; + mac_nr_context_info_t context_nr; + unique_byte_buffer_t pdu; + } pcap_pdu_t; + + virtual void write_pdu(pcap_pdu_t& pdu) = 0; + void run_thread() final; + + std::mutex mutex; + srslog::basic_logger& logger; + bool running = false; + block_queue queue; + uint16_t ue_id = 0; + +private: + void pack_and_queue(uint8_t* payload, + uint32_t payload_len, + uint16_t ue_id, + uint32_t reTX, + bool crc_ok, + uint8_t cc_idx, + uint32_t tti, + uint16_t crnti_, + uint8_t direction, + uint8_t rnti_type); + void pack_and_queue_nr(uint8_t* payload, + uint32_t payload_len, + uint32_t tti, + uint16_t crnti, + uint16_t ue_id, + uint8_t harqid, + uint8_t direction, + uint8_t rnti_type); +}; + +} // namespace srslte + +#endif // SRSLTE_MAC_PCAP_BASE_H diff --git a/lib/include/srslte/common/mac_pcap_net.h b/lib/include/srslte/common/mac_pcap_net.h new file mode 100644 index 000000000..a470d373c --- /dev/null +++ b/lib/include/srslte/common/mac_pcap_net.h @@ -0,0 +1,44 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2020 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 SRSLTE_MAC_PCAP_NET_H +#define SRSLTE_MAC_PCAP_NET_H + +#include "srslte/common/common.h" +#include "srslte/common/mac_pcap_base.h" +#include "srslte/common/network_utils.h" +#include "srslte/srslte.h" + +namespace srslte { +class mac_pcap_net : public mac_pcap_base +{ +public: + mac_pcap_net(); + ~mac_pcap_net(); + uint32_t open(std::string client_ip_addr_, + std::string bind_addr_str = "0.0.0.0", + uint16_t client_udp_port_ = 5847, + uint16_t bind_udp_port_ = 5687, + uint32_t ue_id_ = 0); + uint32_t close(); + +private: + void write_pdu(srslte::mac_pcap_base::pcap_pdu_t& pdu); + void write_mac_lte_pdu_to_net(srslte::mac_pcap_base::pcap_pdu_t& pdu); + void write_mac_nr_pdu_to_net(srslte::mac_pcap_base::pcap_pdu_t& pdu); + + srslte::socket_handler_t socket; + struct sockaddr_in client_addr; +}; +} // namespace srslte + +#endif // SRSLTE_MAC_PCAP_NET_H diff --git a/lib/include/srslte/common/nas_pcap.h b/lib/include/srslte/common/nas_pcap.h index e5194a565..7fe316ef7 100644 --- a/lib/include/srslte/common/nas_pcap.h +++ b/lib/include/srslte/common/nas_pcap.h @@ -23,6 +23,7 @@ #define SRSLTE_NAS_PCAP_H #include "srslte/common/pcap.h" +#include namespace srslte { @@ -36,15 +37,16 @@ public: pcap_file = NULL; } void enable(); - void open(const char* filename, uint32_t ue_id = 0); + uint32_t open(std::string filename_, uint32_t ue_id = 0); void close(); void write_nas(uint8_t* pdu, uint32_t pdu_len_bytes); private: - bool enable_write; - FILE* pcap_file; - uint32_t ue_id; - void pack_and_write(uint8_t* pdu, uint32_t pdu_len_bytes); + bool enable_write; + std::string filename; + FILE* pcap_file; + uint32_t ue_id; + void pack_and_write(uint8_t* pdu, uint32_t pdu_len_bytes); }; } // namespace srslte diff --git a/lib/include/srslte/common/pcap.h b/lib/include/srslte/common/pcap.h index 83771a25b..322a05677 100644 --- a/lib/include/srslte/common/pcap.h +++ b/lib/include/srslte/common/pcap.h @@ -26,6 +26,8 @@ #include #include +#define PCAP_CONTEXT_HEADER_MAX 256 + #define MAC_LTE_DLT 147 #define NAS_LTE_DLT 148 #define UDP_DLT 149 // UDP needs to be selected as protocol @@ -198,6 +200,8 @@ void LTE_PCAP_Close(FILE* fd); /* Write an individual MAC PDU (PCAP packet header + mac-context + mac-pdu) */ int LTE_PCAP_MAC_WritePDU(FILE* fd, MAC_Context_Info_t* context, const unsigned char* PDU, unsigned int length); +int LTE_PCAP_MAC_UDP_WritePDU(FILE* fd, MAC_Context_Info_t* context, const unsigned char* PDU, unsigned int length); +int LTE_PCAP_PACK_MAC_CONTEXT_TO_BUFFER(MAC_Context_Info_t* context, uint8_t* PDU, unsigned int length); /* Write an individual NAS PDU (PCAP packet header + nas-context + nas-pdu) */ int LTE_PCAP_NAS_WritePDU(FILE* fd, NAS_Context_Info_t* context, const unsigned char* PDU, unsigned int length); @@ -209,7 +213,8 @@ int LTE_PCAP_RLC_WritePDU(FILE* fd, RLC_Context_Info_t* context, const unsigned int LTE_PCAP_S1AP_WritePDU(FILE* fd, S1AP_Context_Info_t* context, const unsigned char* PDU, unsigned int length); /* Write an individual NR MAC PDU (PCAP packet header + UDP header + nr-mac-context + mac-pdu) */ -int NR_PCAP_MAC_WritePDU(FILE* fd, mac_nr_context_info_t* context, const unsigned char* PDU, unsigned int length); +int NR_PCAP_MAC_UDP_WritePDU(FILE* fd, mac_nr_context_info_t* context, const unsigned char* PDU, unsigned int length); +int NR_PCAP_PACK_MAC_CONTEXT_TO_BUFFER(mac_nr_context_info_t* context, uint8_t* buffer, unsigned int length); #ifdef __cplusplus } diff --git a/lib/include/srslte/common/task_scheduler.h b/lib/include/srslte/common/task_scheduler.h index 0e8a89652..b2fb04d51 100644 --- a/lib/include/srslte/common/task_scheduler.h +++ b/lib/include/srslte/common/task_scheduler.h @@ -32,26 +32,17 @@ namespace srslte { class task_scheduler { public: - explicit task_scheduler(uint32_t default_extern_tasks_size = 512, - uint32_t nof_background_threads = 0, - uint32_t nof_timers_prealloc = 100) : - external_tasks{default_extern_tasks_size}, - timers{nof_timers_prealloc}, - background_tasks{nof_background_threads} + 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_id = external_tasks.add_queue(); - - // Start background thread - if (background_tasks.nof_workers() > 0) { - background_tasks.start(); - } } + task_scheduler(const task_scheduler&) = delete; + task_scheduler(task_scheduler&&) = delete; + task_scheduler& operator=(const task_scheduler&) = delete; + task_scheduler& operator=(task_scheduler&&) = delete; - void stop() - { - background_tasks.stop(); - external_tasks.reset(); - } + void stop() { external_tasks.reset(); } srslte::unique_timer get_unique_timer() { return timers.get_unique_timer(); } @@ -65,17 +56,6 @@ public: //! Enqueues internal task to be run in next tic void defer_task(srslte::move_task_t func) { internal_tasks.push_back(std::move(func)); } - //! Delegates a task to a thread pool that runs in the background - void enqueue_background_task(std::function f) - { - if (background_tasks.nof_workers() > 0) { - background_tasks.push_task(std::move(f)); - } else { - external_tasks.push(background_queue_id, - std::bind([](const std::function& task) { task(0); }, std::move(f))); - } - } - //! Defer the handling of the result of a background task to next tic void notify_background_task_result(srslte::move_task_t task) { @@ -126,10 +106,9 @@ private: } } - srslte::task_thread_pool background_tasks; ///< Thread pool used for long, low-priority tasks - int background_queue_id = -1; ///< Queue for handling the outcomes of tasks run in the background - srslte::task_multiqueue external_tasks; - srslte::timer_handler timers; + int background_queue_id = -1; ///< Queue for handling the outcomes of tasks run in the background + srslte::task_multiqueue external_tasks; + srslte::timer_handler timers; std::deque internal_tasks; ///< enqueues stack tasks from within main thread. Avoids locking }; @@ -140,8 +119,7 @@ public: task_sched_handle(task_scheduler* sched_) : sched(sched_) {} srslte::unique_timer get_unique_timer() { return sched->get_unique_timer(); } - void enqueue_background_task(std::function f) { sched->enqueue_background_task(std::move(f)); } - void notify_background_task_result(srslte::move_task_t task) + void notify_background_task_result(srslte::move_task_t task) { sched->notify_background_task_result(std::move(task)); } @@ -162,8 +140,7 @@ public: ext_task_sched_handle(task_scheduler* sched_) : sched(sched_) {} srslte::unique_timer get_unique_timer() { return sched->get_unique_timer(); } - void enqueue_background_task(std::function f) { sched->enqueue_background_task(std::move(f)); } - void notify_background_task_result(srslte::move_task_t task) + void notify_background_task_result(srslte::move_task_t task) { sched->notify_background_task_result(std::move(task)); } diff --git a/lib/include/srslte/common/test_common.h b/lib/include/srslte/common/test_common.h index e2f5b8b44..ce4013e91 100644 --- a/lib/include/srslte/common/test_common.h +++ b/lib/include/srslte/common/test_common.h @@ -152,6 +152,51 @@ private: std::atomic warning_counter; }; +/// This custom sink intercepts log messages allowing users to check if a certain log entry has been generated. +/// Calling spy.has_message("something") will return true if any log entries generated so far contain the string +/// "something". +/// The log entries history can be cleared with reset so old entries can be discarded. +class log_sink_message_spy : public srslog::sink +{ +public: + explicit log_sink_message_spy(std::unique_ptr f) : + srslog::sink(std::move(f)), s(srslog::get_default_sink()) + {} + + /// Identifier of this custom sink. + static const char* name() { return "log_sink_message_spy"; } + + /// Discards all registered log entries. + void reset() + { + // Flush to make sure all entries have been processed by the backend. + srslog::flush(); + entries.clear(); + } + + /// Returns true if the string in msg is found in the registered log entries. + bool has_message(const std::string& msg) const + { + srslog::flush(); + return std::find_if(entries.cbegin(), entries.cend(), [&](const std::string& entry) { + return entry.find(msg) != std::string::npos; + }) != entries.cend(); + } + + srslog::detail::error_string write(srslog::detail::memory_buffer buffer) override + { + entries.emplace_back(buffer.data(), buffer.size()); + + return s.write(buffer); + } + + srslog::detail::error_string flush() override { return s.flush(); } + +private: + srslog::sink& s; + std::vector entries; +}; + // specialization of test_log_filter to store last logged message class nullsink_log : public test_log_filter { diff --git a/lib/include/srslte/common/thread_pool.h b/lib/include/srslte/common/thread_pool.h index ac31a0d4d..a108c00a2 100644 --- a/lib/include/srslte/common/thread_pool.h +++ b/lib/include/srslte/common/thread_pool.h @@ -29,6 +29,8 @@ #ifndef SRSLTE_THREAD_POOL_H #define SRSLTE_THREAD_POOL_H +#include "srslte/adt/move_callback.h" +#include "srslte/srslog/srslog.h" #include #include #include @@ -95,17 +97,22 @@ private: class task_thread_pool { - using task_t = std::function; + using task_t = srslte::move_callback; public: - explicit task_thread_pool(uint32_t nof_workers); + task_thread_pool(uint32_t nof_workers = 1, bool start_deferred = false, int32_t prio_ = -1, uint32_t mask_ = 255); + task_thread_pool(const task_thread_pool&) = delete; + task_thread_pool(task_thread_pool&&) = delete; + task_thread_pool& operator=(const task_thread_pool&) = delete; + task_thread_pool& operator=(task_thread_pool&&) = delete; ~task_thread_pool(); - void start(int32_t prio = -1, uint32_t mask = 255); - void stop(); - void push_task(const task_t& task); + void stop(); + void start(int32_t prio_ = -1, uint32_t mask_ = 255); + void set_nof_workers(uint32_t nof_workers); + void push_task(task_t&& task); - uint32_t nof_pending_tasks(); + uint32_t nof_pending_tasks() const; size_t nof_workers() const { return workers.size(); } private: @@ -114,7 +121,6 @@ private: public: explicit worker_t(task_thread_pool* parent_, uint32_t id); void stop(); - void setup(int32_t prio, uint32_t mask); bool is_running() const { return running; } uint32_t id() const { return id_; } @@ -128,13 +134,19 @@ private: bool running = false; }; - std::queue pending_tasks; - std::vector workers; - std::mutex queue_mutex; - std::condition_variable cv_empty; - bool running; + int32_t prio = -1; + uint32_t mask = 255; + srslog::basic_logger& logger; + + std::queue pending_tasks; + std::vector > workers; + mutable std::mutex queue_mutex; + std::condition_variable cv_empty; + bool running = false; }; +srslte::task_thread_pool& get_background_workers(); + } // namespace srslte #endif // SRSLTE_THREAD_POOL_H diff --git a/lib/include/srslte/common/timers.h b/lib/include/srslte/common/timers.h index 9dd7b67ea..e453c75fa 100644 --- a/lib/include/srslte/common/timers.h +++ b/lib/include/srslte/common/timers.h @@ -189,8 +189,6 @@ public: void stop() { impl()->stop(); } - void clear() { impl()->clear(); } - void release() { impl()->clear(); diff --git a/lib/include/srslte/interfaces/enb_metrics_interface.h b/lib/include/srslte/interfaces/enb_metrics_interface.h index 29e197954..1d36cb875 100644 --- a/lib/include/srslte/interfaces/enb_metrics_interface.h +++ b/lib/include/srslte/interfaces/enb_metrics_interface.h @@ -29,6 +29,7 @@ #include "srsenb/hdr/stack/rrc/rrc_metrics.h" #include "srsenb/hdr/stack/upper/common_enb.h" #include "srsenb/hdr/stack/upper/s1ap_metrics.h" +#include "srslte/system/sys_metrics.h" #include "srslte/common/metrics_hub.h" #include "srslte/radio/radio_metrics.h" #include "srslte/upper/pdcp_metrics.h" @@ -57,6 +58,7 @@ struct enb_metrics_t { srslte::rf_metrics_t rf; std::vector phy; stack_metrics_t stack; + srslte::sys_metrics_t sys; bool running; }; diff --git a/lib/include/srslte/interfaces/enb_phy_interfaces.h b/lib/include/srslte/interfaces/enb_phy_interfaces.h index 8f4bf54a2..06edbde3f 100644 --- a/lib/include/srslte/interfaces/enb_phy_interfaces.h +++ b/lib/include/srslte/interfaces/enb_phy_interfaces.h @@ -37,14 +37,6 @@ public: */ virtual void rem_rnti(uint16_t rnti) = 0; - /** - * Pregenerates the scrambling sequences for a given RNTI. - * WARNING: This function make take several ms to complete. - * - * @param rnti identifier of the user - */ - virtual int pregen_sequences(uint16_t rnti) = 0; - /** * * @param stop diff --git a/lib/include/srslte/interfaces/phy_interface_types.h b/lib/include/srslte/interfaces/phy_interface_types.h index 841a42305..e2907a042 100644 --- a/lib/include/srslte/interfaces/phy_interface_types.h +++ b/lib/include/srslte/interfaces/phy_interface_types.h @@ -22,7 +22,7 @@ #ifndef SRSLTE_PHY_INTERFACE_TYPES_H #define SRSLTE_PHY_INTERFACE_TYPES_H -#include "srslte/phy/phch/prach.h" +#include "srslte/srslte.h" /// Common types defined by the PHY layer. @@ -49,4 +49,31 @@ inline bool operator!=(const srslte_prach_cfg_t& a, const srslte_prach_cfg_t& b) return !(a == b); } +namespace srsue { + +struct phy_meas_nr_t { + float rsrp; + float rsrq; + float sinr; + float cfo_hz; + uint32_t arfcn_nr; + uint32_t pci_nr; +}; + +struct phy_meas_t { + float rsrp; + float rsrq; + float cfo_hz; + uint32_t earfcn; + uint32_t pci; +}; + +struct phy_cell_t { + uint32_t pci; + uint32_t earfcn; + float cfo_hz; +}; + +} // namespace srsue + #endif // SRSLTE_PHY_INTERFACE_TYPES_H diff --git a/lib/include/srslte/interfaces/rrc_interface_types.h b/lib/include/srslte/interfaces/rrc_interface_types.h index ab5ecadaf..3e446c636 100644 --- a/lib/include/srslte/interfaces/rrc_interface_types.h +++ b/lib/include/srslte/interfaces/rrc_interface_types.h @@ -22,8 +22,8 @@ #ifndef SRSLTE_RRC_INTERFACE_TYPES_H #define SRSLTE_RRC_INTERFACE_TYPES_H -#include "srslte/common/common.h" #include "srslte/common/bcd_helpers.h" +#include "srslte/common/common.h" #include "srslte/config.h" #include "srslte/srslte.h" #include diff --git a/lib/include/srslte/interfaces/rrc_nr_interface_types.h b/lib/include/srslte/interfaces/rrc_nr_interface_types.h index 23131e86b..7081f1ac9 100644 --- a/lib/include/srslte/interfaces/rrc_nr_interface_types.h +++ b/lib/include/srslte/interfaces/rrc_nr_interface_types.h @@ -39,6 +39,7 @@ struct phy_cfg_nr_t { srslte_prach_cfg_t prach = {}; srslte_ue_dl_nr_pdcch_cfg_t pdcch = {}; srslte_ue_dl_nr_harq_ack_cfg_t harq_ack = {}; + srslte_csi_hl_cfg_t csi = {}; phy_cfg_nr_t() { @@ -507,6 +508,13 @@ struct phy_cfg_nr_t { // nrofSymbols: 14 // startingSymbolIndex: 0 // timeDomainOCC: 2 + pucch.sr_resources[1].resource.format = SRSLTE_PUCCH_NR_FORMAT_1; + pucch.sr_resources[1].resource.starting_prb = 0; + pucch.sr_resources[1].resource.initial_cyclic_shift = 8; + pucch.sr_resources[1].resource.nof_symbols = 14; + pucch.sr_resources[1].resource.start_symbol_idx = 0; + pucch.sr_resources[1].resource.time_domain_occ = 2; + // Item 17 // PUCCH-Resource // pucch-ResourceId: 17 @@ -516,6 +524,13 @@ struct phy_cfg_nr_t { // nrofPRBs: 1 // nrofSymbols: 2 // startingSymbolIndex: 2 + srslte_pucch_nr_resource_t pucch_res_17 = {}; + pucch_res_17.starting_prb = 1; + pucch_res_17.format = SRSLTE_PUCCH_NR_FORMAT_2; + pucch_res_17.nof_prb = 1; + pucch_res_17.nof_symbols = 2; + pucch_res_17.start_symbol_idx = 2; + // format1: setup (1) // setup // format2: setup (1) @@ -529,6 +544,7 @@ struct phy_cfg_nr_t { } } } + pucch_res_17.max_code_rate = 2; // schedulingRequestResourceToAddModList: 1 item // Item 0 @@ -538,6 +554,10 @@ struct phy_cfg_nr_t { // periodicityAndOffset: sl40 (10) // sl40: 8 // resource: 16 + pucch.sr_resources[1].sr_id = 0; + pucch.sr_resources[1].period = 40; + pucch.sr_resources[1].offset = 8; + pucch.sr_resources[1].configured = true; // dl-DataToUL-ACK: 7 items // Item 0 @@ -562,6 +582,42 @@ struct phy_cfg_nr_t { harq_ack.dl_data_to_ul_ack[5] = 12; harq_ack.dl_data_to_ul_ack[6] = 11; harq_ack.nof_dl_data_to_ul_ack = 7; + + // csi-ReportConfigToAddModList: 1 item + // Item 0 + // CSI-ReportConfig + // reportConfigId: 0 + // resourcesForChannelMeasurement: 0 + // csi-IM-ResourcesForInterference: 1 + // reportConfigType: periodic (0) + // periodic + // reportSlotConfig: slots80 (7) + // slots80: 9 + // pucch-CSI-ResourceList: 1 item + // Item 0 + // PUCCH-CSI-Resource + // uplinkBandwidthPartId: 0 + // pucch-Resource: 17 + // reportQuantity: cri-RI-PMI-CQI (1) + // cri-RI-PMI-CQI: NULL + // reportFreqConfiguration + // cqi-FormatIndicator: widebandCQI (0) + // timeRestrictionForChannelMeasurements: notConfigured (1) + // timeRestrictionForInterferenceMeasurements: notConfigured (1) + // groupBasedBeamReporting: disabled (1) + // disabled + // cqi-Table: table2 (1) + // subbandSize: value1 (0) + csi.reports[0].type = SRSLTE_CSI_REPORT_TYPE_PERIODIC; + csi.reports[0].channel_meas_id = 0; + csi.reports[0].interf_meas_present = true; + csi.reports[0].interf_meas_id = 1; + csi.reports[0].periodic.period = 80; + csi.reports[0].periodic.offset = 9; + csi.reports[0].periodic.resource = pucch_res_17; + csi.reports[0].quantity = SRSLTE_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI; + csi.reports[0].freq_cfg = SRSLTE_CSI_REPORT_FREQ_WIDEBAND; + csi.reports[0].cqi_table = SRSLTE_CSI_CQI_TABLE_2; } }; } // namespace srslte diff --git a/lib/include/srslte/interfaces/sched_interface.h b/lib/include/srslte/interfaces/sched_interface.h index f0ec3cf3b..9e41e98a8 100644 --- a/lib/include/srslte/interfaces/sched_interface.h +++ b/lib/include/srslte/interfaces/sched_interface.h @@ -63,10 +63,10 @@ public: uint32_t min_nof_ctrl_symbols = 1; uint32_t max_nof_ctrl_symbols = 3; int max_aggr_level = 3; + bool pucch_mux_enabled = false; }; struct cell_cfg_t { - // Main cell configuration (used to calculate DCI locations in scheduler) srslte_cell_t cell; diff --git a/lib/include/srslte/interfaces/ue_gw_interfaces.h b/lib/include/srslte/interfaces/ue_gw_interfaces.h new file mode 100644 index 000000000..4fedb6c9d --- /dev/null +++ b/lib/include/srslte/interfaces/ue_gw_interfaces.h @@ -0,0 +1,67 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2020 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 SRSLTE_UE_GW_INTERFACES_H +#define SRSLTE_UE_GW_INTERFACES_H + +#include "srslte/asn1/liblte_mme.h" + +namespace srsue { + +class gw_interface_nas +{ +public: + virtual int setup_if_addr(uint32_t eps_bearer_id, + uint32_t lcid, + uint8_t pdn_type, + uint32_t ip_addr, + uint8_t* ipv6_if_id, + char* err_str) = 0; + virtual int apply_traffic_flow_template(const uint8_t& eps_bearer_id, + const uint8_t& lcid, + const LIBLTE_MME_TRAFFIC_FLOW_TEMPLATE_STRUCT* tft) = 0; + + typedef enum { + TEST_LOOP_INACTIVE = 0, + TEST_LOOP_MODE_A_ACTIVE, + TEST_LOOP_MODE_B_ACTIVE, + TEST_LOOP_MODE_C_ACTIVE + } test_loop_mode_state_t; + + /** + * Updates the test loop mode. The IP delay parameter is only valid for Mode B. + * @param mode + * @param ip_pdu_delay_ms The PDU delay in ms + */ + virtual void set_test_loop_mode(const test_loop_mode_state_t mode, const uint32_t ip_pdu_delay_ms = 0) = 0; +}; + +class gw_interface_rrc +{ +public: + virtual void add_mch_port(uint32_t lcid, uint32_t port) = 0; + virtual int update_lcid(uint32_t eps_bearer_id, uint32_t new_lcid) = 0; +}; + +class gw_interface_pdcp +{ +public: + virtual void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t pdu) = 0; + virtual void write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t pdu) = 0; +}; + +class gw_interface_stack : public gw_interface_nas, public gw_interface_rrc, public gw_interface_pdcp +{}; + +} // namespace srsue + +#endif // SRSLTE_UE_GW_INTERFACES_H diff --git a/lib/include/srslte/interfaces/ue_interfaces.h b/lib/include/srslte/interfaces/ue_interfaces.h index 5b2858172..35c507ba1 100644 --- a/lib/include/srslte/interfaces/ue_interfaces.h +++ b/lib/include/srslte/interfaces/ue_interfaces.h @@ -28,658 +28,11 @@ #ifndef SRSLTE_UE_INTERFACES_H #define SRSLTE_UE_INTERFACES_H -#include -#include - -#include "mac_interface_types.h" -#include "pdcp_interface_types.h" -#include "rlc_interface_types.h" -#include "rrc_interface_types.h" -#include "srslte/asn1/asn1_utils.h" -#include "srslte/asn1/liblte_mme.h" -#include "srslte/common/common.h" -#include "srslte/common/interfaces_common.h" -#include "srslte/common/security.h" -#include "srslte/common/stack_procedure.h" -#include "srslte/common/tti_point.h" -#include "srslte/phy/channel/channel.h" -#include "srslte/phy/rf/rf.h" -#include "srslte/upper/pdcp_entity_base.h" +#include "ue_mac_interfaces.h" +#include "ue_rrc_interfaces.h" namespace srsue { -typedef enum { AUTH_OK, AUTH_FAILED, AUTH_SYNCH_FAILURE } auth_result_t; - -// USIM interface for NAS -class usim_interface_nas -{ -public: - virtual std::string get_imsi_str() = 0; - virtual std::string get_imei_str() = 0; - virtual bool get_imsi_vec(uint8_t* imsi_, uint32_t n) = 0; - virtual bool get_imei_vec(uint8_t* imei_, uint32_t n) = 0; - virtual bool get_home_plmn_id(srslte::plmn_id_t* home_plmn_id) = 0; - virtual auth_result_t generate_authentication_response(uint8_t* rand, - uint8_t* autn_enb, - uint16_t mcc, - uint16_t mnc, - uint8_t* res, - int* res_len, - uint8_t* k_asme) = 0; - virtual void generate_nas_keys(uint8_t* k_asme, - uint8_t* k_nas_enc, - uint8_t* k_nas_int, - srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo, - srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo) = 0; -}; - -// USIM interface for RRC -class usim_interface_rrc -{ -public: - virtual void generate_as_keys(uint8_t* k_asme, uint32_t count_ul, srslte::as_security_config_t* sec_cfg) = 0; - virtual void generate_as_keys_ho(uint32_t pci, uint32_t earfcn, int ncc, srslte::as_security_config_t* sec_cfg) = 0; - virtual void store_keys_before_ho(const srslte::as_security_config_t& as_cfg) = 0; - virtual void restore_keys_from_failed_ho(srslte::as_security_config_t* as_cfg) = 0; -}; - -// GW interface for NAS -class gw_interface_nas -{ -public: - virtual int setup_if_addr(uint32_t eps_bearer_id, - uint32_t lcid, - uint8_t pdn_type, - uint32_t ip_addr, - uint8_t* ipv6_if_id, - char* err_str) = 0; - virtual int apply_traffic_flow_template(const uint8_t& eps_bearer_id, - const uint8_t& lcid, - const LIBLTE_MME_TRAFFIC_FLOW_TEMPLATE_STRUCT* tft) = 0; - - typedef enum { - TEST_LOOP_INACTIVE = 0, - TEST_LOOP_MODE_A_ACTIVE, - TEST_LOOP_MODE_B_ACTIVE, - TEST_LOOP_MODE_C_ACTIVE - } test_loop_mode_state_t; - - /** - * Updates the test loop mode. The IP delay parameter is only valid for Mode B. - * @param mode - * @param ip_pdu_delay_ms The PDU delay in ms - */ - virtual void set_test_loop_mode(const test_loop_mode_state_t mode, const uint32_t ip_pdu_delay_ms = 0) = 0; -}; - -// GW interface for RRC -class gw_interface_rrc -{ -public: - virtual void add_mch_port(uint32_t lcid, uint32_t port) = 0; - virtual int update_lcid(uint32_t eps_bearer_id, uint32_t new_lcid) = 0; -}; - -// GW interface for PDCP -class gw_interface_pdcp -{ -public: - virtual void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t pdu) = 0; - virtual void write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t pdu) = 0; -}; - -// RRC interface for MAC -class rrc_interface_mac_common -{ -public: - virtual void ra_problem() = 0; -}; - -class rrc_interface_mac : public rrc_interface_mac_common -{ -public: - virtual void ra_completed() = 0; - virtual void release_pucch_srs() = 0; -}; - -struct phy_cell_t { - uint32_t pci; - uint32_t earfcn; - float cfo_hz; -}; - -// Measurement object from phy -typedef struct { - float rsrp; - float rsrq; - float cfo_hz; - uint32_t earfcn; - uint32_t pci; -} phy_meas_t; - -typedef struct { - float rsrp; - float rsrq; - float sinr; - float cfo_hz; - uint32_t arfcn_nr; - uint32_t pci_nr; -} phy_meas_nr_t; - -// RRC interface for RRC NR -class rrc_eutra_interface_rrc_nr -{ -public: - virtual void new_cell_meas_nr(const std::vector& meas) = 0; - virtual void nr_rrc_con_reconfig_complete(bool status) = 0; -}; - -// RRC interface for PHY -class rrc_interface_phy_lte -{ -public: - virtual void in_sync() = 0; - virtual void out_of_sync() = 0; - virtual void new_cell_meas(const std::vector& meas) = 0; - - typedef struct { - enum { CELL_FOUND = 0, CELL_NOT_FOUND, ERROR } found; - enum { MORE_FREQS = 0, NO_MORE_FREQS } last_freq; - } cell_search_ret_t; - - virtual void cell_search_complete(cell_search_ret_t ret, phy_cell_t found_cell) = 0; - virtual void cell_select_complete(bool status) = 0; - virtual void set_config_complete(bool status) = 0; - virtual void set_scell_complete(bool status) = 0; -}; - -// RRC interface for NAS -class rrc_interface_nas -{ -public: - typedef struct { - srslte::plmn_id_t plmn_id; - uint16_t tac; - } found_plmn_t; - - const static int MAX_FOUND_PLMNS = 16; - - virtual ~rrc_interface_nas() = default; - virtual void write_sdu(srslte::unique_byte_buffer_t sdu) = 0; - virtual uint16_t get_mcc() = 0; - virtual uint16_t get_mnc() = 0; - virtual void enable_capabilities() = 0; - virtual bool plmn_search() = 0; - virtual void plmn_select(srslte::plmn_id_t plmn_id) = 0; - virtual bool connection_request(srslte::establishment_cause_t cause, - srslte::unique_byte_buffer_t dedicatedInfoNAS) = 0; - virtual void set_ue_identity(srslte::s_tmsi_t s_tmsi) = 0; - virtual bool is_connected() = 0; - virtual void paging_completed(bool outcome) = 0; - virtual std::string get_rb_name(uint32_t lcid) = 0; - virtual uint32_t get_lcid_for_eps_bearer(const uint32_t& eps_bearer_id) = 0; - virtual bool has_nr_dc() = 0; -}; - -// RRC interface for PDCP -class rrc_interface_pdcp -{ -public: - virtual void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t pdu) = 0; - virtual void write_pdu_bcch_bch(srslte::unique_byte_buffer_t pdu) = 0; - virtual void write_pdu_bcch_dlsch(srslte::unique_byte_buffer_t pdu) = 0; - virtual void write_pdu_pcch(srslte::unique_byte_buffer_t pdu) = 0; - virtual void write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t pdu) = 0; - virtual std::string get_rb_name(uint32_t lcid) = 0; -}; - -// RRC interface for RLC -class rrc_interface_rlc -{ -public: - virtual void max_retx_attempted() = 0; - virtual std::string get_rb_name(uint32_t lcid) = 0; - virtual void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t pdu) = 0; -}; - -// NAS interface for RRC -class nas_interface_rrc -{ -public: - virtual void left_rrc_connected() = 0; - virtual void set_barring(srslte::barring_t barring) = 0; - virtual bool paging(srslte::s_tmsi_t* ue_identity) = 0; - virtual bool is_registered() = 0; - virtual void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t pdu) = 0; - virtual uint32_t get_k_enb_count() = 0; - virtual bool get_k_asme(uint8_t* k_asme_, uint32_t n) = 0; - virtual uint32_t get_ipv4_addr() = 0; - virtual bool get_ipv6_addr(uint8_t* ipv6_addr) = 0; - virtual void - plmn_search_completed(const rrc_interface_nas::found_plmn_t found_plmns[rrc_interface_nas::MAX_FOUND_PLMNS], - int nof_plmns) = 0; - virtual bool connection_request_completed(bool outcome) = 0; -}; - -// PDCP interface for RRC -class pdcp_interface_rrc -{ -public: - virtual void reestablish() = 0; - virtual void reestablish(uint32_t lcid) = 0; - virtual void reset() = 0; - virtual void write_sdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu, int sn = -1) = 0; - virtual void add_bearer(uint32_t lcid, srslte::pdcp_config_t cnfg) = 0; - virtual void change_lcid(uint32_t old_lcid, uint32_t new_lcid) = 0; - virtual void config_security(uint32_t lcid, srslte::as_security_config_t sec_cfg) = 0; - virtual void config_security_all(srslte::as_security_config_t sec_cfg) = 0; - virtual void enable_integrity(uint32_t lcid, srslte::srslte_direction_t direction) = 0; - virtual void enable_encryption(uint32_t lcid, - srslte::srslte_direction_t direction = srslte::srslte_direction_t::DIRECTION_TXRX) = 0; - virtual void send_status_report() = 0; - virtual void send_status_report(uint32_t lcid) = 0; -}; -// RRC NR interface for RRC (LTE) -class rrc_nr_interface_rrc -{ -public: - virtual void get_eutra_nr_capabilities(srslte::byte_buffer_t* eutra_nr_caps) = 0; - virtual void get_nr_capabilities(srslte::byte_buffer_t* nr_cap) = 0; - virtual void phy_set_cells_to_meas(uint32_t carrier_freq_r15) = 0; - virtual void phy_meas_stop() = 0; - virtual bool rrc_reconfiguration(bool endc_release_and_add_r15, - bool nr_secondary_cell_group_cfg_r15_present, - asn1::dyn_octstring nr_secondary_cell_group_cfg_r15, - bool sk_counter_r15_present, - uint32_t sk_counter_r15, - bool nr_radio_bearer_cfg1_r15_present, - asn1::dyn_octstring nr_radio_bearer_cfg1_r15) = 0; - virtual bool is_config_pending() = 0; -}; - -class usim_interface_rrc_nr -{ -public: - virtual void generate_nr_context(uint16_t sk_counter, srslte::as_security_config_t* sec_cfg) = 0; - virtual void update_nr_context(srslte::as_security_config_t* sec_cfg) = 0; -}; - -// PDCP interface for RLC -class pdcp_interface_rlc -{ -public: - /* RLC calls PDCP to push a PDCP PDU. */ - virtual void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0; - virtual void write_pdu_bcch_bch(srslte::unique_byte_buffer_t sdu) = 0; - virtual void write_pdu_bcch_dlsch(srslte::unique_byte_buffer_t sdu) = 0; - virtual void write_pdu_pcch(srslte::unique_byte_buffer_t sdu) = 0; - virtual void write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0; - virtual void notify_delivery(uint32_t lcid, const std::vector& pdcp_sn) = 0; - virtual void notify_failure(uint32_t lcid, const std::vector& pdcp_sn) = 0; -}; - -class pdcp_interface_gw -{ -public: - virtual void write_sdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0; - virtual bool is_lcid_enabled(uint32_t lcid) = 0; -}; - -// RLC interface for RRC -class rlc_interface_rrc -{ -public: - virtual void reset() = 0; - virtual void reestablish() = 0; - virtual void reestablish(uint32_t lcid) = 0; - virtual void add_bearer(uint32_t lcid, const srslte::rlc_config_t& cnfg) = 0; - virtual void add_bearer_mrb(uint32_t lcid) = 0; - virtual void del_bearer(uint32_t lcid) = 0; - virtual void suspend_bearer(uint32_t lcid) = 0; - virtual void resume_bearer(uint32_t lcid) = 0; - virtual void change_lcid(uint32_t old_lcid, uint32_t new_lcid) = 0; - virtual bool has_bearer(uint32_t lcid) = 0; - virtual bool has_data(const uint32_t lcid) = 0; - virtual bool is_suspended(const uint32_t lcid) = 0; - virtual void write_sdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0; -}; - -// RLC interface for PDCP -class rlc_interface_pdcp -{ -public: - ///< PDCP calls RLC to push an RLC SDU. SDU gets placed into the buffer - ///< MAC pulls RLC PDUs according to TB size - virtual void write_sdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0; - - ///< Indicate RLC that a certain SN can be discarded - virtual void discard_sdu(uint32_t lcid, uint32_t discard_sn) = 0; - - ///< Helper to query RLC mode - virtual bool rb_is_um(uint32_t lcid) = 0; - - ///< Allow PDCP to query SDU queue status - virtual bool sdu_queue_is_full(uint32_t lcid) = 0; -}; - -// RLC interface for MAC -class rlc_interface_mac : public srslte::read_pdu_interface -{ -public: - /* MAC calls has_data() to query whether a logical channel has data to transmit (without - * knowing how much. This function should return quickly. */ - virtual bool has_data_locked(const uint32_t lcid) = 0; - - /* MAC calls RLC to get the buffer state for a logical channel. */ - virtual uint32_t get_buffer_state(const uint32_t lcid) = 0; - - const static int MAX_PDU_SEGMENTS = 20; - - /* 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; - - /* 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. */ - virtual void write_pdu(uint32_t lcid, uint8_t* payload, uint32_t nof_bytes) = 0; - virtual void write_pdu_bcch_bch(srslte::unique_byte_buffer_t payload) = 0; - virtual void write_pdu_bcch_dlsch(uint8_t* payload, uint32_t nof_bytes) = 0; - virtual void write_pdu_pcch(srslte::unique_byte_buffer_t payload) = 0; - virtual void write_pdu_mch(uint32_t lcid, uint8_t* payload, uint32_t nof_bytes) = 0; -}; - -/** MAC interface - * - */ -/* Interface PHY -> MAC */ -class mac_interface_phy_lte -{ -public: - typedef struct { - uint32_t nof_mbsfn_services; - } mac_phy_cfg_mbsfn_t; - - typedef struct { - uint32_t tbs; - bool ndi; - bool ndi_present; - int rv; - } mac_tb_t; - - typedef struct { - mac_tb_t tb[SRSLTE_MAX_TB]; - uint32_t pid; - uint16_t rnti; - bool is_sps_release; - uint32_t tti; - } mac_grant_dl_t; - - typedef struct { - mac_tb_t tb; - uint32_t pid; - uint16_t rnti; - bool phich_available; - bool hi_value; - bool is_rar; - uint32_t tti_tx; - } mac_grant_ul_t; - - typedef struct { - bool enabled; - uint32_t rv; - uint8_t* payload; - union { - srslte_softbuffer_rx_t* rx; - srslte_softbuffer_tx_t* tx; - } softbuffer; - } tb_action_t; - - typedef struct { - tb_action_t tb[SRSLTE_MAX_TB]; - - bool generate_ack; - } tb_action_dl_t; - - typedef struct { - tb_action_t tb; - uint32_t current_tx_nb; - bool expect_ack; - bool is_rar; - } tb_action_ul_t; - - /* Query the MAC for the current RNTI to look for - */ - virtual uint16_t get_dl_sched_rnti(uint32_t tti) = 0; - virtual uint16_t get_ul_sched_rnti(uint32_t tti) = 0; - - /* Indicate reception of UL dci. - * payload_ptr points to memory where MAC PDU must be written by MAC layer */ - virtual void new_grant_ul(uint32_t cc_idx, mac_grant_ul_t grant, tb_action_ul_t* action) = 0; - - /* Indicate reception of DL dci. */ - virtual void new_grant_dl(uint32_t cc_idx, mac_grant_dl_t grant, tb_action_dl_t* action) = 0; - - /* Indicate successful decoding of PDSCH AND PCH TB. */ - virtual void tb_decoded(uint32_t cc_idx, mac_grant_dl_t grant, bool ack[SRSLTE_MAX_CODEWORDS]) = 0; - - /* Indicate successful decoding of BCH TB through PBCH */ - virtual void bch_decoded_ok(uint32_t cc_idx, uint8_t* payload, uint32_t len) = 0; - - /* Indicate successful decoding of MCH TB through PMCH */ - virtual void mch_decoded(uint32_t len, bool crc) = 0; - - /* Obtain action for a new MCH subframe. */ - virtual void new_mch_dl(const srslte_pdsch_grant_t& phy_grant, tb_action_dl_t* action) = 0; - - /* Communicate the number of mbsfn services available */ - virtual void set_mbsfn_config(uint32_t nof_mbsfn_services) = 0; -}; - -/* Interface RRC -> MAC shared between different RATs */ -class mac_interface_rrc_common -{ -public: - // Class to handle UE specific RNTIs between RRC and MAC - typedef struct { - uint16_t crnti; - uint16_t rar_rnti; - uint16_t temp_rnti; - uint16_t tpc_rnti; - uint16_t sps_rnti; - uint64_t contention_id; - } ue_rnti_t; -}; - -/* Interface RRC -> MAC */ -class mac_interface_rrc : public mac_interface_rrc_common -{ -public: - /* Instructs the MAC to start receiving BCCH */ - virtual void bcch_start_rx(int si_window_start, int si_window_length) = 0; - virtual void bcch_stop_rx() = 0; - - /* Instructs the MAC to start receiving PCCH */ - virtual void pcch_start_rx() = 0; - - /* RRC configures a logical channel */ - virtual void setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD) = 0; - - /* Instructs the MAC to start receiving an MCH */ - virtual void mch_start_rx(uint32_t lcid) = 0; - - /* Set entire MAC config */ - virtual void set_config(srslte::mac_cfg_t& mac_cfg) = 0; - - /* Update SR config only for PUCCH release */ - virtual void set_config(srslte::sr_cfg_t& sr_cfg) = 0; - - virtual void set_rach_ded_cfg(uint32_t preamble_index, uint32_t prach_mask) = 0; - - virtual void get_rntis(ue_rnti_t* rntis) = 0; - virtual void set_contention_id(uint64_t uecri) = 0; - virtual void set_ho_rnti(uint16_t crnti, uint16_t target_pci) = 0; - - virtual void reconfiguration(const uint32_t& cc_idx, const bool& enable) = 0; - virtual void reset() = 0; -}; - -/** PHY interface - * - */ - -typedef struct { - std::string type = "lte"; - srslte::phy_log_args_t log; - - std::string dl_earfcn = "3400"; // comma-separated list of DL EARFCNs - std::string ul_earfcn = ""; // comma-separated list of UL EARFCNs - std::vector dl_earfcn_list = {3400}; // vectorized version of dl_earfcn that gets populated during init - std::map ul_earfcn_map; // Map linking DL EARFCN and UL EARFCN - - std::string dl_nr_arfcn = "632628"; // comma-separated list of DL NR ARFCNs - std::vector dl_nr_arfcn_list = { - 632628}; // vectorized version of dl_nr_arfcn that gets populated during init - - float dl_freq = -1.0f; - float ul_freq = -1.0f; - - bool ul_pwr_ctrl_en = false; - float prach_gain = -1; - uint32_t pdsch_max_its = 8; - bool meas_evm = false; - uint32_t nof_phy_threads = 3; - - int worker_cpu_mask = -1; - int sync_cpu_affinity = -1; - - uint32_t nof_lte_carriers = 1; - uint32_t nof_nr_carriers = 0; - uint32_t nr_nof_prb = 50; - double nr_freq_hz = 2630e6; - uint32_t nof_rx_ant = 1; - std::string equalizer_mode = "mmse"; - int cqi_max = 15; - int cqi_fixed = -1; - float snr_ema_coeff = 0.1f; - std::string snr_estim_alg = "refs"; - bool agc_enable = true; - bool correct_sync_error = false; - bool cfo_is_doppler = false; - bool cfo_integer_enabled = false; - float cfo_correct_tol_hz = 1.0f; - float cfo_pss_ema = DEFAULT_CFO_EMA_TRACK; - float cfo_loop_bw_pss = DEFAULT_CFO_BW_PSS; - float cfo_loop_bw_ref = DEFAULT_CFO_BW_REF; - float cfo_loop_ref_min = DEFAULT_CFO_REF_MIN; - float cfo_loop_pss_tol = DEFAULT_CFO_PSS_MIN; - float sfo_ema = DEFAULT_SFO_EMA_COEFF; - uint32_t sfo_correct_period = DEFAULT_SAMPLE_OFFSET_CORRECT_PERIOD; - uint32_t cfo_loop_pss_conv = DEFAULT_PSS_STABLE_TIMEOUT; - uint32_t cfo_ref_mask = 1023; - bool interpolate_subframe_enabled = false; - bool estimator_fil_auto = false; - float estimator_fil_stddev = 1.0f; - uint32_t estimator_fil_order = 4; - float snr_to_cqi_offset = 0.0f; - std::string sss_algorithm = "full"; - float rx_gain_offset = 62; - bool pdsch_csi_enabled = true; - bool pdsch_8bit_decoder = false; - uint32_t intra_freq_meas_len_ms = 20; - uint32_t intra_freq_meas_period_ms = 200; - float force_ul_amplitude = 0.0f; - - float in_sync_rsrp_dbm_th = -130.0f; - float in_sync_snr_db_th = 1.0f; - uint32_t nof_in_sync_events = 10; - uint32_t nof_out_of_sync_events = 20; - - srslte::channel::args_t dl_channel_args; - srslte::channel::args_t ul_channel_args; - - srslte::vnf_args_t vnf_args; -} phy_args_t; - -/* RAT agnostic Interface MAC -> PHY */ -class phy_interface_mac_common -{ -public: - /* Sets a C-RNTI allowing the PHY to pregenerate signals if necessary */ - virtual void set_crnti(uint16_t rnti) = 0; - - /* Time advance commands */ - virtual void set_timeadv_rar(uint32_t ta_cmd) = 0; - virtual void set_timeadv(uint32_t ta_cmd) = 0; - - /* Activate / Disactivate SCell*/ - virtual void set_activation_deactivation_scell(uint32_t cmd, uint32_t tti) = 0; - - /* Sets RAR dci payload */ - virtual void set_rar_grant(uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN], uint16_t rnti) = 0; - - virtual uint32_t get_current_tti() = 0; - - virtual float get_phr() = 0; - virtual float get_pathloss_db() = 0; -}; - -/* Interface MAC -> PHY */ -class phy_interface_mac_lte : public phy_interface_mac_common -{ -public: - typedef struct { - bool is_transmitted; - uint32_t tti_ra; - uint32_t f_id; - uint32_t preamble_format; - } prach_info_t; - - virtual void - prach_send(uint32_t preamble_idx, int allowed_subframe, float target_power_dbm, float ta_base_sec = 0.0f) = 0; - virtual prach_info_t prach_get_info() = 0; - - /* Indicates the transmission of a SR signal in the next opportunity */ - virtual void sr_send() = 0; - virtual int sr_last_tx_tti() = 0; - - virtual void set_mch_period_stop(uint32_t stop) = 0; -}; - -class phy_interface_rrc_lte -{ -public: - virtual bool set_config(srslte::phy_cfg_t config, uint32_t cc_idx = 0) = 0; - virtual bool set_scell(srslte_cell_t cell_info, uint32_t cc_idx, uint32_t earfcn) = 0; - virtual void set_config_tdd(srslte_tdd_config_t& tdd_config) = 0; - virtual void set_config_mbsfn_sib2(srslte::mbsfn_sf_cfg_t* cfg_list, uint32_t nof_cfgs) = 0; - virtual void set_config_mbsfn_sib13(const srslte::sib13_t& sib13) = 0; - virtual void set_config_mbsfn_mcch(const srslte::mcch_msg_t& mcch) = 0; - - virtual void deactivate_scells() = 0; - - /* Measurements interface */ - virtual void set_cells_to_meas(uint32_t earfcn, const std::set& pci) = 0; - virtual void meas_stop() = 0; - - /* Cell search and selection procedures */ - 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; -}; - -// STACK interface for GW -class stack_interface_gw : public pdcp_interface_gw -{ -public: - virtual bool is_registered() = 0; - virtual bool start_service_request() = 0; -}; - -class gw_interface_stack : public gw_interface_nas, public gw_interface_rrc, public gw_interface_pdcp -{}; - // STACK interface for RRC class stack_interface_rrc { @@ -695,10 +48,6 @@ public: virtual void run_tti(const uint32_t tti, const uint32_t tti_jump) = 0; }; -// Combined interface for stack (MAC and RRC) to access PHY -class phy_interface_stack_lte : public phy_interface_mac_lte, public phy_interface_rrc_lte -{}; - } // namespace srsue #endif // SRSLTE_UE_INTERFACES_H diff --git a/lib/include/srslte/interfaces/ue_mac_interfaces.h b/lib/include/srslte/interfaces/ue_mac_interfaces.h new file mode 100644 index 000000000..cc6e75fbe --- /dev/null +++ b/lib/include/srslte/interfaces/ue_mac_interfaces.h @@ -0,0 +1,151 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2020 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 SRSLTE_UE_MAC_INTERFACES_H +#define SRSLTE_UE_MAC_INTERFACES_H + +#include "mac_interface_types.h" + +namespace srsue { + +class mac_interface_phy_lte +{ +public: + typedef struct { + uint32_t nof_mbsfn_services; + } mac_phy_cfg_mbsfn_t; + + typedef struct { + uint32_t tbs; + bool ndi; + bool ndi_present; + int rv; + } mac_tb_t; + + typedef struct { + mac_tb_t tb[SRSLTE_MAX_TB]; + uint32_t pid; + uint16_t rnti; + bool is_sps_release; + uint32_t tti; + } mac_grant_dl_t; + + typedef struct { + mac_tb_t tb; + uint32_t pid; + uint16_t rnti; + bool phich_available; + bool hi_value; + bool is_rar; + uint32_t tti_tx; + } mac_grant_ul_t; + + typedef struct { + bool enabled; + uint32_t rv; + uint8_t* payload; + union { + srslte_softbuffer_rx_t* rx; + srslte_softbuffer_tx_t* tx; + } softbuffer; + } tb_action_t; + + typedef struct { + tb_action_t tb[SRSLTE_MAX_TB]; + + bool generate_ack; + } tb_action_dl_t; + + typedef struct { + tb_action_t tb; + uint32_t current_tx_nb; + bool expect_ack; + bool is_rar; + } tb_action_ul_t; + + /* Query the MAC for the current RNTI to look for + */ + virtual uint16_t get_dl_sched_rnti(uint32_t tti) = 0; + virtual uint16_t get_ul_sched_rnti(uint32_t tti) = 0; + + /* Indicate reception of UL dci. + * payload_ptr points to memory where MAC PDU must be written by MAC layer */ + virtual void new_grant_ul(uint32_t cc_idx, mac_grant_ul_t grant, tb_action_ul_t* action) = 0; + + /* Indicate reception of DL dci. */ + virtual void new_grant_dl(uint32_t cc_idx, mac_grant_dl_t grant, tb_action_dl_t* action) = 0; + + /* Indicate successful decoding of PDSCH AND PCH TB. */ + virtual void tb_decoded(uint32_t cc_idx, mac_grant_dl_t grant, bool ack[SRSLTE_MAX_CODEWORDS]) = 0; + + /* Indicate successful decoding of BCH TB through PBCH */ + virtual void bch_decoded_ok(uint32_t cc_idx, uint8_t* payload, uint32_t len) = 0; + + /* Indicate successful decoding of MCH TB through PMCH */ + virtual void mch_decoded(uint32_t len, bool crc) = 0; + + /* Obtain action for a new MCH subframe. */ + virtual void new_mch_dl(const srslte_pdsch_grant_t& phy_grant, tb_action_dl_t* action) = 0; + + /* Communicate the number of mbsfn services available */ + virtual void set_mbsfn_config(uint32_t nof_mbsfn_services) = 0; +}; + +class mac_interface_rrc_common +{ +public: + // Class to handle UE specific RNTIs between RRC and MAC + typedef struct { + uint16_t crnti; + uint16_t rar_rnti; + uint16_t temp_rnti; + uint16_t tpc_rnti; + uint16_t sps_rnti; + uint64_t contention_id; + } ue_rnti_t; +}; + +class mac_interface_rrc : public mac_interface_rrc_common +{ +public: + /* Instructs the MAC to start receiving BCCH */ + virtual void bcch_start_rx(int si_window_start, int si_window_length) = 0; + virtual void bcch_stop_rx() = 0; + + /* Instructs the MAC to start receiving PCCH */ + virtual void pcch_start_rx() = 0; + + /* RRC configures a logical channel */ + virtual void setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD) = 0; + + /* Instructs the MAC to start receiving an MCH */ + virtual void mch_start_rx(uint32_t lcid) = 0; + + /* Set entire MAC config */ + virtual void set_config(srslte::mac_cfg_t& mac_cfg) = 0; + + /* Update SR config only for PUCCH release */ + virtual void set_config(srslte::sr_cfg_t& sr_cfg) = 0; + + virtual void set_rach_ded_cfg(uint32_t preamble_index, uint32_t prach_mask) = 0; + + virtual void get_rntis(ue_rnti_t* rntis) = 0; + virtual void set_contention_id(uint64_t uecri) = 0; + virtual void set_ho_rnti(uint16_t crnti, uint16_t target_pci) = 0; + + virtual void reconfiguration(const uint32_t& cc_idx, const bool& enable) = 0; + virtual void reset() = 0; +}; + +} // namespace srsue + +#endif // SRSLTE_UE_MAC_INTERFACES_H diff --git a/lib/include/srslte/interfaces/ue_nas_interfaces.h b/lib/include/srslte/interfaces/ue_nas_interfaces.h new file mode 100644 index 000000000..b5f30c77c --- /dev/null +++ b/lib/include/srslte/interfaces/ue_nas_interfaces.h @@ -0,0 +1,44 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2020 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 SRSLTE_UE_NAS_INTERFACES_H +#define SRSLTE_UE_NAS_INTERFACES_H + +#include "srslte/interfaces/rrc_interface_types.h" + +namespace srsue { + +class nas_interface_rrc +{ +public: + const static int MAX_FOUND_PLMNS = 16; + struct found_plmn_t { + srslte::plmn_id_t plmn_id; + uint16_t tac; + }; + + virtual void left_rrc_connected() = 0; + virtual void set_barring(srslte::barring_t barring) = 0; + virtual bool paging(srslte::s_tmsi_t* ue_identity) = 0; + virtual bool is_registered() = 0; + virtual void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t pdu) = 0; + virtual uint32_t get_k_enb_count() = 0; + virtual bool get_k_asme(uint8_t* k_asme_, uint32_t n) = 0; + virtual uint32_t get_ipv4_addr() = 0; + virtual bool get_ipv6_addr(uint8_t* ipv6_addr) = 0; + virtual void plmn_search_completed(const found_plmn_t found_plmns[MAX_FOUND_PLMNS], int nof_plmns) = 0; + virtual bool connection_request_completed(bool outcome) = 0; +}; + +} // namespace srsue + +#endif // SRSLTE_UE_NAS_INTERFACES_H diff --git a/lib/include/srslte/interfaces/ue_nr_interfaces.h b/lib/include/srslte/interfaces/ue_nr_interfaces.h index 1c02179a9..4212dd9fb 100644 --- a/lib/include/srslte/interfaces/ue_nr_interfaces.h +++ b/lib/include/srslte/interfaces/ue_nr_interfaces.h @@ -26,6 +26,7 @@ #include "srslte/interfaces/mac_interface_types.h" #include "srslte/interfaces/rrc_nr_interface_types.h" #include +#include #include namespace srsue { @@ -55,6 +56,19 @@ public: uint32_t tbs; } mac_nr_grant_ul_t; + /// For UL, payload buffer remains in MAC + typedef struct { + bool enabled; + uint32_t rv; + srslte::byte_buffer_t* payload; + srslte_softbuffer_tx_t* softbuffer; + } tb_ul_t; + + /// Struct provided by MAC with all necessary information for PHY + typedef struct { + tb_ul_t tb; // only single TB in UL + } tb_action_ul_t; + virtual int sf_indication(const uint32_t tti) = 0; ///< FIXME: rename to slot indication // Query the MAC for the current RNTI to look for @@ -68,10 +82,16 @@ public: /// Indicate succussfully received TB to MAC. The TB buffer is allocated in the PHY and handed as unique_ptr to MAC virtual void tb_decoded(const uint32_t cc_idx, mac_nr_grant_dl_t& grant) = 0; - /// Indicate reception of UL grant (only TBS is provided). Buffer for resulting MAC PDU is provided by MAC and is - /// passed as pointer to PHY during tx_reuqest - virtual void - new_grant_ul(const uint32_t cc_idx, const mac_nr_grant_ul_t& grant, srslte::byte_buffer_t* phy_tx_pdu) = 0; + /** + * @brief Indicate reception of UL grant to MAC + * + * Buffer for resulting MAC PDU is provided and managed (owned) by MAC and is passed as pointer in ul_action + * + * @param cc_idx The carrier index on which the grant has been received + * @param grant Reference to the grant + * @param action Pointer to the TB action to be filled by MAC + */ + virtual void new_grant_ul(const uint32_t cc_idx, const mac_nr_grant_ul_t& grant, tb_action_ul_t* action) = 0; /** * @brief Indicate the successful transmission of a PRACH. @@ -110,6 +130,8 @@ struct phy_args_nr_t { srslte::phy_log_args_t log; srslte_ue_dl_nr_args_t dl; srslte_ue_ul_nr_args_t ul; + std::set fixed_sr = {1}; + uint32_t fix_wideband_cqi = 15; // Set to a non-zero value for fixing the wide-band CQI report phy_args_nr_t() { @@ -121,6 +143,8 @@ struct phy_args_nr_t { ul.nof_max_prb = 100; ul.pusch.measure_time = true; ul.pusch.sch.disable_simd = false; + + // fixed_sr.insert(0); // Enable SR_id = 0 by default for testing purposes } }; @@ -146,6 +170,9 @@ public: const int preamble_index, const float preamble_received_target_power, const float ta_base_sec = 0.0f) = 0; + + /// Instruct PHY to transmit SR for a given identifier + virtual void sr_send(uint32_t sr_id) = 0; }; class phy_interface_rrc_nr diff --git a/lib/include/srslte/interfaces/ue_pdcp_interfaces.h b/lib/include/srslte/interfaces/ue_pdcp_interfaces.h new file mode 100644 index 000000000..681902b54 --- /dev/null +++ b/lib/include/srslte/interfaces/ue_pdcp_interfaces.h @@ -0,0 +1,68 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2020 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 SRSLTE_UE_PDCP_INTERFACES_H +#define SRSLTE_UE_PDCP_INTERFACES_H + +#include "pdcp_interface_types.h" + +namespace srsue { + +class pdcp_interface_rrc +{ +public: + virtual void reestablish() = 0; + virtual void reestablish(uint32_t lcid) = 0; + virtual void reset() = 0; + virtual void write_sdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu, int sn = -1) = 0; + virtual void add_bearer(uint32_t lcid, srslte::pdcp_config_t cnfg) = 0; + virtual void change_lcid(uint32_t old_lcid, uint32_t new_lcid) = 0; + virtual void config_security(uint32_t lcid, srslte::as_security_config_t sec_cfg) = 0; + virtual void config_security_all(srslte::as_security_config_t sec_cfg) = 0; + virtual void enable_integrity(uint32_t lcid, srslte::srslte_direction_t direction) = 0; + virtual void enable_encryption(uint32_t lcid, + srslte::srslte_direction_t direction = srslte::srslte_direction_t::DIRECTION_TXRX) = 0; + virtual void send_status_report() = 0; + virtual void send_status_report(uint32_t lcid) = 0; +}; + +class pdcp_interface_rlc +{ +public: + /* RLC calls PDCP to push a PDCP PDU. */ + virtual void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0; + virtual void write_pdu_bcch_bch(srslte::unique_byte_buffer_t sdu) = 0; + virtual void write_pdu_bcch_dlsch(srslte::unique_byte_buffer_t sdu) = 0; + virtual void write_pdu_pcch(srslte::unique_byte_buffer_t sdu) = 0; + virtual void write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0; + virtual void notify_delivery(uint32_t lcid, const std::vector& pdcp_sn) = 0; + virtual void notify_failure(uint32_t lcid, const std::vector& pdcp_sn) = 0; +}; + +class pdcp_interface_gw +{ +public: + virtual void write_sdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0; + virtual bool is_lcid_enabled(uint32_t lcid) = 0; +}; + +// STACK interface for GW +class stack_interface_gw : public pdcp_interface_gw +{ +public: + virtual bool is_registered() = 0; + virtual bool start_service_request() = 0; +}; + +} // namespace srsue + +#endif // SRSLTE_UE_PDCP_INTERFACES_H diff --git a/lib/include/srslte/interfaces/ue_phy_interfaces.h b/lib/include/srslte/interfaces/ue_phy_interfaces.h new file mode 100644 index 000000000..5faa63be0 --- /dev/null +++ b/lib/include/srslte/interfaces/ue_phy_interfaces.h @@ -0,0 +1,174 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2020 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 SRSLTE_UE_PHY_INTERFACES_H +#define SRSLTE_UE_PHY_INTERFACES_H + +#include "srslte/srslte.h" + +#include "phy_interface_types.h" +#include "rrc_interface_types.h" +#include "srslte/common/interfaces_common.h" +#include "srslte/phy/channel/channel.h" + +#include +#include +#include + +namespace srsue { + +struct phy_args_t { + std::string type = "lte"; + srslte::phy_log_args_t log; + + std::string dl_earfcn = "3400"; // comma-separated list of DL EARFCNs + std::string ul_earfcn = ""; // comma-separated list of UL EARFCNs + std::vector dl_earfcn_list = {3400}; // vectorized version of dl_earfcn that gets populated during init + std::map ul_earfcn_map; // Map linking DL EARFCN and UL EARFCN + + std::string dl_nr_arfcn = "632628"; // comma-separated list of DL NR ARFCNs + std::vector dl_nr_arfcn_list = { + 632628}; // vectorized version of dl_nr_arfcn that gets populated during init + + float dl_freq = -1.0f; + float ul_freq = -1.0f; + + bool ul_pwr_ctrl_en = false; + float prach_gain = -1; + uint32_t pdsch_max_its = 8; + bool meas_evm = false; + uint32_t nof_phy_threads = 3; + + int worker_cpu_mask = -1; + int sync_cpu_affinity = -1; + + uint32_t nof_lte_carriers = 1; + uint32_t nof_nr_carriers = 0; + uint32_t nr_nof_prb = 50; + double nr_freq_hz = 2630e6; + uint32_t nof_rx_ant = 1; + std::string equalizer_mode = "mmse"; + int cqi_max = 15; + int cqi_fixed = -1; + float snr_ema_coeff = 0.1f; + std::string snr_estim_alg = "refs"; + bool agc_enable = true; + bool correct_sync_error = false; + bool cfo_is_doppler = false; + bool cfo_integer_enabled = false; + float cfo_correct_tol_hz = 1.0f; + float cfo_pss_ema = DEFAULT_CFO_EMA_TRACK; + float cfo_loop_bw_pss = DEFAULT_CFO_BW_PSS; + float cfo_loop_bw_ref = DEFAULT_CFO_BW_REF; + float cfo_loop_ref_min = DEFAULT_CFO_REF_MIN; + float cfo_loop_pss_tol = DEFAULT_CFO_PSS_MIN; + float sfo_ema = DEFAULT_SFO_EMA_COEFF; + uint32_t sfo_correct_period = DEFAULT_SAMPLE_OFFSET_CORRECT_PERIOD; + uint32_t cfo_loop_pss_conv = DEFAULT_PSS_STABLE_TIMEOUT; + uint32_t cfo_ref_mask = 1023; + bool interpolate_subframe_enabled = false; + bool estimator_fil_auto = false; + float estimator_fil_stddev = 1.0f; + uint32_t estimator_fil_order = 4; + float snr_to_cqi_offset = 0.0f; + std::string sss_algorithm = "full"; + float rx_gain_offset = 62; + bool pdsch_csi_enabled = true; + bool pdsch_8bit_decoder = false; + uint32_t intra_freq_meas_len_ms = 20; + uint32_t intra_freq_meas_period_ms = 200; + float force_ul_amplitude = 0.0f; + + float in_sync_rsrp_dbm_th = -130.0f; + float in_sync_snr_db_th = 1.0f; + uint32_t nof_in_sync_events = 10; + uint32_t nof_out_of_sync_events = 20; + + srslte::channel::args_t dl_channel_args; + srslte::channel::args_t ul_channel_args; + + srslte::vnf_args_t vnf_args; +}; + +/* RAT agnostic Interface MAC -> PHY */ +class phy_interface_mac_common +{ +public: + /* Time advance commands */ + virtual void set_timeadv_rar(uint32_t ta_cmd) = 0; + virtual void set_timeadv(uint32_t ta_cmd) = 0; + + /* Activate / Disactivate SCell*/ + virtual void set_activation_deactivation_scell(uint32_t cmd, uint32_t tti) = 0; + + /* Sets RAR dci payload */ + virtual void set_rar_grant(uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN], uint16_t rnti) = 0; + + virtual uint32_t get_current_tti() = 0; + + virtual float get_phr() = 0; + virtual float get_pathloss_db() = 0; +}; + +/* Interface MAC -> PHY */ +class phy_interface_mac_lte : public phy_interface_mac_common +{ +public: + typedef struct { + bool is_transmitted; + uint32_t tti_ra; + uint32_t f_id; + uint32_t preamble_format; + } prach_info_t; + + virtual void + prach_send(uint32_t preamble_idx, int allowed_subframe, float target_power_dbm, float ta_base_sec = 0.0f) = 0; + virtual prach_info_t prach_get_info() = 0; + + /* Indicates the transmission of a SR signal in the next opportunity */ + virtual void sr_send() = 0; + virtual int sr_last_tx_tti() = 0; + + virtual void set_mch_period_stop(uint32_t stop) = 0; +}; + +class phy_interface_rrc_lte +{ +public: + virtual bool set_config(srslte::phy_cfg_t config, uint32_t cc_idx = 0) = 0; + virtual bool set_scell(srslte_cell_t cell_info, uint32_t cc_idx, uint32_t earfcn) = 0; + virtual void set_config_tdd(srslte_tdd_config_t& tdd_config) = 0; + virtual void set_config_mbsfn_sib2(srslte::mbsfn_sf_cfg_t* cfg_list, uint32_t nof_cfgs) = 0; + virtual void set_config_mbsfn_sib13(const srslte::sib13_t& sib13) = 0; + virtual void set_config_mbsfn_mcch(const srslte::mcch_msg_t& mcch) = 0; + + virtual void deactivate_scells() = 0; + + /* Measurements interface */ + virtual void set_cells_to_meas(uint32_t earfcn, const std::set& pci) = 0; + virtual void meas_stop() = 0; + + /* Cell search and selection procedures */ + 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 +class phy_interface_stack_lte : public phy_interface_mac_lte, public phy_interface_rrc_lte +{}; + +} // namespace srsue + +#endif // SRSLTE_UE_PHY_INTERFACES_H diff --git a/lib/include/srslte/interfaces/ue_rlc_interfaces.h b/lib/include/srslte/interfaces/ue_rlc_interfaces.h new file mode 100644 index 000000000..004120eac --- /dev/null +++ b/lib/include/srslte/interfaces/ue_rlc_interfaces.h @@ -0,0 +1,83 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2020 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 SRSLTE_UE_RLC_INTERFACES_H +#define SRSLTE_UE_RLC_INTERFACES_H + +#include "srslte/common/interfaces_common.h" +#include "srslte/interfaces/rlc_interface_types.h" + +namespace srsue { + +class rlc_interface_rrc +{ +public: + virtual void reset() = 0; + virtual void reestablish() = 0; + virtual void reestablish(uint32_t lcid) = 0; + virtual void add_bearer(uint32_t lcid, const srslte::rlc_config_t& cnfg) = 0; + virtual void add_bearer_mrb(uint32_t lcid) = 0; + virtual void del_bearer(uint32_t lcid) = 0; + virtual void suspend_bearer(uint32_t lcid) = 0; + virtual void resume_bearer(uint32_t lcid) = 0; + virtual void change_lcid(uint32_t old_lcid, uint32_t new_lcid) = 0; + virtual bool has_bearer(uint32_t lcid) = 0; + virtual bool has_data(const uint32_t lcid) = 0; + virtual bool is_suspended(const uint32_t lcid) = 0; + virtual void write_sdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0; +}; + +class rlc_interface_pdcp +{ +public: + ///< PDCP calls RLC to push an RLC SDU. SDU gets placed into the buffer + ///< MAC pulls RLC PDUs according to TB size + virtual void write_sdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0; + + ///< Indicate RLC that a certain SN can be discarded + virtual void discard_sdu(uint32_t lcid, uint32_t discard_sn) = 0; + + ///< Helper to query RLC mode + virtual bool rb_is_um(uint32_t lcid) = 0; + + ///< Allow PDCP to query SDU queue status + virtual bool sdu_queue_is_full(uint32_t lcid) = 0; +}; + +class rlc_interface_mac : public srslte::read_pdu_interface +{ +public: + /* MAC calls has_data() to query whether a logical channel has data to transmit (without + * knowing how much. This function should return quickly. */ + virtual bool has_data_locked(const uint32_t lcid) = 0; + + /* MAC calls RLC to get the buffer state for a logical channel. */ + virtual uint32_t get_buffer_state(const uint32_t lcid) = 0; + + const static int MAX_PDU_SEGMENTS = 20; + + /* 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; + + /* 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. */ + virtual void write_pdu(uint32_t lcid, uint8_t* payload, uint32_t nof_bytes) = 0; + virtual void write_pdu_bcch_bch(srslte::unique_byte_buffer_t payload) = 0; + virtual void write_pdu_bcch_dlsch(uint8_t* payload, uint32_t nof_bytes) = 0; + virtual void write_pdu_pcch(srslte::unique_byte_buffer_t payload) = 0; + virtual void write_pdu_mch(uint32_t lcid, uint8_t* payload, uint32_t nof_bytes) = 0; +}; + +} // namespace srsue + +#endif // SRSLTE_UE_RLC_INTERFACES_H diff --git a/lib/include/srslte/interfaces/ue_rrc_interfaces.h b/lib/include/srslte/interfaces/ue_rrc_interfaces.h new file mode 100644 index 000000000..f76525f3d --- /dev/null +++ b/lib/include/srslte/interfaces/ue_rrc_interfaces.h @@ -0,0 +1,120 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2020 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 SRSLTE_UE_RRC_INTERFACES_H +#define SRSLTE_UE_RRC_INTERFACES_H + +#include "phy_interface_types.h" +#include "rrc_interface_types.h" +#include "srslte/asn1/asn1_utils.h" +#include "srslte/common/byte_buffer.h" +#include "srslte/common/tti_point.h" + +namespace srsue { + +class rrc_interface_mac_common +{ +public: + virtual void ra_problem() = 0; +}; + +class rrc_interface_mac : public rrc_interface_mac_common +{ +public: + virtual void ra_completed() = 0; + virtual void release_pucch_srs() = 0; +}; + +class rrc_eutra_interface_rrc_nr +{ +public: + virtual void new_cell_meas_nr(const std::vector& meas) = 0; + virtual void nr_rrc_con_reconfig_complete(bool status) = 0; +}; + +class rrc_interface_phy_lte +{ +public: + virtual void in_sync() = 0; + virtual void out_of_sync() = 0; + virtual void new_cell_meas(const std::vector& meas) = 0; + + typedef struct { + enum { CELL_FOUND = 0, CELL_NOT_FOUND, ERROR } found; + enum { MORE_FREQS = 0, NO_MORE_FREQS } last_freq; + } cell_search_ret_t; + + virtual void cell_search_complete(cell_search_ret_t ret, phy_cell_t found_cell) = 0; + virtual void cell_select_complete(bool status) = 0; + virtual void set_config_complete(bool status) = 0; + virtual void set_scell_complete(bool status) = 0; +}; + +class rrc_interface_nas +{ +public: + virtual ~rrc_interface_nas() = default; + virtual void write_sdu(srslte::unique_byte_buffer_t sdu) = 0; + virtual uint16_t get_mcc() = 0; + virtual uint16_t get_mnc() = 0; + virtual void enable_capabilities() = 0; + virtual bool plmn_search() = 0; + virtual void plmn_select(srslte::plmn_id_t plmn_id) = 0; + virtual bool connection_request(srslte::establishment_cause_t cause, + srslte::unique_byte_buffer_t dedicatedInfoNAS) = 0; + virtual void set_ue_identity(srslte::s_tmsi_t s_tmsi) = 0; + virtual bool is_connected() = 0; + virtual void paging_completed(bool outcome) = 0; + virtual std::string get_rb_name(uint32_t lcid) = 0; + virtual uint32_t get_lcid_for_eps_bearer(const uint32_t& eps_bearer_id) = 0; + virtual bool has_nr_dc() = 0; +}; + +class rrc_interface_pdcp +{ +public: + virtual void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t pdu) = 0; + virtual void write_pdu_bcch_bch(srslte::unique_byte_buffer_t pdu) = 0; + virtual void write_pdu_bcch_dlsch(srslte::unique_byte_buffer_t pdu) = 0; + virtual void write_pdu_pcch(srslte::unique_byte_buffer_t pdu) = 0; + virtual void write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t pdu) = 0; + virtual std::string get_rb_name(uint32_t lcid) = 0; +}; + +class rrc_interface_rlc +{ +public: + virtual void max_retx_attempted() = 0; + virtual std::string get_rb_name(uint32_t lcid) = 0; + virtual void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t pdu) = 0; +}; + +class rrc_nr_interface_rrc +{ +public: + virtual void get_eutra_nr_capabilities(srslte::byte_buffer_t* eutra_nr_caps) = 0; + virtual void get_nr_capabilities(srslte::byte_buffer_t* nr_cap) = 0; + virtual void phy_set_cells_to_meas(uint32_t carrier_freq_r15) = 0; + virtual void phy_meas_stop() = 0; + virtual bool rrc_reconfiguration(bool endc_release_and_add_r15, + bool nr_secondary_cell_group_cfg_r15_present, + asn1::dyn_octstring nr_secondary_cell_group_cfg_r15, + bool sk_counter_r15_present, + uint32_t sk_counter_r15, + bool nr_radio_bearer_cfg1_r15_present, + asn1::dyn_octstring nr_radio_bearer_cfg1_r15) = 0; + virtual bool is_config_pending() = 0; +}; + +} // namespace srsue + +#endif // SRSLTE_UE_RRC_INTERFACES_H diff --git a/lib/include/srslte/interfaces/ue_usim_interfaces.h b/lib/include/srslte/interfaces/ue_usim_interfaces.h new file mode 100644 index 000000000..ecb0a4a84 --- /dev/null +++ b/lib/include/srslte/interfaces/ue_usim_interfaces.h @@ -0,0 +1,65 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2020 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 SRSLTE_UE_USIM_INTERFACES_H +#define SRSLTE_UE_USIM_INTERFACES_H + +#include "rrc_interface_types.h" +#include + +namespace srsue { + +enum auth_result_t { AUTH_OK, AUTH_FAILED, AUTH_SYNCH_FAILURE }; + +// USIM interface for NAS +class usim_interface_nas +{ +public: + virtual std::string get_imsi_str() = 0; + virtual std::string get_imei_str() = 0; + virtual bool get_imsi_vec(uint8_t* imsi_, uint32_t n) = 0; + virtual bool get_imei_vec(uint8_t* imei_, uint32_t n) = 0; + virtual bool get_home_plmn_id(srslte::plmn_id_t* home_plmn_id) = 0; + virtual auth_result_t generate_authentication_response(uint8_t* rand, + uint8_t* autn_enb, + uint16_t mcc, + uint16_t mnc, + uint8_t* res, + int* res_len, + uint8_t* k_asme) = 0; + virtual void generate_nas_keys(uint8_t* k_asme, + uint8_t* k_nas_enc, + uint8_t* k_nas_int, + srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo, + srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo) = 0; +}; + +// USIM interface for RRC +class usim_interface_rrc +{ +public: + virtual void generate_as_keys(uint8_t* k_asme, uint32_t count_ul, srslte::as_security_config_t* sec_cfg) = 0; + virtual void generate_as_keys_ho(uint32_t pci, uint32_t earfcn, int ncc, srslte::as_security_config_t* sec_cfg) = 0; + virtual void store_keys_before_ho(const srslte::as_security_config_t& as_cfg) = 0; + virtual void restore_keys_from_failed_ho(srslte::as_security_config_t* as_cfg) = 0; +}; + +class usim_interface_rrc_nr +{ +public: + virtual void generate_nr_context(uint16_t sk_counter, srslte::as_security_config_t* sec_cfg) = 0; + virtual void update_nr_context(srslte::as_security_config_t* sec_cfg) = 0; +}; + +} // namespace srsue + +#endif // SRSLTE_UE_USIM_INTERFACES_H diff --git a/lib/include/srslte/phy/common/sequence.h b/lib/include/srslte/phy/common/sequence.h index eada05c3c..870a8f624 100644 --- a/lib/include/srslte/phy/common/sequence.h +++ b/lib/include/srslte/phy/common/sequence.h @@ -71,9 +71,9 @@ SRSLTE_API void srslte_sequence_apply_s(const int16_t* in, int16_t* out, uint32_ SRSLTE_API void srslte_sequence_apply_c(const int8_t* in, int8_t* out, uint32_t length, uint32_t seed); -SRSLTE_API void srslte_sequence_apply_bit(const uint8_t* in, uint8_t* out, uint32_t length, uint32_t seed); +SRSLTE_API void srslte_sequence_apply_packed(const uint8_t* in, uint8_t* out, uint32_t length, uint32_t seed); -SRSLTE_API void srslte_sequence_apply_bit_packed(const uint8_t* in, uint8_t* out, uint32_t length, uint32_t seed); +SRSLTE_API void srslte_sequence_apply_bit(const uint8_t* in, uint8_t* out, uint32_t length, uint32_t seed); SRSLTE_API int srslte_sequence_pbch(srslte_sequence_t* seq, srslte_cp_t cp, uint32_t cell_id); @@ -86,9 +86,65 @@ SRSLTE_API int srslte_sequence_pdcch(srslte_sequence_t* seq, uint32_t nslot, uin SRSLTE_API int srslte_sequence_pdsch(srslte_sequence_t* seq, uint16_t rnti, int q, uint32_t nslot, uint32_t cell_id, uint32_t len); +SRSLTE_API void srslte_sequence_pdsch_apply_pack(const uint8_t* in, + uint8_t* out, + uint16_t rnti, + int q, + uint32_t nslot, + uint32_t cell_id, + uint32_t len); + +SRSLTE_API void srslte_sequence_pdsch_apply_f(const float* in, + float* out, + uint16_t rnti, + int q, + uint32_t nslot, + uint32_t cell_id, + uint32_t len); + +SRSLTE_API void srslte_sequence_pdsch_apply_s(const int16_t* in, + int16_t* out, + uint16_t rnti, + int q, + uint32_t nslot, + uint32_t cell_id, + uint32_t len); + +SRSLTE_API void srslte_sequence_pdsch_apply_c(const int8_t* in, + int8_t* out, + uint16_t rnti, + int q, + uint32_t nslot, + uint32_t cell_id, + uint32_t len); + SRSLTE_API int srslte_sequence_pusch(srslte_sequence_t* seq, uint16_t rnti, uint32_t nslot, uint32_t cell_id, uint32_t len); +SRSLTE_API void srslte_sequence_pusch_apply_pack(const uint8_t* in, + uint8_t* out, + uint16_t rnti, + uint32_t nslot, + uint32_t cell_id, + uint32_t len); + +SRSLTE_API void srslte_sequence_pusch_apply_c(const int8_t* in, + int8_t* out, + uint16_t rnti, + uint32_t nslot, + uint32_t cell_id, + uint32_t len); + +SRSLTE_API void srslte_sequence_pusch_apply_s(const int16_t* in, + int16_t* out, + uint16_t rnti, + uint32_t nslot, + uint32_t cell_id, + uint32_t len); + +SRSLTE_API void +srslte_sequence_pusch_gen_unpack(uint8_t* out, uint16_t rnti, uint32_t nslot, uint32_t cell_id, uint32_t len); + SRSLTE_API int srslte_sequence_pucch(srslte_sequence_t* seq, uint16_t rnti, uint32_t nslot, uint32_t cell_id); SRSLTE_API int srslte_sequence_pmch(srslte_sequence_t* seq, uint32_t nslot, uint32_t mbsfn_id, uint32_t len); diff --git a/lib/include/srslte/phy/enb/enb_dl.h b/lib/include/srslte/phy/enb/enb_dl.h index 26246db9b..9071f93e7 100644 --- a/lib/include/srslte/phy/enb/enb_dl.h +++ b/lib/include/srslte/phy/enb/enb_dl.h @@ -102,10 +102,6 @@ SRSLTE_API void srslte_enb_dl_free(srslte_enb_dl_t* q); SRSLTE_API int srslte_enb_dl_set_cell(srslte_enb_dl_t* q, srslte_cell_t cell); -SRSLTE_API int srslte_enb_dl_add_rnti(srslte_enb_dl_t* q, uint16_t rnti); - -SRSLTE_API void srslte_enb_dl_rem_rnti(srslte_enb_dl_t* q, uint16_t rnti); - SRSLTE_API bool srslte_enb_dl_location_is_common_ncce(srslte_enb_dl_t* q, uint32_t ncce); SRSLTE_API void srslte_enb_dl_put_base(srslte_enb_dl_t* q, srslte_dl_sf_cfg_t* dl_sf); diff --git a/lib/include/srslte/phy/enb/enb_ul.h b/lib/include/srslte/phy/enb/enb_ul.h index f9e493217..56e138c93 100644 --- a/lib/include/srslte/phy/enb/enb_ul.h +++ b/lib/include/srslte/phy/enb/enb_ul.h @@ -72,10 +72,6 @@ SRSLTE_API int srslte_enb_ul_set_cell(srslte_enb_ul_t* q, srslte_refsignal_dmrs_pusch_cfg_t* pusch_cfg, srslte_refsignal_srs_cfg_t* srs_cfg); -SRSLTE_API int srslte_enb_ul_add_rnti(srslte_enb_ul_t* q, uint16_t rnti); - -SRSLTE_API void srslte_enb_ul_rem_rnti(srslte_enb_ul_t* q, uint16_t rnti); - SRSLTE_API void srslte_enb_ul_fft(srslte_enb_ul_t* q); SRSLTE_API int srslte_enb_ul_get_pucch(srslte_enb_ul_t* q, diff --git a/lib/include/srslte/phy/phch/csi.h b/lib/include/srslte/phy/phch/csi.h new file mode 100644 index 000000000..240097a8c --- /dev/null +++ b/lib/include/srslte/phy/phch/csi.h @@ -0,0 +1,69 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2020 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 SRSLTE_CSI_NR_H +#define SRSLTE_CSI_NR_H + +#include "uci_cfg_nr.h" + +/** + * @brief Fills Uplink Control Information data with triggered reports for the given slot + * @param cfg CSI report configuration + * @param slot_idx Slot index within the radio frame + * @param measurements CSI measurements + * @param[out] uci_data Uplink Control Information data + * @return The number CSI reports for transmission if the provided data is valid, SRSLTE_ERROR code otherwise + */ +SRSLTE_API int srslte_csi_generate_reports(const srslte_csi_hl_cfg_t* cfg, + uint32_t slot_idx, + const srslte_csi_measurements_t measurements[SRSLTE_CSI_MAX_NOF_RESOURCES], + srslte_csi_report_cfg_t report_cfg[SRSLTE_CSI_MAX_NOF_REPORT], + srslte_csi_report_value_t report_value[SRSLTE_CSI_MAX_NOF_REPORT]); + +/** + * @brief Compute number of CSI bits necessary to transmit all the CSI reports for a PUCCH transmission + * @param report_list Provides the CSI report list + * @param nof_reports Number of CSI reports in the list + * @return The number of bits if the provided list is valid, SRSLTE_ERROR code otherwise + */ +SRSLTE_API int srslte_csi_nof_bits(const srslte_csi_report_cfg_t* report_list, uint32_t nof_reports); + +/** + * @brief Pack CSI part 1 bits for a PUCCH transmission + * @param report_list Provides the CSI report list + * @param nof_reports Number of CSI reports in the list + * @param o_csi1 CSI bits + * @param max_o_csi1 Maximum number of CSI bits + * @return number of packed bits if provided data is valid, SRSLTE_ERROR code otherwise + */ +SRSLTE_API int srslte_csi_part1_pack(const srslte_csi_report_cfg_t* report_cfg, + const srslte_csi_report_value_t* report_value, + uint32_t nof_reports, + uint8_t* o_csi1, + uint32_t max_o_csi1); + +/** + * @brief Converts to string a given list of CSI reports + * @param report_cfg Report configuration list + * @param report_value Report value list + * @param nof_reports Number of reports + * @param str String pointer + * @param str_len Maximum string length + * @return Number of used characters + */ +SRSLTE_API uint32_t srslte_csi_str(const srslte_csi_report_cfg_t* report_cfg, + const srslte_csi_report_value_t* report_value, + uint32_t nof_reports, + char* str, + uint32_t str_len); + +#endif // SRSLTE_CSI_NR_H diff --git a/lib/include/srslte/phy/phch/csi_cfg.h b/lib/include/srslte/phy/phch/csi_cfg.h new file mode 100644 index 000000000..48a33699b --- /dev/null +++ b/lib/include/srslte/phy/phch/csi_cfg.h @@ -0,0 +1,165 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2020 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 SRSLTE_CSI_CFG_H +#define SRSLTE_CSI_CFG_H + +#include "pucch_cfg_nr.h" +#include "srslte/config.h" +#include + +/** + * @brief Maximum number of CSI report configurations defined in TS 38.331 maxNrofCSI-ReportConfigurations + */ +#define SRSLTE_CSI_MAX_NOF_REPORT 48 + +/** + * @brief Maximum number of CSI-RS resources defined in TS 38.331 maxNrofCSI-ResourceConfigurations + */ +#define SRSLTE_CSI_MAX_NOF_RESOURCES 112 +/** + * @brief CSI report types defined in TS 38.331 CSI-ReportConfig + */ +typedef enum SRSLTE_API { + SRSLTE_CSI_REPORT_TYPE_NONE = 0, + SRSLTE_CSI_REPORT_TYPE_PERIODIC, + SRSLTE_CSI_REPORT_TYPE_SEMI_PERSISTENT_ON_PUCCH, + SRSLTE_CSI_REPORT_TYPE_SEMI_PERSISTENT_ON_PUSCH, + SRSLTE_CSI_REPORT_TYPE_APERIODIC, +} srslte_csi_report_type_t; + +/** + * @brief CSI report quantities defined in TS 38.331 CSI-ReportConfig + */ +typedef enum SRSLTE_API { + SRSLTE_CSI_REPORT_QUANTITY_NONE = 0, + SRSLTE_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI, + SRSLTE_CSI_REPORT_QUANTITY_CRI_RI_I1, + SRSLTE_CSI_REPORT_QUANTITY_CRI_RI_I1_CQI, + SRSLTE_CSI_REPORT_QUANTITY_CRI_RI_CQI, + SRSLTE_CSI_REPORT_QUANTITY_CRI_RSRP, + SRSLTE_CSI_REPORT_QUANTITY_SSB_INDEX_RSRP, + SRSLTE_CSI_REPORT_QUANTITY_CRI_RI_LI_PMI_CQI +} srslte_csi_report_quantity_t; + +/** + * @brief CSI report frequency configuration defined in TS 38.331 CSI-ReportConfig + */ +typedef enum SRSLTE_API { + SRSLTE_CSI_REPORT_FREQ_WIDEBAND = 0, + SRSLTE_CSI_REPORT_FREQ_SUBBAND +} srslte_csi_report_freq_t; + +/** + * @brief CQI table selection + */ +typedef enum SRSLTE_API { + SRSLTE_CSI_CQI_TABLE_1 = 0, + SRSLTE_CSI_CQI_TABLE_2, + SRSLTE_CSI_CQI_TABLE_3, +} srslte_csi_cqi_table_t; + +/** + * @brief CSI periodic report configuration from upper layers + * @remark Described in TS 38.331 CSI-ReportConfig + */ +typedef struct SRSLTE_API { + uint32_t period; ///< Period in slots + uint32_t offset; ///< Offset from beginning of the period in slots + srslte_pucch_nr_resource_t resource; ///< PUCCH resource to use for reporting +} srslte_csi_periodic_report_cfg_t; + +/** + * @brief CSI report configuration from higher layers + */ +typedef struct SRSLTE_API { + uint32_t channel_meas_id; ///< Channel measurement resource identifier + uint32_t interf_meas_id; ///< Interference measurement resource identifier + bool interf_meas_present; ///< Indicates if interference measurement identifier is present + srslte_csi_report_type_t type; ///< CSI report type (none, periodic, semiPersistentOnPUCCH, ...) + union { + void* none; ///< Reserved, no configured + srslte_csi_periodic_report_cfg_t periodic; ///< Used for periodic reporting + // ... add here other types + }; + srslte_csi_report_quantity_t quantity; ///< Report quantity + srslte_csi_cqi_table_t cqi_table; ///< CQI table selection + srslte_csi_report_freq_t freq_cfg; ///< Determine whether it is wideband or subband +} srslte_csi_hl_report_cfg_t; + +/** + * @brief General CSI configuration provided by higher layers + */ +typedef struct SRSLTE_API { + srslte_csi_hl_report_cfg_t reports[SRSLTE_CSI_MAX_NOF_REPORT]; ///< CSI report configuration + // ... add here physical CSI measurement sets +} srslte_csi_hl_cfg_t; + +/** + * @brief Generic measurement structure + */ +typedef struct SRSLTE_API { + uint32_t cri; ///< CSI-RS Resource Indicator + float wideband_rsrp_dBm; ///< Measured NZP-CSI-RS RSRP (Ignore for IM-CSI-RS) + float wideband_epre_dBm; ///< Measured EPRE + float wideband_snr_db; ///< SNR calculated from NZP-CSI-RS RSRP and EPRE (Ignore for IM-CSI-RS) + + // Resource set context + uint32_t nof_ports; ///< Number of antenna ports + uint32_t K_csi_rs; ///< Number of CSI-RS in the corresponding resource set +} srslte_csi_measurements_t; + +/** + * @brief CSI report configuration + */ +typedef struct SRSLTE_API { + srslte_csi_report_type_t type; ///< CSI report type (none, periodic, semiPersistentOnPUCCH, ...) + srslte_csi_report_quantity_t quantity; ///< Report quantity + srslte_pucch_nr_resource_t pucch_resource; ///< PUCCH resource to use for periodic reporting + srslte_csi_report_freq_t freq_cfg; ///< Determine whether it is wideband or subband + + // Resource set context + uint32_t nof_ports; ///< Number of antenna ports + uint32_t K_csi_rs; ///< Number of CSI-RS in the corresponding resource set +} srslte_csi_report_cfg_t; + +/** + * @brief Wideband CSI report values + */ +typedef struct SRSLTE_API { + uint32_t ri; + uint32_t pmi; + uint32_t cqi; +} srslte_csi_report_wideband_cri_ri_pmi_cqi_t; + +/** + * @brief Unified CSI report values + */ +typedef struct SRSLTE_API { + uint32_t cri; ///< CSI-RS Resource Indicator + union { + void* none; + srslte_csi_report_wideband_cri_ri_pmi_cqi_t wideband_cri_ri_pmi_cqi; + }; + bool valid; ///< Used by receiver only +} srslte_csi_report_value_t; + +/** + * @brief Complete report configuration and value + */ +typedef struct SRSLTE_API { + srslte_csi_report_cfg_t cfg[SRSLTE_CSI_MAX_NOF_REPORT]; ///< Configuration ready for encoding + srslte_csi_report_value_t value[SRSLTE_CSI_MAX_NOF_REPORT]; ///< Quantified values + uint32_t nof_reports; ///< Total number of reports to transmit +} srslte_csi_reports_t; + +#endif // SRSLTE_CSI_CFG_H diff --git a/lib/include/srslte/phy/phch/pdsch.h b/lib/include/srslte/phy/phch/pdsch.h index 9f41e32ac..652972e63 100644 --- a/lib/include/srslte/phy/phch/pdsch.h +++ b/lib/include/srslte/phy/phch/pdsch.h @@ -44,12 +44,6 @@ #include "srslte/phy/phch/sch.h" #include "srslte/phy/scrambling/scrambling.h" -typedef struct { - srslte_sequence_t seq[SRSLTE_MAX_CODEWORDS][SRSLTE_NOF_SF_X_FRAME]; - uint32_t cell_id; - bool sequence_generated; -} srslte_pdsch_user_t; - /* PDSCH object */ typedef struct SRSLTE_API { srslte_cell_t cell; @@ -57,8 +51,7 @@ typedef struct SRSLTE_API { uint32_t nof_rx_antennas; uint32_t max_re; - uint16_t ue_rnti; - bool is_ue; + bool is_ue; bool llr_is_8bit; @@ -79,11 +72,6 @@ typedef struct SRSLTE_API { srslte_evm_buffer_t* evm_buffer[SRSLTE_MAX_CODEWORDS]; float avg_evm; - // This is to generate the scrambling seq for multiple CRNTIs - srslte_pdsch_user_t** users; - - srslte_sequence_t tmp_seq; - srslte_sch_t dl_sch; void* coworker_ptr; @@ -108,10 +96,6 @@ SRSLTE_API int srslte_pdsch_enable_coworker(srslte_pdsch_t* q); SRSLTE_API int srslte_pdsch_set_cell(srslte_pdsch_t* q, srslte_cell_t cell); -SRSLTE_API int srslte_pdsch_set_rnti(srslte_pdsch_t* q, uint16_t rnti); - -SRSLTE_API void srslte_pdsch_free_rnti(srslte_pdsch_t* q, uint16_t rnti); - /* These functions do not modify the state and run in real-time */ SRSLTE_API int srslte_pdsch_encode(srslte_pdsch_t* q, srslte_dl_sf_cfg_t* sf, diff --git a/lib/include/srslte/phy/phch/pucch.h b/lib/include/srslte/phy/phch/pucch.h index 59b8d90a1..d7bb73a0f 100644 --- a/lib/include/srslte/phy/phch/pucch.h +++ b/lib/include/srslte/phy/phch/pucch.h @@ -58,12 +58,6 @@ #define SRSLTE_PUCCH_DEFAULT_THRESHOLD_FORMAT3 (0.5f) #define SRSLTE_PUCCH_DEFAULT_THRESHOLD_DMRS (0.4f) -typedef struct { - srslte_sequence_t seq_f2[SRSLTE_NOF_SF_X_FRAME]; - uint32_t cell_id; - bool sequence_generated; -} srslte_pucch_user_t; - /* PUCCH object */ typedef struct SRSLTE_API { srslte_cell_t cell; @@ -71,10 +65,8 @@ typedef struct SRSLTE_API { srslte_uci_cqi_pucch_t cqi; - srslte_pucch_user_t** users; - srslte_sequence_t tmp_seq; - uint16_t ue_rnti; - bool is_ue; + srslte_sequence_t seq_f2; + bool is_ue; int16_t llr[SRSLTE_PUCCH3_NOF_BITS]; uint8_t bits_scram[SRSLTE_PUCCH_MAX_BITS]; @@ -109,10 +101,6 @@ SRSLTE_API void srslte_pucch_free(srslte_pucch_t* q); /* These functions modify the state of the object and may take some time */ SRSLTE_API int srslte_pucch_set_cell(srslte_pucch_t* q, srslte_cell_t cell); -SRSLTE_API int srslte_pucch_set_rnti(srslte_pucch_t* q, uint16_t rnti); - -SRSLTE_API void srslte_pucch_free_rnti(srslte_pucch_t* q, uint16_t rnti); - /* These functions do not modify the state and run in real-time */ SRSLTE_API void srslte_pucch_uci_gen_cfg(srslte_pucch_t* q, srslte_pucch_cfg_t* cfg, srslte_uci_data_t* uci_data); @@ -148,7 +136,7 @@ SRSLTE_API int srslte_pucch_format2ab_mod_bits(srslte_pucch_format_t format, uin SRSLTE_API uint32_t srslte_pucch_m(const srslte_pucch_cfg_t* cfg, srslte_cp_t cp); -SRSLTE_API uint32_t srslte_pucch_n_prb(srslte_cell_t* cell, srslte_pucch_cfg_t* cfg, uint32_t ns); +SRSLTE_API uint32_t srslte_pucch_n_prb(const srslte_cell_t* cell, const srslte_pucch_cfg_t* cfg, uint32_t ns); SRSLTE_API int srslte_pucch_n_cs_cell(srslte_cell_t cell, uint32_t n_cs_cell[SRSLTE_NSLOTS_X_FRAME][SRSLTE_CP_NORM_NSYMB]); diff --git a/lib/include/srslte/phy/phch/pucch_cfg_nr.h b/lib/include/srslte/phy/phch/pucch_cfg_nr.h index 21c2ae206..cc2b9d34c 100644 --- a/lib/include/srslte/phy/phch/pucch_cfg_nr.h +++ b/lib/include/srslte/phy/phch/pucch_cfg_nr.h @@ -86,6 +86,11 @@ */ #define SRSLTE_PUCCH_NR_MAX_NOF_SETS 4 +/** + * Maximum number of SR resources (TS 38.331 maxNrofSR-Resources) + */ +#define SRSLTE_PUCCH_MAX_NOF_SR_RESOURCES 8 + typedef enum SRSLTE_API { SRSLTE_PUCCH_NR_FORMAT_0 = 0, SRSLTE_PUCCH_NR_FORMAT_1, @@ -151,10 +156,24 @@ typedef struct SRSLTE_API { uint32_t max_payload_size; ///< Maximum payload size, set to 0 if not present } srslte_pucch_nr_resource_set_t; +/** + * @brief Scheduling Request resource described in TS 38.331 SchedulingRequestResourceConfig + * @note Every SR configuration corresponds to one or more logical channels (resources) + */ +typedef struct SRSLTE_API { + uint32_t sr_id; ///< Scheduling Request identifier + uint32_t period; ///< Period in slots + uint32_t offset; ///< Offset from beginning of the period in slots + srslte_pucch_nr_resource_t resource; ///< PUCCH resource + bool configured; ///< Set to true if higher layers added this value, otherwise set to false +} srslte_pucch_nr_sr_resource_t; + typedef struct SRSLTE_API { srslte_pucch_nr_common_cfg_t common; ///< NR-PUCCH configuration common for all formats and resources srslte_pucch_nr_resource_set_t sets[SRSLTE_PUCCH_NR_MAX_NOF_SETS]; ///< Resource sets, indexed by pucch-ResourceSetId bool enabled; ///< Set to true if any set is enabled + srslte_pucch_nr_sr_resource_t + sr_resources[SRSLTE_PUCCH_MAX_NOF_SR_RESOURCES]; ///< SR resources, indexed by identifier } srslte_pucch_nr_hl_cfg_t; /** diff --git a/lib/include/srslte/phy/phch/pusch.h b/lib/include/srslte/phy/phch/pusch.h index e358222bc..58bec2b84 100644 --- a/lib/include/srslte/phy/phch/pusch.h +++ b/lib/include/srslte/phy/phch/pusch.h @@ -45,12 +45,6 @@ #include "srslte/phy/phch/sch.h" #include "srslte/phy/scrambling/scrambling.h" -typedef struct { - srslte_sequence_t seq[SRSLTE_NOF_SF_X_FRAME]; - uint32_t cell_id; - bool sequence_generated; -} srslte_pusch_user_t; - /* PUSCH object */ typedef struct SRSLTE_API { srslte_cell_t cell; @@ -76,10 +70,6 @@ typedef struct SRSLTE_API { srslte_modem_table_t mod[SRSLTE_MOD_NITEMS]; srslte_sch_t ul_sch; - // This is to generate the scrambling seq for multiple CRNTIs - srslte_pusch_user_t** users; - srslte_sequence_t tmp_seq; - // EVM buffer srslte_evm_buffer_t* evm_buffer; @@ -108,10 +98,6 @@ SRSLTE_API void srslte_pusch_free(srslte_pusch_t* q); /* These functions modify the state of the object and may take some time */ SRSLTE_API int srslte_pusch_set_cell(srslte_pusch_t* q, srslte_cell_t cell); -SRSLTE_API int srslte_pusch_set_rnti(srslte_pusch_t* q, uint16_t rnti); - -SRSLTE_API void srslte_pusch_free_rnti(srslte_pusch_t* q, uint16_t rnti); - /** * Asserts PUSCH grant attributes are in range * @param grant Pointer to PUSCH grant diff --git a/lib/include/srslte/phy/phch/ra.h b/lib/include/srslte/phy/phch/ra.h index 6819364a5..fe9af6419 100644 --- a/lib/include/srslte/phy/phch/ra.h +++ b/lib/include/srslte/phy/phch/ra.h @@ -102,6 +102,6 @@ SRSLTE_API int srslte_ra_mcs_from_tbs_idx(uint32_t tbs_idx, bool use_tbs_index_a SRSLTE_API int srslte_ra_tbs_from_idx(uint32_t tbs_idx, uint32_t n_prb); -SRSLTE_API int srslte_ra_tbs_to_table_idx(uint32_t tbs, uint32_t n_prb); +SRSLTE_API int srslte_ra_tbs_to_table_idx(uint32_t tbs, uint32_t n_prb, uint32_t max_tbs_idx); #endif // SRSLTE_RA_H diff --git a/lib/include/srslte/phy/phch/ra_ul_nr.h b/lib/include/srslte/phy/phch/ra_ul_nr.h index 52ceb7779..728d78cfe 100644 --- a/lib/include/srslte/phy/phch/ra_ul_nr.h +++ b/lib/include/srslte/phy/phch/ra_ul_nr.h @@ -119,4 +119,11 @@ SRSLTE_API int srslte_ra_ul_nr_pucch_resource(const srslte_pucch_nr_hl_cfg_t* pu const srslte_uci_cfg_nr_t* uci_cfg, srslte_pucch_nr_resource_t* resource); +/** + * @brief Computes the number of SR bits + * @param K Number of SR transmission opportunities, including negative + * @return The number of bits according to the number of SRs + */ +SRSLTE_API uint32_t srslte_ra_ul_nr_nof_sr_bits(uint32_t K); + #endif // SRSLTE_RA_UL_NR_H diff --git a/lib/include/srslte/phy/phch/uci_cfg_nr.h b/lib/include/srslte/phy/phch/uci_cfg_nr.h index 41d6b57ee..1691834d2 100644 --- a/lib/include/srslte/phy/phch/uci_cfg_nr.h +++ b/lib/include/srslte/phy/phch/uci_cfg_nr.h @@ -22,6 +22,7 @@ #ifndef SRSLTE_UCI_CFG_NR_H #define SRSLTE_UCI_CFG_NR_H +#include "csi_cfg.h" #include "srslte/phy/common/phy_common.h" #include #include @@ -59,30 +60,31 @@ */ typedef struct SRSLTE_API { /// Common Parameters - uint32_t o_ack; ///< Number of HARQ-ACK bits - uint32_t o_sr; ///< Number of SR bits - uint32_t o_csi1; ///< Number of CSI1 report number of bits - uint32_t o_csi2; ///< Number of CSI2 report number of bits + uint32_t o_ack; ///< Number of HARQ-ACK bits + uint32_t o_sr; ///< Number of SR bits + srslte_csi_report_cfg_t csi[SRSLTE_CSI_MAX_NOF_REPORT]; ///< CSI report configuration + uint32_t nof_csi; ///< Number of CSI reports /// PUSCH only parameters srslte_mod_t modulation; ///< Modulation /// PUCCH only parameters - uint16_t rnti; ///< RNTI - uint32_t pucch_resource_id; ///< PUCCH resource indicator field in the DCI format 1_0 or DCI format 1_1 - uint32_t n_cce_0; ///< index of a first CCE for the PDCCH reception - uint32_t N_cce; ///< number of CCEs in a CORESET of a PDCCH reception with DCI format 1_0 or DCI format 1_1 + uint16_t rnti; ///< RNTI + uint32_t pucch_resource_id; ///< PUCCH resource indicator field in the DCI format 1_0 or DCI format 1_1 + uint32_t n_cce_0; ///< index of a first CCE for the PDCCH reception + uint32_t N_cce; ///< number of CCEs in a CORESET of a PDCCH reception with DCI format 1_0 or 1_1 + uint32_t sr_resource_id; ///< Scheduling request resource identifier, only valid if positive SR + bool sr_positive_present; ///< Set to true if there is at least one positive SR } srslte_uci_cfg_nr_t; /** * @brief Uplink Control Information (UCI) message packed information */ typedef struct SRSLTE_API { - uint8_t ack[SRSLTE_UCI_NR_MAX_ACK_BITS]; ///< HARQ ACK feedback bits - uint8_t sr[SRSLTE_UCI_NR_MAX_SR_BITS]; ///< Scheduling Request bits - uint8_t csi1[SRSLTE_UCI_NR_MAX_CSI1_BITS]; ///< Channel State Information part 1 - uint8_t csi2[SRSLTE_UCI_NR_MAX_CSI2_BITS]; ///< Channel State Information part 2 - bool valid; ///< Indicates whether the message has been decoded successfully, ignored in the transmitter + uint8_t ack[SRSLTE_UCI_NR_MAX_ACK_BITS]; ///< HARQ ACK feedback bits + uint32_t sr; ///< Number of positive SR + srslte_csi_report_value_t csi[SRSLTE_CSI_MAX_NOF_REPORT]; ///< Packed CSI report values + bool valid; ///< Indicates whether the message has been decoded successfully, ignored in the transmitter } srslte_uci_value_nr_t; /** diff --git a/lib/include/srslte/phy/ue/ue_dl.h b/lib/include/srslte/phy/ue/ue_dl.h index d5ef1f00a..9f02ca153 100644 --- a/lib/include/srslte/phy/ue/ue_dl.h +++ b/lib/include/srslte/phy/ue/ue_dl.h @@ -79,7 +79,6 @@ typedef struct SRSLTE_API { srslte_cell_t cell; uint32_t nof_rx_antennas; uint16_t current_mbsfn_area_id; - uint16_t pregen_rnti; // Objects for all DL Physical Channels srslte_pcfich_t pcfich; @@ -100,13 +99,11 @@ typedef struct SRSLTE_API { srslte_ofdm_t fft_mbsfn; // Buffers to store channel symbols after demodulation - cf_t* sf_symbols[SRSLTE_MAX_PORTS]; + cf_t* sf_symbols[SRSLTE_MAX_PORTS]; + dci_blind_search_t current_ss_common; - // Variables for blind DCI search - dci_blind_search_t current_ss_ue[SRSLTE_MI_MAX_REGS][SRSLTE_NOF_CFI][SRSLTE_NOF_SF_X_FRAME]; - dci_blind_search_t current_ss_common[SRSLTE_MI_MAX_REGS][SRSLTE_NOF_CFI]; - srslte_dci_msg_t pending_ul_dci_msg[SRSLTE_MAX_DCI_MSG]; - uint32_t pending_ul_dci_count; + srslte_dci_msg_t pending_ul_dci_msg[SRSLTE_MAX_DCI_MSG]; + uint32_t pending_ul_dci_count; srslte_dci_location_t allocated_locations[SRSLTE_MAX_DCI_MSG]; uint32_t nof_allocated_locations; @@ -167,8 +164,6 @@ SRSLTE_API void srslte_ue_dl_free(srslte_ue_dl_t* q); SRSLTE_API int srslte_ue_dl_set_cell(srslte_ue_dl_t* q, srslte_cell_t cell); -SRSLTE_API void srslte_ue_dl_set_rnti(srslte_ue_dl_t* q, uint16_t rnti); - SRSLTE_API int srslte_ue_dl_set_mbsfn_area_id(srslte_ue_dl_t* q, uint16_t mbsfn_area_id); SRSLTE_API void srslte_ue_dl_set_non_mbsfn_region(srslte_ue_dl_t* q, uint8_t non_mbsfn_region_length); diff --git a/lib/include/srslte/phy/ue/ue_ul.h b/lib/include/srslte/phy/ue/ue_ul.h index 00e0acd1f..cdbb8a069 100644 --- a/lib/include/srslte/phy/ue/ue_ul.h +++ b/lib/include/srslte/phy/ue/ue_ul.h @@ -79,7 +79,6 @@ typedef enum { } srslte_ue_ul_normalize_mode_t; typedef struct SRSLTE_API { - srslte_ul_cfg_t ul_cfg; bool grant_available; uint32_t cc_idx; @@ -95,8 +94,7 @@ typedef struct SRSLTE_API { typedef struct SRSLTE_API { srslte_cell_t cell; - uint16_t current_rnti; - bool signals_pregenerated; + bool signals_pregenerated; srslte_ofdm_t fft; srslte_cfo_t cfo; @@ -123,8 +121,6 @@ SRSLTE_API void srslte_ue_ul_free(srslte_ue_ul_t* q); SRSLTE_API int srslte_ue_ul_set_cell(srslte_ue_ul_t* q, srslte_cell_t cell); -SRSLTE_API void srslte_ue_ul_set_rnti(srslte_ue_ul_t* q, uint16_t rnti); - SRSLTE_API int srslte_ue_ul_pregen_signals(srslte_ue_ul_t* q, srslte_ue_ul_cfg_t* cfg); SRSLTE_API int srslte_ue_ul_dci_to_pusch_grant(srslte_ue_ul_t* q, diff --git a/lib/include/srslte/phy/ue/ue_ul_nr.h b/lib/include/srslte/phy/ue/ue_ul_nr.h index f4793f832..c7abe4908 100644 --- a/lib/include/srslte/phy/ue/ue_ul_nr.h +++ b/lib/include/srslte/phy/ue/ue_ul_nr.h @@ -84,4 +84,21 @@ SRSLTE_API int srslte_ue_ul_nr_pucch_info(const srslte_pucch_nr_resource_t* reso char* str, uint32_t str_len); +/** + * @brief Decides whether the provided slot index within the radio frame is a SR transmission opportunity + * + * @remark Implemented according to TS 38.213 9.2.4 UE procedure for reporting SR + * + * @param sr_resources Provides the SR configuration from the upper layers + * @param slot_idx Slot index in the radio frame + * @param[out] sr_resource_id Optional SR resource index (or identifier) + * + * @return the number of SR opportunities if the provided slot index is a SR transmission opportunity, SRSLTE_ERROR code + * if provided parameters are invalid + */ +SRSLTE_API int +srslte_ue_ul_nr_sr_send_slot(const srslte_pucch_nr_sr_resource_t sr_resources[SRSLTE_PUCCH_MAX_NOF_SR_RESOURCES], + uint32_t slot_idx, + uint32_t sr_resource_id[SRSLTE_PUCCH_MAX_NOF_SR_RESOURCES]); + #endif // SRSLTE_UE_UL_DATA_H diff --git a/lib/include/srslte/phy/utils/vector.h b/lib/include/srslte/phy/utils/vector.h index 97a308e4b..e99cc75c1 100644 --- a/lib/include/srslte/phy/utils/vector.h +++ b/lib/include/srslte/phy/utils/vector.h @@ -36,6 +36,7 @@ extern "C" { #include "srslte/config.h" #include +#include #include #include @@ -108,6 +109,7 @@ SRSLTE_API void* srslte_vec_realloc(void* ptr, uint32_t old_size, uint32_t new_s SRSLTE_API void srslte_vec_zero(void* ptr, uint32_t nsamples); SRSLTE_API void srslte_vec_cf_zero(cf_t* ptr, uint32_t nsamples); SRSLTE_API void srslte_vec_f_zero(float* ptr, uint32_t nsamples); +SRSLTE_API void srslte_vec_i8_zero(int8_t* ptr, uint32_t nsamples); SRSLTE_API void srslte_vec_u8_zero(uint8_t* ptr, uint32_t nsamples); SRSLTE_API void srslte_vec_i16_zero(int16_t* ptr, uint32_t nsamples); SRSLTE_API void srslte_vec_u32_zero(uint32_t* ptr, uint32_t nsamples); diff --git a/lib/include/srslte/srslte.h b/lib/include/srslte/srslte.h index f7374d492..dff5f3dc4 100644 --- a/lib/include/srslte/srslte.h +++ b/lib/include/srslte/srslte.h @@ -90,6 +90,7 @@ extern "C" { #include "srslte/phy/fec/softbuffer.h" #include "srslte/phy/phch/cqi.h" +#include "srslte/phy/phch/csi.h" #include "srslte/phy/phch/dci.h" #include "srslte/phy/phch/dci_nr.h" #include "srslte/phy/phch/pbch.h" diff --git a/lib/include/srslte/system/sys_metrics.h b/lib/include/srslte/system/sys_metrics.h new file mode 100644 index 000000000..ff7cca5c5 --- /dev/null +++ b/lib/include/srslte/system/sys_metrics.h @@ -0,0 +1,33 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2020 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 SRSLTE_SYS_METRICS_H +#define SRSLTE_SYS_METRICS_H + +#include + +namespace srslte { + +/// Metrics of cpu usage, memory consumption and number of thread used by the process. +struct sys_metrics_t { + uint32_t process_realmem_kB = 0; + uint32_t process_virtualmem_kB = 0; + float process_realmem = -1.f; + float process_virtualmem = -1.f; + uint32_t thread_count = 0; + float process_cpu_usage = -1.f; + float system_mem = -1.f; +}; + +} // namespace srslte + +#endif // SRSLTE_SYS_METRICS_H diff --git a/lib/include/srslte/system/sys_metrics_processor.h b/lib/include/srslte/system/sys_metrics_processor.h new file mode 100644 index 000000000..88326f1e3 --- /dev/null +++ b/lib/include/srslte/system/sys_metrics_processor.h @@ -0,0 +1,66 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2020 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 SRSLTE_SYS_METRICS_PROCESSOR_H +#define SRSLTE_SYS_METRICS_PROCESSOR_H + +#include "srslte/system/sys_metrics.h" +#include +#include + +namespace srslte { + +/// Process information from the system to create sys_metrics_t. The information is processed from the /proc/ system. +class sys_metrics_processor +{ + /// Helper class used to parse the information from the /proc/[pid]/stats. + struct proc_stats_info { + proc_stats_info(); + + // Initialize the variables that will be used. + int32_t num_threads = 0; + uint32_t utime = 0; + uint32_t stime = 0; + + // Rest of the information of the stats file. + int32_t pid, ppid, pgrp, session, tty_nr, tpgid, exit_signal, processor, exit_code, cutime, cstime, priority, nice, + itrealvalue, rss, cguest_time; + uint32_t minflt, cminflt, majflt, cmajflt, vsize, rsslim, startcode, endcode, startstack, kstkesp, kstkeip, signal, + blocked, sigignore, sigcatch, wchan, nswap, cnswap, guest_time, start_data, end_data, start_brk, arg_start, + arg_end, env_start, env_end, flags, rt_priority, policy; + uint64_t starttime, delaycct_blkio_ticks; + uint8_t state; + std::string comm; + }; + +public: + /// Measures and returns the system metrics. + sys_metrics_t get_metrics(); + +private: + /// Calculates and returns the cpu usage in %. current_query is the most recent proc_stats_info, and + /// delta_time_in_seconds is the elapsed time between the last measure and current in seconds. NOTE: Returns -1.0f on + /// error. + float calculate_cpu_usage(const proc_stats_info& current_query, float delta_time_in_seconds) const; + + /// Calculate the memory parameters and writes them in metrics. + /// NOTE: on error, metrics memory parameters are set to 0. + void calculate_mem_usage(sys_metrics_t& metrics) const; + +private: + proc_stats_info last_query = {}; + std::chrono::time_point last_query_time = std::chrono::steady_clock::now(); +}; + +} // namespace srslte + +#endif // SRSLTE_SYS_METRICS_PROCESSOR_H diff --git a/lib/include/srslte/test/ue_test_interfaces.h b/lib/include/srslte/test/ue_test_interfaces.h index 85eee4be9..b4550eb33 100644 --- a/lib/include/srslte/test/ue_test_interfaces.h +++ b/lib/include/srslte/test/ue_test_interfaces.h @@ -23,7 +23,10 @@ #define SRSUE_DUMMY_CLASSES_H #include "srslte/common/task_scheduler.h" +#include "srslte/interfaces/phy_interface_types.h" #include "srslte/interfaces/ue_interfaces.h" +#include "srslte/interfaces/ue_phy_interfaces.h" +#include "srslte/interfaces/ue_rlc_interfaces.h" namespace srsue { @@ -49,7 +52,7 @@ public: // run pending tasks without updating timers void run_pending_tasks() { task_sched.run_pending_tasks(); } - srslte::task_scheduler task_sched{512, 0, 100}; + srslte::task_scheduler task_sched{512, 100}; }; class rlc_dummy_interface : public rlc_interface_mac diff --git a/lib/include/srslte/upper/pdcp.h b/lib/include/srslte/upper/pdcp.h index 2b834b1b9..d59c5e964 100644 --- a/lib/include/srslte/upper/pdcp.h +++ b/lib/include/srslte/upper/pdcp.h @@ -25,8 +25,9 @@ #include "srslte/common/common.h" #include "srslte/common/log.h" #include "srslte/common/task_scheduler.h" -#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/interfaces/ue_pdcp_interfaces.h" #include "srslte/upper/pdcp_entity_lte.h" +#include namespace srslte { diff --git a/lib/include/srslte/upper/pdcp_entity_lte.h b/lib/include/srslte/upper/pdcp_entity_lte.h index abd854802..96f55dd9e 100644 --- a/lib/include/srslte/upper/pdcp_entity_lte.h +++ b/lib/include/srslte/upper/pdcp_entity_lte.h @@ -22,16 +22,82 @@ #ifndef SRSLTE_PDCP_ENTITY_LTE_H #define SRSLTE_PDCP_ENTITY_LTE_H +#include "srslte/adt/circular_array.h" #include "srslte/common/buffer_pool.h" #include "srslte/common/common.h" #include "srslte/common/log.h" #include "srslte/common/security.h" #include "srslte/common/threads.h" -#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/interfaces/ue_rrc_interfaces.h" #include "srslte/upper/pdcp_entity_base.h" +namespace srsue { + +class gw_interface_pdcp; +class rlc_interface_pdcp; + +} // namespace srsue + namespace srslte { +class undelivered_sdus_queue +{ +public: + explicit undelivered_sdus_queue(srslte::task_sched_handle task_sched); + + bool empty() const { return count == 0; } + bool is_full() const { return count >= capacity; } + uint32_t size() const { return count; } + static uint32_t get_capacity() { return capacity; } + bool has_sdu(uint32_t sn) const + { + assert(sn != invalid_sn && "provided PDCP SN is invalid"); + return sdus[sn].sdu != nullptr and sdus[sn].sdu->md.pdcp_sn == sn; + } + // Getter for the number of discard timers. Used for debugging. + size_t nof_discard_timers() const; + + bool add_sdu(uint32_t sn, + const srslte::unique_byte_buffer_t& sdu, + uint32_t discard_timeout, + const std::function& callback); + + unique_byte_buffer_t& operator[](uint32_t sn) + { + assert(has_sdu(sn)); + return sdus[sn].sdu; + } + bool clear_sdu(uint32_t sn); + void clear(); + + uint32_t get_bytes() const { return bytes; } + uint32_t get_fms() const { return fms; } + void set_fms(uint32_t fms_) { fms = fms_; } + void update_fms(); + void update_lms(uint32_t sn); + + uint32_t get_lms() const { return lms; } + + std::map get_buffered_sdus(); + +private: + const static uint32_t capacity = 4096; + const static uint32_t invalid_sn = -1; + + static uint32_t increment_sn(uint32_t sn) { return (sn + 1) % capacity; } + + struct sdu_data { + srslte::unique_byte_buffer_t sdu; + srslte::unique_timer discard_timer; + }; + + uint32_t count = 0; + uint32_t bytes = 0; + uint32_t fms = 0; + uint32_t lms = 0; + srslte::circular_array sdus; +}; + /**************************************************************************** * Structs and Defines * Ref: 3GPP TS 36.323 v10.1.0 @@ -43,6 +109,7 @@ namespace srslte { * LTE PDCP Entity * Class for LTE PDCP entities ***************************************************************************/ + class pdcp_entity_lte final : public pdcp_entity_base { public: @@ -82,13 +149,12 @@ public: void get_bearer_state(pdcp_lte_state_t* state) override; void set_bearer_state(const pdcp_lte_state_t& state) override; - // Getter for the number of discard timers. Used for debugging. - uint32_t nof_discard_timers() const; - // Metrics helpers pdcp_bearer_metrics_t get_metrics() override; void reset_metrics() override; + size_t nof_discard_timers() const { return undelivered_sdus != nullptr ? undelivered_sdus->nof_discard_timers() : 0; } + private: srsue::rlc_interface_pdcp* rlc = nullptr; srsue::rrc_interface_pdcp* rrc = nullptr; @@ -100,20 +166,18 @@ private: uint32_t reordering_window = 0; uint32_t maximum_pdcp_sn = 0; - // Discard callback (discardTimer) - class discard_callback; - std::vector discard_timers; - unique_timer* get_discard_timer(uint32_t sn); - void stop_discard_timer(uint32_t sn); - - // TX Queue - uint32_t maximum_allocated_sns_window = 2048; - std::map undelivered_sdus_queue; - + // PDU handlers void handle_control_pdu(srslte::unique_byte_buffer_t pdu); void handle_srb_pdu(srslte::unique_byte_buffer_t pdu); void handle_um_drb_pdu(srslte::unique_byte_buffer_t pdu); void handle_am_drb_pdu(srslte::unique_byte_buffer_t pdu); + + // Discard callback (discardTimer) + class discard_callback; + + // TX Queue + uint32_t maximum_allocated_sns_window = 2048; + std::unique_ptr undelivered_sdus; }; // Discard callback (discardTimer) diff --git a/lib/include/srslte/upper/pdcp_entity_nr.h b/lib/include/srslte/upper/pdcp_entity_nr.h index 391e457be..d90a218cf 100644 --- a/lib/include/srslte/upper/pdcp_entity_nr.h +++ b/lib/include/srslte/upper/pdcp_entity_nr.h @@ -30,7 +30,9 @@ #include "srslte/common/security.h" #include "srslte/common/task_scheduler.h" #include "srslte/common/threads.h" +#include "srslte/interfaces/ue_gw_interfaces.h" #include "srslte/interfaces/ue_interfaces.h" +#include "srslte/interfaces/ue_rlc_interfaces.h" #include namespace srslte { diff --git a/lib/include/srslte/upper/rlc.h b/lib/include/srslte/upper/rlc.h index 92c0818e0..ca3ceef73 100644 --- a/lib/include/srslte/upper/rlc.h +++ b/lib/include/srslte/upper/rlc.h @@ -25,7 +25,10 @@ #include "srslte/common/buffer_pool.h" #include "srslte/common/common.h" #include "srslte/common/log.h" -#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/common/task_scheduler.h" +#include "srslte/interfaces/ue_pdcp_interfaces.h" +#include "srslte/interfaces/ue_rlc_interfaces.h" +#include "srslte/interfaces/ue_rrc_interfaces.h" #include "srslte/upper/rlc_common.h" #include "srslte/upper/rlc_metrics.h" diff --git a/lib/include/srslte/upper/rlc_am_base.h b/lib/include/srslte/upper/rlc_am_base.h index 9d9aae9c2..6106934d2 100644 --- a/lib/include/srslte/upper/rlc_am_base.h +++ b/lib/include/srslte/upper/rlc_am_base.h @@ -25,7 +25,6 @@ #include "srslte/common/buffer_pool.h" #include "srslte/common/common.h" #include "srslte/common/log.h" -#include "srslte/interfaces/ue_interfaces.h" #include "srslte/upper/byte_buffer_queue.h" #include "srslte/upper/rlc_common.h" #include @@ -42,4 +41,11 @@ bool rlc_am_is_control_pdu(byte_buffer_t* pdu); } // namespace srslte +namespace srsue { + +class pdcp_interface_rlc; +class rrc_interface_rlc; + +} // namespace srsue + #endif // SRSLTE_RLC_AM_BASE_H diff --git a/lib/include/srslte/upper/rlc_am_lte.h b/lib/include/srslte/upper/rlc_am_lte.h index e29c3442e..c9240aa78 100644 --- a/lib/include/srslte/upper/rlc_am_lte.h +++ b/lib/include/srslte/upper/rlc_am_lte.h @@ -27,8 +27,8 @@ #include "srslte/common/buffer_pool.h" #include "srslte/common/common.h" #include "srslte/common/log.h" +#include "srslte/common/task_scheduler.h" #include "srslte/common/timeout.h" -#include "srslte/interfaces/ue_interfaces.h" #include "srslte/upper/byte_buffer_queue.h" #include "srslte/upper/rlc_am_base.h" #include "srslte/upper/rlc_common.h" @@ -43,6 +43,7 @@ namespace srslte { struct rlc_amd_rx_pdu_t { rlc_amd_pdu_header_t header; unique_byte_buffer_t buf; + uint32_t rlc_sn; }; struct rlc_amd_rx_pdu_segments_t { @@ -78,14 +79,16 @@ struct pdcp_sdu_info_t { std::vector rlc_sn_info_list; // List of RLC PDUs in transit and whether they have been acked or not. }; -struct tx_window_t { - tx_window_t() { clear(); } - void add_pdu(size_t sn) +template +struct rlc_ringbuffer_t { + rlc_ringbuffer_t() { clear(); } + T& add_pdu(size_t sn) { - assert(not active_flag[sn]); + assert(not has_sn(sn)); window[sn].rlc_sn = sn; active_flag[sn] = true; count++; + return window[sn]; } void remove_pdu(size_t sn) { @@ -94,7 +97,7 @@ struct tx_window_t { active_flag[sn] = false; count--; } - rlc_amd_tx_pdu_t& operator[](size_t sn) + T& operator[](size_t sn) { assert(has_sn(sn)); return window[sn]; @@ -104,30 +107,27 @@ struct tx_window_t { void clear() { std::fill(active_flag.begin(), active_flag.end(), false); - for (size_t i = 0; i < window.size(); ++i) { - window[i].pdcp_sns.clear(); - } count = 0; } - bool has_sn(uint32_t sn) const { return active_flag[sn] and window[sn].rlc_sn == sn; } - rlc_amd_tx_pdu_t& front() + + bool has_sn(uint32_t sn) const { return active_flag[sn] and (window[sn].rlc_sn == sn); } + + // Return the sum data bytes of all active PDUs (check PDU is non-null) + uint32_t get_buffered_bytes() { - assert(not empty()); - uint32_t min_rlc_sn = std::numeric_limits::max(), min_idx = std::numeric_limits::max(); - for (uint32_t i = 0; i < window.size(); ++i) { - if (active_flag[i] and window[i].rlc_sn < min_rlc_sn) { - min_idx = i; - min_rlc_sn = window[i].rlc_sn; + uint32_t buff_size = 0; + for (const auto& pdu : window) { + if (pdu.buf != nullptr) { + buff_size += pdu.buf->N_bytes; } } - assert(has_sn(min_rlc_sn)); - return window[min_idx]; + return buff_size; } private: - size_t count = 0; - srslte::circular_array active_flag = {}; - srslte::circular_array window; + size_t count = 0; + srslte::circular_array active_flag = {}; + srslte::circular_array window; }; struct buffered_pdcp_pdu_list { @@ -179,6 +179,51 @@ private: uint32_t count = 0; }; +class pdu_retx_queue +{ +public: + rlc_amd_retx_t& push() + { + assert(not full()); + rlc_amd_retx_t& p = buffer[wpos]; + wpos = (wpos + 1) % RLC_AM_WINDOW_SIZE; + return p; + } + + void pop() { rpos = (rpos + 1) % RLC_AM_WINDOW_SIZE; } + + rlc_amd_retx_t& front() + { + assert(not empty()); + return buffer[rpos]; + } + + void clear() + { + wpos = 0; + rpos = 0; + } + + bool has_sn(uint32_t sn) const + { + for (size_t i = rpos; i != wpos; i = (i + 1) % RLC_AM_WINDOW_SIZE) { + if (buffer[i].sn == sn) { + return true; + } + } + return false; + } + + size_t size() const { return (wpos >= rpos) ? wpos - rpos : RLC_AM_WINDOW_SIZE + wpos - rpos; } + bool empty() const { return wpos == rpos; } + bool full() const { return size() == RLC_AM_WINDOW_SIZE - 1; } + +private: + std::array buffer; + size_t wpos = 0; + size_t rpos = 0; +}; + class rlc_am_lte : public rlc_common { public: @@ -247,17 +292,17 @@ private: int build_retx_pdu(uint8_t* payload, uint32_t nof_bytes); int build_segment(uint8_t* payload, uint32_t nof_bytes, rlc_amd_retx_t retx); int build_data_pdu(uint8_t* payload, uint32_t nof_bytes); - void update_notification_ack_info(const rlc_amd_tx_pdu_t& tx_pdu, std::vector& notify_info_vec); + void update_notification_ack_info(const rlc_amd_tx_pdu_t& tx_pdu); void debug_state(); - bool retx_queue_has_sn(uint32_t sn); int required_buffer_size(rlc_amd_retx_t retx); void retransmit_pdu(); // Helpers bool poll_required(); bool do_status(); + void check_sn_reached_max_retx(uint32_t sn); rlc_am_lte* parent = nullptr; byte_buffer_pool* pool = nullptr; @@ -308,8 +353,9 @@ private: bsr_callback_t bsr_callback; // Tx windows - tx_window_t tx_window; - std::deque retx_queue; + rlc_ringbuffer_t tx_window; + pdu_retx_queue retx_queue; + std::vector notify_info_vec; // Mutexes pthread_mutex_t mutex; @@ -378,7 +424,7 @@ private: pthread_mutex_t mutex; // Rx windows - std::map rx_window; + rlc_ringbuffer_t rx_window; std::map rx_segments; bool poll_received = false; diff --git a/lib/include/srslte/upper/rlc_am_nr.h b/lib/include/srslte/upper/rlc_am_nr.h index d5926e0e4..91c193172 100644 --- a/lib/include/srslte/upper/rlc_am_nr.h +++ b/lib/include/srslte/upper/rlc_am_nr.h @@ -25,7 +25,6 @@ #include "srslte/common/buffer_pool.h" #include "srslte/common/common.h" #include "srslte/common/log.h" -#include "srslte/interfaces/ue_interfaces.h" #include "srslte/upper/byte_buffer_queue.h" #include "srslte/upper/rlc_am_base.h" #include diff --git a/lib/include/srslte/upper/rlc_common.h b/lib/include/srslte/upper/rlc_common.h index e43cdc409..dfe9e03ae 100644 --- a/lib/include/srslte/upper/rlc_common.h +++ b/lib/include/srslte/upper/rlc_common.h @@ -24,6 +24,7 @@ #include "srslte/common/block_queue.h" #include "srslte/common/logmap.h" +#include "srslte/interfaces/rlc_interface_types.h" #include "srslte/upper/rlc_metrics.h" #include diff --git a/lib/include/srslte/upper/rlc_tm.h b/lib/include/srslte/upper/rlc_tm.h index af8a6bbf4..a7b625f47 100644 --- a/lib/include/srslte/upper/rlc_tm.h +++ b/lib/include/srslte/upper/rlc_tm.h @@ -25,10 +25,16 @@ #include "srslte/common/buffer_pool.h" #include "srslte/common/common.h" #include "srslte/common/log.h" -#include "srslte/interfaces/ue_interfaces.h" #include "srslte/upper/byte_buffer_queue.h" #include "srslte/upper/rlc_common.h" +namespace srsue { + +class pdcp_interface_rlc; +class rrc_interface_rlc; + +} // namespace srsue + namespace srslte { class rlc_tm final : public rlc_common diff --git a/lib/include/srslte/upper/rlc_um_base.h b/lib/include/srslte/upper/rlc_um_base.h index 159b29d29..aecc64b8b 100644 --- a/lib/include/srslte/upper/rlc_um_base.h +++ b/lib/include/srslte/upper/rlc_um_base.h @@ -26,7 +26,7 @@ #include "srslte/common/buffer_pool.h" #include "srslte/common/common.h" #include "srslte/common/log.h" -#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/common/task_scheduler.h" #include "srslte/upper/byte_buffer_queue.h" #include "srslte/upper/rlc_common.h" #include @@ -34,6 +34,13 @@ #include #include +namespace srsue { + +class pdcp_interface_rlc; +class rrc_interface_rlc; + +} // namespace srsue + namespace srslte { class rlc_um_base : public rlc_common diff --git a/lib/include/srslte/upper/rlc_um_lte.h b/lib/include/srslte/upper/rlc_um_lte.h index 69befff76..79e98e271 100644 --- a/lib/include/srslte/upper/rlc_um_lte.h +++ b/lib/include/srslte/upper/rlc_um_lte.h @@ -25,7 +25,6 @@ #include "srslte/common/buffer_pool.h" #include "srslte/common/common.h" #include "srslte/common/log.h" -#include "srslte/interfaces/ue_interfaces.h" #include "srslte/upper/byte_buffer_queue.h" #include "srslte/upper/rlc_um_base.h" #include diff --git a/lib/src/CMakeLists.txt b/lib/src/CMakeLists.txt index 567e97fe5..6ec1927f6 100644 --- a/lib/src/CMakeLists.txt +++ b/lib/src/CMakeLists.txt @@ -24,4 +24,5 @@ add_subdirectory(mac) add_subdirectory(phy) add_subdirectory(radio) add_subdirectory(srslog) +add_subdirectory(system) add_subdirectory(upper) diff --git a/lib/src/asn1/liblte_mme.cc b/lib/src/asn1/liblte_mme.cc index 32debefae..85ecd7173 100644 --- a/lib/src/asn1/liblte_mme.cc +++ b/lib/src/asn1/liblte_mme.cc @@ -5911,6 +5911,7 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_emm_information_msg(LIBLTE_BYTE_MSG_STRUCT* { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; + uint8* msg_end = msg->msg + msg->N_bytes; uint8 sec_hdr_type; if (msg != NULL && emm_info != NULL) { @@ -5935,7 +5936,7 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_emm_information_msg(LIBLTE_BYTE_MSG_STRUCT* } // Short Name For Network - if (LIBLTE_MME_SHORT_NAME_FOR_NETWORK_IEI == *msg_ptr) { + if (msg_ptr < msg_end && LIBLTE_MME_SHORT_NAME_FOR_NETWORK_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_network_name_ie(&msg_ptr, &emm_info->short_net_name); emm_info->short_net_name_present = true; @@ -5944,7 +5945,7 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_emm_information_msg(LIBLTE_BYTE_MSG_STRUCT* } // Local Time Zone - if (LIBLTE_MME_LOCAL_TIME_ZONE_IEI == *msg_ptr) { + if (msg_ptr < msg_end && LIBLTE_MME_LOCAL_TIME_ZONE_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_time_zone_ie(&msg_ptr, &emm_info->local_time_zone); emm_info->local_time_zone_present = true; @@ -5953,7 +5954,7 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_emm_information_msg(LIBLTE_BYTE_MSG_STRUCT* } // Universal Time And Local Time Zone - if (LIBLTE_MME_UNIVERSAL_TIME_AND_LOCAL_TIME_ZONE_IEI == *msg_ptr) { + if (msg_ptr < msg_end && LIBLTE_MME_UNIVERSAL_TIME_AND_LOCAL_TIME_ZONE_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_time_zone_and_time_ie(&msg_ptr, &emm_info->utc_and_local_time_zone); emm_info->utc_and_local_time_zone_present = true; @@ -5962,7 +5963,7 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_emm_information_msg(LIBLTE_BYTE_MSG_STRUCT* } // Network Daylight Saving Time - if (LIBLTE_MME_NETWORK_DAYLIGHT_SAVING_TIME_IEI == *msg_ptr) { + if (msg_ptr < msg_end && LIBLTE_MME_NETWORK_DAYLIGHT_SAVING_TIME_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_daylight_saving_time_ie(&msg_ptr, &emm_info->net_dst); emm_info->net_dst_present = true; diff --git a/lib/src/asn1/rrc_nr_utils.cc b/lib/src/asn1/rrc_nr_utils.cc index 0b4c3edb1..3864eba5f 100644 --- a/lib/src/asn1/rrc_nr_utils.cc +++ b/lib/src/asn1/rrc_nr_utils.cc @@ -120,9 +120,48 @@ srslte::pdcp_config_t make_drb_pdcp_config_t(const uint8_t bearer_id, bool is_ue case 10: discard_timer = pdcp_discard_timer_t::ms10; break; + case 20: + discard_timer = pdcp_discard_timer_t::ms20; + break; + case 30: + discard_timer = pdcp_discard_timer_t::ms30; + break; + case 40: + discard_timer = pdcp_discard_timer_t::ms40; + break; + case 50: + discard_timer = pdcp_discard_timer_t::ms50; + break; + case 60: + discard_timer = pdcp_discard_timer_t::ms60; + break; + case 75: + discard_timer = pdcp_discard_timer_t::ms75; + break; case 100: discard_timer = pdcp_discard_timer_t::ms100; break; + case 150: + discard_timer = pdcp_discard_timer_t::ms150; + break; + case 200: + discard_timer = pdcp_discard_timer_t::ms200; + break; + case 250: + discard_timer = pdcp_discard_timer_t::ms250; + break; + case 300: + discard_timer = pdcp_discard_timer_t::ms300; + break; + case 500: + discard_timer = pdcp_discard_timer_t::ms500; + break; + case 750: + discard_timer = pdcp_discard_timer_t::ms750; + break; + case 1500: + discard_timer = pdcp_discard_timer_t::ms1500; + break; default: discard_timer = pdcp_discard_timer_t::infinity; break; diff --git a/lib/src/common/CMakeLists.txt b/lib/src/common/CMakeLists.txt index efa2671aa..d44e9cb5a 100644 --- a/lib/src/common/CMakeLists.txt +++ b/lib/src/common/CMakeLists.txt @@ -32,8 +32,10 @@ set(SOURCES arch_select.cc logmap.cc logger_srslog_wrapper.cc mac_pcap.cc + mac_pcap_base.cc nas_pcap.cc network_utils.cc + mac_pcap_net.cc pcap.c rlc_pcap.cc s1ap_pcap.cc @@ -58,7 +60,7 @@ add_dependencies(srslte_common gen_build_info) add_executable(arch_select arch_select.cc) target_include_directories(srslte_common PUBLIC ${SEC_INCLUDE_DIRS} ${CMAKE_SOURCE_DIR} ${BACKWARD_INCLUDE_DIRS}) -target_link_libraries(srslte_common srslte_phy srslog ${SEC_LIBRARIES} ${BACKWARD_LIBRARIES}) +target_link_libraries(srslte_common srslte_phy srslog ${SEC_LIBRARIES} ${BACKWARD_LIBRARIES} ${SCTP_LIBRARIES}) target_compile_definitions(srslte_common PRIVATE ${BACKWARD_DEFINITIONS}) INSTALL(TARGETS srslte_common DESTINATION ${LIBRARY_DIR}) diff --git a/lib/src/common/basic_vnf.cc b/lib/src/common/basic_vnf.cc index 1e0a7f194..0882c570b 100644 --- a/lib/src/common/basic_vnf.cc +++ b/lib/src/common/basic_vnf.cc @@ -226,8 +226,9 @@ int srslte_basic_vnf::handle_ul_ind(basic_vnf_api::ul_ind_msg_t* msg) ul_grant.tti = msg->tti; ul_grant.tbs = msg->pdus.length; ul_grant.rnti = msg->rnti; - srslte::unique_byte_buffer_t tx_pdu = srslte::make_byte_buffer(); - m_ue_stack->new_grant_ul(cc_idx, ul_grant, tx_pdu.get()); + + srsue::stack_interface_phy_nr::tb_action_ul_t ul_action = {}; + m_ue_stack->new_grant_ul(cc_idx, ul_grant, &ul_action); return SRSLTE_SUCCESS; } diff --git a/lib/src/common/mac_pcap.cc b/lib/src/common/mac_pcap.cc index b7653d753..29dc541f7 100644 --- a/lib/src/common/mac_pcap.cc +++ b/lib/src/common/mac_pcap.cc @@ -20,27 +20,16 @@ */ #include "srslte/common/mac_pcap.h" -#include "srslte/config.h" -#include "srslte/phy/common/phy_common.h" -#include +#include "srslte/common/threads.h" namespace srslte { - -mac_pcap::mac_pcap(srslte_rat_t rat_) : - logger(srslog::fetch_basic_logger("MAC")), thread("PCAP_WRITER_" + to_string(rat_)), rat(rat_) -{} +mac_pcap::mac_pcap() : mac_pcap_base() {} mac_pcap::~mac_pcap() { close(); } -void mac_pcap::enable(bool enable_) -{ - std::lock_guard lock(mutex); - running = enable_; -} - uint32_t mac_pcap::open(std::string filename_, uint32_t ue_id_) { std::lock_guard lock(mutex); @@ -50,18 +39,7 @@ uint32_t mac_pcap::open(std::string filename_, uint32_t ue_id_) } // set DLT for selected RAT - switch (rat) { - case srslte_rat_t::lte: - dlt = MAC_LTE_DLT; - break; - case srslte_rat_t::nr: - dlt = UDP_DLT; - break; - default: - logger.error("Error opening PCAP. Unsupported RAT selected."); - return SRSLTE_ERROR; - } - + dlt = UDP_DLT; pcap_file = LTE_PCAP_Open(dlt, filename_.c_str()); if (pcap_file == nullptr) { logger.error("Couldn't open %s to write PCAP", filename_.c_str()); @@ -97,7 +75,7 @@ uint32_t mac_pcap::close() // close file handle { std::lock_guard lock(mutex); - srslte::console("Saving %s MAC PCAP (DLT=%d) to %s\n", to_string(rat).c_str(), dlt, filename.c_str()); + srslte::console("Saving MAC PCAP (DLT=%d) to %s\n", dlt, filename.c_str()); LTE_PCAP_Close(pcap_file); pcap_file = nullptr; } @@ -105,15 +83,15 @@ uint32_t mac_pcap::close() return SRSLTE_SUCCESS; } -void mac_pcap::write_pdu(pcap_pdu_t& pdu) +void mac_pcap::write_pdu(srslte::mac_pcap_base::pcap_pdu_t& pdu) { if (pdu.pdu != nullptr) { - switch (rat) { + switch (pdu.rat) { case srslte_rat_t::lte: - LTE_PCAP_MAC_WritePDU(pcap_file, &pdu.context, pdu.pdu->msg, pdu.pdu->N_bytes); + LTE_PCAP_MAC_UDP_WritePDU(pcap_file, &pdu.context, pdu.pdu->msg, pdu.pdu->N_bytes); break; case srslte_rat_t::nr: - NR_PCAP_MAC_WritePDU(pcap_file, &pdu.context_nr, pdu.pdu->msg, pdu.pdu->N_bytes); + NR_PCAP_MAC_UDP_WritePDU(pcap_file, &pdu.context_nr, pdu.pdu->msg, pdu.pdu->N_bytes); break; default: logger.error("Error writing PDU to PCAP. Unsupported RAT selected."); @@ -121,256 +99,4 @@ void mac_pcap::write_pdu(pcap_pdu_t& pdu) } } -void mac_pcap::run_thread() -{ - // blocking write until stopped - while (running) { - pcap_pdu_t pdu = queue.wait_pop(); - { - std::lock_guard lock(mutex); - write_pdu(pdu); - } - } - - // write remainder of queue - std::lock_guard lock(mutex); - pcap_pdu_t pdu = {}; - while (queue.try_pop(&pdu)) { - write_pdu(pdu); - } -} - -void mac_pcap::set_ue_id(uint16_t ue_id_) -{ - std::lock_guard lock(mutex); - ue_id = ue_id_; -} - -// Function called from PHY worker context, locking not needed as PDU queue is thread-safe -void mac_pcap::pack_and_queue(uint8_t* payload, - uint32_t payload_len, - uint32_t reTX, - bool crc_ok, - uint8_t cc_idx, - uint32_t tti, - uint16_t crnti, - uint8_t direction, - uint8_t rnti_type) -{ - if (running && payload != nullptr) { - pcap_pdu_t pdu = {}; - pdu.context.radioType = FDD_RADIO; - pdu.context.direction = direction; - pdu.context.rntiType = rnti_type; - pdu.context.rnti = crnti; - pdu.context.ueid = (uint16_t)ue_id; - pdu.context.isRetx = (uint8_t)reTX; - pdu.context.crcStatusOK = crc_ok; - pdu.context.cc_idx = cc_idx; - pdu.context.sysFrameNumber = (uint16_t)(tti / 10); - pdu.context.subFrameNumber = (uint16_t)(tti % 10); - - // try to allocate PDU buffer - pdu.pdu = srslte::make_byte_buffer(); - if (pdu.pdu != nullptr && pdu.pdu->get_tailroom() >= payload_len) { - // copy payload into PDU buffer - memcpy(pdu.pdu->msg, payload, payload_len); - pdu.pdu->N_bytes = payload_len; - queue.push(std::move(pdu)); - } else { - logger.info("Dropping PDU in PCAP. No buffer available or not enough space (pdu_len=%d).", payload_len); - } - } -} - -// Function called from PHY worker context, locking not needed as PDU queue is thread-safe -void mac_pcap::pack_and_queue_nr(uint8_t* payload, - uint32_t payload_len, - uint32_t tti, - uint16_t crnti, - uint8_t harqid, - uint8_t direction, - uint8_t rnti_type) -{ - if (running && payload != nullptr) { - pcap_pdu_t pdu = {}; - pdu.context_nr.radioType = FDD_RADIO; - pdu.context_nr.direction = direction; - pdu.context_nr.rntiType = rnti_type; - pdu.context_nr.rnti = crnti; - pdu.context_nr.ueid = ue_id; - pdu.context_nr.harqid = harqid; - pdu.context_nr.system_frame_number = tti / 10; - pdu.context_nr.sub_frame_number = tti % 10; - - // try to allocate PDU buffer - pdu.pdu = srslte::make_byte_buffer(); - if (pdu.pdu != nullptr && pdu.pdu->get_tailroom() >= payload_len) { - // copy payload into PDU buffer - memcpy(pdu.pdu->msg, payload, payload_len); - pdu.pdu->N_bytes = payload_len; - queue.push(std::move(pdu)); - } else { - logger.info("Dropping PDU in NR PCAP. No buffer available or not enough space (pdu_len=%d).", payload_len); - } - } -} - -void mac_pcap::write_dl_crnti(uint8_t* pdu, - uint32_t pdu_len_bytes, - uint16_t rnti, - bool crc_ok, - uint32_t tti, - uint8_t cc_idx) -{ - pack_and_queue(pdu, pdu_len_bytes, 0, crc_ok, cc_idx, tti, rnti, DIRECTION_DOWNLINK, C_RNTI); -} -void mac_pcap::write_dl_ranti(uint8_t* pdu, - uint32_t pdu_len_bytes, - uint16_t rnti, - bool crc_ok, - uint32_t tti, - uint8_t cc_idx) -{ - pack_and_queue(pdu, pdu_len_bytes, 0, crc_ok, cc_idx, tti, rnti, DIRECTION_DOWNLINK, RA_RNTI); -} -void mac_pcap::write_ul_crnti(uint8_t* pdu, - uint32_t pdu_len_bytes, - uint16_t rnti, - uint32_t reTX, - uint32_t tti, - uint8_t cc_idx) -{ - pack_and_queue(pdu, pdu_len_bytes, reTX, true, cc_idx, tti, rnti, DIRECTION_UPLINK, C_RNTI); -} - -void mac_pcap::write_sl_crnti(uint8_t* pdu, - uint32_t pdu_len_bytes, - uint16_t rnti, - uint32_t reTX, - uint32_t tti, - uint8_t cc_idx) -{ - pack_and_queue(pdu, pdu_len_bytes, reTX, true, cc_idx, tti, rnti, DIRECTION_UPLINK, SL_RNTI); -} - -void mac_pcap::write_dl_bch(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti, uint8_t cc_idx) -{ - pack_and_queue(pdu, pdu_len_bytes, 0, crc_ok, cc_idx, tti, 0, DIRECTION_DOWNLINK, NO_RNTI); -} -void mac_pcap::write_dl_pch(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti, uint8_t cc_idx) -{ - pack_and_queue(pdu, pdu_len_bytes, 0, crc_ok, cc_idx, tti, SRSLTE_PRNTI, DIRECTION_DOWNLINK, P_RNTI); -} -void mac_pcap::write_dl_mch(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti, uint8_t cc_idx) -{ - pack_and_queue(pdu, pdu_len_bytes, 0, crc_ok, cc_idx, tti, SRSLTE_MRNTI, DIRECTION_DOWNLINK, M_RNTI); -} -void mac_pcap::write_dl_sirnti(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti, uint8_t cc_idx) -{ - pack_and_queue(pdu, pdu_len_bytes, 0, crc_ok, cc_idx, tti, SRSLTE_SIRNTI, DIRECTION_DOWNLINK, SI_RNTI); -} - -void mac_pcap::write_dl_crnti_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti) -{ - pack_and_queue_nr(pdu, pdu_len_bytes, tti, rnti, harqid, DIRECTION_DOWNLINK, C_RNTI); -} - -void mac_pcap::write_ul_crnti_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti) -{ - pack_and_queue_nr(pdu, pdu_len_bytes, tti, rnti, harqid, DIRECTION_UPLINK, C_RNTI); -} - -void mac_pcap::write_dl_ra_rnti_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti) -{ - pack_and_queue_nr(pdu, pdu_len_bytes, tti, rnti, harqid, DIRECTION_DOWNLINK, RA_RNTI); -} - -void mac_pcap::write_dl_bch_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti) -{ - pack_and_queue_nr(pdu, pdu_len_bytes, tti, rnti, harqid, DIRECTION_DOWNLINK, NO_RNTI); -} - -void mac_pcap::write_dl_pch_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti) -{ - pack_and_queue_nr(pdu, pdu_len_bytes, tti, rnti, harqid, DIRECTION_DOWNLINK, P_RNTI); -} - -void mac_pcap::write_dl_si_rnti_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti) -{ - pack_and_queue_nr(pdu, pdu_len_bytes, tti, rnti, harqid, DIRECTION_DOWNLINK, SI_RNTI); -} - -void mac_pcap::write_ul_rrc_pdu(const uint8_t* input, const int32_t input_len) -{ - uint8_t pdu[1024]; - bzero(pdu, sizeof(pdu)); - - // Size is limited by PDU buffer and MAC subheader (format 1 < 128 B) - if (input_len > 128 - 7) { - logger.error("PDU too large."); - return; - } - - // MAC PDU Header (Short BSR) (1:54) (Padding:remainder) [3 subheaders] - // Sub-header (lcid=Short BSR) - // 0... .... = SCH reserved bit: 0x0 - // .0.. .... = Format2: Data length is < 32768 bytes - // ..1. .... = Extension: 0x1 - // ...1 1101 = LCID: Short BSR (0x1d) - // Sub-header (lcid=1, length=54) - // 0... .... = SCH reserved bit: 0x0 - // .0.. .... = Format2: Data length is < 32768 bytes - // ..1. .... = Extension: 0x1 - // ...0 0001 = LCID: 1 (0x01) - // 0... .... = Format: Data length is < 128 bytes - // .011 0110 = Length: 54 (Will be dynamically updated) - // Sub-header (lcid=Padding, length is remainder) - // 0... .... = SCH reserved bit: 0x0 - // .0.. .... = Format2: Data length is < 32768 bytes - // ..0. .... = Extension: 0x0 - // ...1 1111 = LCID: Padding (0x1f) - uint8_t mac_hdr[] = {0x3D, 0x21, 0x36, 0x1F, 0x0C}; - - // Update MAC length - mac_hdr[2] = input_len + 7; // rlc_hdr (2) + pdcp_hdr (1) + MAC (4) - - // AM Header (P) sn=4 - // 1... .... = Frame type: Data PDU (0x1) - // .0.. .... = Re-segmentation Flag: AMD PDU (0x0) - // ..1. .... = Polling Bit: Status report is requested (0x1) - // ...0 0... = Framing Info: First byte begins a RLC SDU and last byte ends a RLC SDU (0x0) - // .... .0.. = Extension: Data field follows from the octet following the fixed part of the header (0x0) - // .... ..00 0000 0100 = Sequence Number: 4 - uint8_t rlc_hdr[] = {0xA0, 0x04}; - - // PDCP-LTE sn=3 - // 000. .... = Reserved: 0 - // ...0 0011 = Seq Num: 3 - uint8_t pdcp_hdr[] = {0x03}; - - uint8_t* pdu_ptr = pdu; - - memcpy(pdu_ptr, mac_hdr, sizeof(mac_hdr)); - pdu_ptr += sizeof(mac_hdr); - memcpy(pdu_ptr, rlc_hdr, sizeof(rlc_hdr)); - pdu_ptr += sizeof(rlc_hdr); - memcpy(pdu_ptr, pdcp_hdr, sizeof(pdcp_hdr)); - pdu_ptr += sizeof(pdcp_hdr); - memcpy(pdu_ptr, input, input_len); - pdu_ptr += input_len; - - // MAC - uint8_t pad = 0x00; - for (uint32_t i = 0; i < 4; i++) { - memcpy(pdu_ptr, &pad, 1); - pdu_ptr += 1; - } - - // Pad - memcpy(pdu_ptr, &pad, 1); - pdu_ptr += 1; - - write_ul_crnti(pdu, pdu_ptr - pdu, 14931, true, 0, 0); -} -} // namespace srslte +} // namespace srslte \ No newline at end of file diff --git a/lib/src/common/mac_pcap_base.cc b/lib/src/common/mac_pcap_base.cc new file mode 100644 index 000000000..979cfaab8 --- /dev/null +++ b/lib/src/common/mac_pcap_base.cc @@ -0,0 +1,336 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2020 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 "srslte/common/mac_pcap_base.h" +#include "srslte/config.h" +#include "srslte/phy/common/phy_common.h" +#include + +namespace srslte { + +mac_pcap_base::mac_pcap_base() : logger(srslog::fetch_basic_logger("MAC")), thread("PCAP_WRITER_MAC") {} + +mac_pcap_base::~mac_pcap_base() {} + +void mac_pcap_base::enable(bool enable_) +{ + std::lock_guard lock(mutex); + running = enable_; +} + +void mac_pcap_base::set_ue_id(uint16_t ue_id_) +{ + std::lock_guard lock(mutex); + ue_id = ue_id_; +} + +void mac_pcap_base::run_thread() +{ + // blocking write until stopped + while (running) { + pcap_pdu_t pdu = queue.wait_pop(); + { + std::lock_guard lock(mutex); + write_pdu(pdu); + } + } + + // write remainder of queue + std::lock_guard lock(mutex); + pcap_pdu_t pdu = {}; + while (queue.try_pop(&pdu)) { + write_pdu(pdu); + } +} + +// Function called from PHY worker context, locking not needed as PDU queue is thread-safe +void mac_pcap_base::pack_and_queue(uint8_t* payload, + uint32_t payload_len, + uint16_t ue_id, + uint32_t reTX, + bool crc_ok, + uint8_t cc_idx, + uint32_t tti, + uint16_t crnti, + uint8_t direction, + uint8_t rnti_type) +{ + if (running && payload != nullptr) { + pcap_pdu_t pdu = {}; + pdu.rat = srslte::srslte_rat_t::lte; + pdu.context.radioType = FDD_RADIO; + pdu.context.direction = direction; + pdu.context.rntiType = rnti_type; + pdu.context.rnti = crnti; + pdu.context.ueid = ue_id; + pdu.context.isRetx = (uint8_t)reTX; + pdu.context.crcStatusOK = crc_ok; + pdu.context.cc_idx = cc_idx; + pdu.context.sysFrameNumber = (uint16_t)(tti / 10); + pdu.context.subFrameNumber = (uint16_t)(tti % 10); + + // try to allocate PDU buffer + pdu.pdu = srslte::make_byte_buffer(); + if (pdu.pdu != nullptr && pdu.pdu->get_tailroom() >= payload_len) { + // copy payload into PDU buffer + memcpy(pdu.pdu->msg, payload, payload_len); + pdu.pdu->N_bytes = payload_len; + queue.push(std::move(pdu)); + } else { + logger.info("Dropping PDU in PCAP. No buffer available or not enough space (pdu_len=%d).", payload_len); + } + } +} + +// Function called from PHY worker context, locking not needed as PDU queue is thread-safe +void mac_pcap_base::pack_and_queue_nr(uint8_t* payload, + uint32_t payload_len, + uint32_t tti, + uint16_t crnti, + uint16_t ue_id, + uint8_t harqid, + uint8_t direction, + uint8_t rnti_type) +{ + if (running && payload != nullptr) { + pcap_pdu_t pdu = {}; + pdu.rat = srslte_rat_t::nr; + pdu.context_nr.radioType = FDD_RADIO; + pdu.context_nr.direction = direction; + pdu.context_nr.rntiType = rnti_type; + pdu.context_nr.rnti = crnti; + pdu.context_nr.ueid = ue_id; + pdu.context_nr.harqid = harqid; + pdu.context_nr.system_frame_number = tti / 10; + pdu.context_nr.sub_frame_number = tti % 10; + + // try to allocate PDU buffer + pdu.pdu = srslte::make_byte_buffer(); + if (pdu.pdu != nullptr && pdu.pdu->get_tailroom() >= payload_len) { + // copy payload into PDU buffer + memcpy(pdu.pdu->msg, payload, payload_len); + pdu.pdu->N_bytes = payload_len; + queue.push(std::move(pdu)); + } else { + logger.info("Dropping PDU in NR PCAP. No buffer available or not enough space (pdu_len=%d).", payload_len); + } + } +} + +void mac_pcap_base::write_dl_crnti(uint8_t* pdu, + uint32_t pdu_len_bytes, + uint16_t rnti, + bool crc_ok, + uint32_t tti, + uint8_t cc_idx) +{ + pack_and_queue(pdu, pdu_len_bytes, ue_id, 0, crc_ok, cc_idx, tti, rnti, DIRECTION_DOWNLINK, C_RNTI); +} +void mac_pcap_base::write_dl_ranti(uint8_t* pdu, + uint32_t pdu_len_bytes, + uint16_t rnti, + bool crc_ok, + uint32_t tti, + uint8_t cc_idx) +{ + pack_and_queue(pdu, pdu_len_bytes, ue_id, 0, crc_ok, cc_idx, tti, rnti, DIRECTION_DOWNLINK, RA_RNTI); +} +void mac_pcap_base::write_ul_crnti(uint8_t* pdu, + uint32_t pdu_len_bytes, + uint16_t rnti, + uint32_t reTX, + uint32_t tti, + uint8_t cc_idx) +{ + pack_and_queue(pdu, pdu_len_bytes, ue_id, reTX, true, cc_idx, tti, rnti, DIRECTION_UPLINK, C_RNTI); +} + +void mac_pcap_base::write_ul_crnti(uint8_t* pdu, + uint32_t pdu_len_bytes, + uint16_t rnti, + uint16_t ue_id, + uint32_t reTX, + uint32_t tti, + uint8_t cc_idx) +{ + pack_and_queue(pdu, pdu_len_bytes, ue_id, reTX, true, cc_idx, tti, rnti, DIRECTION_UPLINK, C_RNTI); +} + +void mac_pcap_base::write_dl_crnti(uint8_t* pdu, + uint32_t pdu_len_bytes, + uint16_t rnti, + uint16_t ue_id, + bool crc_ok, + uint32_t tti, + uint8_t cc_idx) +{ + pack_and_queue(pdu, pdu_len_bytes, ue_id, 0, crc_ok, cc_idx, tti, rnti, DIRECTION_DOWNLINK, C_RNTI); +} + +void mac_pcap_base::write_sl_crnti(uint8_t* pdu, + uint32_t pdu_len_bytes, + uint16_t rnti, + uint32_t reTX, + uint32_t tti, + uint8_t cc_idx) +{ + pack_and_queue(pdu, pdu_len_bytes, ue_id, reTX, true, cc_idx, tti, rnti, DIRECTION_UPLINK, SL_RNTI); +} + +void mac_pcap_base::write_dl_bch(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti, uint8_t cc_idx) +{ + pack_and_queue(pdu, pdu_len_bytes, ue_id, 0, crc_ok, cc_idx, tti, 0, DIRECTION_DOWNLINK, NO_RNTI); +} +void mac_pcap_base::write_dl_pch(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti, uint8_t cc_idx) +{ + pack_and_queue(pdu, pdu_len_bytes, ue_id, 0, crc_ok, cc_idx, tti, SRSLTE_PRNTI, DIRECTION_DOWNLINK, P_RNTI); +} +void mac_pcap_base::write_dl_mch(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti, uint8_t cc_idx) +{ + pack_and_queue(pdu, pdu_len_bytes, ue_id, 0, crc_ok, cc_idx, tti, SRSLTE_MRNTI, DIRECTION_DOWNLINK, M_RNTI); +} +void mac_pcap_base::write_dl_sirnti(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti, uint8_t cc_idx) +{ + pack_and_queue(pdu, pdu_len_bytes, ue_id, 0, crc_ok, cc_idx, tti, SRSLTE_SIRNTI, DIRECTION_DOWNLINK, SI_RNTI); +} + +void mac_pcap_base::write_dl_crnti_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti) +{ + pack_and_queue_nr(pdu, pdu_len_bytes, tti, rnti, ue_id, harqid, DIRECTION_DOWNLINK, C_RNTI); +} + +void mac_pcap_base::write_dl_crnti_nr(uint8_t* pdu, + uint32_t pdu_len_bytes, + uint16_t crnti, + uint16_t ue_id, + uint8_t harqid, + uint32_t tti) +{ + pack_and_queue_nr(pdu, pdu_len_bytes, tti, crnti, ue_id, harqid, DIRECTION_DOWNLINK, C_RNTI); +} + +void mac_pcap_base::write_ul_crnti_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti) +{ + pack_and_queue_nr(pdu, pdu_len_bytes, tti, rnti, ue_id, harqid, DIRECTION_UPLINK, C_RNTI); +} + +void mac_pcap_base::write_ul_crnti_nr(uint8_t* pdu, + uint32_t pdu_len_bytes, + uint16_t rnti, + uint16_t ue_id, + uint8_t harqid, + uint32_t tti) +{ + pack_and_queue_nr(pdu, pdu_len_bytes, tti, rnti, ue_id, harqid, DIRECTION_UPLINK, C_RNTI); +} + +void mac_pcap_base::write_dl_ra_rnti_nr(uint8_t* pdu, + uint32_t pdu_len_bytes, + uint16_t rnti, + uint8_t harqid, + uint32_t tti) +{ + pack_and_queue_nr(pdu, pdu_len_bytes, tti, rnti, ue_id, harqid, DIRECTION_DOWNLINK, RA_RNTI); +} + +void mac_pcap_base::write_dl_bch_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti) +{ + pack_and_queue_nr(pdu, pdu_len_bytes, tti, rnti, ue_id, harqid, DIRECTION_DOWNLINK, NO_RNTI); +} + +void mac_pcap_base::write_dl_pch_nr(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti) +{ + pack_and_queue_nr(pdu, pdu_len_bytes, tti, rnti, ue_id, harqid, DIRECTION_DOWNLINK, P_RNTI); +} + +void mac_pcap_base::write_dl_si_rnti_nr(uint8_t* pdu, + uint32_t pdu_len_bytes, + uint16_t rnti, + uint8_t harqid, + uint32_t tti) +{ + pack_and_queue_nr(pdu, pdu_len_bytes, tti, rnti, ue_id, harqid, DIRECTION_DOWNLINK, SI_RNTI); +} + +void mac_pcap_base::write_ul_rrc_pdu(const uint8_t* input, const int32_t input_len) +{ + uint8_t pdu[1024]; + bzero(pdu, sizeof(pdu)); + + // Size is limited by PDU buffer and MAC subheader (format 1 < 128 B) + if (input_len > 128 - 7) { + logger.error("PDU too large."); + return; + } + + // MAC PDU Header (Short BSR) (1:54) (Padding:remainder) [3 subheaders] + // Sub-header (lcid=Short BSR) + // 0... .... = SCH reserved bit: 0x0 + // .0.. .... = Format2: Data length is < 32768 bytes + // ..1. .... = Extension: 0x1 + // ...1 1101 = LCID: Short BSR (0x1d) + // Sub-header (lcid=1, length=54) + // 0... .... = SCH reserved bit: 0x0 + // .0.. .... = Format2: Data length is < 32768 bytes + // ..1. .... = Extension: 0x1 + // ...0 0001 = LCID: 1 (0x01) + // 0... .... = Format: Data length is < 128 bytes + // .011 0110 = Length: 54 (Will be dynamically updated) + // Sub-header (lcid=Padding, length is remainder) + // 0... .... = SCH reserved bit: 0x0 + // .0.. .... = Format2: Data length is < 32768 bytes + // ..0. .... = Extension: 0x0 + // ...1 1111 = LCID: Padding (0x1f) + uint8_t mac_hdr[] = {0x3D, 0x21, 0x36, 0x1F, 0x0C}; + + // Update MAC length + mac_hdr[2] = input_len + 7; // rlc_hdr (2) + pdcp_hdr (1) + MAC (4) + + // AM Header (P) sn=4 + // 1... .... = Frame type: Data PDU (0x1) + // .0.. .... = Re-segmentation Flag: AMD PDU (0x0) + // ..1. .... = Polling Bit: Status report is requested (0x1) + // ...0 0... = Framing Info: First byte begins a RLC SDU and last byte ends a RLC SDU (0x0) + // .... .0.. = Extension: Data field follows from the octet following the fixed part of the header (0x0) + // .... ..00 0000 0100 = Sequence Number: 4 + uint8_t rlc_hdr[] = {0xA0, 0x04}; + + // PDCP-LTE sn=3 + // 000. .... = Reserved: 0 + // ...0 0011 = Seq Num: 3 + uint8_t pdcp_hdr[] = {0x03}; + + uint8_t* pdu_ptr = pdu; + + memcpy(pdu_ptr, mac_hdr, sizeof(mac_hdr)); + pdu_ptr += sizeof(mac_hdr); + memcpy(pdu_ptr, rlc_hdr, sizeof(rlc_hdr)); + pdu_ptr += sizeof(rlc_hdr); + memcpy(pdu_ptr, pdcp_hdr, sizeof(pdcp_hdr)); + pdu_ptr += sizeof(pdcp_hdr); + memcpy(pdu_ptr, input, input_len); + pdu_ptr += input_len; + + // MAC + uint8_t pad = 0x00; + for (uint32_t i = 0; i < 4; i++) { + memcpy(pdu_ptr, &pad, 1); + pdu_ptr += 1; + } + + // Pad + memcpy(pdu_ptr, &pad, 1); + pdu_ptr += 1; + + write_ul_crnti(pdu, pdu_ptr - pdu, 14931, true, 0, 0); +} +} // namespace srslte diff --git a/lib/src/common/mac_pcap_net.cc b/lib/src/common/mac_pcap_net.cc new file mode 100644 index 000000000..3b098be7b --- /dev/null +++ b/lib/src/common/mac_pcap_net.cc @@ -0,0 +1,170 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2020 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 "srslte/common/mac_pcap_net.h" + +namespace srslte { + +mac_pcap_net::mac_pcap_net() : mac_pcap_base() {} + +mac_pcap_net::~mac_pcap_net() +{ + close(); +} +uint32_t mac_pcap_net::open(std::string client_ip_addr_, + std::string bind_addr_str, + uint16_t client_udp_port_, + uint16_t bind_udp_port_, + uint32_t ue_id_) +{ + std::lock_guard lock(mutex); + + if (socket.is_init()) { + logger.error("PCAP socket writer for %s already running. Close first.", bind_addr_str.c_str()); + return SRSLTE_ERROR; + } + + if (not socket.open_socket( + net_utils::addr_family::ipv4, net_utils::socket_type::datagram, net_utils::protocol_type::UDP)) { + logger.error("Couldn't open socket %s to write PCAP", bind_addr_str.c_str()); + return SRSLTE_ERROR; + } + if (not socket.bind_addr(bind_addr_str.c_str(), bind_udp_port_)) { + socket.reset(); + logger.error("Couldn't bind socket %s to write PCAP", bind_addr_str.c_str()); + return SRSLTE_ERROR; + } + + logger.info("Sending MAC PCAP frames to %s:%d (from %s:%d)", + client_ip_addr_.c_str(), + client_udp_port_, + bind_addr_str.c_str(), + bind_udp_port_); + client_addr.sin_family = AF_INET; + client_addr.sin_addr.s_addr = inet_addr(client_ip_addr_.c_str()); + client_addr.sin_port = htons(client_udp_port_); + running = true; + ue_id = ue_id_; + // start writer thread + start(); + + return SRSLTE_SUCCESS; +} + +uint32_t mac_pcap_net::close() +{ + { + std::lock_guard lock(mutex); + if (running == false || socket.is_init() == false) { + return SRSLTE_ERROR; + } + + // tell writer thread to stop + running = false; + pcap_pdu_t pdu = {}; + queue.push(std::move(pdu)); + } + + wait_thread_finish(); + // close socket handle + if (socket.is_init()) { + std::lock_guard lock(mutex); + socket.close(); + } + + return SRSLTE_SUCCESS; +} + +void mac_pcap_net::write_pdu(pcap_pdu_t& pdu) +{ + if (pdu.pdu != nullptr && socket.is_init()) { + switch (pdu.rat) { + case srslte_rat_t::lte: + write_mac_lte_pdu_to_net(pdu); + break; + case srslte_rat_t::nr: + write_mac_nr_pdu_to_net(pdu); + break; + default: + logger.error("Error writing PDU to PCAP socket. Unsupported RAT selected."); + } + } +} + +void mac_pcap_net::write_mac_lte_pdu_to_net(pcap_pdu_t& pdu) +{ + int bytes_sent; + uint32_t offset = 0; + uint8_t buffer[PCAP_CONTEXT_HEADER_MAX]; + + // MAC_LTE_START_STRING for UDP heuristics + memcpy(buffer + offset, MAC_LTE_START_STRING, strlen(MAC_LTE_START_STRING)); + offset += strlen(MAC_LTE_START_STRING); + + offset += LTE_PCAP_PACK_MAC_CONTEXT_TO_BUFFER(&pdu.context, buffer + offset, PCAP_CONTEXT_HEADER_MAX); + + if (pdu.pdu.get()->get_headroom() < offset) { + logger.error("PDU headroom is to small for adding context buffer"); + return; + } + + pdu.pdu.get()->msg -= offset; + memcpy(pdu.pdu.get()->msg, buffer, offset); + pdu.pdu.get()->N_bytes += offset; + + bytes_sent = sendto(socket.get_socket(), + pdu.pdu.get()->msg, + pdu.pdu.get()->N_bytes, + 0, + (const struct sockaddr*)&client_addr, + sizeof(client_addr)); + + if ((int)pdu.pdu.get()->N_bytes != bytes_sent || bytes_sent < 0) { + logger.error( + "Sending UDP packet mismatches %d != %d (err %s)", pdu.pdu.get()->N_bytes, bytes_sent, strerror(errno)); + } +} + +void mac_pcap_net::write_mac_nr_pdu_to_net(pcap_pdu_t& pdu) +{ + int bytes_sent; + uint32_t offset = 0; + uint8_t buffer[PCAP_CONTEXT_HEADER_MAX]; + + // MAC_LTE_START_STRING for UDP heuristics + memcpy(buffer + offset, MAC_LTE_START_STRING, strlen(MAC_LTE_START_STRING)); + offset += strlen(MAC_LTE_START_STRING); + + offset += NR_PCAP_PACK_MAC_CONTEXT_TO_BUFFER(&pdu.context_nr, buffer + offset, PCAP_CONTEXT_HEADER_MAX); + + if (pdu.pdu.get()->get_headroom() < offset) { + logger.error("PDU headroom is to small for adding context buffer"); + return; + } + + pdu.pdu.get()->msg -= offset; + memcpy(pdu.pdu.get()->msg, buffer, offset); + pdu.pdu.get()->N_bytes += offset; + + bytes_sent = sendto(socket.get_socket(), + pdu.pdu.get()->msg, + pdu.pdu.get()->N_bytes, + 0, + (const struct sockaddr*)&client_addr, + sizeof(client_addr)); + + if ((int)pdu.pdu.get()->N_bytes != bytes_sent || bytes_sent < 0) { + logger.error( + "Sending UDP packet mismatches %d != %d (err %s)", pdu.pdu.get()->N_bytes, bytes_sent, strerror(errno)); + } +} +} // namespace srslte \ No newline at end of file diff --git a/lib/src/common/nas_pcap.cc b/lib/src/common/nas_pcap.cc index 009423a3d..b5cec2f46 100644 --- a/lib/src/common/nas_pcap.cc +++ b/lib/src/common/nas_pcap.cc @@ -30,15 +30,22 @@ void nas_pcap::enable() { enable_write = true; } -void nas_pcap::open(const char* filename, uint32_t ue_id_) + +uint32_t nas_pcap::open(std::string filename_, uint32_t ue_id_) { - pcap_file = LTE_PCAP_Open(NAS_LTE_DLT, filename); + filename = filename_; + pcap_file = LTE_PCAP_Open(NAS_LTE_DLT, filename.c_str()); + if (pcap_file == nullptr) { + return SRSLTE_ERROR; + } ue_id = ue_id_; enable_write = true; + return SRSLTE_SUCCESS; } + void nas_pcap::close() { - fprintf(stdout, "Saving NAS PCAP file (DLT=%d)\n", NAS_LTE_DLT); + fprintf(stdout, "Saving NAS PCAP file (DLT=%d) to %s \n", NAS_LTE_DLT, filename.c_str()); LTE_PCAP_Close(pcap_file); } diff --git a/lib/src/common/network_utils.cc b/lib/src/common/network_utils.cc index 431c23e80..adfaeddbb 100644 --- a/lib/src/common/network_utils.cc +++ b/lib/src/common/network_utils.cc @@ -422,9 +422,13 @@ public: bool operator()(int fd) override { - srslte::unique_byte_buffer_t pdu(new byte_buffer_t()); - sockaddr_in from = {}; - socklen_t fromlen = sizeof(from); + srslte::unique_byte_buffer_t pdu = srslte::make_byte_buffer(); + if (pdu == nullptr) { + logger.error("Unable to allocate byte buffer"); + return true; + } + sockaddr_in from = {}; + socklen_t fromlen = sizeof(from); ssize_t n_recv = recvfrom(fd, pdu->msg, pdu->get_tailroom(), 0, (struct sockaddr*)&from, &fromlen); if (n_recv == -1 and errno != EAGAIN) { @@ -458,11 +462,15 @@ public: bool operator()(int fd) override { // inside rx_sockets thread. Read socket - srslte::unique_byte_buffer_t pdu = srslte::make_byte_buffer(); - sockaddr_in from = {}; - socklen_t fromlen = sizeof(from); - sctp_sndrcvinfo sri = {}; - int flags = 0; + srslte::unique_byte_buffer_t pdu = srslte::make_byte_buffer(); + if (pdu == nullptr) { + logger.error("Unable to allocate byte buffer"); + return true; + } + sockaddr_in from = {}; + socklen_t fromlen = sizeof(from); + sctp_sndrcvinfo sri = {}; + int flags = 0; ssize_t n_recv = sctp_recvmsg(fd, pdu->msg, pdu->get_tailroom(), (struct sockaddr*)&from, &fromlen, &sri, &flags); if (n_recv == -1 and errno != EAGAIN) { logger.error("Error reading from SCTP socket: %s", strerror(errno)); diff --git a/lib/src/common/pcap.c b/lib/src/common/pcap.c index ec2916e33..bb536a24e 100644 --- a/lib/src/common/pcap.c +++ b/lib/src/common/pcap.c @@ -21,6 +21,7 @@ #include "srslte/common/pcap.h" #include +#include #include #include #include @@ -58,13 +59,62 @@ void LTE_PCAP_Close(FILE* fd) } } +/* Packs MAC Contect to a buffer */ +inline int LTE_PCAP_PACK_MAC_CONTEXT_TO_BUFFER(MAC_Context_Info_t* context, uint8_t* buffer, unsigned int length) +{ + int offset = 0; + uint16_t tmp16; + + if (buffer == NULL || length < PCAP_CONTEXT_HEADER_MAX) { + printf("Error: Can't write to empty file handle\n"); + return -1; + } + + /*****************************************************************/ + /* Context information (same as written by UDP heuristic clients */ + buffer[offset++] = context->radioType; + buffer[offset++] = context->direction; + buffer[offset++] = context->rntiType; + + /* RNTI */ + buffer[offset++] = MAC_LTE_RNTI_TAG; + tmp16 = htons(context->rnti); + memcpy(buffer + offset, &tmp16, 2); + offset += 2; + + /* UEId */ + buffer[offset++] = MAC_LTE_UEID_TAG; + tmp16 = htons(context->ueid); + memcpy(buffer + offset, &tmp16, 2); + offset += 2; + + /* Subframe Number and System Frame Number */ + /* SFN is stored in 12 MSB and SF in 4 LSB */ + buffer[offset++] = MAC_LTE_FRAME_SUBFRAME_TAG; + tmp16 = (context->sysFrameNumber << 4) | context->subFrameNumber; + tmp16 = htons(tmp16); + memcpy(buffer + offset, &tmp16, 2); + offset += 2; + + /* CRC Status */ + buffer[offset++] = MAC_LTE_CRC_STATUS_TAG; + buffer[offset++] = context->crcStatusOK; + + /* NB-IoT mode tag */ + buffer[offset++] = MAC_LTE_NB_MODE_TAG; + buffer[offset++] = context->nbiotMode; + + /* Data tag immediately preceding PDU */ + buffer[offset++] = MAC_LTE_PAYLOAD_TAG; + return offset; +} + /* Write an individual PDU (PCAP packet header + mac-context + mac-pdu) */ -int LTE_PCAP_MAC_WritePDU(FILE* fd, MAC_Context_Info_t* context, const unsigned char* PDU, unsigned int length) +inline int LTE_PCAP_MAC_WritePDU(FILE* fd, MAC_Context_Info_t* context, const unsigned char* PDU, unsigned int length) { pcaprec_hdr_t packet_header; - char context_header[256]; + uint8_t context_header[PCAP_CONTEXT_HEADER_MAX]; int offset = 0; - uint16_t tmp16; /* Can't write if file wasn't successfully opened */ if (fd == NULL) { @@ -72,46 +122,60 @@ int LTE_PCAP_MAC_WritePDU(FILE* fd, MAC_Context_Info_t* context, const unsigned return 0; } - /*****************************************************************/ - /* Context information (same as written by UDP heuristic clients */ - context_header[offset++] = context->radioType; - context_header[offset++] = context->direction; - context_header[offset++] = context->rntiType; + offset += LTE_PCAP_PACK_MAC_CONTEXT_TO_BUFFER(context, &context_header[offset], PCAP_CONTEXT_HEADER_MAX); - /* RNTI */ - context_header[offset++] = MAC_LTE_RNTI_TAG; - tmp16 = htons(context->rnti); - memcpy(context_header + offset, &tmp16, 2); + /****************************************************************/ + /* PCAP Header */ + struct timeval t; + gettimeofday(&t, NULL); + packet_header.ts_sec = t.tv_sec; + packet_header.ts_usec = t.tv_usec; + packet_header.incl_len = offset + length; + packet_header.orig_len = offset + length; + + /***************************************************************/ + /* Now write everything to the file */ + fwrite(&packet_header, sizeof(pcaprec_hdr_t), 1, fd); + fwrite(context_header, 1, offset, fd); + fwrite(PDU, 1, length, fd); + + return 1; +} + +/* Write an individual PDU (PCAP packet header + mac-context + mac-pdu) */ +inline int +LTE_PCAP_MAC_UDP_WritePDU(FILE* fd, MAC_Context_Info_t* context, const unsigned char* PDU, unsigned int length) +{ + pcaprec_hdr_t packet_header; + uint8_t context_header[PCAP_CONTEXT_HEADER_MAX] = {}; + int offset = 0; + struct udphdr* udp_header; + // uint16_t tmp16; + + /* Can't write if file wasn't successfully opened */ + if (fd == NULL) { + printf("Error: Can't write to empty file handle\n"); + return 0; + } + // Add dummy UDP header, start with src and dest port + udp_header = (struct udphdr*)context_header; + udp_header->dest = htons(0xdead); + offset += 2; + udp_header->source = htons(0xbeef); + offset += 2; + // length to be filled later + udp_header->len = 0x0000; + offset += 2; + // dummy CRC + udp_header->check = 0x0000; offset += 2; - /* UEId */ - context_header[offset++] = MAC_LTE_UEID_TAG; - tmp16 = htons(context->ueid); - memcpy(context_header + offset, &tmp16, 2); - offset += 2; + // Start magic string + memcpy(&context_header[offset], MAC_LTE_START_STRING, strlen(MAC_LTE_START_STRING)); + offset += strlen(MAC_LTE_START_STRING); - /* Subframe Number and System Frame Number */ - /* SFN is stored in 12 MSB and SF in 4 LSB */ - context_header[offset++] = MAC_LTE_FRAME_SUBFRAME_TAG; - tmp16 = (context->sysFrameNumber << 4) | context->subFrameNumber; - tmp16 = htons(tmp16); - memcpy(context_header + offset, &tmp16, 2); - offset += 2; - - /* CRC Status */ - context_header[offset++] = MAC_LTE_CRC_STATUS_TAG; - context_header[offset++] = context->crcStatusOK; - - /* CC index */ - context_header[offset++] = MAC_LTE_CARRIER_ID_TAG; - context_header[offset++] = context->cc_idx; - - /* NB-IoT mode tag */ - context_header[offset++] = MAC_LTE_NB_MODE_TAG; - context_header[offset++] = context->nbiotMode; - - /* Data tag immediately preceding PDU */ - context_header[offset++] = MAC_LTE_PAYLOAD_TAG; + offset += LTE_PCAP_PACK_MAC_CONTEXT_TO_BUFFER(context, &context_header[offset], PCAP_CONTEXT_HEADER_MAX); + udp_header->len = htons(length + offset); /****************************************************************/ /* PCAP Header */ @@ -167,8 +231,8 @@ int LTE_PCAP_NAS_WritePDU(FILE* fd, NAS_Context_Info_t* context, const unsigned int LTE_PCAP_RLC_WritePDU(FILE* fd, RLC_Context_Info_t* context, const unsigned char* PDU, unsigned int length) { pcaprec_hdr_t packet_header; - char context_header[256] = {}; - int offset = 0; + char context_header[PCAP_CONTEXT_HEADER_MAX] = {}; + int offset = 0; uint16_t tmp16; /* Can't write if file wasn't successfully opened */ @@ -280,72 +344,92 @@ int LTE_PCAP_S1AP_WritePDU(FILE* fd, S1AP_Context_Info_t* context, const unsigne /************************************************************************** * API functions for writing MAC-NR PCAP files * **************************************************************************/ +inline int NR_PCAP_PACK_MAC_CONTEXT_TO_BUFFER(mac_nr_context_info_t* context, uint8_t* buffer, unsigned int length) +{ + int offset = 0; + uint16_t tmp16; + + if (buffer == NULL || length < PCAP_CONTEXT_HEADER_MAX) { + printf("Error: Writing buffer null or length to small \n"); + return -1; + } + + /*****************************************************************/ + /* Context information (same as written by UDP heuristic clients */ + buffer[offset++] = context->radioType; + buffer[offset++] = context->direction; + buffer[offset++] = context->rntiType; + + /* RNTI */ + buffer[offset++] = MAC_LTE_RNTI_TAG; + tmp16 = htons(context->rnti); + memcpy(buffer + offset, &tmp16, 2); + offset += 2; + + /* UEId */ + buffer[offset++] = MAC_LTE_UEID_TAG; + tmp16 = htons(context->ueid); + memcpy(buffer + offset, &tmp16, 2); + offset += 2; + + /* HARQID */ + buffer[offset++] = MAC_NR_HARQID; + buffer[offset++] = context->harqid; + + /* PHR Type2 other cell */ + buffer[offset++] = MAC_NR_PHR_TYPE2_OTHERCELL_TAG; + buffer[offset++] = context->phr_type2_othercell; + + /* Subframe Number and System Frame Number */ + /* SFN is stored in 12 MSB and SF in 4 LSB */ + buffer[offset++] = MAC_LTE_FRAME_SUBFRAME_TAG; + tmp16 = (context->system_frame_number << 4) | context->sub_frame_number; + tmp16 = htons(tmp16); + memcpy(buffer + offset, &tmp16, 2); + offset += 2; + + /* Data tag immediately preceding PDU */ + buffer[offset++] = MAC_LTE_PAYLOAD_TAG; + return offset; +} /* Write an individual NR MAC PDU (PCAP packet header + UDP header + nr-mac-context + mac-pdu) */ -int NR_PCAP_MAC_WritePDU(FILE* fd, mac_nr_context_info_t* context, const unsigned char* PDU, unsigned int length) +int NR_PCAP_MAC_UDP_WritePDU(FILE* fd, mac_nr_context_info_t* context, const unsigned char* PDU, unsigned int length) { - char context_header[256] = {}; - int offset = 0; + uint8_t context_header[PCAP_CONTEXT_HEADER_MAX] = {}; + struct udphdr* udp_header; + int offset = 0; /* Can't write if file wasn't successfully opened */ if (fd == NULL) { printf("Error: Can't write to empty file handle\n"); - return 0; + return -1; } // Add dummy UDP header, start with src and dest port - context_header[offset++] = 0xde; - context_header[offset++] = 0xad; - context_header[offset++] = 0xbe; - context_header[offset++] = 0xef; - // length - uint16_t tmp16 = htons(length + 31); - memcpy(context_header + offset, &tmp16, 2); + udp_header = (struct udphdr*)context_header; + udp_header->dest = htons(0xdead); + offset += 2; + udp_header->source = htons(0xbeef); + offset += 2; + // length to be filled later + udp_header->len = 0x0000; offset += 2; // dummy CRC - context_header[offset++] = 0x00; - context_header[offset++] = 0x00; + udp_header->check = 0x0000; + offset += 2; // Start magic string memcpy(&context_header[offset], MAC_NR_START_STRING, strlen(MAC_NR_START_STRING)); offset += strlen(MAC_NR_START_STRING); - /*****************************************************************/ - /* Context information (same as written by UDP heuristic clients */ - context_header[offset++] = context->radioType; - context_header[offset++] = context->direction; - context_header[offset++] = context->rntiType; + offset += NR_PCAP_PACK_MAC_CONTEXT_TO_BUFFER(context, &context_header[offset], PCAP_CONTEXT_HEADER_MAX); - /* RNTI */ - context_header[offset++] = MAC_LTE_RNTI_TAG; - tmp16 = htons(context->rnti); - memcpy(context_header + offset, &tmp16, 2); - offset += 2; + udp_header->len = htons(offset + length); - /* UEId */ - context_header[offset++] = MAC_LTE_UEID_TAG; - tmp16 = htons(context->ueid); - memcpy(context_header + offset, &tmp16, 2); - offset += 2; - - /* HARQID */ - context_header[offset++] = MAC_NR_HARQID; - context_header[offset++] = context->harqid; - - /* PHR Type2 other cell */ - context_header[offset++] = MAC_NR_PHR_TYPE2_OTHERCELL_TAG; - context_header[offset++] = context->phr_type2_othercell; - - /* Subframe Number and System Frame Number */ - /* SFN is stored in 12 MSB and SF in 4 LSB */ - context_header[offset++] = MAC_LTE_FRAME_SUBFRAME_TAG; - tmp16 = (context->system_frame_number << 4) | context->sub_frame_number; - tmp16 = htons(tmp16); - memcpy(context_header + offset, &tmp16, 2); - offset += 2; - - /* Data tag immediately preceding PDU */ - context_header[offset++] = MAC_LTE_PAYLOAD_TAG; + if (offset != 31) { + printf("ERROR Does not match offset %d != 31\n", offset); + } /****************************************************************/ /* PCAP Header */ diff --git a/lib/src/common/thread_pool.cc b/lib/src/common/thread_pool.cc index 749bfa74e..2425de8c4 100644 --- a/lib/src/common/thread_pool.cc +++ b/lib/src/common/thread_pool.cc @@ -20,6 +20,7 @@ */ #include "srslte/common/thread_pool.h" +#include "srslte/srslog/srslog.h" #include #include #include @@ -253,11 +254,11 @@ uint32_t thread_pool::get_nof_workers() * once a worker is available *************************************************************************/ -task_thread_pool::task_thread_pool(uint32_t nof_workers) : running(false) +task_thread_pool::task_thread_pool(uint32_t nof_workers, bool start_deferred, int32_t prio_, uint32_t mask_) : + logger(srslog::fetch_basic_logger("POOL")), workers(std::max(1u, nof_workers)) { - workers.reserve(nof_workers); - for (uint32_t i = 0; i < nof_workers; ++i) { - workers.emplace_back(this, i); + if (not start_deferred) { + start(prio_, mask_); } } @@ -266,12 +267,34 @@ task_thread_pool::~task_thread_pool() stop(); } -void task_thread_pool::start(int32_t prio, uint32_t mask) +void task_thread_pool::set_nof_workers(uint32_t nof_workers) { std::lock_guard lock(queue_mutex); + if (workers.size() > nof_workers) { + logger.error("Reducing the number of workers dynamically not supported"); + return; + } + uint32_t old_size = workers.size(); + workers.resize(nof_workers); + if (running) { + for (uint32_t i = old_size; i < nof_workers; ++i) { + workers[i].reset(new worker_t(this, i)); + } + } +} + +void task_thread_pool::start(int32_t prio_, uint32_t mask_) +{ + std::lock_guard lock(queue_mutex); + if (running) { + logger.error("Starting thread pool that has already started"); + return; + } + prio = prio_; + mask = mask_; running = true; - for (worker_t& w : workers) { - w.setup(prio, mask); + for (uint32_t i = 0; i < workers.size(); ++i) { + workers[i].reset(new worker_t(this, i)); } } @@ -281,8 +304,8 @@ void task_thread_pool::stop() if (running) { running = false; bool workers_running = false; - for (worker_t& w : workers) { - if (w.is_running()) { + for (std::unique_ptr& w : workers) { + if (w->is_running()) { workers_running = true; break; } @@ -291,21 +314,12 @@ void task_thread_pool::stop() if (workers_running) { cv_empty.notify_all(); } - for (worker_t& w : workers) { - w.stop(); + for (std::unique_ptr& w : workers) { + w->stop(); } } } -void task_thread_pool::push_task(const task_t& task) -{ - { - std::lock_guard lock(queue_mutex); - pending_tasks.push(task); - } - cv_empty.notify_one(); -} - void task_thread_pool::push_task(task_t&& task) { { @@ -315,17 +329,20 @@ void task_thread_pool::push_task(task_t&& task) cv_empty.notify_one(); } -uint32_t task_thread_pool::nof_pending_tasks() +uint32_t task_thread_pool::nof_pending_tasks() const { std::lock_guard lock(queue_mutex); return pending_tasks.size(); } task_thread_pool::worker_t::worker_t(srslte::task_thread_pool* parent_, uint32_t my_id) : - parent(parent_), - thread(std::string("TASKWORKER") + std::to_string(my_id)), - id_(my_id) + parent(parent_), thread(std::string("TASKWORKER") + std::to_string(my_id)), id_(my_id), running(true) { + if (parent->mask == 255) { + start(parent->prio); + } else { + start_cpu_mask(parent->prio, parent->mask); + } } void task_thread_pool::worker_t::stop() @@ -333,16 +350,6 @@ void task_thread_pool::worker_t::stop() wait_thread_finish(); } -void task_thread_pool::worker_t::setup(int32_t prio, uint32_t mask) -{ - running = true; - if (mask == 255) { - start(prio); - } else { - start_cpu_mask(prio, mask); - } -} - bool task_thread_pool::worker_t::wait_task(task_t* task) { std::unique_lock lock(parent->queue_mutex); @@ -364,7 +371,7 @@ void task_thread_pool::worker_t::run_thread() // main loop task_t task; while (wait_task(&task)) { - task(id()); + task(); } // on exit, notify pool class @@ -372,4 +379,11 @@ void task_thread_pool::worker_t::run_thread() running = false; } +// Global thread pool for long, low-priority tasks +task_thread_pool& get_background_workers() +{ + static task_thread_pool background_workers; + return background_workers; +} + } // namespace srslte diff --git a/lib/src/mac/pdu.cc b/lib/src/mac/pdu.cc index 5cd4e692f..ad3262a74 100644 --- a/lib/src/mac/pdu.cc +++ b/lib/src/mac/pdu.cc @@ -25,7 +25,11 @@ #include #include "srslte/mac/pdu.h" -#include "srslte/srslte.h" + +extern "C" { +#include "srslte/phy/utils/bit.h" +#include "srslte/phy/utils/vector.h" +} // Table 6.1.3.1-1 Buffer size levels for BSR static uint32_t btable[64] = { @@ -475,7 +479,7 @@ int sch_pdu::get_sdu_space() } else { ret = rem_len - (size_header_sdu(subheaders[last_sdu_idx].get_payload_size()) - 1) - 1; } - ret = SRSLTE_MIN(ret >= 0 ? ret : 0, buffer_tx->get_tailroom()); + ret = std::min(ret >= 0 ? ret : 0u, buffer_tx->get_tailroom()); return ret; } diff --git a/lib/src/phy/ch_estimation/dmrs_pucch.c b/lib/src/phy/ch_estimation/dmrs_pucch.c index 602bbb3b1..0ba5b4c48 100644 --- a/lib/src/phy/ch_estimation/dmrs_pucch.c +++ b/lib/src/phy/ch_estimation/dmrs_pucch.c @@ -298,8 +298,8 @@ static uint32_t dmrs_pucch_format2_cinit(const srslte_carrier_nr_t* car const srslte_slot_cfg_t* slot, uint32_t l) { - uint32_t n = SRSLTE_SLOT_NR_MOD(slot->idx, carrier->numerology); - uint32_t n_id = (cfg->scrambling_id_present) ? cfg->scambling_id : carrier->id; + uint64_t n = slot->idx; + uint64_t n_id = (cfg->scrambling_id_present) ? cfg->scambling_id : carrier->id; return SRSLTE_SEQUENCE_MOD((((SRSLTE_NSYMB_PER_SLOT_NR * n + l + 1UL) * (2UL * n_id + 1UL)) << 17UL) + 2UL * n_id); } diff --git a/lib/src/phy/common/sequence.c b/lib/src/phy/common/sequence.c index 90c68b1d2..4661cd3c3 100644 --- a/lib/src/phy/common/sequence.c +++ b/lib/src/phy/common/sequence.c @@ -46,9 +46,9 @@ /** * Parallel bit generation for x1/x2 sequences parameters. Exploits the fact that the sequence generation is 31 chips - * ahead and the maximum register shift is 3 (for x2). + * ahead and the maximum register shift is 3 (for x2). The maximum number of parallel bits is 28, 16 is optimal for SSE. */ -#define SEQUENCE_PAR_BITS (28U) +#define SEQUENCE_PAR_BITS (24U) #define SEQUENCE_MASK ((1U << SEQUENCE_PAR_BITS) - 1U) /** @@ -151,7 +151,6 @@ static uint32_t sequence_x2_init[SEQUENCE_SEED_LEN] = {}; */ __attribute__((constructor)) __attribute__((unused)) static void srslte_lte_pr_pregen() { - // Compute transition step sequence_x1_init = 1; for (uint32_t n = 0; n < SEQUENCE_NC; n++) { @@ -308,7 +307,6 @@ int srslte_sequence_set_LTE_pr(srslte_sequence_t* q, uint32_t len, uint32_t seed static inline void sequence_generate_signed(const uint8_t* c_unpacked, int8_t* c_char, int16_t* c_short, float* c_float, uint32_t len) { - int i = 0; #ifdef LV_HAVE_SSE @@ -485,7 +483,6 @@ void srslte_sequence_apply_f(const float* in, float* out, uint32_t length, uint3 } for (; i < length; i++) { - ((uint32_t*)out)[i] = ((uint32_t*)in)[i] ^ (((x1 ^ x2) & 1U) << 31U); // Step sequences @@ -496,8 +493,9 @@ void srslte_sequence_apply_f(const float* in, float* out, uint32_t length, uint3 void srslte_sequence_apply_s(const int16_t* in, int16_t* out, uint32_t length, uint32_t seed) { - uint32_t x1 = sequence_x1_init; // X1 initial state is fix - uint32_t x2 = sequence_get_x2_init(seed); // loads x2 initial state + const int16_t s[2] = {+1, -1}; + 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; @@ -529,9 +527,9 @@ void srslte_sequence_apply_s(const int16_t* in, int16_t* out, uint32_t length, u _mm_storeu_si128((__m128i*)(out + i + j), v); } -#endif +#endif // LV_HAVE_SSE for (; j < SEQUENCE_PAR_BITS; j++) { - out[i + j] = in[i + j] * (((c >> j) & 1U) ? -1 : +1); + out[i + j] = in[i + j] * s[(c >> j) & 1U]; } // Step sequences @@ -541,7 +539,7 @@ void srslte_sequence_apply_s(const int16_t* in, int16_t* out, uint32_t length, u } for (; i < length; i++) { - out[i] = in[i] * (((x1 ^ x2) & 1U) ? -1 : +1); + out[i] = in[i] * s[(x1 ^ x2) & 1U]; // Step sequences x1 = sequence_gen_LTE_pr_memless_step_x1(x1); @@ -668,14 +666,11 @@ void srslte_sequence_apply_bit(const uint8_t* in, uint8_t* out, uint32_t length, } } -void srslte_sequence_apply_bit_packed(const uint8_t* in, uint8_t* out, uint32_t length, uint32_t seed) +void srslte_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 uint32_t x2 = sequence_get_x2_init(seed); // loads x2 initial state - uint64_t buffer = 0; - uint32_t count = 0; - const uint8_t reverse_lut[256] = { 0b00000000, 0b10000000, 0b01000000, 0b11000000, 0b00100000, 0b10100000, 0b01100000, 0b11100000, 0b00010000, 0b10010000, 0b01010000, 0b11010000, 0b00110000, 0b10110000, 0b01110000, 0b11110000, 0b00001000, 0b10001000, @@ -708,7 +703,12 @@ void srslte_sequence_apply_bit_packed(const uint8_t* in, uint8_t* out, uint32_t 0b00111111, 0b10111111, 0b01111111, 0b11111111, }; - for (uint32_t i = 0; i < length / 8; i++) { + uint32_t i = 0; +#if SEQUENCE_PAR_BITS % 8 != 0 + uint64_t buffer = 0; + uint32_t count = 0; + + for (; i < length / 8; i++) { // Generate sequence bits while (count < 8) { uint32_t c = (uint32_t)(x1 ^ x2); @@ -727,4 +727,52 @@ void srslte_sequence_apply_bit_packed(const uint8_t* in, uint8_t* out, uint32_t buffer = buffer >> 8UL; count -= 8; } + + // Process spare bits + uint32_t rem8 = length % 8; + if (rem8 != 0) { + // Generate sequence bits + while (count < rem8) { + uint32_t c = (uint32_t)(x1 ^ x2); + buffer = buffer | ((SEQUENCE_MASK & c) << count); + + // Step sequences + x1 = sequence_gen_LTE_pr_memless_step_par_x1(x1); + x2 = sequence_gen_LTE_pr_memless_step_par_x2(x2); + + // Increase count + count += SEQUENCE_PAR_BITS; + } + + out[i] = in[i] ^ reverse_lut[buffer & ((1U << rem8) - 1U) & 255U]; + } +#else // SEQUENCE_PAR_BITS % 8 == 0 + while (i < (length / 8 - (SEQUENCE_PAR_BITS - 1) / 8)) { + uint32_t c = (uint32_t)(x1 ^ x2); + + for (uint32_t j = 0; j < SEQUENCE_PAR_BITS / 8; j++) { + out[i] = in[i] ^ reverse_lut[c & 255U]; + c = c >> 8U; + i++; + } + + // Step sequences + x1 = sequence_gen_LTE_pr_memless_step_par_x1(x1); + x2 = sequence_gen_LTE_pr_memless_step_par_x2(x2); + } + + // Process spare bytes + uint32_t c = (uint32_t)(x1 ^ x2); + while (i < length / 8) { + out[i] = in[i] ^ reverse_lut[c & 255U]; + c = c >> 8U; + i++; + } + + // Process spare bits + uint32_t rem8 = length % 8; + if (rem8 != 0) { + out[i] = in[i] ^ reverse_lut[c & ((1U << rem8) - 1U) & 255U]; + } +#endif // SEQUENCE_PAR_BITS % 8 == 0 } diff --git a/lib/src/phy/common/test/sequence_test.c b/lib/src/phy/common/test/sequence_test.c index 44ef84ec1..0e3e5bc94 100644 --- a/lib/src/phy/common/test/sequence_test.c +++ b/lib/src/phy/common/test/sequence_test.c @@ -40,7 +40,7 @@ static uint8_t c_unpacked[MAX_SEQ_LEN]; static float ones_float[Nc + MAX_SEQ_LEN + 31]; static int16_t ones_short[Nc + MAX_SEQ_LEN + 31]; static int8_t ones_char[Nc + MAX_SEQ_LEN + 31]; -static uint8_t ones_packed[MAX_SEQ_LEN / 8]; +static uint8_t ones_packed[(MAX_SEQ_LEN * 7) / 8]; static uint8_t ones_unpacked[MAX_SEQ_LEN]; static int test_sequence(srslte_sequence_t* sequence, uint32_t seed, uint32_t length, uint32_t repetitions) @@ -152,7 +152,7 @@ static int test_sequence(srslte_sequence_t* sequence, uint32_t seed, uint32_t le // Test in-place packed XOR gettimeofday(&t[1], NULL); for (uint32_t r = 0; r < repetitions; r++) { - srslte_sequence_apply_bit_packed(ones_packed, c_packed, length, seed); + srslte_sequence_apply_packed(ones_packed, c_packed, length, seed); } gettimeofday(&t[2], NULL); get_time_interval(t); @@ -163,12 +163,12 @@ static int test_sequence(srslte_sequence_t* sequence, uint32_t seed, uint32_t le ret = SRSLTE_ERROR; } - if (memcmp(c_packed_gold, sequence->c_bytes, length / 8) != 0) { + if (memcmp(c_packed_gold, sequence->c_bytes, (length + 7) / 8) != 0) { ERROR("Unmatched c_packed"); ret = SRSLTE_ERROR; } - if (memcmp(c_packed_gold, c_packed, length / 8) != 0) { + if (memcmp(c_packed_gold, c_packed, (length + 7) / 8) != 0) { ERROR("Unmatched c_packed"); ret = SRSLTE_ERROR; } @@ -207,7 +207,7 @@ int main(int argc, char** argv) ones_short[i] = 1; ones_char[i] = 1; ones_unpacked[i] = 0; - if (i < MAX_SEQ_LEN / 8) { + if (i < (MAX_SEQ_LEN * 7) / 8) { ones_packed[i] = 0; } } diff --git a/lib/src/phy/enb/enb_dl.c b/lib/src/phy/enb/enb_dl.c index d12d00bb6..bfcbb729e 100644 --- a/lib/src/phy/enb/enb_dl.c +++ b/lib/src/phy/enb/enb_dl.c @@ -232,16 +232,6 @@ int srslte_enb_dl_set_cell(srslte_enb_dl_t* q, srslte_cell_t cell) return ret; } -int srslte_enb_dl_add_rnti(srslte_enb_dl_t* q, uint16_t rnti) -{ - return srslte_pdsch_set_rnti(&q->pdsch, rnti); -} - -void srslte_enb_dl_rem_rnti(srslte_enb_dl_t* q, uint16_t rnti) -{ - srslte_pdsch_free_rnti(&q->pdsch, rnti); -} - #ifdef resolve void srslte_enb_dl_apply_power_allocation(srslte_enb_dl_t* q) { diff --git a/lib/src/phy/enb/enb_ul.c b/lib/src/phy/enb/enb_ul.c index 81c4e4262..a81d63f61 100644 --- a/lib/src/phy/enb/enb_ul.c +++ b/lib/src/phy/enb/enb_ul.c @@ -148,25 +148,6 @@ int srslte_enb_ul_set_cell(srslte_enb_ul_t* q, return ret; } -int srslte_enb_ul_add_rnti(srslte_enb_ul_t* q, uint16_t rnti) -{ - if (srslte_pucch_set_rnti(&q->pucch, rnti)) { - ERROR("Error setting PUCCH rnti"); - return -1; - } - if (srslte_pusch_set_rnti(&q->pusch, rnti)) { - ERROR("Error setting PUSCH rnti"); - return -1; - } - return 0; -} - -void srslte_enb_ul_rem_rnti(srslte_enb_ul_t* q, uint16_t rnti) -{ - srslte_pucch_free_rnti(&q->pucch, rnti); - srslte_pusch_free_rnti(&q->pusch, rnti); -} - void srslte_enb_ul_fft(srslte_enb_ul_t* q) { srslte_ofdm_rx_sf(&q->fft); diff --git a/lib/src/phy/fec/ldpc/ldpc_dec_c_avx512.c b/lib/src/phy/fec/ldpc/ldpc_dec_c_avx512.c index 4dc8ad351..1ee8562c4 100644 --- a/lib/src/phy/fec/ldpc/ldpc_dec_c_avx512.c +++ b/lib/src/phy/fec/ldpc/ldpc_dec_c_avx512.c @@ -63,8 +63,8 @@ static const int8_t infinity7 = (1U << 6U) - 1; * \brief Represents a node of the base factor graph. */ typedef union bg_node_avx512_t { - int8_t c[SRSLTE_AVX512_B_SIZE]; /*!< Each base node may contain up to \ref SRSLTE_AVX512_B_SIZE lifted nodes. */ - __m512i v; /*!< All the lifted nodes of the current base node as a 512-bit line. */ + int8_t* c; /*!< Each base node may contain up to \ref SRSLTE_AVX512_B_SIZE lifted nodes. */ + __m512i* v; /*!< All the lifted nodes of the current base node as a 512-bit line. */ } bg_node_avx512_t; /*! @@ -73,11 +73,11 @@ typedef union bg_node_avx512_t { struct ldpc_regs_c_avx512 { __m512i scaling_fctr; /*!< \brief Scaling factor for the normalized min-sum decoding algorithm. */ - bg_node_avx512_t* soft_bits; /*!< \brief A-posteriori log-likelihood ratios. */ - __m512i* check_to_var; /*!< \brief Check-to-variable messages. */ - __m512i* var_to_check; /*!< \brief Variable-to-check messages. */ - __m512i* var_to_check_to_free; /*!< \brief the Variable-to-check messages with one extra _mm512 allocated space. */ - __m512i* rotated_v2c; /*!< \brief To store a rotated version of the variable-to-check messages. */ + bg_node_avx512_t soft_bits; /*!< \brief A-posteriori log-likelihood ratios. */ + __m512i* check_to_var; /*!< \brief Check-to-variable messages. */ + __m512i* var_to_check; /*!< \brief Variable-to-check messages. */ + __m512i* var_to_check_to_free; /*!< \brief the Variable-to-check messages with one extra _mm512 allocated space. */ + __m512i* rotated_v2c; /*!< \brief To store a rotated version of the variable-to-check messages. */ __m512i* this_c2v_epi8; /*!< \brief Helper register for the current c2v node. */ __m512i* this_c2v_epi8_to_free; /*!< \brief Helper register for the current c2v node with one extra __m512 allocated @@ -132,43 +132,34 @@ void* create_ldpc_dec_c_avx512(uint8_t bgN, uint8_t bgM, uint16_t ls, float scal uint8_t bgK = bgN - bgM; uint16_t hrr = bgK + 4; - if ((vp = srslte_vec_malloc(sizeof(struct ldpc_regs_c_avx512))) == NULL) { + if ((vp = SRSLTE_MEM_ALLOC(struct ldpc_regs_c_avx512, 1)) == NULL) { + return NULL; + } + SRSLTE_MEM_ZERO(vp, struct ldpc_regs_c_avx512, 1); + + if ((vp->soft_bits.v = SRSLTE_MEM_ALLOC(__m512i, bgN)) == NULL) { + delete_ldpc_dec_c_avx512(vp); return NULL; } - if ((vp->soft_bits = srslte_vec_malloc(bgN * sizeof(bg_node_avx512_t))) == NULL) { - free(vp); + if ((vp->check_to_var = SRSLTE_MEM_ALLOC(__m512i, (hrr + 1) * bgM)) == NULL) { + delete_ldpc_dec_c_avx512(vp); return NULL; } - if ((vp->check_to_var = srslte_vec_malloc((hrr + 1) * bgM * sizeof(__m512i))) == NULL) { - free(vp->soft_bits); - free(vp); - return NULL; - } - - if ((vp->var_to_check_to_free = srslte_vec_malloc(((hrr + 1) + 2) * sizeof(__m512i))) == NULL) { - free(vp->check_to_var); - free(vp->soft_bits); - free(vp); + if ((vp->var_to_check_to_free = SRSLTE_MEM_ALLOC(__m512i, (hrr + 1) + 2)) == NULL) { + delete_ldpc_dec_c_avx512(vp); return NULL; } vp->var_to_check = &vp->var_to_check_to_free[1]; - if ((vp->rotated_v2c = srslte_vec_malloc((hrr + 1) * sizeof(__m512i))) == NULL) { - free(vp->var_to_check_to_free); - free(vp->check_to_var); - free(vp->soft_bits); - free(vp); + if ((vp->rotated_v2c = SRSLTE_MEM_ALLOC(__m512i, hrr + 1)) == NULL) { + delete_ldpc_dec_c_avx512(vp); return NULL; } - if ((vp->this_c2v_epi8_to_free = srslte_vec_malloc((1 + 2) * sizeof(__m512i))) == NULL) { - free(vp->rotated_v2c); - free(vp->var_to_check_to_free); - free(vp->check_to_var); - free(vp->soft_bits); - free(vp); + if ((vp->this_c2v_epi8_to_free = SRSLTE_MEM_ALLOC(__m512i, 1 + 2)) == NULL) { + delete_ldpc_dec_c_avx512(vp); return NULL; } vp->this_c2v_epi8 = @@ -190,14 +181,25 @@ void delete_ldpc_dec_c_avx512(void* p) { struct ldpc_regs_c_avx512* vp = p; - if (vp != NULL) { - free(vp->this_c2v_epi8_to_free); - free(vp->rotated_v2c); - free(vp->var_to_check_to_free); - free(vp->check_to_var); - free(vp->soft_bits); - free(vp); + if (vp == NULL) { + return; } + if (vp->this_c2v_epi8_to_free) { + free(vp->this_c2v_epi8_to_free); + } + if (vp->rotated_v2c) { + free(vp->rotated_v2c); + } + if (vp->var_to_check_to_free) { + free(vp->var_to_check_to_free); + } + if (vp->check_to_var) { + free(vp->check_to_var); + } + if (vp->soft_bits.v) { + free(vp->soft_bits.v); + } + free(vp); } int init_ldpc_dec_c_avx512(void* p, const int8_t* llrs, uint16_t ls) @@ -213,19 +215,19 @@ int init_ldpc_dec_c_avx512(void* p, const int8_t* llrs, uint16_t ls) // First 2 punctured bits int ini = SRSLTE_AVX512_B_SIZE + SRSLTE_AVX512_B_SIZE; - bzero(vp->soft_bits->c, ini); + srslte_vec_i8_zero(vp->soft_bits.c, ini); for (i = 0; i < vp->finalN; i = i + ls) { for (k = 0; k < ls; k++) { - vp->soft_bits->c[ini + k] = llrs[i + k]; + vp->soft_bits.c[ini + k] = llrs[i + k]; } // this might be removed - bzero(&vp->soft_bits->c[ini + ls], (SRSLTE_AVX512_B_SIZE - ls) * sizeof(int8_t)); + srslte_vec_i8_zero(&vp->soft_bits.c[ini + ls], SRSLTE_AVX512_B_SIZE - ls); ini = ini + SRSLTE_AVX512_B_SIZE; } - bzero(vp->check_to_var, (vp->hrr + 1) * vp->bgM * sizeof(__m512i)); - bzero(vp->var_to_check, (vp->hrr + 1) * sizeof(__m512i)); + SRSLTE_MEM_ZERO(vp->check_to_var, __m512i, (vp->hrr + 1) * vp->bgM); + SRSLTE_MEM_ZERO(vp->var_to_check, __m512i, vp->hrr + 1); return 0; } @@ -240,7 +242,7 @@ int extract_ldpc_message_c_avx512(void* p, uint8_t* message, uint16_t liftK) int ini = 0; for (int i = 0; i < liftK; i = i + vp->ls) { for (int k = 0; k < vp->ls; k++) { - message[i + k] = (vp->soft_bits->c[ini + k] < 0); + message[i + k] = (vp->soft_bits.c[ini + k] < 0); } ini = ini + SRSLTE_AVX512_B_SIZE; } @@ -259,15 +261,12 @@ int update_ldpc_var_to_check_c_avx512(void* p, int i_layer) __m512i* this_check_to_var = vp->check_to_var + i_layer * (vp->hrr + 1); // Update the high-rate region. - inner_var_to_check_c_avx512(&(vp->soft_bits[0].v), this_check_to_var, vp->var_to_check, infinity7, vp->hrr); + inner_var_to_check_c_avx512(vp->soft_bits.v, this_check_to_var, vp->var_to_check, infinity7, vp->hrr); if (i_layer >= 4) { // Update the extension region. - inner_var_to_check_c_avx512(&(vp->soft_bits[0].v) + vp->hrr + i_layer - 4, - this_check_to_var + vp->hrr, - vp->var_to_check + vp->hrr, - infinity7, - 1); + inner_var_to_check_c_avx512( + vp->soft_bits.v + vp->hrr + i_layer - 4, this_check_to_var + vp->hrr, vp->var_to_check + vp->hrr, infinity7, 1); } return 0; @@ -391,7 +390,7 @@ int update_ldpc_soft_bits_c_avx512(void* p, int i_layer, const int8_t (*these_va mask_epi8 = _mm512_cmpgt_epi8_mask(_mm512_neg_infty7_epi8, tmp_epi8); - vp->soft_bits[current_var_index].v = _mm512_mask_blend_epi8(mask_epi8, tmp_epi8, _mm512_neg_infty8_epi8); + vp->soft_bits.v[current_var_index] = _mm512_mask_blend_epi8(mask_epi8, tmp_epi8, _mm512_neg_infty8_epi8); current_var_index = (*these_var_indices)[i + 1]; } diff --git a/lib/src/phy/fec/ldpc/ldpc_enc_avx2.c b/lib/src/phy/fec/ldpc/ldpc_enc_avx2.c index 774b295d7..9af2f23fc 100644 --- a/lib/src/phy/fec/ldpc/ldpc_enc_avx2.c +++ b/lib/src/phy/fec/ldpc/ldpc_enc_avx2.c @@ -48,16 +48,16 @@ * \brief Represents a node of the base factor graph. */ typedef union bg_node_t { - uint8_t c[SRSLTE_AVX2_B_SIZE]; /*!< Each base node may contain up to \ref SRSLTE_AVX2_B_SIZE lifted nodes. */ - __m256i v; /*!< All the lifted nodes of the current base node as a 256-bit line. */ + uint8_t* c; /*!< Each base node may contain up to \ref SRSLTE_AVX2_B_SIZE lifted nodes. */ + __m256i* v; /*!< All the lifted nodes of the current base node as a 256-bit line. */ } bg_node_t; /*! * \brief Inner registers for the optimized LDPC encoder. */ struct ldpc_enc_avx2 { - bg_node_t* codeword; /*!< \brief Contains the entire codeword, before puncturing. */ - __m256i* aux; /*!< \brief Auxiliary register. */ + bg_node_t codeword; /*!< \brief Contains the entire codeword, before puncturing. */ + __m256i* aux; /*!< \brief Auxiliary register. */ }; /*! @@ -104,18 +104,17 @@ void* create_ldpc_enc_avx2(srslte_ldpc_encoder_t* q) { struct ldpc_enc_avx2* vp = NULL; - if ((vp = malloc(sizeof(struct ldpc_enc_avx2))) == NULL) { + if ((vp = SRSLTE_MEM_ALLOC(struct ldpc_enc_avx2, 1)) == NULL) { return NULL; } - if ((vp->codeword = srslte_vec_malloc(q->bgN * sizeof(bg_node_t))) == NULL) { - free(vp); + if ((vp->codeword.v = SRSLTE_MEM_ALLOC(__m256i, q->bgN)) == NULL) { + delete_ldpc_enc_avx2(vp); return NULL; } - if ((vp->aux = srslte_vec_malloc(q->bgM * sizeof(__m256i))) == NULL) { - free(vp->codeword); - free(vp); + if ((vp->aux = SRSLTE_MEM_ALLOC(__m256i, q->bgM)) == NULL) { + delete_ldpc_enc_avx2(vp); return NULL; } @@ -126,11 +125,16 @@ void delete_ldpc_enc_avx2(void* p) { struct ldpc_enc_avx2* vp = p; - if (vp != NULL) { - free(vp->aux); - free(vp->codeword); - free(vp); + if (vp == NULL) { + return; } + if (vp->aux) { + free(vp->aux); + } + if (vp->codeword.v) { + free(vp->codeword.v); + } + free(vp); } int load_avx2(void* p, const uint8_t* input, const uint8_t msg_len, const uint8_t cdwd_len, const uint16_t ls) @@ -145,14 +149,14 @@ int load_avx2(void* p, const uint8_t* input, const uint8_t msg_len, const uint8_ int node_size = SRSLTE_AVX2_B_SIZE; for (int i = 0; i < msg_len * ls; i = i + ls) { for (int k = 0; k < ls; k++) { - vp->codeword->c[ini + k] = input[i + k]; + vp->codeword.c[ini + k] = input[i + k]; } // this zero padding can be removed - bzero(&(vp->codeword->c[ini + ls]), (node_size - ls) * sizeof(uint8_t)); + srslte_vec_u8_zero(&vp->codeword.c[ini + ls], node_size - ls); ini = ini + node_size; } - bzero(vp->codeword + msg_len, (cdwd_len - msg_len) * sizeof(__m256i)); + SRSLTE_MEM_ZERO(vp->codeword.v + msg_len, __m256i, cdwd_len - msg_len); return 0; } @@ -168,7 +172,7 @@ int return_codeword_avx2(void* p, uint8_t* output, const uint8_t cdwd_len, const int ini = SRSLTE_AVX2_B_SIZE + SRSLTE_AVX2_B_SIZE; for (int i = 0; i < (cdwd_len - 2) * ls; i = i + ls) { for (int k = 0; k < ls; k++) { - output[i + k] = vp->codeword->c[ini + k]; + output[i + k] = vp->codeword.c[ini + k]; } ini = ini + SRSLTE_AVX2_B_SIZE; } @@ -193,14 +197,14 @@ void encode_ext_region_avx2(srslte_ldpc_encoder_t* q, uint8_t n_layers) skip = q->bgK + m; // the systematic part has already been computed - vp->codeword[skip].v = vp->aux[m]; + vp->codeword.v[skip] = vp->aux[m]; // sum the contribution due to the high-rate region, with the proper circular shifts for (k = 0; k < 4; k++) { this_shift = q->pcm + q->bgK + k + m * q->bgN; if (*this_shift != NO_CNCT) { - tmp_epi8 = rotate_node_right(vp->codeword[q->bgK + k].v, *this_shift, q->ls); - vp->codeword[skip].v = _mm256_xor_si256(vp->codeword[skip].v, tmp_epi8); + tmp_epi8 = rotate_node_right(vp->codeword.v[q->bgK + k], *this_shift, q->ls); + vp->codeword.v[skip] = _mm256_xor_si256(vp->codeword.v[skip], tmp_epi8); } } } @@ -237,7 +241,7 @@ void preprocess_systematic_bits_avx2(srslte_ldpc_encoder_t* q) // xor array aux[m] with a circularly shifted version of the current input chunk, unless // the current check node and variable node are not connected. if (*this_shift != NO_CNCT) { - tmp_epi8 = rotate_node_right(vp->codeword[k].v, *this_shift, ls); + tmp_epi8 = rotate_node_right(vp->codeword.v[k], *this_shift, ls); tmp_epi8 = _mm256_and_si256(tmp_epi8, one_epi8); vp->aux[m] = _mm256_xor_si256(vp->aux[m], tmp_epi8); } @@ -258,17 +262,17 @@ void encode_high_rate_case1_avx2(void* o) int skip3 = q->bgK + 3; // first chunk of parity bits - vp->codeword[skip0].v = _mm256_xor_si256(vp->aux[0], vp->aux[1]); - vp->codeword[skip0].v = _mm256_xor_si256(vp->codeword[skip0].v, vp->aux[2]); - vp->codeword[skip0].v = _mm256_xor_si256(vp->codeword[skip0].v, vp->aux[3]); + vp->codeword.v[skip0] = _mm256_xor_si256(vp->aux[0], vp->aux[1]); + vp->codeword.v[skip0] = _mm256_xor_si256(vp->codeword.v[skip0], vp->aux[2]); + vp->codeword.v[skip0] = _mm256_xor_si256(vp->codeword.v[skip0], vp->aux[3]); - __m256i tmp_epi8 = rotate_node_right(vp->codeword[skip0].v, 1, ls); + __m256i tmp_epi8 = rotate_node_right(vp->codeword.v[skip0], 1, ls); // second chunk of parity bits - vp->codeword[skip1].v = _mm256_xor_si256(vp->aux[0], tmp_epi8); + vp->codeword.v[skip1] = _mm256_xor_si256(vp->aux[0], tmp_epi8); // fourth chunk of parity bits - vp->codeword[skip3].v = _mm256_xor_si256(vp->aux[3], tmp_epi8); + vp->codeword.v[skip3] = _mm256_xor_si256(vp->aux[3], tmp_epi8); // third chunk of parity bits - vp->codeword[skip2].v = _mm256_xor_si256(vp->aux[2], vp->codeword[skip3].v); + vp->codeword.v[skip2] = _mm256_xor_si256(vp->aux[2], vp->codeword.v[skip3]); } void encode_high_rate_case2_avx2(void* o) @@ -287,14 +291,14 @@ void encode_high_rate_case2_avx2(void* o) __m256i tmp_epi8 = _mm256_xor_si256(vp->aux[0], vp->aux[1]); tmp_epi8 = _mm256_xor_si256(tmp_epi8, vp->aux[2]); tmp_epi8 = _mm256_xor_si256(tmp_epi8, vp->aux[3]); - vp->codeword[skip0].v = rotate_node_left(tmp_epi8, 105 % ls, ls); + vp->codeword.v[skip0] = rotate_node_left(tmp_epi8, 105 % ls, ls); // second chunk of parity bits - vp->codeword[skip1].v = _mm256_xor_si256(vp->aux[0], vp->codeword[skip0].v); + vp->codeword.v[skip1] = _mm256_xor_si256(vp->aux[0], vp->codeword.v[skip0]); // fourth chunk of parity bits - vp->codeword[skip3].v = _mm256_xor_si256(vp->aux[3], vp->codeword[skip0].v); + vp->codeword.v[skip3] = _mm256_xor_si256(vp->aux[3], vp->codeword.v[skip0]); // third chunk of parity bits - vp->codeword[skip2].v = _mm256_xor_si256(vp->aux[2], vp->codeword[skip3].v); + vp->codeword.v[skip2] = _mm256_xor_si256(vp->aux[2], vp->codeword.v[skip3]); } void encode_high_rate_case3_avx2(void* o) @@ -313,14 +317,14 @@ void encode_high_rate_case3_avx2(void* o) __m256i tmp_epi8 = _mm256_xor_si256(vp->aux[0], vp->aux[1]); tmp_epi8 = _mm256_xor_si256(tmp_epi8, vp->aux[2]); tmp_epi8 = _mm256_xor_si256(tmp_epi8, vp->aux[3]); - vp->codeword[skip0].v = rotate_node_left(tmp_epi8, 1, ls); + vp->codeword.v[skip0] = rotate_node_left(tmp_epi8, 1, ls); // second chunk of parity bits - vp->codeword[skip1].v = _mm256_xor_si256(vp->aux[0], vp->codeword[skip0].v); + vp->codeword.v[skip1] = _mm256_xor_si256(vp->aux[0], vp->codeword.v[skip0]); // third chunk of parity bits - vp->codeword[skip2].v = _mm256_xor_si256(vp->aux[1], vp->codeword[skip1].v); + vp->codeword.v[skip2] = _mm256_xor_si256(vp->aux[1], vp->codeword.v[skip1]); // fourth chunk of parity bits - vp->codeword[skip3].v = _mm256_xor_si256(vp->aux[3], vp->codeword[skip0].v); + vp->codeword.v[skip3] = _mm256_xor_si256(vp->aux[3], vp->codeword.v[skip0]); } void encode_high_rate_case4_avx2(void* o) @@ -336,17 +340,17 @@ void encode_high_rate_case4_avx2(void* o) int skip3 = q->bgK + 3; // first chunk of parity bits - vp->codeword[skip0].v = _mm256_xor_si256(vp->aux[0], vp->aux[1]); - vp->codeword[skip0].v = _mm256_xor_si256(vp->codeword[skip0].v, vp->aux[2]); - vp->codeword[skip0].v = _mm256_xor_si256(vp->codeword[skip0].v, vp->aux[3]); + vp->codeword.v[skip0] = _mm256_xor_si256(vp->aux[0], vp->aux[1]); + vp->codeword.v[skip0] = _mm256_xor_si256(vp->codeword.v[skip0], vp->aux[2]); + vp->codeword.v[skip0] = _mm256_xor_si256(vp->codeword.v[skip0], vp->aux[3]); - __m256i tmp_epi8 = rotate_node_right(vp->codeword[skip0].v, 1, ls); + __m256i tmp_epi8 = rotate_node_right(vp->codeword.v[skip0], 1, ls); // second chunk of parity bits - vp->codeword[skip1].v = _mm256_xor_si256(vp->aux[0], tmp_epi8); + vp->codeword.v[skip1] = _mm256_xor_si256(vp->aux[0], tmp_epi8); // third chunk of parity bits - vp->codeword[skip2].v = _mm256_xor_si256(vp->aux[1], vp->codeword[skip1].v); + vp->codeword.v[skip2] = _mm256_xor_si256(vp->aux[1], vp->codeword.v[skip1]); // fourth chunk of parity bits - vp->codeword[skip3].v = _mm256_xor_si256(vp->aux[3], tmp_epi8); + vp->codeword.v[skip3] = _mm256_xor_si256(vp->aux[3], tmp_epi8); } static __m256i _mm256_rotatelli_si256(__m256i a, int imm) diff --git a/lib/src/phy/phch/csi.c b/lib/src/phy/phch/csi.c new file mode 100644 index 000000000..7b426da71 --- /dev/null +++ b/lib/src/phy/phch/csi.c @@ -0,0 +1,221 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2020 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 "srslte/phy/phch/csi.h" +#include "srslte/phy/utils/bit.h" +#include "srslte/phy/utils/debug.h" +#include + +#define CSI_WIDEBAND_CSI_NOF_BITS 4 + +/// Implements SNRI to CQI conversion +uint32_t csi_snri_db_to_cqi(srslte_csi_cqi_table_t table, float snri_db) +{ + return 6; +} + +// Implements CSI report triggers +static bool csi_report_trigger(const srslte_csi_hl_report_cfg_t* cfg, uint32_t slot_idx) +{ + switch (cfg->type) { + case SRSLTE_CSI_REPORT_TYPE_PERIODIC: + return (slot_idx + cfg->periodic.period - cfg->periodic.offset) % cfg->periodic.period == 0; + default:; // Do nothing + } + return false; +} + +static void csi_wideband_cri_ri_pmi_cqi_quantify(const srslte_csi_hl_report_cfg_t* cfg, + const srslte_csi_measurements_t* channel_meas, + const srslte_csi_measurements_t* interf_meas, + srslte_csi_report_cfg_t* report_cfg, + srslte_csi_report_value_t* report_value) +{ + // Take SNR by default + float wideband_sinr_db = channel_meas->wideband_snr_db; + + // If interference is provided, use the channel RSRP and interference EPRE to calculate the SINR + if (interf_meas != NULL) { + wideband_sinr_db = channel_meas->wideband_rsrp_dBm - interf_meas->wideband_epre_dBm; + } + + // Fill report configuration + report_cfg->type = cfg->type; + report_cfg->quantity = SRSLTE_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI; + report_cfg->freq_cfg = SRSLTE_CSI_REPORT_FREQ_WIDEBAND; + report_cfg->nof_ports = channel_meas->nof_ports; + report_cfg->K_csi_rs = channel_meas->K_csi_rs; + + // Save PUCCH resource only if periodic type + if (cfg->type == SRSLTE_CSI_REPORT_TYPE_PERIODIC) { + report_cfg->pucch_resource = cfg->periodic.resource; + } + + // Fill quantified values + report_value->wideband_cri_ri_pmi_cqi.cqi = csi_snri_db_to_cqi(cfg->cqi_table, wideband_sinr_db); + report_value->wideband_cri_ri_pmi_cqi.ri = 0; + report_value->wideband_cri_ri_pmi_cqi.pmi = 0; +} + +static uint32_t csi_wideband_cri_ri_pmi_cqi_nof_bits(const srslte_csi_report_cfg_t* cfg) +{ + // Compute number of bits for CRI + uint32_t nof_bits_cri = 0; + if (cfg->K_csi_rs > 0) { + nof_bits_cri = (uint32_t)ceilf(log2f((float)cfg->K_csi_rs)); + } + + switch (cfg->nof_ports) { + case 1: + return CSI_WIDEBAND_CSI_NOF_BITS + nof_bits_cri; + default: + ERROR("Invalid or not implemented number of ports (%d)", cfg->nof_ports); + } + return 0; +} + +static int csi_wideband_cri_ri_pmi_cqi_pack(const srslte_csi_report_cfg_t* cfg, + const srslte_csi_report_value_t* value, + uint8_t* o_csi1) +{ + // Compute number of bits for CRI + uint32_t nof_bits_cri = 0; + if (cfg->K_csi_rs > 0) { + nof_bits_cri = (uint32_t)ceilf(log2f((float)cfg->K_csi_rs)); + } + + // Write wideband CQI + srslte_bit_unpack(value->wideband_cri_ri_pmi_cqi.cqi, &o_csi1, CSI_WIDEBAND_CSI_NOF_BITS); + + // Compute number of bits for CRI and write + srslte_bit_unpack(value->cri, &o_csi1, nof_bits_cri); + + return nof_bits_cri + CSI_WIDEBAND_CSI_NOF_BITS; +} + +int srslte_csi_generate_reports(const srslte_csi_hl_cfg_t* cfg, + uint32_t slot_idx, + const srslte_csi_measurements_t measurements[SRSLTE_CSI_MAX_NOF_RESOURCES], + srslte_csi_report_cfg_t report_cfg[SRSLTE_CSI_MAX_NOF_REPORT], + srslte_csi_report_value_t report_value[SRSLTE_CSI_MAX_NOF_REPORT]) +{ + uint32_t count = 0; + + // Check inputs + if (cfg == NULL || measurements == NULL || report_cfg == NULL || report_value == NULL) { + return SRSLTE_ERROR_INVALID_INPUTS; + } + + // Iterate every possible configured CSI report + for (uint32_t i = 0; i < SRSLTE_CSI_MAX_NOF_REPORT; i++) { + // Skip if report is not configured or triggered + if (!csi_report_trigger(&cfg->reports[i], slot_idx)) { + continue; + } + + // Select channel measurement + if (cfg->reports->channel_meas_id >= SRSLTE_CSI_MAX_NOF_RESOURCES) { + ERROR("Channel measurement ID (%d) is out of range", cfg->reports->channel_meas_id); + return SRSLTE_ERROR; + } + const srslte_csi_measurements_t* channel_meas = &measurements[cfg->reports->channel_meas_id]; + + // Select interference measurement + const srslte_csi_measurements_t* interf_meas = NULL; + if (cfg->reports->interf_meas_present) { + if (cfg->reports->interf_meas_id >= SRSLTE_CSI_MAX_NOF_RESOURCES) { + ERROR("Interference measurement ID (%d) is out of range", cfg->reports->interf_meas_id); + return SRSLTE_ERROR; + } + interf_meas = &measurements[cfg->reports->interf_meas_id]; + } + + // Quantify measurements according to frequency and quantity configuration + if (cfg->reports->freq_cfg == SRSLTE_CSI_REPORT_FREQ_WIDEBAND && + cfg->reports->quantity == SRSLTE_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI) { + csi_wideband_cri_ri_pmi_cqi_quantify( + &cfg->reports[i], channel_meas, interf_meas, &report_cfg[count], &report_value[count]); + count++; + } else { + ; // Ignore other types + } + } + + return (int)count; +} + +int srslte_csi_nof_bits(const srslte_csi_report_cfg_t* report_list, uint32_t nof_reports) +{ + uint32_t count = 0; + + // Check input pointer + if (report_list == NULL) { + return SRSLTE_ERROR_INVALID_INPUTS; + } + + // Iterate all report configurations + for (uint32_t i = 0; i < nof_reports; i++) { + const srslte_csi_report_cfg_t* report = &report_list[i]; + if (report->quantity && report->quantity == SRSLTE_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI) { + count += csi_wideband_cri_ri_pmi_cqi_nof_bits(report); + } + } + + return (int)count; +} + +int srslte_csi_part1_pack(const srslte_csi_report_cfg_t* report_cfg, + const srslte_csi_report_value_t* report_value, + uint32_t nof_reports, + uint8_t* o_csi1, + uint32_t max_o_csi1) +{ + uint32_t count = 0; + + if (report_cfg == NULL || report_value == NULL || o_csi1 == NULL) { + return SRSLTE_ERROR_INVALID_INPUTS; + } + + int n = srslte_csi_nof_bits(report_cfg, nof_reports); + if (n > (int)max_o_csi1) { + ERROR("The maximum number of CSI bits (%d) is not enough to accommodate %d bits", max_o_csi1, n); + return SRSLTE_ERROR; + } + + for (uint32_t i = 0; i < nof_reports && count < max_o_csi1; i++) { + if (report_cfg[i].freq_cfg == SRSLTE_CSI_REPORT_FREQ_WIDEBAND && + report_cfg[i].quantity == SRSLTE_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI) { + count += csi_wideband_cri_ri_pmi_cqi_pack(&report_cfg[i], &report_value[i], &o_csi1[count]); + } else { + ERROR("CSI frequency (%d) and quantity (%d) combination is not implemented", + report_cfg[i].freq_cfg, + report_cfg[i].quantity); + } + } + + return (int)count; +} + +uint32_t srslte_csi_str(const srslte_csi_report_cfg_t* report_cfg, + const srslte_csi_report_value_t* report_value, + uint32_t nof_reports, + char* str, + uint32_t str_len) +{ + uint32_t len = 0; + for (uint32_t i = 0; i < nof_reports; i++) { + if (report_cfg[i].freq_cfg == SRSLTE_CSI_REPORT_FREQ_WIDEBAND && + report_cfg[i].quantity == SRSLTE_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI) { + len = srslte_print_check(str, str_len, len, ", cqi=%d", report_value[i].wideband_cri_ri_pmi_cqi.cqi); + } + } + return len; +} \ No newline at end of file diff --git a/lib/src/phy/phch/pdsch.c b/lib/src/phy/phch/pdsch.c index 62b86d6e0..3620aaf05 100644 --- a/lib/src/phy/phch/pdsch.c +++ b/lib/src/phy/phch/pdsch.c @@ -321,16 +321,6 @@ static int pdsch_init(srslte_pdsch_t* q, uint32_t max_prb, bool is_ue, uint32_t } } - q->users = calloc(sizeof(srslte_pdsch_user_t*), q->is_ue ? 1 : (1 + SRSLTE_SIRNTI)); - if (!q->users) { - ERROR("malloc"); - goto clean; - } - - if (srslte_sequence_init(&q->tmp_seq, q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_256QAM))) { - goto clean; - } - for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { if (!q->csi[i]) { q->csi[i] = srslte_vec_f_malloc(q->max_re * 2); @@ -459,20 +449,6 @@ void srslte_pdsch_free(srslte_pdsch_t* q) } } } - if (q->users) { - if (q->is_ue) { - srslte_pdsch_free_rnti(q, 0); - } else { - for (int u = 0; u <= SRSLTE_SIRNTI; u++) { - if (q->users[u]) { - srslte_pdsch_free_rnti(q, u); - } - } - } - free(q->users); - } - - srslte_sequence_free(&q->tmp_seq); for (int i = 0; i < SRSLTE_MOD_NITEMS; i++) { srslte_modem_table_free(&q->mod[i]); @@ -507,68 +483,6 @@ int srslte_pdsch_set_cell(srslte_pdsch_t* q, srslte_cell_t cell) return ret; } -/* Precalculate the PDSCH scramble sequences for a given RNTI. This function takes a while - * to execute, so shall be called once the final C-RNTI has been allocated for the session. - */ -int srslte_pdsch_set_rnti(srslte_pdsch_t* q, uint16_t rnti) -{ - uint32_t rnti_idx = q->is_ue ? 0 : rnti; - - // Decide whether re-generating the sequence - if (!q->users[rnti_idx]) { - // If the sequence is not allocated generate - q->users[rnti_idx] = calloc(1, sizeof(srslte_pdsch_user_t)); - if (!q->users[rnti_idx]) { - ERROR("Alocating PDSCH user"); - return SRSLTE_ERROR; - } - } else if (q->users[rnti_idx]->sequence_generated && q->users[rnti_idx]->cell_id == q->cell.id && !q->is_ue) { - // The sequence was generated, cell has not changed and it is eNb, save any efforts - return SRSLTE_SUCCESS; - } - - // Set sequence as not generated - q->users[rnti_idx]->sequence_generated = false; - - // For each subframe - for (int sf_idx = 0; sf_idx < SRSLTE_NOF_SF_X_FRAME; sf_idx++) { - // For each codeword - for (int j = 0; j < SRSLTE_MAX_CODEWORDS; j++) { - if (srslte_sequence_pdsch(&q->users[rnti_idx]->seq[j][sf_idx], - rnti, - j, - SRSLTE_NOF_SLOTS_PER_SF * sf_idx, - q->cell.id, - q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_256QAM))) { - ERROR("Error initializing PDSCH scrambling sequence"); - srslte_pdsch_free_rnti(q, rnti); - return SRSLTE_ERROR; - } - } - } - - // Save generation states - q->ue_rnti = rnti; - q->users[rnti_idx]->cell_id = q->cell.id; - q->users[rnti_idx]->sequence_generated = true; - - return SRSLTE_SUCCESS; -} - -void srslte_pdsch_free_rnti(srslte_pdsch_t* q, uint16_t rnti) -{ - uint32_t rnti_idx = q->is_ue ? 0 : rnti; - if (q->users[rnti_idx]) { - for (int i = 0; i < SRSLTE_NOF_SF_X_FRAME; i++) { - for (int j = 0; j < SRSLTE_MAX_CODEWORDS; j++) { - srslte_sequence_free(&q->users[rnti_idx]->seq[j][i]); - } - } - free(q->users[rnti_idx]); - q->users[rnti_idx] = NULL; - q->ue_rnti = 0; - } -} static float apply_power_allocation(srslte_pdsch_t* q, srslte_pdsch_cfg_t* cfg, cf_t* sf_symbols_m[SRSLTE_MAX_PORTS]) { uint32_t nof_symbols_slot = cfg->grant.nof_symb_slot[0]; @@ -606,21 +520,6 @@ static float apply_power_allocation(srslte_pdsch_t* q, srslte_pdsch_cfg_t* cfg, return rho_a; } -static srslte_sequence_t* -get_user_sequence(srslte_pdsch_t* q, uint16_t rnti, uint32_t codeword_idx, uint32_t sf_idx, uint32_t len) -{ - uint32_t rnti_idx = q->is_ue ? 0 : rnti; - - // The scrambling sequence is pregenerated for all RNTIs in the eNodeB but only for C-RNTI in the UE - if (q->users[rnti_idx] && q->users[rnti_idx]->sequence_generated && q->users[rnti_idx]->cell_id == q->cell.id && - (!q->is_ue || q->ue_rnti == rnti)) { - return &q->users[rnti_idx]->seq[codeword_idx][sf_idx]; - } else { - srslte_sequence_pdsch(&q->tmp_seq, rnti, codeword_idx, 2 * sf_idx, q->cell.id, len); - return &q->tmp_seq; - } -} - static void csi_correction(srslte_pdsch_t* q, srslte_pdsch_cfg_t* cfg, uint32_t codeword_idx, uint32_t tb_idx, void* e) { uint32_t qm = 0; @@ -830,19 +729,23 @@ static int srslte_pdsch_codeword_decode(srslte_pdsch_t* q, data[tb_idx].evm = NAN; } - /* Select scrambling sequence */ - srslte_sequence_t* seq = - get_user_sequence(q, cfg->rnti, codeword_idx, sf->tti % 10, cfg->grant.tb[tb_idx].nof_bits); - if (!seq) { - ERROR("Error getting user sequence for rnti=0x%x", cfg->rnti); - return -1; - } - /* Bit scrambling */ if (q->llr_is_8bit) { - srslte_scrambling_sb_offset(seq, q->e[codeword_idx], 0, cfg->grant.tb[tb_idx].nof_bits); + srslte_sequence_pdsch_apply_c(q->e[codeword_idx], + q->e[codeword_idx], + cfg->rnti, + codeword_idx, + 2 * (sf->tti % SRSLTE_NOF_SF_X_FRAME), + q->cell.id, + cfg->grant.tb[tb_idx].nof_bits); } else { - srslte_scrambling_s_offset(seq, q->e[codeword_idx], 0, cfg->grant.tb[tb_idx].nof_bits); + srslte_sequence_pdsch_apply_s(q->e[codeword_idx], + q->e[codeword_idx], + cfg->rnti, + codeword_idx, + 2 * (sf->tti % SRSLTE_NOF_SF_X_FRAME), + q->cell.id, + cfg->grant.tb[tb_idx].nof_bits); } if (cfg->csi_enable) { @@ -1107,16 +1010,14 @@ static int srslte_pdsch_codeword_encode(srslte_pdsch_t* q, return SRSLTE_ERROR; } - /* Select scrambling sequence */ - srslte_sequence_t* seq = - get_user_sequence(q, cfg->rnti, codeword_idx, sf->tti % 10, cfg->grant.tb[tb_idx].nof_bits); - if (!seq) { - ERROR("Error getting user sequence for rnti=0x%x", cfg->rnti); - return -1; - } - /* Bit scrambling */ - srslte_scrambling_bytes(seq, (uint8_t*)q->e[codeword_idx], cfg->grant.tb[tb_idx].nof_bits); + srslte_sequence_pdsch_apply_pack((uint8_t*)q->e[codeword_idx], + (uint8_t*)q->e[codeword_idx], + cfg->rnti, + codeword_idx, + 2 * (sf->tti % SRSLTE_NOF_SF_X_FRAME), + q->cell.id, + cfg->grant.tb[tb_idx].nof_bits); /* Bit mapping */ srslte_mod_modulate_bytes( diff --git a/lib/src/phy/phch/pucch.c b/lib/src/phy/phch/pucch.c index a26454bf4..e41c97d04 100644 --- a/lib/src/phy/phch/pucch.c +++ b/lib/src/phy/phch/pucch.c @@ -58,13 +58,7 @@ int srslte_pucch_init_(srslte_pucch_t* q, bool is_ue) q->is_ue = is_ue; - q->users = calloc(sizeof(srslte_pucch_user_t*), q->is_ue ? 1 : (1 + SRSLTE_SIRNTI)); - if (!q->users) { - perror("malloc"); - goto clean_exit; - } - - if (srslte_sequence_init(&q->tmp_seq, 20)) { + if (srslte_sequence_init(&q->seq_f2, 20)) { goto clean_exit; } @@ -98,18 +92,7 @@ int srslte_pucch_init_enb(srslte_pucch_t* q) void srslte_pucch_free(srslte_pucch_t* q) { - if (q->users) { - if (q->is_ue) { - srslte_pucch_free_rnti(q, 0); - } else { - for (int rnti = 0; rnti <= SRSLTE_SIRNTI; rnti++) { - srslte_pucch_free_rnti(q, rnti); - } - } - free(q->users); - } - - srslte_sequence_free(&q->tmp_seq); + srslte_sequence_free(&q->seq_f2); srslte_uci_cqi_pucch_free(&q->cqi); if (q->z) { @@ -148,58 +131,6 @@ int srslte_pucch_set_cell(srslte_pucch_t* q, srslte_cell_t cell) return ret; } -void srslte_pucch_free_rnti(srslte_pucch_t* q, uint16_t rnti) -{ - uint32_t rnti_idx = q->is_ue ? 0 : rnti; - - if (q->users[rnti_idx]) { - for (int i = 0; i < SRSLTE_NOF_SF_X_FRAME; i++) { - srslte_sequence_free(&q->users[rnti_idx]->seq_f2[i]); - } - free(q->users[rnti_idx]); - q->users[rnti_idx] = NULL; - q->ue_rnti = 0; - } -} - -int srslte_pucch_set_rnti(srslte_pucch_t* q, uint16_t rnti) -{ - uint32_t rnti_idx = q->is_ue ? 0 : rnti; - - // Decide whether re-generating the sequence - if (!q->users[rnti_idx]) { - // If the sequence is not allocated generate - q->users[rnti_idx] = calloc(1, sizeof(srslte_pdsch_user_t)); - if (!q->users[rnti_idx]) { - ERROR("Alocating PDSCH user"); - return SRSLTE_ERROR; - } - } else if (q->users[rnti_idx]->sequence_generated && q->users[rnti_idx]->cell_id == q->cell.id && !q->is_ue) { - // The sequence was generated, cell has not changed and it is eNb, save any efforts - return SRSLTE_SUCCESS; - } - - // Set sequence as not generated - q->users[rnti_idx]->sequence_generated = false; - - // For each subframe - for (int sf_idx = 0; sf_idx < SRSLTE_NOF_SF_X_FRAME; sf_idx++) { - if (srslte_sequence_pucch( - &q->users[rnti_idx]->seq_f2[sf_idx], rnti, SRSLTE_NOF_SLOTS_PER_SF * sf_idx, q->cell.id)) { - ERROR("Error initializing PUCCH scrambling sequence"); - srslte_pucch_free_rnti(q, rnti); - return SRSLTE_ERROR; - } - } - - // Save generation states - q->ue_rnti = rnti; - q->users[rnti_idx]->cell_id = q->cell.id; - q->users[rnti_idx]->sequence_generated = true; - - return SRSLTE_SUCCESS; -} - static cf_t uci_encode_format1() { return 1.0; @@ -227,34 +158,11 @@ static cf_t uci_encode_format1b(uint8_t bits[2]) } } -static srslte_sequence_t* get_user_sequence(srslte_pucch_t* q, uint16_t rnti, uint32_t sf_idx) -{ - uint32_t rnti_idx = q->is_ue ? 0 : rnti; - - // The scrambling sequence is pregenerated for all RNTIs in the eNodeB but only for C-RNTI in the UE - if (rnti >= SRSLTE_CRNTI_START && rnti < SRSLTE_CRNTI_END) { - if (q->users[rnti_idx] && q->users[rnti_idx]->sequence_generated && q->users[rnti_idx]->cell_id == q->cell.id && - (!q->is_ue || q->ue_rnti == rnti)) { - return &q->users[rnti_idx]->seq_f2[sf_idx]; - } else { - if (srslte_sequence_pucch(&q->tmp_seq, rnti, 2 * sf_idx, q->cell.id)) { - ERROR("Error computing PUCCH Format 2 scrambling sequence"); - return NULL; - } - return &q->tmp_seq; - } - } else { - ERROR("Invalid RNTI=0x%x", rnti); - return NULL; - } -} - /* Encode PUCCH bits according to Table 5.4.1-1 in Section 5.4.1 of 36.211 */ static int uci_mod_bits(srslte_pucch_t* q, srslte_ul_sf_cfg_t* sf, srslte_pucch_cfg_t* cfg, uint8_t bits[SRSLTE_PUCCH_MAX_BITS]) { - uint8_t tmp[2]; - srslte_sequence_t* seq; + uint8_t tmp[2]; switch (cfg->format) { case SRSLTE_PUCCH_FORMAT_1: q->d[0] = uci_encode_format1(); @@ -270,26 +178,22 @@ uci_mod_bits(srslte_pucch_t* q, srslte_ul_sf_cfg_t* sf, srslte_pucch_cfg_t* cfg, case SRSLTE_PUCCH_FORMAT_2: case SRSLTE_PUCCH_FORMAT_2A: case SRSLTE_PUCCH_FORMAT_2B: - seq = get_user_sequence(q, cfg->rnti, sf->tti % 10); - if (seq) { - memcpy(q->bits_scram, bits, SRSLTE_PUCCH2_NOF_BITS * sizeof(uint8_t)); - srslte_scrambling_b_offset(seq, q->bits_scram, 0, SRSLTE_PUCCH2_NOF_BITS); - srslte_mod_modulate(&q->mod, q->bits_scram, q->d, SRSLTE_PUCCH2_NOF_BITS); - } else { - ERROR("Error modulating PUCCH2 bits: could not generate sequence"); - return -1; - } - break; - case SRSLTE_PUCCH_FORMAT_3: - seq = get_user_sequence(q, cfg->rnti, sf->tti % 10); - if (seq) { - memcpy(q->bits_scram, bits, SRSLTE_PUCCH3_NOF_BITS * sizeof(uint8_t)); - srslte_scrambling_b_offset(seq, q->bits_scram, 0, SRSLTE_PUCCH3_NOF_BITS); - srslte_mod_modulate(&q->mod, q->bits_scram, q->d, SRSLTE_PUCCH3_NOF_BITS); - } else { - ERROR("Error modulating PUCCH3 bits: rnti not set"); + if (srslte_sequence_pucch(&q->seq_f2, cfg->rnti, 2 * (sf->tti % 10), q->cell.id)) { + ERROR("Error computing PUCCH Format 2 scrambling sequence\n"); return SRSLTE_ERROR; } + srslte_vec_u8_copy(q->bits_scram, bits, SRSLTE_PUCCH2_NOF_BITS); + srslte_scrambling_b_offset(&q->seq_f2, q->bits_scram, 0, SRSLTE_PUCCH2_NOF_BITS); + srslte_mod_modulate(&q->mod, q->bits_scram, q->d, SRSLTE_PUCCH2_NOF_BITS); + break; + case SRSLTE_PUCCH_FORMAT_3: + if (srslte_sequence_pucch(&q->seq_f2, cfg->rnti, 2 * (sf->tti % 10), q->cell.id)) { + ERROR("Error computing PUCCH Format 2 scrambling sequence\n"); + return SRSLTE_ERROR; + } + srslte_vec_u8_copy(q->bits_scram, bits, SRSLTE_PUCCH3_NOF_BITS); + srslte_scrambling_b_offset(&q->seq_f2, q->bits_scram, 0, SRSLTE_PUCCH3_NOF_BITS); + srslte_mod_modulate(&q->mod, q->bits_scram, q->d, SRSLTE_PUCCH3_NOF_BITS); break; default: ERROR("PUCCH format %s not supported", srslte_pucch_format_text(cfg->format)); @@ -641,19 +545,15 @@ static int decode_signal_format3(srslte_pucch_t* q, srslte_vec_sc_prod_cfc(q->d, 2.0f / (N_sf_0 + N_sf_1), q->d, SRSLTE_NRE * 2); - srslte_sequence_t* seq = get_user_sequence(q, cfg->rnti, sf->tti % 10); - if (seq) { - srslte_demod_soft_demodulate_s(SRSLTE_MOD_QPSK, q->d, q->llr, SRSLTE_PUCCH3_NOF_BITS); + srslte_demod_soft_demodulate_s(SRSLTE_MOD_QPSK, q->d, q->llr, SRSLTE_PUCCH3_NOF_BITS); - srslte_scrambling_s_offset(seq, q->llr, 0, SRSLTE_PUCCH3_NOF_BITS); - - return (int)srslte_block_decode_i16(q->llr, SRSLTE_PUCCH3_NOF_BITS, bits, SRSLTE_UCI_MAX_ACK_SR_BITS); - } else { - ERROR("Error modulating PUCCH3 bits: rnti not set"); + if (srslte_sequence_pucch(&q->seq_f2, cfg->rnti, 2 * (sf->tti % 10), q->cell.id)) { + ERROR("Error computing PUCCH Format 2 scrambling sequence\n"); return SRSLTE_ERROR; } + srslte_scrambling_s_offset(&q->seq_f2, q->llr, 0, SRSLTE_PUCCH3_NOF_BITS); - return SRSLTE_SUCCESS; + return (int)srslte_block_decode_i16(q->llr, SRSLTE_PUCCH3_NOF_BITS, bits, SRSLTE_UCI_MAX_ACK_SR_BITS); } static int encode_signal(srslte_pucch_t* q, @@ -725,8 +625,7 @@ static bool decode_signal(srslte_pucch_t* q, float corr = 0, corr_max = -1e9; uint8_t b_max = 0, b2_max = 0; // default bit value, eg. HI is NACK - srslte_sequence_t* seq; - cf_t ref[SRSLTE_PUCCH_MAX_SYMBOLS]; + cf_t ref[SRSLTE_PUCCH_MAX_SYMBOLS]; switch (cfg->format) { case SRSLTE_PUCCH_FORMAT_1: @@ -781,30 +680,28 @@ static bool decode_signal(srslte_pucch_t* q, case SRSLTE_PUCCH_FORMAT_2: case SRSLTE_PUCCH_FORMAT_2A: case SRSLTE_PUCCH_FORMAT_2B: - seq = get_user_sequence(q, cfg->rnti, sf->tti % SRSLTE_NOF_SF_X_FRAME); - if (seq) { - encode_signal_format12(q, sf, cfg, NULL, ref, true); - srslte_vec_prod_conj_ccc(q->z, ref, q->z_tmp, SRSLTE_PUCCH_MAX_SYMBOLS); - for (int i = 0; i < (SRSLTE_PUCCH2_N_SF * SRSLTE_NOF_SLOTS_PER_SF); i++) { - q->z[i] = srslte_vec_acc_cc(&q->z_tmp[i * SRSLTE_NRE], SRSLTE_NRE) / SRSLTE_NRE; - } - srslte_demod_soft_demodulate_s(SRSLTE_MOD_QPSK, q->z, llr_pucch2, SRSLTE_PUCCH2_NOF_BITS / 2); - srslte_scrambling_s_offset(seq, llr_pucch2, 0, SRSLTE_PUCCH2_NOF_BITS); - - // Calculate the LLR RMS for normalising - float llr_pow = srslte_vec_avg_power_sf(llr_pucch2, SRSLTE_PUCCH2_NOF_BITS); - - if (isnormal(llr_pow)) { - float llr_rms = sqrtf(llr_pow) * SRSLTE_PUCCH2_NOF_BITS; - corr = ((float)srslte_uci_decode_cqi_pucch(&q->cqi, llr_pucch2, pucch_bits, nof_uci_bits)) / (llr_rms); - } else { - corr = 0; - } - detected = true; - } else { - ERROR("Decoding PUCCH2: could not generate sequence"); - return -1; + if (srslte_sequence_pucch(&q->seq_f2, cfg->rnti, 2 * (sf->tti % 10), q->cell.id)) { + ERROR("Error computing PUCCH Format 2 scrambling sequence\n"); + return SRSLTE_ERROR; } + encode_signal_format12(q, sf, cfg, NULL, ref, true); + srslte_vec_prod_conj_ccc(q->z, ref, q->z_tmp, SRSLTE_PUCCH_MAX_SYMBOLS); + for (int i = 0; i < (SRSLTE_PUCCH2_N_SF * SRSLTE_NOF_SLOTS_PER_SF); i++) { + q->z[i] = srslte_vec_acc_cc(&q->z_tmp[i * SRSLTE_NRE], SRSLTE_NRE) / SRSLTE_NRE; + } + srslte_demod_soft_demodulate_s(SRSLTE_MOD_QPSK, q->z, llr_pucch2, SRSLTE_PUCCH2_NOF_BITS / 2); + srslte_scrambling_s_offset(&q->seq_f2, llr_pucch2, 0, SRSLTE_PUCCH2_NOF_BITS); + + // Calculate the LLR RMS for normalising + float llr_pow = srslte_vec_avg_power_sf(llr_pucch2, SRSLTE_PUCCH2_NOF_BITS); + + if (isnormal(llr_pow)) { + float llr_rms = sqrtf(llr_pow) * SRSLTE_PUCCH2_NOF_BITS; + corr = ((float)srslte_uci_decode_cqi_pucch(&q->cqi, llr_pucch2, pucch_bits, nof_uci_bits)) / (llr_rms); + } else { + corr = 0; + } + detected = true; break; case SRSLTE_PUCCH_FORMAT_3: corr = (float)decode_signal_format3(q, sf, cfg, pucch_bits, q->z) / 4800.0f; @@ -1065,7 +962,7 @@ bool srslte_pucch_cfg_isvalid(srslte_pucch_cfg_t* cfg, uint32_t nof_prb) } } -uint32_t srslte_pucch_n_prb(srslte_cell_t* cell, srslte_pucch_cfg_t* cfg, uint32_t ns) +uint32_t srslte_pucch_n_prb(const srslte_cell_t* cell, const srslte_pucch_cfg_t* cfg, uint32_t ns) { uint32_t m = srslte_pucch_m(cfg, cell->cp); // Determine n_prb diff --git a/lib/src/phy/phch/pusch.c b/lib/src/phy/phch/pusch.c index 3da59bd00..6f7f27643 100644 --- a/lib/src/phy/phch/pusch.c +++ b/lib/src/phy/phch/pusch.c @@ -125,16 +125,6 @@ static int pusch_init(srslte_pusch_t* q, uint32_t max_prb, bool is_ue) q->is_ue = is_ue; - q->users = calloc(sizeof(srslte_pusch_user_t*), q->is_ue ? 1 : (1 + SRSLTE_SIRNTI)); - if (!q->users) { - perror("malloc"); - goto clean; - } - - if (srslte_sequence_init(&q->tmp_seq, q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM))) { - goto clean; - } - srslte_sch_init(&q->ul_sch); if (srslte_dft_precoding_init(&q->dft_precoding, max_prb, is_ue)) { @@ -219,19 +209,6 @@ void srslte_pusch_free(srslte_pusch_t* q) } srslte_dft_precoding_free(&q->dft_precoding); - if (q->users) { - if (q->is_ue) { - srslte_pusch_free_rnti(q, 0); - } else { - for (int rnti = 0; rnti <= SRSLTE_SIRNTI; rnti++) { - srslte_pusch_free_rnti(q, rnti); - } - } - free(q->users); - } - - srslte_sequence_free(&q->tmp_seq); - for (i = 0; i < SRSLTE_MOD_NITEMS; i++) { srslte_modem_table_free(&q->mod[i]); } @@ -257,86 +234,6 @@ int srslte_pusch_set_cell(srslte_pusch_t* q, srslte_cell_t cell) return ret; } -/* Precalculate the PUSCH scramble sequences for a given RNTI. This function takes a while - * to execute, so shall be called once the final C-RNTI has been allocated for the session. - * For the connection procedure, use srslte_pusch_encode() functions */ -int srslte_pusch_set_rnti(srslte_pusch_t* q, uint16_t rnti) -{ - uint32_t rnti_idx = q->is_ue ? 0 : rnti; - - // Decide whether re-generating the sequence - if (!q->users[rnti_idx]) { - // If the sequence is not allocated generate - q->users[rnti_idx] = calloc(1, sizeof(srslte_pdsch_user_t)); - if (!q->users[rnti_idx]) { - ERROR("Alocating PDSCH user"); - return SRSLTE_ERROR; - } - } else if (q->users[rnti_idx]->sequence_generated && q->users[rnti_idx]->cell_id == q->cell.id && !q->is_ue) { - // The sequence was generated, cell has not changed and it is eNb, save any efforts - return SRSLTE_SUCCESS; - } - - // Set sequence as not generated - q->users[rnti_idx]->sequence_generated = false; - - // For each subframe - for (int sf_idx = 0; sf_idx < SRSLTE_NOF_SF_X_FRAME; sf_idx++) { - if (srslte_sequence_pusch(&q->users[rnti_idx]->seq[sf_idx], - rnti, - SRSLTE_NOF_SLOTS_PER_SF * sf_idx, - q->cell.id, - q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM))) { - ERROR("Error initializing PUSCH scrambling sequence"); - srslte_pusch_free_rnti(q, rnti); - return SRSLTE_ERROR; - } - } - - // Save generation states - q->ue_rnti = rnti; - q->users[rnti_idx]->cell_id = q->cell.id; - q->users[rnti_idx]->sequence_generated = true; - - return SRSLTE_SUCCESS; -} - -void srslte_pusch_free_rnti(srslte_pusch_t* q, uint16_t rnti) -{ - uint32_t rnti_idx = q->is_ue ? 0 : rnti; - - if (q->users[rnti_idx]) { - for (int i = 0; i < SRSLTE_NOF_SF_X_FRAME; i++) { - srslte_sequence_free(&q->users[rnti_idx]->seq[i]); - } - free(q->users[rnti_idx]); - q->users[rnti_idx] = NULL; - q->ue_rnti = 0; - } -} - -static srslte_sequence_t* get_user_sequence(srslte_pusch_t* q, uint16_t rnti, uint32_t sf_idx, uint32_t len) -{ - uint32_t rnti_idx = q->is_ue ? 0 : rnti; - - if (SRSLTE_RNTI_ISUSER(rnti)) { - // The scrambling sequence is pregenerated for all RNTIs in the eNodeB but only for C-RNTI in the UE - if (q->users[rnti_idx] && q->users[rnti_idx]->sequence_generated && q->users[rnti_idx]->cell_id == q->cell.id && - (!q->is_ue || q->ue_rnti == rnti)) { - return &q->users[rnti_idx]->seq[sf_idx]; - } else { - if (srslte_sequence_pusch(&q->tmp_seq, rnti, 2 * sf_idx, q->cell.id, len)) { - ERROR("Error generating temporal scrambling sequence"); - return NULL; - } - return &q->tmp_seq; - } - } else { - ERROR("Invalid RNTI=0x%x", rnti); - return NULL; - } -} - int srslte_pusch_assert_grant(const srslte_pusch_grant_t* grant) { // Check for valid number of PRB @@ -407,15 +304,13 @@ int srslte_pusch_encode(srslte_pusch_t* q, uint32_t nof_ri_ack_bits = (uint32_t)ret; - // Generate scrambling sequence if not pre-generated - srslte_sequence_t* seq = get_user_sequence(q, cfg->rnti, sf->tti % 10, cfg->grant.tb.nof_bits); - if (!seq) { - ERROR("Error getting user sequence for rnti=0x%x", cfg->rnti); - return -1; - } - // Run scrambling - srslte_scrambling_bytes(seq, (uint8_t*)q->q, cfg->grant.tb.nof_bits); + srslte_sequence_pusch_apply_pack((uint8_t*)q->q, + (uint8_t*)q->q, + cfg->rnti, + 2 * (sf->tti % SRSLTE_NOF_SF_X_FRAME), + q->cell.id, + cfg->grant.tb.nof_bits); // Correct UCI placeholder/repetition bits uint8_t* d = q->q; @@ -537,25 +432,25 @@ int srslte_pusch_decode(srslte_pusch_t* q, out->evm = NAN; } - // Generate scrambling sequence if not pre-generated - srslte_sequence_t* seq = get_user_sequence(q, cfg->rnti, sf->tti % 10, cfg->grant.tb.nof_bits); - if (!seq) { - ERROR("Error getting user sequence for rnti=0x%x", cfg->rnti); - return -1; - } - // Descrambling if (q->llr_is_8bit) { - srslte_scrambling_sb_offset(seq, q->q, 0, cfg->grant.tb.nof_bits); + srslte_sequence_pusch_apply_c( + q->q, q->q, cfg->rnti, 2 * (sf->tti % SRSLTE_NOF_SF_X_FRAME), q->cell.id, cfg->grant.tb.nof_bits); } else { - srslte_scrambling_s_offset(seq, q->q, 0, cfg->grant.tb.nof_bits); + srslte_sequence_pusch_apply_s( + q->q, q->q, cfg->rnti, 2 * (sf->tti % SRSLTE_NOF_SF_X_FRAME), q->cell.id, cfg->grant.tb.nof_bits); } + // Generate packed sequence for UCI decoder + uint8_t* c = (uint8_t*)q->z; // Reuse Z + srslte_sequence_pusch_gen_unpack( + c, cfg->rnti, 2 * (sf->tti % SRSLTE_NOF_SF_X_FRAME), q->cell.id, cfg->grant.tb.nof_bits); + // Set max number of iterations srslte_sch_set_max_noi(&q->ul_sch, cfg->max_nof_iterations); // Decode - ret = srslte_ulsch_decode(&q->ul_sch, cfg, q->q, q->g, seq->c, out->data, &out->uci); + ret = srslte_ulsch_decode(&q->ul_sch, cfg, q->q, q->g, c, out->data, &out->uci); out->crc = (ret == 0); // Save number of iterations diff --git a/lib/src/phy/phch/ra.c b/lib/src/phy/phch/ra.c index 4e0ab1439..175c2c4f9 100644 --- a/lib/src/phy/phch/ra.c +++ b/lib/src/phy/phch/ra.c @@ -190,15 +190,15 @@ srslte_mod_t srslte_ra_ul_mod_from_mcs(uint32_t mcs) static int srslte_ra_dl_mcs_from_tbs_idx(uint32_t tbs_idx, bool use_tbs_index_alt) { if (use_tbs_index_alt) { - for (int i = 0; i < 28; i++) { - if (tbs_idx == dl_mcs_tbs_idx_table2[i]) { - return i; + for (int mcs = 27; mcs >= 0; mcs--) { + if (tbs_idx == dl_mcs_tbs_idx_table2[mcs]) { + return mcs; } } } else { - for (int i = 0; i < 29; i++) { - if (tbs_idx == dl_mcs_tbs_idx_table[i]) { - return i; + for (int mcs = 28; mcs >= 0; mcs--) { + if (tbs_idx == dl_mcs_tbs_idx_table[mcs]) { + return mcs; } } } @@ -207,9 +207,10 @@ static int srslte_ra_dl_mcs_from_tbs_idx(uint32_t tbs_idx, bool use_tbs_index_al static int srslte_ra_ul_mcs_from_tbs_idx(uint32_t tbs_idx) { - for (int i = 0; i < 29; i++) { - if (tbs_idx == ul_mcs_tbs_idx_table[i]) { - return i; + // Note: go in descent order to find max mcs possible + for (int mcs = 28; mcs >= 0; mcs--) { + if (tbs_idx == ul_mcs_tbs_idx_table[mcs]) { + return mcs; } } return SRSLTE_ERROR; @@ -233,21 +234,22 @@ int srslte_ra_tbs_from_idx(uint32_t tbs_idx, uint32_t n_prb) /* Returns lowest nearest index of TBS value in table 7.1.7.2 on 36.213 * or -1 if the TBS value is not within the valid TBS values */ -int srslte_ra_tbs_to_table_idx(uint32_t tbs, uint32_t n_prb) +/* + * Returns upper bound (exclusive) of TBS index interval whose TBS value encompasses the provided TBS + * \remark taken from table 7.1.7.2 on 36.213 + * @return upper bound of TBS index (0..27), -2 if bad arguments + */ +int srslte_ra_tbs_to_table_idx(uint32_t tbs, uint32_t n_prb, uint32_t max_tbs_idx) { - uint32_t idx; - if (n_prb > 0 && n_prb <= SRSLTE_MAX_PRB) { - - if (tbs <= tbs_table[0][n_prb - 1]) { - return 0; - } - if (tbs >= tbs_table[26][n_prb - 1]) { - return 27; - } - for (idx = 0; idx < 26; idx++) { - if (tbs_table[idx][n_prb - 1] <= tbs && tbs_table[idx + 1][n_prb - 1] >= tbs) { - return idx + 1; - } + if (n_prb == 0 || n_prb > SRSLTE_MAX_PRB) { + return SRSLTE_ERROR_INVALID_INPUTS; + } + if (tbs < tbs_table[0][n_prb - 1]) { + return 0; + } + for (int tbs_idx = max_tbs_idx; tbs_idx >= 0; tbs_idx--) { + if (tbs_table[tbs_idx][n_prb - 1] <= tbs) { + return tbs_idx + 1; } } return SRSLTE_ERROR; diff --git a/lib/src/phy/phch/ra_dl.c b/lib/src/phy/phch/ra_dl.c index 195618155..e72aae7d2 100644 --- a/lib/src/phy/phch/ra_dl.c +++ b/lib/src/phy/phch/ra_dl.c @@ -362,6 +362,15 @@ static int dl_dci_compute_tb(bool pdsch_use_tbs_index_alt, const srslte_dci_dl_t } } + // 256QAM table is allowed if: + // - if the higher layer parameter altCQI-Table-r12 is configured, and + // - if the PDSCH is assigned by a PDCCH/EPDCCH with DCI format 1/1B/1D/2/2A/2B/2C/2D with + // - CRC scrambled by C-RNTI, + // Otherwise, use 64QAM table (default table for R8). + if (dci->format == SRSLTE_DCI_FORMAT1A || !SRSLTE_RNTI_ISUSER(dci->rnti)) { + pdsch_use_tbs_index_alt = false; + } + if (!SRSLTE_RNTI_ISUSER(dci->rnti) && !SRSLTE_RNTI_ISMBSFN(dci->rnti)) { if (dci->format == SRSLTE_DCI_FORMAT1A) { n_prb = dci->type2_alloc.n_prb1a == SRSLTE_RA_TYPE2_NPRB1A_2 ? 2 : 3; diff --git a/lib/src/phy/phch/ra_ul_nr.c b/lib/src/phy/phch/ra_ul_nr.c index aa3c20024..23c53db6e 100644 --- a/lib/src/phy/phch/ra_ul_nr.c +++ b/lib/src/phy/phch/ra_ul_nr.c @@ -23,6 +23,7 @@ #include "ra_helper.h" #include "srslte/phy/ch_estimation/dmrs_pucch.h" #include "srslte/phy/common/phy_common.h" +#include "srslte/phy/phch/csi.h" #include "srslte/phy/utils/debug.h" #include "srslte/phy/utils/vector.h" @@ -381,7 +382,7 @@ int srslte_ra_ul_nr_pucch_format_2_3_min_prb(const srslte_pucch_nr_resource_t* r } // Compute total number of UCI bits - uint32_t O_total = uci_cfg->o_ack + uci_cfg->o_sr + uci_cfg->o_csi1 + uci_cfg->o_csi2; + uint32_t O_total = uci_cfg->o_ack + uci_cfg->o_sr + srslte_csi_nof_bits(uci_cfg->csi, uci_cfg->nof_csi); // Add CRC bits if any O_total += srslte_uci_nr_crc_len(O_total); @@ -459,12 +460,53 @@ int srslte_ra_ul_nr_pucch_resource(const srslte_pucch_nr_hl_cfg_t* pucch_cfg, const srslte_uci_cfg_nr_t* uci_cfg, srslte_pucch_nr_resource_t* resource) { - if (pucch_cfg == NULL || uci_cfg == NULL) { + if (pucch_cfg == NULL || uci_cfg == NULL || resource == NULL) { return SRSLTE_ERROR_INVALID_INPUTS; } uint32_t O_uci = srslte_uci_nr_total_bits(uci_cfg); + // Use SR PUCCH resource + // - At least one positive SR + // - up to 2 HARQ-ACK + // - No CSI report + if (uci_cfg->sr_positive_present > 0 && uci_cfg->o_ack <= SRSLTE_PUCCH_NR_FORMAT1_MAX_NOF_BITS && + uci_cfg->nof_csi == 0) { + uint32_t sr_resource_id = uci_cfg->sr_resource_id; + if (sr_resource_id >= SRSLTE_PUCCH_MAX_NOF_SR_RESOURCES) { + ERROR("SR resource ID (%d) exceeds the maximum ID (%d)", sr_resource_id, SRSLTE_PUCCH_MAX_NOF_SR_RESOURCES); + return SRSLTE_ERROR; + } + + if (!pucch_cfg->sr_resources[sr_resource_id].configured) { + ERROR("SR resource ID (%d) is not configured", sr_resource_id); + return SRSLTE_ERROR; + } + + // Set PUCCH resource + *resource = pucch_cfg->sr_resources[sr_resource_id].resource; + + // No more logic is required in this case + return SRSLTE_SUCCESS; + } + + // Use format 2, 3 or 4 resource from higher layers + // - Irrelevant SR opportunities + // - More than 2 HARQ-ACK + // - No CSI report + if (uci_cfg->o_sr > 0 && uci_cfg->o_ack > SRSLTE_PUCCH_NR_FORMAT1_MAX_NOF_BITS && uci_cfg->nof_csi == 0) { + return ra_ul_nr_pucch_resource_hl(pucch_cfg, O_uci, uci_cfg->pucch_resource_id, resource); + } + + // Use format 2, 3 or 4 CSI report resource from higher layers + // - Irrelevant SR opportunities + // - No HARQ-ACK + // - Single periodic CSI report + if (uci_cfg->o_ack == 0 && uci_cfg->nof_csi == 1 && uci_cfg->csi[0].type == SRSLTE_CSI_REPORT_TYPE_PERIODIC) { + *resource = uci_cfg->csi[0].pucch_resource; + return SRSLTE_SUCCESS; + } + // If a UE does not have dedicated PUCCH resource configuration, provided by PUCCH-ResourceSet in PUCCH-Config, // a PUCCH resource set is provided by pucch-ResourceCommon through an index to a row of Table 9.2.1-1 for size // transmission of HARQ-ACK information on PUCCH in an initial UL BWP of N BWP PRBs. @@ -474,3 +516,11 @@ int srslte_ra_ul_nr_pucch_resource(const srslte_pucch_nr_hl_cfg_t* pucch_cfg, } return ra_ul_nr_pucch_resource_hl(pucch_cfg, O_uci, uci_cfg->pucch_resource_id, resource); } + +uint32_t srslte_ra_ul_nr_nof_sr_bits(uint32_t K) +{ + if (K > 0) { + return (uint32_t)ceilf(log2f((float)K + 1.0f)); + } + return 0; +} \ No newline at end of file diff --git a/lib/src/phy/phch/sch.c b/lib/src/phy/phch/sch.c index 6e83e075f..82d64fea3 100644 --- a/lib/src/phy/phch/sch.c +++ b/lib/src/phy/phch/sch.c @@ -1127,10 +1127,6 @@ int srslte_ulsch_decode(srslte_sch_t* q, uint32_t Q_prime_ri = (uint32_t)ret; - /* - if (cfg->uci_cfg.cqi.data_enable) { - printf("deinter_input: Qm=%d, nb_q=%d, nof_symb=%d, Q_prime_ri=%d\n", Qm, nb_q, cfg->grant.nof_symb, Q_prime_ri); - }*/ // Deinterleave data and CQI in ULSCH ulsch_deinterleave(q_bits, Qm, @@ -1257,13 +1253,8 @@ int srslte_ulsch_encode(srslte_sch_t* q, } Q_prime_cqi = (uint32_t)ret; - /* - if (Q_prime_cqi) { - printf("Encoding cqi Q=%d: ", Q_prime_cqi*Qm); - srslte_vec_fprint_b(stdout, q->temp_g_bits, Q_prime_cqi*Qm); - }*/ - srslte_bit_pack_vector(q->temp_g_bits, g_bits, Q_prime_cqi * Qm); + // Reset the buffer because will be reused in ulsch_interleave srslte_vec_u8_zero(q->temp_g_bits, Q_prime_cqi * Qm); } diff --git a/lib/src/phy/phch/sequences.c b/lib/src/phy/phch/sequences.c index 86544a8dc..a135590d1 100644 --- a/lib/src/phy/phch/sequences.c +++ b/lib/src/phy/phch/sequences.c @@ -21,6 +21,7 @@ #include "srslte/phy/common/phy_common.h" #include "srslte/phy/common/sequence.h" +#include "srslte/phy/utils/vector.h" #include /** @@ -58,17 +59,108 @@ int srslte_sequence_pdcch(srslte_sequence_t* seq, uint32_t nslot, uint32_t cell_ /** * 36.211 6.3.1 */ +static inline uint32_t sequence_pdsch_seed(uint16_t rnti, int q, uint32_t nslot, uint32_t cell_id) +{ + return (rnti << 14) + (q << 13) + ((nslot / 2) << 9) + cell_id; +} + int srslte_sequence_pdsch(srslte_sequence_t* seq, uint16_t rnti, int q, uint32_t nslot, uint32_t cell_id, uint32_t len) { - return srslte_sequence_LTE_pr(seq, len, (rnti << 14) + (q << 13) + ((nslot / 2) << 9) + cell_id); + return srslte_sequence_LTE_pr(seq, len, sequence_pdsch_seed(rnti, q, nslot, cell_id)); +} + +void srslte_sequence_pdsch_apply_pack(const uint8_t* in, + uint8_t* out, + uint16_t rnti, + int q, + uint32_t nslot, + uint32_t cell_id, + uint32_t len) +{ + srslte_sequence_apply_packed(in, out, len, sequence_pdsch_seed(rnti, q, nslot, cell_id)); +} + +void srslte_sequence_pdsch_apply_f(const float* in, + float* out, + uint16_t rnti, + int q, + uint32_t nslot, + uint32_t cell_id, + uint32_t len) +{ + srslte_sequence_apply_f(in, out, len, sequence_pdsch_seed(rnti, q, nslot, cell_id)); +} + +void srslte_sequence_pdsch_apply_s(const int16_t* in, + int16_t* out, + uint16_t rnti, + int q, + uint32_t nslot, + uint32_t cell_id, + uint32_t len) +{ + srslte_sequence_apply_s(in, out, len, sequence_pdsch_seed(rnti, q, nslot, cell_id)); +} + +void srslte_sequence_pdsch_apply_c(const int8_t* in, + int8_t* out, + uint16_t rnti, + int q, + uint32_t nslot, + uint32_t cell_id, + uint32_t len) +{ + srslte_sequence_apply_c(in, out, len, sequence_pdsch_seed(rnti, q, nslot, cell_id)); } /** * 36.211 5.3.1 */ +static inline uint32_t sequence_pusch_seed(uint16_t rnti, uint32_t nslot, uint32_t cell_id) +{ + return (rnti << 14) + ((nslot / 2) << 9) + cell_id; +} + int srslte_sequence_pusch(srslte_sequence_t* seq, uint16_t rnti, uint32_t nslot, uint32_t cell_id, uint32_t len) { - return srslte_sequence_LTE_pr(seq, len, (rnti << 14) + ((nslot / 2) << 9) + cell_id); + return srslte_sequence_LTE_pr(seq, len, sequence_pusch_seed(rnti, nslot, cell_id)); +} + +void srslte_sequence_pusch_apply_pack(const uint8_t* in, + uint8_t* out, + uint16_t rnti, + uint32_t nslot, + uint32_t cell_id, + uint32_t len) +{ + srslte_sequence_apply_packed(in, out, len, sequence_pusch_seed(rnti, nslot, cell_id)); +} + +void srslte_sequence_pusch_apply_s(const int16_t* in, + int16_t* out, + uint16_t rnti, + uint32_t nslot, + uint32_t cell_id, + uint32_t len) +{ + srslte_sequence_apply_s(in, out, len, sequence_pusch_seed(rnti, nslot, cell_id)); +} + +void srslte_sequence_pusch_gen_unpack(uint8_t* out, uint16_t rnti, uint32_t nslot, uint32_t cell_id, uint32_t len) +{ + srslte_vec_u8_zero(out, len); + + srslte_sequence_apply_bit(out, out, len, sequence_pusch_seed(rnti, nslot, cell_id)); +} + +void srslte_sequence_pusch_apply_c(const int8_t* in, + int8_t* out, + uint16_t rnti, + uint32_t nslot, + uint32_t cell_id, + uint32_t len) +{ + srslte_sequence_apply_c(in, out, len, sequence_pusch_seed(rnti, nslot, cell_id)); } /** 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 313fd2854..45ccf6543 100644 --- a/lib/src/phy/phch/test/pdsch_pdcch_file_test.c +++ b/lib/src/phy/phch/test/pdsch_pdcch_file_test.c @@ -145,8 +145,6 @@ int base_init() return -1; } - srslte_ue_dl_set_rnti(&ue_dl, rnti); - DEBUG("Memory init OK"); return 0; } diff --git a/lib/src/phy/phch/test/pdsch_test.c b/lib/src/phy/phch/test/pdsch_test.c index 7f59618f3..dbdf92537 100644 --- a/lib/src/phy/phch/test/pdsch_test.c +++ b/lib/src/phy/phch/test/pdsch_test.c @@ -158,16 +158,14 @@ static int check_softbits(srslte_pdsch_t* pdsch_enb, int ret = SRSLTE_SUCCESS; if (!pdsch_ue->llr_is_8bit && !tb_cw_swap) { - // Generate sequence - srslte_sequence_pdsch(&pdsch_ue->tmp_seq, - rnti, - pdsch_cfg->grant.tb[tb].cw_idx, - 2 * (sf_idx % 10), - cell.id, - pdsch_cfg->grant.tb[tb].nof_bits); - // Scramble - srslte_scrambling_s_offset(&pdsch_ue->tmp_seq, pdsch_ue->e[tb], 0, pdsch_cfg->grant.tb[tb].nof_bits); + srslte_sequence_pdsch_apply_c(pdsch_ue->e[tb], + pdsch_ue->e[tb], + rnti, + pdsch_cfg->grant.tb[tb].cw_idx, + 2 * (sf_idx % 10), + cell.id, + pdsch_cfg->grant.tb[tb].nof_bits); int16_t* rx = pdsch_ue->e[tb]; uint8_t* rx_bytes = pdsch_ue->e[tb]; @@ -337,8 +335,6 @@ int main(int argc, char** argv) pdsch_rx.llr_is_8bit = use_8_bit; pdsch_rx.dl_sch.llr_is_8bit = use_8_bit; - srslte_pdsch_set_rnti(&pdsch_rx, rnti); - for (uint32_t i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { softbuffers_rx[i] = calloc(sizeof(srslte_softbuffer_rx_t), 1); if (!softbuffers_rx[i]) { @@ -384,8 +380,6 @@ int main(int argc, char** argv) goto quit; } - srslte_pdsch_set_rnti(&pdsch_tx, rnti); - for (uint32_t i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { softbuffers_tx[i] = calloc(sizeof(srslte_softbuffer_tx_t), 1); if (!softbuffers_tx[i]) { diff --git a/lib/src/phy/phch/test/pucch_test.c b/lib/src/phy/phch/test/pucch_test.c index f4d4147f5..661efda6d 100644 --- a/lib/src/phy/phch/test/pucch_test.c +++ b/lib/src/phy/phch/test/pucch_test.c @@ -165,10 +165,6 @@ int main(int argc, char** argv) ERROR("Error creating PDSCH object"); exit(-1); } - if (srslte_pucch_set_rnti(&pucch_ue, 11)) { - ERROR("Error setting C-RNTI"); - goto quit; - } if (srslte_pucch_init_enb(&pucch_enb)) { ERROR("Error creating PDSCH object"); exit(-1); @@ -177,10 +173,6 @@ int main(int argc, char** argv) ERROR("Error creating PDSCH object"); exit(-1); } - if (srslte_pucch_set_rnti(&pucch_enb, 11)) { - ERROR("Error setting C-RNTI"); - goto quit; - } if (srslte_refsignal_ul_set_cell(&dmrs, cell)) { ERROR("Error creating PDSCH object"); exit(-1); diff --git a/lib/src/phy/phch/test/pusch_test.c b/lib/src/phy/phch/test/pusch_test.c index 240da4ee5..604e64772 100644 --- a/lib/src/phy/phch/test/pusch_test.c +++ b/lib/src/phy/phch/test/pusch_test.c @@ -245,8 +245,6 @@ int main(int argc, char** argv) uint16_t rnti = 62; dci.rnti = rnti; cfg.rnti = rnti; - srslte_pusch_set_rnti(&pusch_tx, rnti); - srslte_pusch_set_rnti(&pusch_rx, rnti); uint32_t nof_re = SRSLTE_NRE * cell.nof_prb * 2 * SRSLTE_CP_NSYMB(cell.cp); sf_symbols = srslte_vec_cf_malloc(nof_re); diff --git a/lib/src/phy/phch/uci_nr.c b/lib/src/phy/phch/uci_nr.c index e76d71e5d..5f0e5461f 100644 --- a/lib/src/phy/phch/uci_nr.c +++ b/lib/src/phy/phch/uci_nr.c @@ -22,6 +22,7 @@ #include "srslte/phy/phch/uci_nr.h" #include "srslte/phy/fec/block/block.h" #include "srslte/phy/fec/polar/polar_chanalloc.h" +#include "srslte/phy/phch/csi.h" #include "srslte/phy/phch/uci_cfg.h" #include "srslte/phy/utils/bit.h" #include "srslte/phy/utils/vector.h" @@ -163,7 +164,8 @@ static int uci_nr_pack_ack_sr(const srslte_uci_cfg_nr_t* cfg, const srslte_uci_v A += cfg->o_ack; // Append SR bits - srslte_vec_u8_copy(&sequence[A], value->sr, cfg->o_sr); + uint8_t* bits = &sequence[A]; + srslte_bit_unpack(value->sr, &bits, cfg->o_sr); A += cfg->o_sr; if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) { @@ -174,7 +176,7 @@ static int uci_nr_pack_ack_sr(const srslte_uci_cfg_nr_t* cfg, const srslte_uci_v return A; } -static int uci_nr_unpack_ack_sr(const srslte_uci_cfg_nr_t* cfg, const uint8_t* sequence, srslte_uci_value_nr_t* value) +static int uci_nr_unpack_ack_sr(const srslte_uci_cfg_nr_t* cfg, uint8_t* sequence, srslte_uci_value_nr_t* value) { int A = 0; @@ -183,7 +185,8 @@ static int uci_nr_unpack_ack_sr(const srslte_uci_cfg_nr_t* cfg, const uint8_t* s A += cfg->o_ack; // Append SR bits - srslte_vec_u8_copy(value->sr, &sequence[A], cfg->o_sr); + uint8_t* bits = &sequence[A]; + value->sr = srslte_bit_pack(&bits, cfg->o_sr); A += cfg->o_sr; if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) { @@ -196,15 +199,16 @@ static int uci_nr_unpack_ack_sr(const srslte_uci_cfg_nr_t* cfg, const uint8_t* s static int uci_nr_A(const srslte_uci_cfg_nr_t* cfg) { + int o_csi = srslte_csi_nof_bits(cfg->csi, cfg->nof_csi); + // 6.3.1.1.1 HARQ-ACK/SR only UCI bit sequence generation - if (cfg->o_csi1 == 0 && cfg->o_csi2 == 0) { + if (o_csi == 0) { return cfg->o_ack + cfg->o_sr; } // 6.3.1.1.2 CSI only if (cfg->o_ack == 0 && cfg->o_sr == 0) { - ERROR("CSI only are not implemented"); - return SRSLTE_ERROR; + return o_csi; } // 6.3.1.1.3 HARQ-ACK/SR and CSI @@ -214,15 +218,16 @@ static int uci_nr_A(const srslte_uci_cfg_nr_t* cfg) static int uci_nr_packing(const srslte_uci_cfg_nr_t* cfg, const srslte_uci_value_nr_t* value, uint8_t* sequence) { + int o_csi = srslte_csi_nof_bits(cfg->csi, cfg->nof_csi); + // 6.3.1.1.1 HARQ-ACK/SR only UCI bit sequence generation - if (cfg->o_csi1 == 0 && cfg->o_csi2 == 0) { + if (o_csi == 0) { return uci_nr_pack_ack_sr(cfg, value, sequence); } // 6.3.1.1.2 CSI only if (cfg->o_ack == 0 && cfg->o_sr == 0) { - ERROR("CSI only are not implemented"); - return SRSLTE_ERROR; + return srslte_csi_part1_pack(cfg->csi, value->csi, cfg->nof_csi, sequence, SRSLTE_UCI_NR_MAX_NOF_BITS); } // 6.3.1.1.3 HARQ-ACK/SR and CSI @@ -230,10 +235,12 @@ static int uci_nr_packing(const srslte_uci_cfg_nr_t* cfg, const srslte_uci_value return SRSLTE_ERROR; } -static int uci_nr_unpacking(const srslte_uci_cfg_nr_t* cfg, const uint8_t* sequence, srslte_uci_value_nr_t* value) +static int uci_nr_unpacking(const srslte_uci_cfg_nr_t* cfg, uint8_t* sequence, srslte_uci_value_nr_t* value) { + int o_csi = srslte_csi_nof_bits(cfg->csi, cfg->nof_csi); + // 6.3.1.1.1 HARQ-ACK/SR only UCI bit sequence generation - if (cfg->o_csi1 == 0 && cfg->o_csi2 == 0) { + if (o_csi == 0) { return uci_nr_unpack_ack_sr(cfg, sequence, value); } @@ -746,10 +753,10 @@ int srslte_uci_nr_pucch_format_2_3_4_E(const srslte_pucch_nr_resource_t* resourc static int uci_nr_pucch_E_uci(const srslte_pucch_nr_resource_t* pucch_cfg, const srslte_uci_cfg_nr_t* uci_cfg, uint32_t E_tot) { - if (uci_cfg->o_csi1 != 0 && uci_cfg->o_csi2) { - ERROR("Simultaneous CSI part 1 and CSI part 2 is not implemented"); - return SRSLTE_ERROR; - } + // if (uci_cfg->o_csi1 != 0 && uci_cfg->o_csi2) { + // ERROR("Simultaneous CSI part 1 and CSI part 2 is not implemented"); + // return SRSLTE_ERROR; + // } return E_tot; } @@ -800,7 +807,7 @@ uint32_t srslte_uci_nr_total_bits(const srslte_uci_cfg_nr_t* uci_cfg) return 0; } - return uci_cfg->o_ack + uci_cfg->o_csi1 + uci_cfg->o_csi2 + uci_cfg->o_sr; + return uci_cfg->o_ack + uci_cfg->o_sr + srslte_csi_nof_bits(uci_cfg->csi, uci_cfg->nof_csi); } uint32_t srslte_uci_nr_info(const srslte_uci_data_nr_t* uci_data, char* str, uint32_t str_len) @@ -815,22 +822,12 @@ uint32_t srslte_uci_nr_info(const srslte_uci_data_nr_t* uci_data, char* str, uin len = srslte_print_check(str, str_len, len, ", ack=%s", str2); } - if (uci_data->cfg.o_csi1 > 0) { - char str2[10]; - srslte_vec_sprint_bin(str2, 10, uci_data->value.csi1, uci_data->cfg.o_csi1); - len = srslte_print_check(str, str_len, len, ", csi1=%s", str2); - } - - if (uci_data->cfg.o_csi2 > 0) { - char str2[10]; - srslte_vec_sprint_bin(str2, 10, uci_data->value.csi2, uci_data->cfg.o_csi2); - len = srslte_print_check(str, str_len, len, ", csi2=%s", str2); + if (uci_data->cfg.nof_csi > 0) { + len += srslte_csi_str(uci_data->cfg.csi, uci_data->value.csi, uci_data->cfg.nof_csi, &str[len], str_len - len); } if (uci_data->cfg.o_sr > 0) { - char str2[10]; - srslte_vec_sprint_bin(str2, 10, uci_data->value.sr, uci_data->cfg.o_sr); - len = srslte_print_check(str, str_len, len, ", sr=%s", str2); + len = srslte_print_check(str, str_len, len, ", sr=%d", uci_data->value.sr); } return len; diff --git a/lib/src/phy/rf/rf_zmq_imp_tx.c b/lib/src/phy/rf/rf_zmq_imp_tx.c index 73e7c6342..7f8e92bf4 100644 --- a/lib/src/phy/rf/rf_zmq_imp_tx.c +++ b/lib/src/phy/rf/rf_zmq_imp_tx.c @@ -54,7 +54,7 @@ int rf_zmq_tx_open(rf_zmq_tx_t* q, rf_zmq_opts_t opts, void* zmq_ctx, char* sock ret = zmq_bind(q->sock, sock_args); if (ret) { - fprintf(stderr, "Error: connecting transmitter socket: %s\n", zmq_strerror(zmq_errno())); + fprintf(stderr, "Error: binding transmitter socket (%s): %s\n", sock_args, zmq_strerror(zmq_errno())); goto clean_exit; } diff --git a/lib/src/phy/ue/ue_dl.c b/lib/src/phy/ue/ue_dl.c index 438987870..14df04ceb 100644 --- a/lib/src/phy/ue/ue_dl.c +++ b/lib/src/phy/ue/ue_dl.c @@ -76,7 +76,6 @@ int srslte_ue_dl_init(srslte_ue_dl_t* q, cf_t* in_buffer[SRSLTE_MAX_PORTS], uint q->nof_rx_antennas = nof_rx_antennas; q->mi_auto = true; q->mi_manual_index = 0; - q->pregen_rnti = 0; for (int j = 0; j < SRSLTE_MAX_PORTS; j++) { q->sf_symbols[j] = srslte_vec_cf_malloc(MAX_SFLEN_RE); @@ -249,9 +248,6 @@ int srslte_ue_dl_set_cell(srslte_ue_dl_t* q, srslte_cell_t cell) return SRSLTE_ERROR; } } - if (q->pregen_rnti) { - srslte_ue_dl_set_rnti(q, q->pregen_rnti); - } ret = SRSLTE_SUCCESS; } else { ERROR("Invalid cell properties ue_dl: Id=%d, Ports=%d, PRBs=%d", cell.id, cell.nof_ports, cell.nof_prb); @@ -275,34 +271,6 @@ void srslte_ue_dl_set_mi_manual(srslte_ue_dl_t* q, uint32_t mi_idx) q->mi_manual_index = mi_idx; } -/* Precalculate the PDSCH scramble sequences for a given RNTI. This function takes a while - * to execute, so shall be called once the final C-RNTI has been allocated for the session. - * For the connection procedure, use srslte_pusch_encode_rnti() or srslte_pusch_decode_rnti() functions - */ -void srslte_ue_dl_set_rnti(srslte_ue_dl_t* q, uint16_t rnti) -{ - srslte_pdsch_set_rnti(&q->pdsch, rnti); - - srslte_dl_sf_cfg_t sf_cfg; - ZERO_OBJECT(sf_cfg); - - // Compute UE-specific and Common search space for this RNTI - for (int i = 0; i < SRSLTE_MI_NOF_REGS; i++) { - srslte_pdcch_set_regs(&q->pdcch, &q->regs[i]); - for (int cfi = 1; cfi <= SRSLTE_NOF_CFI; cfi++) { - sf_cfg.cfi = cfi; - for (int sf_idx = 0; sf_idx < SRSLTE_NOF_SF_X_FRAME; sf_idx++) { - sf_cfg.tti = sf_idx; - q->current_ss_ue[i][SRSLTE_CFI_IDX(cfi)][sf_idx].nof_locations = srslte_pdcch_ue_locations( - &q->pdcch, &sf_cfg, q->current_ss_ue[i][SRSLTE_CFI_IDX(cfi)][sf_idx].loc, SRSLTE_MAX_CANDIDATES_UE, rnti); - } - q->current_ss_common[i][SRSLTE_CFI_IDX(cfi)].nof_locations = srslte_pdcch_common_locations( - &q->pdcch, q->current_ss_common[i][SRSLTE_CFI_IDX(cfi)].loc, SRSLTE_MAX_CANDIDATES_COM, cfi); - } - } - q->pregen_rnti = rnti; -} - /* Set the area ID on pmch and chest_dl to generate scrambling sequence and reference * signals. */ @@ -486,9 +454,6 @@ static int dci_blind_search(srslte_ue_dl_t* q, // 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)) { - uint32_t sf_idx = sf->tti % 10; - uint32_t cfi = sf->cfi; - /* * A UE configured to monitor PDCCH candidates whose CRCs are scrambled with C-RNTI or SPS C-RNTI, * with a common payload size and with the same first CCE index ncce, but with different sets of DCI @@ -496,9 +461,8 @@ static int dci_blind_search(srslte_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 (srslte_location_find_ncce(q->current_ss_common[MI_IDX(sf_idx)][cfi - 1].loc, - q->current_ss_common[MI_IDX(sf_idx)][cfi - 1].nof_locations, - dci_msg[nof_dci].location.ncce)) { + if (srslte_location_find_ncce( + q->current_ss_common.loc, q->current_ss_common.nof_locations, dci_msg[nof_dci].location.ncce)) { srslte_dci_cfg_t cfg = *dci_cfg; srslte_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) @@ -556,10 +520,8 @@ static int find_dci_ss(srslte_ue_dl_t* q, uint32_t nof_formats, bool is_ue) { - dci_blind_search_t search_space = {}; - dci_blind_search_t* current_ss = &search_space; + dci_blind_search_t search_space = {}; - uint32_t sf_idx = sf->tti % SRSLTE_NOF_SF_X_FRAME; uint32_t cfi = sf->cfi; srslte_dci_cfg_t dci_cfg = cfg->cfg.dci; @@ -568,39 +530,31 @@ static int find_dci_ss(srslte_ue_dl_t* q, return SRSLTE_ERROR_INVALID_INPUTS; } + // Generate Common Search space + q->current_ss_common.nof_locations = + srslte_pdcch_common_locations(&q->pdcch, q->current_ss_common.loc, SRSLTE_MAX_CANDIDATES_COM, cfi); + // Generate Search Space if (is_ue) { - if (q->pregen_rnti == rnti) { - current_ss = &q->current_ss_ue[MI_IDX(sf_idx)][SRSLTE_CFI_IDX(cfi)][sf_idx]; - } else { - // If locations are not pre-generated, generate them now - current_ss->nof_locations = - srslte_pdcch_ue_locations(&q->pdcch, sf, current_ss->loc, SRSLTE_MAX_CANDIDATES_UE, rnti); - } + search_space.nof_locations = + srslte_pdcch_ue_locations(&q->pdcch, sf, search_space.loc, SRSLTE_MAX_CANDIDATES_UE, rnti); } else { // Disable extended CSI request and SRS request in common SS srslte_dci_cfg_set_common_ss(&dci_cfg); - - if (q->pregen_rnti == rnti) { - current_ss = &q->current_ss_common[MI_IDX(sf_idx)][SRSLTE_CFI_IDX(cfi)]; - } else { - // If locations are not pre-generated, generate them now - current_ss->nof_locations = - srslte_pdcch_common_locations(&q->pdcch, current_ss->loc, SRSLTE_MAX_CANDIDATES_COM, cfi); - } + search_space = q->current_ss_common; } // Search for DCI in the SS - current_ss->nof_formats = nof_formats; - memcpy(current_ss->formats, formats, nof_formats * sizeof(srslte_dci_format_t)); + search_space.nof_formats = nof_formats; + memcpy(search_space.formats, formats, nof_formats * sizeof(srslte_dci_format_t)); INFO("Searching %d formats in %d locations in %s SS, csi=%d", nof_formats, - current_ss->nof_locations, + search_space.nof_locations, is_ue ? "ue" : "common", dci_cfg.multiple_csi_request_enabled); - return dci_blind_search(q, sf, rnti, current_ss, &dci_cfg, dci_msg, cfg->cfg.dci_common_ss); + return dci_blind_search(q, sf, rnti, &search_space, &dci_cfg, dci_msg, cfg->cfg.dci_common_ss); } /* diff --git a/lib/src/phy/ue/ue_ul.c b/lib/src/phy/ue/ue_ul.c index fc253e3c2..94eb3c2ef 100644 --- a/lib/src/phy/ue/ue_ul.c +++ b/lib/src/phy/ue/ue_ul.c @@ -174,17 +174,6 @@ int srslte_ue_ul_set_cell(srslte_ue_ul_t* q, srslte_cell_t cell) return ret; } -/* Precalculate the PUSCH scramble sequences for a given RNTI. This function takes a while - * to execute, so shall be called once the final C-RNTI has been allocated for the session. - * For the connection procedure, use srslte_pusch_encode_rnti() or srslte_pusch_decode_rnti() functions - */ -void srslte_ue_ul_set_rnti(srslte_ue_ul_t* q, uint16_t rnti) -{ - srslte_pusch_set_rnti(&q->pusch, rnti); - srslte_pucch_set_rnti(&q->pucch, rnti); - q->current_rnti = rnti; -} - int srslte_ue_ul_pregen_signals(srslte_ue_ul_t* q, srslte_ue_ul_cfg_t* cfg) { if (q->signals_pregenerated) { @@ -634,7 +623,8 @@ int srslte_ue_ul_encode(srslte_ue_ul_t* q, srslte_ul_sf_cfg_t* sf, srslte_ue_ul_ } else if ((uci_pending(cfg->ul_cfg.pucch.uci_cfg) || data->uci.scheduling_request) && cfg->cc_idx == 0) { // Send PUCCH over PCell only if (!cfg->ul_cfg.pucch.rnti) { - cfg->ul_cfg.pucch.rnti = q->current_rnti; + ERROR("Encoding PUCCH: rnti not set in ul_cfg\n"); + return SRSLTE_ERROR; } ret = pucch_encode(q, sf, cfg, &data->uci) ? -1 : 1; } else if (srs_tx_enabled(&cfg->ul_cfg.srs, sf->tti)) { diff --git a/lib/src/phy/ue/ue_ul_nr.c b/lib/src/phy/ue/ue_ul_nr.c index 1d2f721cb..a37ff5898 100644 --- a/lib/src/phy/ue/ue_ul_nr.c +++ b/lib/src/phy/ue/ue_ul_nr.c @@ -148,8 +148,20 @@ static int ue_ul_nr_encode_pucch_format1(srslte_ue_ul_nr_t* q, const srslte_uci_data_nr_t* uci_data) { uint8_t b[SRSLTE_PUCCH_NR_FORMAT1_MAX_NOF_BITS] = {}; - b[0] = uci_data->value.ack[0]; - uint32_t nof_bits = 1; + + // Set ACK bits + uint32_t nof_bits = SRSLTE_MIN(SRSLTE_PUCCH_NR_FORMAT1_MAX_NOF_BITS, uci_data->cfg.o_ack); + for (uint32_t i = 0; i < nof_bits; i++) { + b[i] = uci_data->value.ack[i]; + } + + // Set SR bits + // For a positive SR transmission using PUCCH format 1, the UE transmits the PUCCH as described in [4, TS + // 38.211] by setting b ( 0 ) = 0 . + if (nof_bits == 0 && uci_data->cfg.o_sr > 0 && uci_data->value.sr > 0) { + b[0] = 0; + nof_bits = 1; + } if (srslte_dmrs_pucch_format1_put(&q->pucch, &q->carrier, cfg, slot, resource, q->sf_symbols[0])) { return SRSLTE_ERROR; @@ -247,3 +259,36 @@ int srslte_ue_ul_nr_pucch_info(const srslte_pucch_nr_resource_t* resource, return len; } + +int srslte_ue_ul_nr_sr_send_slot(const srslte_pucch_nr_sr_resource_t sr_resources[SRSLTE_PUCCH_MAX_NOF_SR_RESOURCES], + uint32_t slot_idx, + uint32_t sr_resource_id[SRSLTE_PUCCH_MAX_NOF_SR_RESOURCES]) +{ + int count = 0; + + // Check inputs + if (sr_resources == NULL) { + return SRSLTE_ERROR_INVALID_INPUTS; + } + + // Iterate over all SR resources + for (uint32_t i = 0; i < SRSLTE_PUCCH_MAX_NOF_SR_RESOURCES; i++) { + const srslte_pucch_nr_sr_resource_t* res = &sr_resources[i]; + + // Skip if resource is not provided + if (!res->configured) { + continue; + } + + // Check periodicity and offset condition + if ((slot_idx + res->period - res->offset) % res->period == 0) { + if (sr_resource_id != NULL) { + sr_resource_id[count] = i; + } + count++; + } + } + + // If the program reached this point is because there is no SR transmission opportunity + return count; +} \ No newline at end of file diff --git a/lib/src/phy/utils/vector.c b/lib/src/phy/utils/vector.c index 766752124..aa397cdbf 100644 --- a/lib/src/phy/utils/vector.c +++ b/lib/src/phy/utils/vector.c @@ -205,6 +205,11 @@ void srslte_vec_u8_zero(uint8_t* ptr, uint32_t nsamples) SRSLTE_MEM_ZERO(ptr, uint8_t, nsamples); } +void srslte_vec_i8_zero(int8_t* ptr, uint32_t nsamples) +{ + SRSLTE_MEM_ZERO(ptr, int8_t, nsamples); +} + void srslte_vec_i16_zero(int16_t* ptr, uint32_t nsamples) { SRSLTE_MEM_ZERO(ptr, int16_t, nsamples); diff --git a/lib/src/system/CMakeLists.txt b/lib/src/system/CMakeLists.txt new file mode 100644 index 000000000..d1f3cd9fd --- /dev/null +++ b/lib/src/system/CMakeLists.txt @@ -0,0 +1,15 @@ +# +# 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. +# + +set(SOURCES + sys_metrics_processor.cc) + +find_package(Threads REQUIRED) + +add_library(system STATIC ${SOURCES}) +target_link_libraries(system "${CMAKE_THREAD_LIBS_INIT}") diff --git a/lib/src/system/sys_metrics_processor.cc b/lib/src/system/sys_metrics_processor.cc new file mode 100644 index 000000000..8e11ebbe0 --- /dev/null +++ b/lib/src/system/sys_metrics_processor.cc @@ -0,0 +1,162 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2020 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 "srslte/system/sys_metrics_processor.h" +#include +#include +#include +#include + +using namespace srslte; + +sys_metrics_processor::proc_stats_info::proc_stats_info() +{ + std::string line; + { + std::ifstream file("/proc/self/stat"); + if (!file) { + return; + } + + std::getline(file, line); + } + + std::istringstream reader(line); + reader >> pid >> comm >> state >> ppid >> pgrp >> session >> tty_nr >> tpgid >> flags >> minflt >> cminflt >> + majflt >> cmajflt >> utime >> stime >> cutime >> cstime >> priority >> nice >> num_threads >> itrealvalue >> + starttime >> vsize >> rss >> rsslim >> startcode >> endcode >> startstack >> kstkeip >> signal >> blocked >> + sigignore >> sigcatch >> wchan >> nswap >> cnswap >> exit_signal >> processor >> rt_priority >> policy >> + delaycct_blkio_ticks >> guest_time >> cguest_time >> start_data >> end_data >> start_brk >> arg_start >> + arg_end >> env_start >> env_end >> exit_code; +} + +sys_metrics_t sys_metrics_processor::get_metrics() +{ + auto current_time = std::chrono::steady_clock::now(); + uint32_t measure_interval_ms = + std::chrono::duration_cast(current_time - last_query_time).count(); + + // The time elapsed between 2 measures must be greater that 100 milliseconds. + if (measure_interval_ms < 100u) { + return {}; + } + + sys_metrics_t metrics; + + // Get the memory metrics. + calculate_mem_usage(metrics); + + // Get the stats from the proc. + proc_stats_info current_query; + metrics.thread_count = current_query.num_threads; + metrics.process_cpu_usage = calculate_cpu_usage(current_query, measure_interval_ms / 1000.f); + + // Update the last values. + last_query_time = current_time; + last_query = std::move(current_query); + + return metrics; +} + +float sys_metrics_processor::calculate_cpu_usage(const proc_stats_info& current_query, + float delta_time_in_seconds) const +{ + // Error current value has to be greater than last value. + if (current_query.stime < last_query.stime || current_query.utime < last_query.utime) { + return -1.f; + } + + // If current and last tick counter equals, means that the process didn't used CPU. + if (current_query.stime == last_query.stime && current_query.utime == last_query.utime) { + return 0.f; + } + + static const uint32_t cpu_count = ::sysconf(_SC_NPROCESSORS_CONF); + static const float ticks_per_second = ::sysconf(_SC_CLK_TCK); + + return ((current_query.stime + current_query.utime) - (last_query.stime + last_query.utime)) * 100.f / + (cpu_count * ticks_per_second * delta_time_in_seconds); +} + +/// Extracts and returns the memory size from the given line. +static uint32_t read_memory_value_from_line(const std::string& line) +{ + std::istringstream reader(line); + std::string label, unit; + uint32_t value; + + reader >> label >> value >> unit; + + return value; +} + +/// Sets the memory parameters of the given metrics to zero. +static void set_mem_to_zero(sys_metrics_t& metrics) +{ + metrics.process_realmem_kB = 0; + metrics.process_virtualmem_kB = 0; + metrics.process_virtualmem = 0; + metrics.process_realmem = 0; + metrics.system_mem = 0; +} + +static void calculate_percentage_memory(sys_metrics_t& metrics) +{ + std::ifstream file("/proc/meminfo"); + std::string line; + + if (!file) { + set_mem_to_zero(metrics); + return; + } + + // Total system's memory is in the first line. + std::getline(file, line); + uint32_t total_mem_kB = read_memory_value_from_line(line); + + // System's available memory is in the third line. + std::getline(file, line); + std::getline(file, line); + uint32_t available_mem_kB = read_memory_value_from_line(line); + + // Calculate the metrics. + metrics.process_realmem = 100.f * (float(metrics.process_realmem_kB) / total_mem_kB); + metrics.process_virtualmem = 100.f * (float(metrics.process_virtualmem_kB) / total_mem_kB); + metrics.system_mem = (1.f - float(available_mem_kB) / float(total_mem_kB)) * 100.f; +} + +void sys_metrics_processor::calculate_mem_usage(sys_metrics_t& metrics) const +{ + std::ifstream file("/proc/self/status"); + std::string line; + + if (!file) { + set_mem_to_zero(metrics); + return; + } + + while (std::getline(file, line)) { + // Looks for Virtual memory. + if (line.find("VmSize:") != std::string::npos) { + metrics.process_virtualmem_kB = read_memory_value_from_line(line); + continue; + } + // Looks for physical memory. + if (line.find("VmRSS:") != std::string::npos) { + metrics.process_realmem_kB = read_memory_value_from_line(line); + continue; + } + } + + // Now calculate the memory usage in percentage. + calculate_percentage_memory(metrics); +} diff --git a/lib/src/upper/pdcp.cc b/lib/src/upper/pdcp.cc index 1ae1cd2ed..68cffb55c 100644 --- a/lib/src/upper/pdcp.cc +++ b/lib/src/upper/pdcp.cc @@ -103,13 +103,8 @@ void pdcp::add_bearer(uint32_t lcid, pdcp_config_t cfg) { if (not valid_lcid(lcid)) { std::unique_ptr entity; - if (cfg.sn_len == srslte::PDCP_SN_LEN_18) { - // create NR entity for 18bit SN length - - entity.reset(new pdcp_entity_nr{rlc, rrc, gw, task_sched, logger, lcid, cfg}); - } else { - entity.reset(new pdcp_entity_lte{rlc, rrc, gw, task_sched, logger, lcid, cfg}); - } + // For now we create an pdcp entity lte for nr due to it's maturity + entity.reset(new pdcp_entity_lte{rlc, rrc, gw, task_sched, logger, lcid, cfg}); if (not pdcp_array.insert(std::make_pair(lcid, std::move(entity))).second) { logger.error("Error inserting PDCP entity in to array."); return; diff --git a/lib/src/upper/pdcp_entity_lte.cc b/lib/src/upper/pdcp_entity_lte.cc index b118e1a1c..155ed03e7 100644 --- a/lib/src/upper/pdcp_entity_lte.cc +++ b/lib/src/upper/pdcp_entity_lte.cc @@ -22,10 +22,16 @@ #include "srslte/upper/pdcp_entity_lte.h" #include "srslte/common/int_helpers.h" #include "srslte/common/security.h" +#include "srslte/interfaces/ue_gw_interfaces.h" +#include "srslte/interfaces/ue_rlc_interfaces.h" #include namespace srslte { +/**************************************************************************** + * PDCP Entity LTE class + ***************************************************************************/ + pdcp_entity_lte::pdcp_entity_lte(srsue::rlc_interface_pdcp* rlc_, srsue::rrc_interface_pdcp* rrc_, srsue::gw_interface_pdcp* gw_, @@ -52,23 +58,9 @@ pdcp_entity_lte::pdcp_entity_lte(srsue::rlc_interface_pdcp* rlc_, st.tx_hfn = 0; st.rx_hfn = 0; st.next_pdcp_rx_sn = 0; - maximum_pdcp_sn = (1 << cfg.sn_len) - 1; + maximum_pdcp_sn = (1u << cfg.sn_len) - 1u; st.last_submitted_pdcp_rx_sn = maximum_pdcp_sn; - uint32_t discard_time_value = static_cast(cfg.discard_timer); - if (discard_time_value > 0) { - // Note: One extra position is reserved at the end for the status report - discard_timers.reserve(maximum_pdcp_sn + 2); - for (uint32_t sn = 0; sn < maximum_pdcp_sn + 2; ++sn) { - discard_timers.emplace_back(task_sched.get_unique_timer()); - discard_callback discard_fnc(this, sn); - discard_timers[sn].set(discard_time_value, discard_fnc); - } - } - - // Queue Helpers - maximum_allocated_sns_window = (1 << cfg.sn_len) / 2; - if (is_drb() && not rlc->rb_is_um(lcid) && cfg.discard_timer == pdcp_discard_timer_t::infinity) { logger.warning( "Setting discard timer to 1500ms, to avoid issues with lingering SDUs in the Unacknowledged SDUs map. LCID=%d", @@ -76,6 +68,9 @@ pdcp_entity_lte::pdcp_entity_lte(srsue::rlc_interface_pdcp* rlc_, cfg.discard_timer = pdcp_discard_timer_t::ms1500; } + // Queue Helpers + maximum_allocated_sns_window = (1u << cfg.sn_len) / 2u; + logger.info("Init %s with bearer ID: %d", rrc->get_rb_name(lcid).c_str(), cfg.bearer_id); logger.info("SN len bits: %d, SN len bytes: %d, reordering window: %d, Maximum SN: %d, discard timer: %d ms", cfg.sn_len, @@ -85,6 +80,10 @@ pdcp_entity_lte::pdcp_entity_lte(srsue::rlc_interface_pdcp* rlc_, static_cast(cfg.discard_timer)); logger.info("Status Report Required: %s", cfg.status_report_required ? "True" : "False"); + if (is_drb() and not rlc->rb_is_um(lcid)) { + undelivered_sdus = std::unique_ptr(new undelivered_sdus_queue(task_sched)); + } + // Check supported config if (!check_valid_config()) { srslte::console("Warning: Invalid PDCP config.\n"); @@ -106,7 +105,6 @@ void pdcp_entity_lte::reestablish() st.tx_hfn = 0; st.rx_hfn = 0; st.next_pdcp_rx_sn = 0; - undelivered_sdus_queue.clear(); } else if (rlc->rb_is_um(lcid)) { // Only reset counter in RLC-UM st.next_pdcp_tx_sn = 0; @@ -114,21 +112,7 @@ void pdcp_entity_lte::reestablish() st.rx_hfn = 0; st.next_pdcp_rx_sn = 0; } else { - // Send status report if required on reestablishment in RLC AM - // send_status_report(); - - // Re-transmit unacknowledged SDUs - /* - send_status_report(); - - // Re-transmit unacknowledged SDUs - std::map undelivered_sdus = std::move(undelivered_sdus_queue); - undelivered_sdus_queue.clear(); - - for (std::map::iterator it = undelivered_sdus.begin(); it != undelivered_sdus.end(); - ++it) { - write_sdu(std::move(it->second), it->first); - }*/ + // Sending the status report will be triggered by the RRC if required } } @@ -164,20 +148,12 @@ void pdcp_entity_lte::write_sdu(unique_byte_buffer_t sdu, int upper_sn) // PDUs will be removed from the queue, either when the lower layers will report // a succesfull transmission or when the discard timer expires. // Status report will also use this queue, to know the First Missing SDU (FMS). - if (!rlc->rb_is_um(lcid)) { + if (!rlc->rb_is_um(lcid) and is_drb()) { if (not store_sdu(used_sn, sdu)) { // Could not store the SDU, discarding + logger.info("Could not store SDU. Discarding %d\n", used_sn); return; } - - // Start discard timer - if (cfg.discard_timer != pdcp_discard_timer_t::infinity) { - unique_timer* timer = get_discard_timer(used_sn); - if (timer != nullptr) { - timer->run(); - logger.debug("Discard Timer set for SN %u. Timeout: %ums", used_sn, static_cast(cfg.discard_timer)); - } - } } // check for pending security config in transmit direction @@ -293,7 +269,6 @@ void pdcp_entity_lte::handle_control_pdu(unique_byte_buffer_t pdu) logger.warning("Unhandled control PDU"); return; } - return; } /**************************************************************************** @@ -455,6 +430,12 @@ void pdcp_entity_lte::send_status_report() return; } + // Don't send status report on SRBs + if (not is_drb()) { + logger.debug("Trying to send PDCP Status Report on SRB"); + return; + } + if (not cfg.status_report_required) { logger.info("Not sending PDCP Status Report as status report required is not set"); return; @@ -462,13 +443,14 @@ void pdcp_entity_lte::send_status_report() // Get First Missing Segment (FMS) uint32_t fms = 0; - if (undelivered_sdus_queue.empty()) { + if (undelivered_sdus->empty()) { fms = st.next_pdcp_tx_sn; } else { - fms = undelivered_sdus_queue.begin()->first; + fms = undelivered_sdus->get_fms(); } - logger.debug("Status report: FMS=%d", fms); + // Get Last Missing Segment + uint32_t lms = undelivered_sdus->get_lms(); // Allocate Status Report PDU unique_byte_buffer_t pdu = make_byte_buffer(); @@ -477,6 +459,7 @@ void pdcp_entity_lte::send_status_report() return; } + logger.debug("Status report: FMS=%d, LMS=%d", fms, lms); // Set control bit and type of PDU pdu->msg[0] = ((uint8_t)PDCP_DC_FIELD_CONTROL_PDU << 7) | ((uint8_t)PDCP_PDU_TYPE_STATUS_REPORT << 4); @@ -499,21 +482,33 @@ void pdcp_entity_lte::send_status_report() } // Add bitmap of missing PDUs, if necessary - if (not undelivered_sdus_queue.empty()) { + if (not undelivered_sdus->empty()) { // First check size of bitmap - uint32_t last_sn = undelivered_sdus_queue.rbegin()->first; - uint32_t bitmap_sz = std::ceil((float)(last_sn - (fms - 1)) / 8); + int32_t diff = lms - (fms - 1); + uint32_t nof_sns = 1u << cfg.sn_len; + if (diff > (int32_t)(nof_sns / 2)) { + logger.info("FMS and LMS are very far apart. Not generating status report. LMS=%d FMS=%d", lms, fms); + return; + } + if (diff <= 0 && diff > -((int32_t)(nof_sns / 2))) { + logger.info("FMS and LMS are very far apart. Not generating status report. LMS=%d FMS=%d", lms, fms); + return; + } + uint32_t sn_diff = (diff > 0) ? diff : nof_sns + diff; + uint32_t bitmap_sz = std::ceil((float)(sn_diff) / 8); memset(&pdu->msg[pdu->N_bytes], 0, bitmap_sz); logger.debug( - "Setting status report bitmap. Last SN acked=%d, Last SN acked in sequence=%d, Bitmap size in bytes=%d", - last_sn, + "Setting status report bitmap. Last missing SN=%d, Last SN acked in sequence=%d, Bitmap size in bytes=%d", + lms, fms - 1, bitmap_sz); - for (auto it = undelivered_sdus_queue.begin(); it != undelivered_sdus_queue.end(); it++) { - uint32_t offset = it->first - fms; - uint32_t bit_offset = offset % 8; - uint32_t byte_offset = offset / 8; - pdu->msg[pdu->N_bytes + byte_offset] |= 1 << (7 - bit_offset); + for (uint32_t offset = 0; offset < sn_diff; ++offset) { + uint32_t sn = (fms + 1 + offset) % (1u << cfg.sn_len); + if (undelivered_sdus->has_sdu(sn)) { + uint32_t bit_offset = offset % 8; + uint32_t byte_offset = offset / 8; + pdu->msg[pdu->N_bytes + byte_offset] |= 1 << (7 - bit_offset); + } } pdu->N_bytes += bitmap_sz; } @@ -521,13 +516,23 @@ void pdcp_entity_lte::send_status_report() // Write PDU to RLC rlc->write_sdu(lcid, std::move(pdu)); - - return; } // Section 5.3.2 receive operation void pdcp_entity_lte::handle_status_report_pdu(unique_byte_buffer_t pdu) { + // Don't handle status report on SRBs + if (not is_drb()) { + logger.debug("Not handling PDCP Status Report on SRB"); + return; + } + + // Check wether RLC AM is being used. + if (rlc->rb_is_um(lcid)) { + logger.info("Not handling PDCP Status Report if RLC is not AM"); + return; + } + logger.info("Handling Status Report PDU. Size=%ld", pdu->N_bytes); uint32_t fms = 0; @@ -555,12 +560,9 @@ void pdcp_entity_lte::handle_status_report_pdu(unique_byte_buffer_t pdu) } // Remove all SDUs with SN smaller than FMS - for (auto it = undelivered_sdus_queue.begin(); it != undelivered_sdus_queue.end();) { - if (it->first < fms) { - stop_discard_timer(it->first); - it = undelivered_sdus_queue.erase(it); - } else { - ++it; + for (uint32_t sn = 0; sn < fms; sn++) { + if (sn < fms && undelivered_sdus->has_sdu(sn)) { + undelivered_sdus->clear_sdu(sn); } } @@ -578,27 +580,31 @@ void pdcp_entity_lte::handle_status_report_pdu(unique_byte_buffer_t pdu) // Discard ACK'ed SDUs for (uint32_t sn : acked_sns) { logger.debug("Status report ACKed SN=%d.", sn); - undelivered_sdus_queue.erase(sn); - stop_discard_timer(sn); + undelivered_sdus->clear_sdu(sn); } } /**************************************************************************** * TX PDUs Queue Helper ***************************************************************************/ + bool pdcp_entity_lte::store_sdu(uint32_t sn, const unique_byte_buffer_t& sdu) { - logger.debug("Storing SDU in undelivered SDUs queue. SN=%d, Queue size=%ld", sn, undelivered_sdus_queue.size()); + logger.debug("Storing SDU in undelivered SDUs queue. SN=%d, Queue size=%ld", sn, undelivered_sdus->size()); // Check wether PDU is already in the queue - if (undelivered_sdus_queue.find(sn) != undelivered_sdus_queue.end()) { + if (undelivered_sdus->has_sdu(sn)) { logger.error("PDU already exists in the queue. TX_COUNT=%d", sn); return false; } + if (undelivered_sdus->is_full()) { + logger.error("Undelivered SDUs queue is full. TX_COUNT=%d", sn); + return false; + } + // Make sure we don't associate more than half of the PDCP SN space of contiguous PDCP SDUs - if (not undelivered_sdus_queue.empty()) { - auto fms_it = undelivered_sdus_queue.begin(); - uint32_t fms_sn = fms_it->first; + if (not undelivered_sdus->empty()) { + uint32_t fms_sn = undelivered_sdus->get_fms(); int32_t diff = sn - fms_sn; if (diff > (int32_t)maximum_allocated_sns_window) { // This SN is too large to assign, it may cause HFN de-synchronization. @@ -607,7 +613,7 @@ bool pdcp_entity_lte::store_sdu(uint32_t sn, const unique_byte_buffer_t& sdu) fms_sn, diff, maximum_allocated_sns_window, - undelivered_sdus_queue.size()); + undelivered_sdus->size()); return false; } if (diff < 0 && diff > -((int32_t)maximum_allocated_sns_window)) { @@ -617,21 +623,19 @@ bool pdcp_entity_lte::store_sdu(uint32_t sn, const unique_byte_buffer_t& sdu) fms_sn, diff, maximum_allocated_sns_window, - undelivered_sdus_queue.size()); + undelivered_sdus->size()); return false; } } - // Copy PDU contents into queue - unique_byte_buffer_t sdu_copy = make_byte_buffer(); - memcpy(sdu_copy->msg, sdu->msg, sdu->N_bytes); - sdu_copy->N_bytes = sdu->N_bytes; - - // Metrics - sdu_copy->set_timestamp(); - - undelivered_sdus_queue.insert(std::make_pair(sn, std::move(sdu_copy))); - return true; + // Copy PDU contents into queue and start discard timer + uint32_t discard_timeout = static_cast(cfg.discard_timer); + discard_callback discard_fnc(this, sn); + bool ret = undelivered_sdus->add_sdu(sn, sdu, discard_timeout, discard_fnc); + if (ret and discard_timeout > 0) { + logger.debug("Discard Timer set for SN %u. Timeout: %ums", sn, discard_timeout); + } + return ret; } /**************************************************************************** @@ -642,19 +646,16 @@ void pdcp_entity_lte::discard_callback::operator()(uint32_t timer_id) { parent->logger.debug("Discard timer expired for PDU with SN = %d", discard_sn); - // Discard PDU if unacknowledged - if (parent->undelivered_sdus_queue.find(discard_sn) != parent->undelivered_sdus_queue.end()) { - parent->undelivered_sdus_queue.erase(discard_sn); - parent->logger.debug("Removed undelivered PDU with TX_COUNT=%d", discard_sn); - } else { - parent->logger.debug("Could not find PDU to discard. TX_COUNT=%d", discard_sn); - } - // Notify the RLC of the discard. It's the RLC to actually discard, if no segment was transmitted yet. parent->rlc->discard_sdu(parent->lcid, discard_sn); - // Remove timer from map - parent->stop_discard_timer(discard_sn); + // Discard PDU if unacknowledged + if (parent->undelivered_sdus->has_sdu(discard_sn)) { + parent->logger.debug("Removed undelivered PDU with TX_COUNT=%d", discard_sn); + parent->undelivered_sdus->clear_sdu(discard_sn); + } else { + parent->logger.debug("Could not find PDU to discard. TX_COUNT=%d", discard_sn); + } } /**************************************************************************** @@ -662,43 +663,53 @@ void pdcp_entity_lte::discard_callback::operator()(uint32_t timer_id) ***************************************************************************/ void pdcp_entity_lte::notify_delivery(const std::vector& pdcp_sns) { - logger.info("Received delivery notification from RLC. Number of PDU notified=%ld", pdcp_sns.size()); + if (not is_drb()) { + return; + } + logger.info("Received delivery notification from RLC. Number of PDU notified=%ld", pdcp_sns.size()); for (uint32_t sn : pdcp_sns) { logger.debug("Delivery notification received for PDU with SN=%d", sn); + if (sn == UINT32_MAX) { + continue; + } // Find undelivered PDU info - std::map::iterator it = undelivered_sdus_queue.find(sn); - if (it == undelivered_sdus_queue.end()) { + if (not undelivered_sdus->has_sdu(sn)) { logger.warning("Could not find PDU for delivery notification. Notified SN=%d", sn); } else { // Metrics + auto& sdu = (*undelivered_sdus)[sn]; tx_pdu_ack_latency_ms.push(std::chrono::duration_cast( - std::chrono::high_resolution_clock::now() - it->second->get_timestamp()) + std::chrono::high_resolution_clock::now() - sdu->get_timestamp()) .count()); - metrics.num_tx_acked_bytes += it->second->N_bytes; - metrics.num_tx_buffered_pdus_bytes -= it->second->N_bytes; + metrics.num_tx_acked_bytes += sdu->N_bytes; + metrics.num_tx_buffered_pdus_bytes -= sdu->N_bytes; // Remove PDU and disarm timer. - undelivered_sdus_queue.erase(sn); - stop_discard_timer(sn); + undelivered_sdus->clear_sdu(sn); } } } void pdcp_entity_lte::notify_failure(const std::vector& pdcp_sns) { + if (not is_drb()) { + return; + } + logger.info("Received failure notification from RLC. Number of PDU notified=%ld", pdcp_sns.size()); for (uint32_t sn : pdcp_sns) { logger.info("Failure notification received for PDU with SN=%d", sn); + if (sn == UINT32_MAX) { + continue; + } // Find undelivered PDU info - std::map::iterator it = undelivered_sdus_queue.find(sn); - if (it == undelivered_sdus_queue.end()) { + if (not undelivered_sdus->has_sdu(sn)) { logger.info("Could not find PDU for failure notification. Notified SN=%d", sn); } else { // Remove PDU and disarm timer. - undelivered_sdus_queue.erase(sn); - stop_discard_timer(sn); + undelivered_sdus->clear_sdu(sn); } } } @@ -742,42 +753,12 @@ void pdcp_entity_lte::set_bearer_state(const pdcp_lte_state_t& state) std::map pdcp_entity_lte::get_buffered_pdus() { - logger.info("Buffered PDUs requested, buffer_size=%d", undelivered_sdus_queue.size()); - - std::map cpy{}; - // Deep copy undelivered SDUs - // TODO: investigate wheter the deep copy can be avoided by moving the undelivered SDU queue. - // That can only be done just before the PDCP is disabled though. - for (auto it = undelivered_sdus_queue.begin(); it != undelivered_sdus_queue.end(); it++) { - cpy[it->first] = make_byte_buffer(); - (*cpy[it->first]) = *(it->second); - logger.debug(it->second->msg, it->second->N_bytes, "Forwarding buffered PDU with SN=%d", it->first); - } - return cpy; -} - -uint32_t pdcp_entity_lte::nof_discard_timers() const -{ - return std::count_if( - discard_timers.begin(), discard_timers.end(), [](const unique_timer& t) { return t.is_running(); }); -} - -unique_timer* pdcp_entity_lte::get_discard_timer(uint32_t sn) -{ - // Note: When SN>max PDCP SN (Status report case), the position will be the last in the vector of discard timers - if (not discard_timers.empty()) { - uint32_t sn_idx = std::min((uint32_t)sn, (uint32_t)(discard_timers.size() - 1)); - return &discard_timers[sn_idx]; - } - return nullptr; -} - -void pdcp_entity_lte::stop_discard_timer(uint32_t sn) -{ - unique_timer* timer = get_discard_timer(sn); - if (timer != nullptr) { - timer->stop(); + if (undelivered_sdus == nullptr) { + logger.error("Buffered PDUs being requested for non-AM DRB"); + return std::map{}; } + logger.info("Buffered PDUs requested, buffer_size=%d", undelivered_sdus->size()); + return undelivered_sdus->get_buffered_sdus(); } /**************************************************************************** @@ -785,10 +766,9 @@ void pdcp_entity_lte::stop_discard_timer(uint32_t sn) ***************************************************************************/ pdcp_bearer_metrics_t pdcp_entity_lte::get_metrics() { - metrics.num_tx_buffered_pdus = undelivered_sdus_queue.size(); - metrics.num_tx_buffered_pdus_bytes = 0; - for (auto sdu_it = undelivered_sdus_queue.begin(); sdu_it != undelivered_sdus_queue.end(); ++sdu_it) { - metrics.num_tx_buffered_pdus_bytes += sdu_it->second->N_bytes; //< Number of bytes of PDUs waiting for ACK + if (undelivered_sdus != nullptr) { + metrics.num_tx_buffered_pdus = undelivered_sdus->size(); + metrics.num_tx_buffered_pdus_bytes = undelivered_sdus->get_bytes(); //< Number of bytes of PDUs waiting for ACK } metrics.tx_notification_latency_ms = tx_pdu_ack_latency_ms.value(); //< Average time in ms from PDU delivery to RLC to ACK notification from RLC @@ -801,4 +781,145 @@ void pdcp_entity_lte::reset_metrics() metrics.tx_notification_latency_ms = 0; } +/**************************************************************************** + * Undelivered SDUs queue helpers + ***************************************************************************/ +undelivered_sdus_queue::undelivered_sdus_queue(srslte::task_sched_handle task_sched) +{ + for (auto& e : sdus) { + e.discard_timer = task_sched.get_unique_timer(); + } +} + +bool undelivered_sdus_queue::add_sdu(uint32_t sn, + const srslte::unique_byte_buffer_t& sdu, + uint32_t discard_timeout, + const std::function& callback) +{ + assert(not has_sdu(sn) && "Cannot add repeated SNs"); + + if (is_full()) { + return false; + } + + // Make sure we don't associate more than half of the PDCP SN space of contiguous PDCP SDUs + if (not empty()) { + int32_t diff = sn - fms; + if (diff > (int32_t)(capacity / 2)) { + return false; + } + if (diff <= 0 && diff > -((int32_t)(capacity / 2))) { + return false; + } + } + + // Allocate buffer and exit on error + srslte::unique_byte_buffer_t tmp = make_byte_buffer(); + if (tmp == nullptr) { + return false; + } + + // Update FMS and LMS if necessary + if (empty()) { + fms = sn; + lms = sn; + } else { + update_lms(sn); + } + // Add SDU + count++; + sdus[sn].sdu = std::move(tmp); + sdus[sn].sdu->md.pdcp_sn = sn; + sdus[sn].sdu->N_bytes = sdu->N_bytes; + memcpy(sdus[sn].sdu->msg, sdu->msg, sdu->N_bytes); + if (discard_timeout > 0) { + sdus[sn].discard_timer.set(discard_timeout, callback); + sdus[sn].discard_timer.run(); + } + sdus[sn].sdu->set_timestamp(); // Metrics + bytes += sdu->N_bytes; + return true; +} + +bool undelivered_sdus_queue::clear_sdu(uint32_t sn) +{ + if (not has_sdu(sn)) { + return false; + } + count--; + bytes -= sdus[sn].sdu->N_bytes; + sdus[sn].discard_timer.stop(); + sdus[sn].sdu.reset(); + // Find next FMS, if necessary + if (sn == fms) { + update_fms(); + } + return true; +} + +void undelivered_sdus_queue::clear() +{ + count = 0; + bytes = 0; + fms = 0; + for (uint32_t sn = 0; sn < capacity; sn++) { + sdus[sn].discard_timer.stop(); + sdus[sn].sdu.reset(); + } +} + +size_t undelivered_sdus_queue::nof_discard_timers() const +{ + return std::count_if(sdus.begin(), sdus.end(), [](const sdu_data& s) { + return s.sdu != nullptr and s.discard_timer.is_valid() and s.discard_timer.is_running(); + }); +} + +void undelivered_sdus_queue::update_fms() +{ + if (empty()) { + fms = increment_sn(fms); + return; + } + + for (uint32_t i = 0; i < capacity / 2; ++i) { + uint32_t sn = increment_sn(fms + i); + if (has_sdu(sn)) { + fms = sn; + return; + } + } + + fms = increment_sn(fms); +} + +void undelivered_sdus_queue::update_lms(uint32_t sn) +{ + if (empty()) { + lms = fms; + return; + } + + int32_t diff = sn - lms; + if (diff > 0 && sn > lms) { + lms = sn; + } else if (diff < 0 && sn < lms) { + lms = sn; + } +} + +std::map undelivered_sdus_queue::get_buffered_sdus() +{ + std::map fwd_sdus; + for (auto& sdu : sdus) { + if (sdu.sdu != nullptr) { + // TODO: Find ways to avoid deep copy + srslte::unique_byte_buffer_t fwd_sdu = make_byte_buffer(); + *fwd_sdu = *sdu.sdu; + fwd_sdus.emplace(sdu.sdu->md.pdcp_sn, std::move(fwd_sdu)); + } + } + return fwd_sdus; +} + } // namespace srslte diff --git a/lib/src/upper/rlc_am_lte.cc b/lib/src/upper/rlc_am_lte.cc index 5c1937c73..cafc775d0 100644 --- a/lib/src/upper/rlc_am_lte.cc +++ b/lib/src/upper/rlc_am_lte.cc @@ -20,6 +20,8 @@ */ #include "srslte/upper/rlc_am_lte.h" +#include "srslte/interfaces/ue_pdcp_interfaces.h" +#include "srslte/interfaces/ue_rrc_interfaces.h" #include @@ -181,6 +183,7 @@ rlc_am_lte::rlc_am_lte_tx::rlc_am_lte_tx(rlc_am_lte* parent_) : status_prohibit_timer(parent_->timers->get_unique_timer()) { pthread_mutex_init(&mutex, NULL); + notify_info_vec.reserve(RLC_AM_WINDOW_SIZE); } rlc_am_lte::rlc_am_lte_tx::~rlc_am_lte_tx() @@ -292,6 +295,25 @@ bool rlc_am_lte::rlc_am_lte_tx::has_data() (not tx_sdu_queue.is_empty())); // or if there is a SDU queued up for transmission } +/** + * Helper to check if a SN has reached the max reTx threshold + * + * Caller _must_ hold the mutex when calling the function. + * If the retx has been reached for a SN the upper layers (i.e. RRC/PDCP) will be informed. + * The SN is _not_ removed from the Tx window, so retransmissions of that SN can still occur. + * + * @param sn The SN of the PDU to check + */ +void rlc_am_lte::rlc_am_lte_tx::check_sn_reached_max_retx(uint32_t sn) +{ + if (tx_window[sn].retx_count == cfg.max_retx_thresh) { + logger.warning("%s Signaling max number of reTx=%d for for SN=%d", RB_NAME, tx_window[sn].retx_count, sn); + parent->rrc->max_retx_attempted(); + parent->pdcp->notify_failure(parent->lcid, tx_window[sn].pdcp_sns); + parent->metrics.num_lost_pdus++; + } +} + uint32_t rlc_am_lte::rlc_am_lte_tx::get_buffer_state() { pthread_mutex_lock(&mutex); @@ -313,7 +335,7 @@ uint32_t rlc_am_lte::rlc_am_lte_tx::get_buffer_state() // Bytes needed for retx if (not retx_queue.empty()) { - rlc_amd_retx_t retx = retx_queue.front(); + rlc_amd_retx_t& retx = retx_queue.front(); logger.debug("%s Buffer state - retx - SN=%d, Segment: %s, %d:%d", RB_NAME, retx.sn, @@ -324,7 +346,7 @@ uint32_t rlc_am_lte::rlc_am_lte_tx::get_buffer_state() int req_bytes = required_buffer_size(retx); if (req_bytes < 0) { logger.error("In get_buffer_state(): Removing retx.sn=%d from queue", retx.sn); - retx_queue.pop_front(); + retx_queue.pop(); } else { n_bytes += req_bytes; logger.debug("Buffer state - retx: %d bytes", n_bytes); @@ -488,15 +510,14 @@ void rlc_am_lte::rlc_am_lte_tx::timer_expired(uint32_t timeout_id) void rlc_am_lte::rlc_am_lte_tx::retransmit_pdu() { if (not tx_window.empty()) { - // select PDU in tx window for retransmission - rlc_amd_tx_pdu_t& pdu = tx_window.front(); + // select first PDU in tx window for retransmission + rlc_amd_tx_pdu_t& pdu = tx_window[vt_a]; logger.info("%s Schedule SN=%d for reTx.", RB_NAME, pdu.rlc_sn); - rlc_amd_retx_t retx = {}; - retx.is_segment = false; - retx.so_start = 0; - retx.so_end = pdu.buf->N_bytes; - retx.sn = pdu.rlc_sn; - retx_queue.push_back(retx); + rlc_amd_retx_t& retx = retx_queue.push(); + retx.is_segment = false; + retx.so_start = 0; + retx.so_end = pdu.buf->N_bytes; + retx.sn = pdu.rlc_sn; } } @@ -582,7 +603,7 @@ int rlc_am_lte::rlc_am_lte_tx::build_retx_pdu(uint8_t* payload, uint32_t nof_byt // Sanity check - drop any retx SNs not present in tx_window while (not tx_window.has_sn(retx.sn)) { - retx_queue.pop_front(); + retx_queue.pop(); if (!retx_queue.empty()) { retx = retx_queue.front(); } else { @@ -595,7 +616,7 @@ int rlc_am_lte::rlc_am_lte_tx::build_retx_pdu(uint8_t* payload, uint32_t nof_byt int req_size = required_buffer_size(retx); if (req_size < 0) { logger.error("In build_retx_pdu(): Removing retx.sn=%d from queue", retx.sn); - retx_queue.pop_front(); + retx_queue.pop(); return -1; } @@ -628,13 +649,9 @@ int rlc_am_lte::rlc_am_lte_tx::build_retx_pdu(uint8_t* payload, uint32_t nof_byt rlc_am_write_data_pdu_header(&new_header, &ptr); memcpy(ptr, tx_window[retx.sn].buf->msg, tx_window[retx.sn].buf->N_bytes); - retx_queue.pop_front(); + retx_queue.pop(); tx_window[retx.sn].retx_count++; - if (tx_window[retx.sn].retx_count >= cfg.max_retx_thresh) { - logger.warning("%s Signaling max number of reTx=%d for for SN=%d", RB_NAME, tx_window[retx.sn].retx_count, retx.sn); - parent->rrc->max_retx_attempted(); - parent->pdcp->notify_failure(parent->lcid, tx_window[retx.sn].pdcp_sns); - } + check_sn_reached_max_retx(retx.sn); logger.info(payload, tx_window[retx.sn].buf->N_bytes, @@ -725,18 +742,12 @@ int rlc_am_lte::rlc_am_lte_tx::build_segment(uint8_t* payload, uint32_t nof_byte break; } - if (pdu_space <= 2) { - break; - } - upper += old_header.li[i]; head_len = rlc_am_packed_length(&new_header); - // Accomodate some extra space for for LIs if old header contained segments too - head_len += old_header.N_li; - pdu_space = nof_bytes - head_len; + if (pdu_space < (retx.so_end - retx.so_start)) { retx.so_end = retx.so_start + pdu_space; } @@ -757,24 +768,43 @@ int rlc_am_lte::rlc_am_lte_tx::build_segment(uint8_t* payload, uint32_t nof_byte } new_header.li[new_header.N_li] = li; - // only increment N_li if more SDU (segments) are being added + // only increment N_li if more SDU (segments) are/can being added if (retx.so_end > upper) { - new_header.N_li++; + // Calculate header space for possible segment addition + rlc_amd_pdu_header_t tmp_header = new_header; + tmp_header.N_li++; + uint32_t tmp_header_len = rlc_am_packed_length(&tmp_header); + uint32_t tmp_data_len = retx.so_end - retx.so_start; + if (tmp_header_len + tmp_data_len <= nof_bytes) { + // Space is sufficiant to fit at least 1 B of yet another segment + new_header.N_li++; + } else { + // can't add new SDU, calculate total data length + uint32_t data_len = 0; + for (uint32_t k = 0; k <= new_header.N_li; ++k) { + data_len += new_header.li[k]; + } + retx.so_end = retx.so_start + data_len; + new_header.fi &= RLC_FI_FIELD_NOT_START_ALIGNED; // segment end is aligned with this SDU + } } } lower += old_header.li[i]; } + // Santity check we don't pack beyond the provided buffer + assert(head_len + (retx.so_end - retx.so_start) <= nof_bytes); + // Update retx_queue if (tx_window[retx.sn].buf->N_bytes == retx.so_end) { - retx_queue.pop_front(); + retx_queue.pop(); new_header.lsf = 1; if (rlc_am_end_aligned(old_header.fi)) { new_header.fi &= RLC_FI_FIELD_NOT_START_ALIGNED; // segment is end aligned } } else if (retx_queue.front().so_end == retx.so_end) { - retx_queue.pop_front(); + retx_queue.pop(); } else { retx_queue.front().is_segment = true; retx_queue.front().so_start = retx.so_end; @@ -785,6 +815,8 @@ int rlc_am_lte::rlc_am_lte_tx::build_segment(uint8_t* payload, uint32_t nof_byte tx_window[retx.sn].retx_count++; } + check_sn_reached_max_retx(retx.sn); + // Write header and pdu uint8_t* ptr = payload; rlc_am_write_data_pdu_header(&new_header, &ptr); @@ -797,7 +829,7 @@ int rlc_am_lte::rlc_am_lte_tx::build_segment(uint8_t* payload, uint32_t nof_byte if (pdu_len > static_cast(nof_bytes)) { logger.error("%s Retx PDU segment length error. Available: %d, Used: %d", RB_NAME, nof_bytes, pdu_len); int header_len = (ptr - payload); - logger.debug("%s Retx PDU segment length error. Header len: %d, Payload len: %d, N_li: %d", + logger.debug("%s Retx PDU segment length error. Actual header len: %d, Payload len: %d, N_li: %d", RB_NAME, header_len, len, @@ -868,7 +900,7 @@ int rlc_am_lte::rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_byt // Check for SDU segment std::vector pdcp_sns; - if (tx_sdu != NULL) { + if (tx_sdu != nullptr) { to_move = ((pdu_space - head_len) >= tx_sdu->N_bytes) ? tx_sdu->N_bytes : pdu_space - head_len; memcpy(pdu_ptr, tx_sdu->msg, to_move); last_li = to_move; @@ -876,16 +908,20 @@ int rlc_am_lte::rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_byt pdu->N_bytes += to_move; tx_sdu->N_bytes -= to_move; tx_sdu->msg += to_move; - if (not undelivered_sdu_info_queue.has_pdcp_sn(tx_sdu->md.pdcp_sn)) { - logger.error("Could not find PDCP SN in SDU info queue (segment). PDCP_SN=%d", tx_sdu->md.pdcp_sn); - return 0; + if (undelivered_sdu_info_queue.has_pdcp_sn(tx_sdu->md.pdcp_sn)) { + pdcp_sdu_info_t& pdcp_sdu = undelivered_sdu_info_queue[tx_sdu->md.pdcp_sn]; + pdcp_sdu.rlc_sn_info_list.push_back({header.sn, false}); + pdcp_sns.push_back(tx_sdu->md.pdcp_sn); + if (tx_sdu->N_bytes == 0) { + pdcp_sdu.fully_txed = true; + } + } else { + // PDCP SNs for the RLC SDU has been removed from the queue + logger.warning("Couldn't find PDCP_SN=%d in SDU info queue (segment)", tx_sdu->md.pdcp_sn); } - pdcp_sdu_info_t& pdcp_sdu = undelivered_sdu_info_queue[tx_sdu->md.pdcp_sn]; - pdcp_sdu.rlc_sn_info_list.push_back({header.sn, false}); - pdcp_sns.push_back(tx_sdu->md.pdcp_sn); + if (tx_sdu->N_bytes == 0) { logger.debug("%s Complete SDU scheduled for tx.", RB_NAME); - pdcp_sdu.fully_txed = true; tx_sdu.reset(); } if (pdu_space > to_move) { @@ -895,11 +931,13 @@ int rlc_am_lte::rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_byt } header.fi |= RLC_FI_FIELD_NOT_START_ALIGNED; // First byte does not correspond to first byte of SDU - logger.debug("%s Building PDU - added SDU segment (len:%d) - pdu_space: %d, head_len: %d ", - RB_NAME, - to_move, - pdu_space, - head_len); + logger.debug( + "%s Building PDU - added SDU segment from previous PDU (len:%d) - pdu_space: %d, head_len: %d header_sn=%d", + RB_NAME, + to_move, + pdu_space, + head_len, + header.sn); } // Pull SDUs from queue @@ -923,16 +961,20 @@ int rlc_am_lte::rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_byt pdu->N_bytes += to_move; tx_sdu->N_bytes -= to_move; tx_sdu->msg += to_move; - if (not undelivered_sdu_info_queue.has_pdcp_sn(tx_sdu->md.pdcp_sn)) { - logger.error("Could not find PDCP SN in SDU info queue. PDCP_SN=%d", tx_sdu->md.pdcp_sn); - return 0; + if (undelivered_sdu_info_queue.has_pdcp_sn(tx_sdu->md.pdcp_sn)) { + pdcp_sdu_info_t& pdcp_sdu = undelivered_sdu_info_queue[tx_sdu->md.pdcp_sn]; + pdcp_sdu.rlc_sn_info_list.push_back({header.sn, false}); + pdcp_sns.push_back(tx_sdu->md.pdcp_sn); + if (tx_sdu->N_bytes == 0) { + pdcp_sdu.fully_txed = true; + } + } else { + // PDCP SNs for the RLC SDU has been removed from the queue + logger.warning("Couldn't find PDCP_SN=%d in SDU info queue.", tx_sdu->md.pdcp_sn); } - pdcp_sdu_info_t& pdcp_sdu = undelivered_sdu_info_queue[tx_sdu->md.pdcp_sn]; - pdcp_sdu.rlc_sn_info_list.push_back({header.sn, false}); - pdcp_sns.push_back(tx_sdu->md.pdcp_sn); + if (tx_sdu->N_bytes == 0) { logger.debug("%s Complete SDU scheduled for tx. PDCP SN=%d", RB_NAME, tx_sdu->md.pdcp_sn); - pdcp_sdu.fully_txed = true; tx_sdu.reset(); } if (pdu_space > to_move) { @@ -1027,9 +1069,8 @@ void rlc_am_lte::rlc_am_lte_tx::handle_control_pdu(uint8_t* payload, uint32_t no } // Handle ACKs and NACKs - bool update_vt_a = true; - uint32_t i = vt_a; - std::vector notify_info_vec; + bool update_vt_a = true; + uint32_t i = vt_a; while (TX_MOD_BASE(i) < TX_MOD_BASE(status.ack_sn) && TX_MOD_BASE(i) < TX_MOD_BASE(vt_s)) { bool nack = false; @@ -1039,12 +1080,13 @@ void rlc_am_lte::rlc_am_lte_tx::handle_control_pdu(uint8_t* payload, uint32_t no update_vt_a = false; if (tx_window.has_sn(i)) { auto& pdu = tx_window[i]; - if (!retx_queue_has_sn(i)) { - rlc_amd_retx_t retx = {}; - retx.sn = i; - retx.is_segment = false; - retx.so_start = 0; - retx.so_end = pdu.buf->N_bytes; + if (!retx_queue.has_sn(i)) { + rlc_amd_retx_t& retx = retx_queue.push(); + assert(tx_window[i].rlc_sn == i); + retx.sn = i; + retx.is_segment = false; + retx.so_start = 0; + retx.so_end = pdu.buf->N_bytes; if (status.nacks[j].has_so) { // sanity check @@ -1074,22 +1116,24 @@ void rlc_am_lte::rlc_am_lte_tx::handle_control_pdu(uint8_t* payload, uint32_t no pdu.buf->N_bytes); } } - retx_queue.push_back(retx); } + } else { + logger.warning("%s NACKed SN=%d already removed from Tx window", RB_NAME, i); } } } if (!nack) { - // ACKed SNs get marked and removed from tx_window if possible + // ACKed SNs get marked and removed from tx_window so PDCP get's only notified once if (tx_window.has_sn(i)) { auto& pdu = tx_window[i]; - update_notification_ack_info(pdu, notify_info_vec); - if (update_vt_a) { - tx_window.remove_pdu(i); - vt_a = (vt_a + 1) % MOD; - vt_ms = (vt_ms + 1) % MOD; - } + update_notification_ack_info(pdu); + tx_window.remove_pdu(i); + } + // Advance window if possible + if (update_vt_a) { + vt_a = (vt_a + 1) % MOD; + vt_ms = (vt_ms + 1) % MOD; } } i = (i + 1) % MOD; @@ -1114,6 +1158,7 @@ void rlc_am_lte::rlc_am_lte_tx::handle_control_pdu(uint8_t* payload, uint32_t no if (not notify_info_vec.empty()) { parent->pdcp->notify_delivery(parent->lcid, notify_info_vec); } + notify_info_vec.clear(); } /* @@ -1121,8 +1166,7 @@ void rlc_am_lte::rlc_am_lte_tx::handle_control_pdu(uint8_t* payload, uint32_t no * @tx_pdu: RLC PDU that was ack'ed. * @notify_info_vec: Vector which will keep track of the PDCP PDU SNs that have been fully ack'ed. */ -void rlc_am_lte::rlc_am_lte_tx::update_notification_ack_info(const rlc_amd_tx_pdu_t& tx_pdu, - std::vector& notify_info_vec) +void rlc_am_lte::rlc_am_lte_tx::update_notification_ack_info(const rlc_amd_tx_pdu_t& tx_pdu) { logger.debug("Updating ACK info: RLC SN=%d, number of notified SDU=%ld, number of undelivered SDUs=%ld", tx_pdu.header.sn, @@ -1234,17 +1278,6 @@ int rlc_am_lte::rlc_am_lte_tx::required_buffer_size(rlc_amd_retx_t retx) return rlc_am_packed_length(&new_header) + (retx.so_end - retx.so_start); } -bool rlc_am_lte::rlc_am_lte_tx::retx_queue_has_sn(uint32_t sn) -{ - std::deque::iterator q_it; - for (q_it = retx_queue.begin(); q_it != retx_queue.end(); ++q_it) { - if (q_it->sn == sn) { - return true; - } - } - return false; -} - /**************************************************************************** * Rx subclass implementation ***************************************************************************/ @@ -1349,8 +1382,7 @@ void rlc_am_lte::rlc_am_lte_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_b return; } - it = rx_window.find(header.sn); - if (rx_window.end() != it) { + if (rx_window.has_sn(header.sn)) { if (header.p) { logger.info("%s Status packet requested through polling bit", RB_NAME); do_status = true; @@ -1360,7 +1392,7 @@ void rlc_am_lte::rlc_am_lte_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_b } // Write to rx window - rlc_amd_rx_pdu_t pdu; + rlc_amd_rx_pdu_t& pdu = rx_window.add_pdu(header.sn); pdu.buf = srslte::make_byte_buffer(); if (pdu.buf == NULL) { #ifdef RLC_AM_BUFFER_DEBUG @@ -1368,6 +1400,7 @@ void rlc_am_lte::rlc_am_lte_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_b exit(-1); #else logger.error("Fatal Error: Couldn't allocate PDU in handle_data_pdu()."); + rx_window.remove_pdu(header.sn); return; #endif } @@ -1386,18 +1419,14 @@ void rlc_am_lte::rlc_am_lte_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_b pdu.buf->N_bytes = nof_bytes; pdu.header = header; - rx_window[header.sn] = std::move(pdu); - // Update vr_h if (RX_MOD_BASE(header.sn) >= RX_MOD_BASE(vr_h)) { vr_h = (header.sn + 1) % MOD; } // Update vr_ms - it = rx_window.find(vr_ms); - while (rx_window.end() != it) { + while (rx_window.has_sn(vr_ms)) { vr_ms = (vr_ms + 1) % MOD; - it = rx_window.find(vr_ms); } // Check poll bit @@ -1549,7 +1578,7 @@ void rlc_am_lte::rlc_am_lte_rx::reassemble_rx_sdus() } // Iterate through rx_window, assembling and delivering SDUs - while (rx_window.end() != rx_window.find(vr_r)) { + while (rx_window.has_sn(vr_r)) { // Handle any SDU segments for (uint32_t i = 0; i < rx_window[vr_r].header.N_li; i++) { len = rx_window[vr_r].header.li[i]; @@ -1671,7 +1700,7 @@ void rlc_am_lte::rlc_am_lte_rx::reassemble_rx_sdus() } it->second.segments.clear(); } - rx_window.erase(vr_r); + rx_window.remove_pdu(vr_r); vr_r = (vr_r + 1) % MOD; vr_mr = (vr_mr + 1) % MOD; } @@ -1723,9 +1752,7 @@ uint32_t rlc_am_lte::rlc_am_lte_rx::get_rx_buffered_bytes() { uint32_t buff_size = 0; pthread_mutex_lock(&mutex); - for (const auto& pdu : rx_window) { - buff_size += pdu.second.buf->N_bytes; - } + buff_size = rx_window.get_buffered_bytes(); pthread_mutex_unlock(&mutex); return buff_size; } @@ -1751,11 +1778,9 @@ void rlc_am_lte::rlc_am_lte_rx::timer_expired(uint32_t timeout_id) logger.debug("%s reordering timeout expiry - updating vr_ms (was %d)", RB_NAME, vr_ms); // 36.322 v10 Section 5.1.3.2.4 - vr_ms = vr_x; - std::map::iterator it = rx_window.find(vr_ms); - while (rx_window.end() != it) { + vr_ms = vr_x; + while (rx_window.has_sn(vr_ms)) { vr_ms = (vr_ms + 1) % MOD; - it = rx_window.find(vr_ms); } if (poll_received) { @@ -1782,7 +1807,7 @@ int rlc_am_lte::rlc_am_lte_rx::get_status_pdu(rlc_status_pdu_t* status, const ui // We don't use segment NACKs - just NACK the full PDU uint32_t i = vr_r; while (RX_MOD_BASE(i) <= RX_MOD_BASE(vr_ms) && status->N_nack < RLC_AM_WINDOW_SIZE) { - if (rx_window.find(i) != rx_window.end() || i == vr_ms) { + if (rx_window.has_sn(i) || i == vr_ms) { // only update ACK_SN if this SN has been received, or if we reached the maximum possible SN status->ack_sn = i; } else { @@ -1807,6 +1832,7 @@ int rlc_am_lte::rlc_am_lte_rx::get_status_pdu(rlc_status_pdu_t* status, const ui rlc_am_packed_length(status), max_pdu_size, status->N_nack); + return 0; } break; } @@ -1825,7 +1851,7 @@ int rlc_am_lte::rlc_am_lte_rx::get_status_pdu_length() status.ack_sn = vr_ms; uint32_t i = vr_r; while (RX_MOD_BASE(i) < RX_MOD_BASE(vr_ms) && status.N_nack < RLC_AM_WINDOW_SIZE) { - if (rx_window.find(i) == rx_window.end()) { + if (not rx_window.has_sn(i)) { status.N_nack++; } i = (i + 1) % MOD; @@ -1925,27 +1951,45 @@ bool rlc_am_lte::rlc_am_lte_rx::add_segment_and_check(rlc_amd_rx_pdu_segments_t* // Reconstruct li fields uint16_t count = 0; uint16_t carryover = 0; - for (it = pdu->segments.begin(); it != pdu->segments.end(); it++) { + uint16_t consumed_bytes = 0; // rolling sum of all allocated LIs during segment reconstruction + + for (it = pdu->segments.begin(); it != pdu->segments.end(); ++it) { logger.debug(" Handling %d PDU segments", it->header.N_li); for (uint32_t i = 0; i < it->header.N_li; i++) { - header.li[header.N_li] = it->header.li[i]; - if (i == 0) { - header.li[header.N_li] += carryover; + // variable marks total offset of each _processed_ LI of this segment + uint32_t total_pdu_offset = it->header.so; + for (uint32_t k = 0; k <= i; k++) { + total_pdu_offset += it->header.li[k]; + } + + logger.debug(" - (total_pdu_offset=%d, consumed_bytes=%d, header.li[i]=%d)",total_pdu_offset, consumed_bytes, header.li[i]); + if (total_pdu_offset > header.li[i] && total_pdu_offset > consumed_bytes) { + header.li[header.N_li] = total_pdu_offset - consumed_bytes; + consumed_bytes = total_pdu_offset; + + logger.debug(" - adding segment %d/%d (%d B, SO=%d, carryover=%d, count=%d)", + i + 1, + it->header.N_li, + header.li[header.N_li], + header.so, + carryover, + count); + header.N_li++; + count += it->header.li[i]; + carryover = 0; + } else { + logger.debug(" - Skipping segment in reTx PDU segment which is already included (%d B, SO=%d)", + it->header.li[i], + header.so); } - logger.debug(" - adding segment %d/%d (%d B, SO=%d, carryover=%d, count=%d)", - i + 1, - it->header.N_li, - header.li[header.N_li], - header.so, - carryover, - count); - header.N_li++; - count += it->header.li[i]; - carryover = 0; } if (count <= it->buf->N_bytes) { - carryover += it->buf->N_bytes - count; + carryover = it->header.so + it->buf->N_bytes; + // substract all previous LIs + for (uint32_t k = 0; k < header.N_li; ++k) { + carryover -= header.li[k]; + } logger.debug("Incremented carryover (it->buf->N_bytes=%d, count=%d). New carryover=%d", it->buf->N_bytes, count, @@ -1966,6 +2010,7 @@ bool rlc_am_lte::rlc_am_lte_rx::add_segment_and_check(rlc_amd_rx_pdu_segments_t* logger.debug("Header is end-aligned, overwrite header.li[%d]=%d", header.N_li, carryover); header.li[header.N_li] = carryover; header.N_li++; + consumed_bytes += carryover; carryover = 0; } count = 0; @@ -2257,6 +2302,11 @@ int rlc_am_write_status_pdu(rlc_status_pdu_t* status, uint8_t* payload) bool rlc_am_is_valid_status_pdu(const rlc_status_pdu_t& status) { for (uint32_t i = 0; i < status.N_nack; ++i) { + // NACK can't be larger than ACK + if ((MOD + status.ack_sn - status.nacks[i].nack_sn) % MOD > RLC_AM_WINDOW_SIZE) { + return false; + } + // Don't NACK the ACK SN if (status.nacks[i].nack_sn == status.ack_sn) { return false; } diff --git a/lib/src/upper/rlc_tm.cc b/lib/src/upper/rlc_tm.cc index 74dcefa6a..1cbb93574 100644 --- a/lib/src/upper/rlc_tm.cc +++ b/lib/src/upper/rlc_tm.cc @@ -20,6 +20,8 @@ */ #include "srslte/upper/rlc_tm.h" +#include "srslte/interfaces/ue_pdcp_interfaces.h" +#include "srslte/interfaces/ue_rrc_interfaces.h" namespace srslte { diff --git a/lib/src/upper/rlc_um_base.cc b/lib/src/upper/rlc_um_base.cc index e69272a9f..134204d8a 100644 --- a/lib/src/upper/rlc_um_base.cc +++ b/lib/src/upper/rlc_um_base.cc @@ -20,6 +20,7 @@ */ #include "srslte/upper/rlc_um_base.h" +#include "srslte/interfaces/ue_rrc_interfaces.h" #include namespace srslte { diff --git a/lib/src/upper/rlc_um_lte.cc b/lib/src/upper/rlc_um_lte.cc index 46b095795..93ed9ac30 100644 --- a/lib/src/upper/rlc_um_lte.cc +++ b/lib/src/upper/rlc_um_lte.cc @@ -20,6 +20,7 @@ */ #include "srslte/upper/rlc_um_lte.h" +#include "srslte/interfaces/ue_pdcp_interfaces.h" #include #define RX_MOD_BASE(x) (((x)-vr_uh - cfg.um.rx_window_size) % cfg.um.rx_mod) diff --git a/lib/src/upper/rlc_um_nr.cc b/lib/src/upper/rlc_um_nr.cc index abb0dedc8..72c0c77b3 100644 --- a/lib/src/upper/rlc_um_nr.cc +++ b/lib/src/upper/rlc_um_nr.cc @@ -20,6 +20,7 @@ */ #include "srslte/upper/rlc_um_nr.h" +#include "srslte/interfaces/ue_pdcp_interfaces.h" #include #define RX_MOD_NR_BASE(x) (((x)-RX_Next_Highest - cfg.um_nr.UM_Window_Size) % cfg.um_nr.mod) @@ -596,6 +597,11 @@ uint32_t rlc_um_nr_read_data_pdu_header(const uint8_t* payload, header->si = (rlc_nr_si_field_t)((*ptr >> 6) & 0x03); // 2 bits SI header->sn = (*ptr & 0x0F) << 4; // 4 bits SN + if (header->si == rlc_nr_si_field_t::full_sdu and header->sn != 0) { + fprintf(stderr, "Malformed PDU, reserved bits are set.\n"); + return 0; + } + // sanity check if (header->si == rlc_nr_si_field_t::first_segment) { // make sure two reserved bits are not set @@ -605,9 +611,12 @@ uint32_t rlc_um_nr_read_data_pdu_header(const uint8_t* payload, } } - // continue unpacking remaining SN - ptr++; - header->sn |= (*ptr & 0xFF); // 8 bits SN + if (header->si != rlc_nr_si_field_t::full_sdu) { + // continue unpacking remaining SN + ptr++; + header->sn |= (*ptr & 0xFF); // 8 bits SN + } + ptr++; } else { fprintf(stderr, "Unsupported SN length\n"); @@ -631,7 +640,9 @@ uint32_t rlc_um_nr_read_data_pdu_header(const uint8_t* payload, uint32_t rlc_um_nr_packed_length(const rlc_um_nr_pdu_header_t& header) { uint32_t len = 0; - if (header.si == rlc_nr_si_field_t::full_sdu || header.si == rlc_nr_si_field_t::first_segment) { + if (header.si == rlc_nr_si_field_t::full_sdu) { + len = 1; + } else if (header.si == rlc_nr_si_field_t::first_segment) { len = 1; if (header.sn_size == rlc_um_nr_sn_size_t::size12bits) { len++; diff --git a/lib/test/common/CMakeLists.txt b/lib/test/common/CMakeLists.txt index c62951b5f..fe88db7ef 100644 --- a/lib/test/common/CMakeLists.txt +++ b/lib/test/common/CMakeLists.txt @@ -100,3 +100,6 @@ target_link_libraries(pnf_dummy srslte_common ${CMAKE_THREAD_LIBS_INIT} ${Boost_ add_executable(pnf_bridge pnf_bridge.cc) target_link_libraries(pnf_bridge srslte_common ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) + +add_executable(mac_pcap_net_test mac_pcap_net_test.cc) +target_link_libraries(mac_pcap_net_test srslte_common ${SCTP_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) \ No newline at end of file diff --git a/lib/test/common/mac_pcap_net_test.cc b/lib/test/common/mac_pcap_net_test.cc new file mode 100644 index 000000000..94d11caf7 --- /dev/null +++ b/lib/test/common/mac_pcap_net_test.cc @@ -0,0 +1,115 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2020 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 "srslte/common/common.h" +#include "srslte/common/mac_pcap_net.h" +#include "srslte/common/test_common.h" +#include +#include + +// Write #num_pdus UL MAC PDUs using PCAP handle +void write_pcap_eutra_thread_function(srslte::mac_pcap_net* pcap_handle, + const std::array& pdu, + uint32_t num_pdus) +{ + for (uint32_t i = 0; i < num_pdus; i++) { + pcap_handle->write_ul_crnti(const_cast(pdu.data()), pdu.size(), 0x1001, true, 1, 0); + } + + std::cout << "Finished thread " << std::this_thread::get_id() << "\n"; +} + +// Write #num_pdus DL MAC NR PDUs using PCAP handle +void write_pcap_nr_thread_function(srslte::mac_pcap_net* pcap_handle, + const std::array& pdu, + uint32_t num_pdus) +{ + for (uint32_t i = 0; i < num_pdus; i++) { + pcap_handle->write_dl_crnti_nr(const_cast(pdu.data()), pdu.size(), 0x1001, 0, 1); + } + + std::cout << "Finished thread " << std::this_thread::get_id() << "\n"; +} + +int lte_mac_pcap_net_test() +{ + std::array tv = { + 0x21, 0x08, 0x22, 0x80, 0x82, 0x1f, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + uint32_t num_threads = 10; + uint32_t num_pdus_per_thread = 100; + + std::unique_ptr pcap_handle = std::unique_ptr(new srslte::mac_pcap_net()); + TESTASSERT(pcap_handle->open("127.0.0.1") == SRSLTE_SUCCESS); + TESTASSERT(pcap_handle->open("127.0.0.1") != SRSLTE_SUCCESS); // open again will fail + + std::vector writer_threads; + + for (uint32_t i = 0; i < num_threads; i++) { + writer_threads.push_back(std::thread(write_pcap_eutra_thread_function, pcap_handle.get(), tv, num_pdus_per_thread)); + } + + // wait for threads to finish + for (std::thread& thread : writer_threads) { + thread.join(); + } + TESTASSERT(pcap_handle->close() == SRSLTE_SUCCESS); + TESTASSERT(pcap_handle->close() != SRSLTE_SUCCESS); // closing twice will fail + + return SRSLTE_SUCCESS; +} + +int nr_mac_pcap_net_test() +{ + std::array tv = {0x42, 0x00, 0x08, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}; + + uint32_t num_threads = 10; + uint32_t num_pdus_per_thread = 100; + + std::unique_ptr pcap_handle = std::unique_ptr(new srslte::mac_pcap_net()); + TESTASSERT(pcap_handle->open("127.0.0.1") == SRSLTE_SUCCESS); + TESTASSERT(pcap_handle->open("127.0.0.1") != SRSLTE_SUCCESS); // open again will fail + + std::vector writer_threads; + + for (uint32_t i = 0; i < num_threads; i++) { + writer_threads.push_back(std::thread(write_pcap_nr_thread_function, pcap_handle.get(), tv, num_pdus_per_thread)); + } + + // wait for threads to finish + for (std::thread& thread : writer_threads) { + thread.join(); + } + + TESTASSERT(pcap_handle->close() == SRSLTE_SUCCESS); + TESTASSERT(pcap_handle->close() != SRSLTE_SUCCESS); // closing twice will fail + + return SRSLTE_SUCCESS; +} + +int main(int argc, char** argv) +{ + auto& mac_logger = srslog::fetch_basic_logger("MAC", false); + mac_logger.set_level(srslog::basic_levels::debug); + mac_logger.set_hex_dump_max_size(-1); + srslog::init(); + + TESTASSERT(lte_mac_pcap_net_test() == SRSLTE_SUCCESS); + TESTASSERT(nr_mac_pcap_net_test() == SRSLTE_SUCCESS); +} \ No newline at end of file diff --git a/lib/test/common/queue_test.cc b/lib/test/common/queue_test.cc index 89935f767..02ace6926 100644 --- a/lib/test/common/queue_test.cc +++ b/lib/test/common/queue_test.cc @@ -23,6 +23,7 @@ #include "srslte/common/multiqueue.h" #include "srslte/common/thread_pool.h" #include +#include #include #include @@ -243,17 +244,15 @@ int test_task_thread_pool() std::cout << "\n====== TEST task thread pool test 1: start ======\n"; // Description: check whether the tasks are successfully distributed between workers - uint32_t nof_workers = 4, nof_runs = 10000; - std::vector count_worker(nof_workers, 0); - std::vector count_mutex(nof_workers); + uint32_t nof_workers = 4, nof_runs = 10000; + std::mutex count_mutex; + std::map count_worker; task_thread_pool thread_pool(nof_workers); - thread_pool.start(); - auto task = [&count_worker, &count_mutex](uint32_t worker_id) { - std::lock_guard lock(count_mutex[worker_id]); - // std::cout << "hello world from worker " << worker_id << std::endl; - count_worker[worker_id]++; + auto task = [&count_worker, &count_mutex]() { + std::lock_guard lock(count_mutex); + count_worker[std::this_thread::get_id()]++; }; for (uint32_t i = 0; i < nof_runs; ++i) { @@ -268,12 +267,12 @@ int test_task_thread_pool() thread_pool.stop(); uint32_t total_count = 0; - for (uint32_t i = 0; i < nof_workers; ++i) { - if (count_worker[i] < 10) { - printf("WARNING: the number of tasks %d assigned to worker %d is too low\n", count_worker[i], i); + for (auto& w : count_worker) { + if (w.second < 10) { + std::cout << "WARNING: the number of tasks " << w.second << " assigned to worker " << w.first << " is too low"; } - total_count += count_worker[i]; - printf("worker %d: %d runs\n", i, count_worker[i]); + total_count += w.second; + std::cout << "worker " << w.first << ": " << w.second << " runs\n"; } if (total_count != nof_runs) { printf("Number of task runs=%d does not match total=%d\n", total_count, nof_runs); @@ -298,14 +297,14 @@ int test_task_thread_pool2() task_thread_pool thread_pool(nof_workers); thread_pool.start(); - auto task = [&workers_started, &workers_finished, &mut](uint32_t worker_id) { + auto task = [&workers_started, &workers_finished, &mut]() { { std::lock_guard lock(mut); workers_started++; } sleep(1); std::lock_guard lock(mut); - std::cout << "worker " << worker_id << " has finished\n"; + std::cout << "worker has finished\n"; workers_finished++; }; diff --git a/lib/test/common/task_scheduler_test.cc b/lib/test/common/task_scheduler_test.cc index a2cbe9d6a..94a413f48 100644 --- a/lib/test/common/task_scheduler_test.cc +++ b/lib/test/common/task_scheduler_test.cc @@ -48,12 +48,10 @@ int test_task_scheduler_no_pool() // TEST: background task is run, despite there are no pool workers state = task_result::null; - task_sched.enqueue_background_task([&task_sched, &state](uint32_t worker_id) { + srslte::get_background_workers().push_task([&task_sched, &state]() { task_sched.notify_background_task_result([&state]() { state = task_result::external; }); }); TESTASSERT(state == task_result::null); - task_sched.run_next_task(); // runs background task - TESTASSERT(state == task_result::null); task_sched.run_next_task(); // runs notification TESTASSERT(state == task_result::external); @@ -65,7 +63,7 @@ int test_task_scheduler_with_pool() srslte::task_scheduler task_sched{5, 2}; task_result state = task_result::null; - task_sched.enqueue_background_task([&task_sched, &state](uint32_t worker_id) { + srslte::get_background_workers().push_task([&task_sched, &state]() { task_sched.notify_background_task_result([&state]() { state = task_result::external; }); }); TESTASSERT(state == task_result::null); diff --git a/lib/test/mac/mac_pcap_test.cc b/lib/test/mac/mac_pcap_test.cc index 653eedfe1..b224b7f4d 100644 --- a/lib/test/mac/mac_pcap_test.cc +++ b/lib/test/mac/mac_pcap_test.cc @@ -62,8 +62,7 @@ int mac_pcap_eutra_test() uint32_t num_threads = 10; uint32_t num_pdus_per_thread = 100; - std::unique_ptr pcap_handle = - std::unique_ptr(new srslte::mac_pcap(srslte::srslte_rat_t::lte)); + std::unique_ptr pcap_handle = std::unique_ptr(new srslte::mac_pcap()); TESTASSERT(pcap_handle->open("mac_pcap_test.pcap") == SRSLTE_SUCCESS); TESTASSERT(pcap_handle->open("mac_pcap_test.pcap") != SRSLTE_SUCCESS); // open again will fail @@ -91,8 +90,7 @@ int mac_pcap_nr_test() uint32_t num_threads = 10; uint32_t num_pdus_per_thread = 100; - std::unique_ptr pcap_handle = - std::unique_ptr(new srslte::mac_pcap(srslte::srslte_rat_t::nr)); + std::unique_ptr pcap_handle = std::unique_ptr(new srslte::mac_pcap()); TESTASSERT(pcap_handle->open("mac_pcap_nr_test.pcap") == SRSLTE_SUCCESS); TESTASSERT(pcap_handle->open("mac_pcap_nr_test.pcap") != SRSLTE_SUCCESS); // open again will fail diff --git a/lib/test/mac/mac_pdu_nr_test.cc b/lib/test/mac/mac_pdu_nr_test.cc index 0d651a974..a1d8b88fa 100644 --- a/lib/test/mac/mac_pdu_nr_test.cc +++ b/lib/test/mac/mac_pdu_nr_test.cc @@ -617,7 +617,7 @@ int mac_dl_sch_pdu_unpack_and_pack_test6() int main(int argc, char** argv) { #if PCAP - pcap_handle = std::unique_ptr(new srslte::mac_pcap(srslte::srslte_rat_t::nr)); + pcap_handle = std::unique_ptr(new srslte::mac_pcap()); pcap_handle->open("mac_nr_pdu_test.pcap"); #endif diff --git a/lib/test/mac/pdu_test.cc b/lib/test/mac/pdu_test.cc index 80f20c9f0..e5b546ca2 100644 --- a/lib/test/mac/pdu_test.cc +++ b/lib/test/mac/pdu_test.cc @@ -24,8 +24,12 @@ #include "srslte/common/logmap.h" #include "srslte/common/mac_pcap.h" #include "srslte/common/test_common.h" -#include "srslte/interfaces/ue_interfaces.h" #include "srslte/mac/pdu.h" + +extern "C" { +#include "srslte/phy/phch/dci.h" +} + #include #include #include @@ -171,7 +175,7 @@ class rlc_dummy : public srslte::read_pdu_interface public: int read_pdu(uint32_t lcid, uint8_t* payload, uint32_t nof_bytes) { - uint32_t len = SRSLTE_MIN(ul_queues[lcid], nof_bytes); + uint32_t len = std::min(ul_queues[lcid], nof_bytes); // set payload bytes to LCID so we can check later if the scheduling was correct memset(payload, lcid, len); diff --git a/lib/test/phy/phy_dl_test.c b/lib/test/phy/phy_dl_test.c index aaf3ab615..c10b24a8e 100644 --- a/lib/test/phy/phy_dl_test.c +++ b/lib/test/phy/phy_dl_test.c @@ -258,21 +258,23 @@ check_softbits(srslte_enb_dl_t* enb_dl, srslte_ue_dl_t* ue_dl, srslte_ue_dl_cfg_ { int ret = SRSLTE_SUCCESS; - // Generate sequence - srslte_sequence_pdsch(&ue_dl->pdsch.tmp_seq, - rnti, - ue_dl_cfg->cfg.pdsch.grant.tb[tb].cw_idx, - 2 * (sf_idx % 10), - cell.id, - ue_dl_cfg->cfg.pdsch.grant.tb[tb].nof_bits); - // Scramble if (ue_dl->pdsch.llr_is_8bit) { - srslte_scrambling_sb_offset( - &ue_dl->pdsch.tmp_seq, ue_dl->pdsch.e[tb], 0, ue_dl_cfg->cfg.pdsch.grant.tb[tb].nof_bits); + srslte_sequence_pdsch_apply_c(ue_dl->pdsch.e[tb], + ue_dl->pdsch.e[tb], + rnti, + ue_dl_cfg->cfg.pdsch.grant.tb[tb].cw_idx, + 2 * (sf_idx % 10), + cell.id, + ue_dl_cfg->cfg.pdsch.grant.tb[tb].nof_bits); } else { - srslte_scrambling_s_offset( - &ue_dl->pdsch.tmp_seq, ue_dl->pdsch.e[tb], 0, ue_dl_cfg->cfg.pdsch.grant.tb[tb].nof_bits); + srslte_sequence_pdsch_apply_s(ue_dl->pdsch.e[tb], + ue_dl->pdsch.e[tb], + rnti, + ue_dl_cfg->cfg.pdsch.grant.tb[tb].cw_idx, + 2 * (sf_idx % 10), + cell.id, + ue_dl_cfg->cfg.pdsch.grant.tb[tb].nof_bits); } int16_t* rx = ue_dl->pdsch.e[tb]; uint8_t* rx_bytes = ue_dl->pdsch.e[tb]; @@ -386,11 +388,6 @@ int main(int argc, char** argv) goto quit; } - if (srslte_enb_dl_add_rnti(enb_dl, rnti)) { - ERROR("Error adding RNTI"); - goto quit; - } - /* * Initialise UE */ @@ -404,8 +401,6 @@ int main(int argc, char** argv) goto quit; } - srslte_ue_dl_set_rnti(ue_dl, rnti); - /* * Create PDCCH Allocations */ diff --git a/lib/test/phy/pucch_ca_test.c b/lib/test/phy/pucch_ca_test.c index 8742259ca..1cbf0b86a 100644 --- a/lib/test/phy/pucch_ca_test.c +++ b/lib/test/phy/pucch_ca_test.c @@ -87,12 +87,10 @@ static int test_pucch_ca(srslte_ack_nack_feedback_mode_t ack_nack_feedback_mode, // Init UE TESTASSERT(!srslte_ue_ul_init(&ue_ul, buffer, cell.nof_prb)); TESTASSERT(!srslte_ue_ul_set_cell(&ue_ul, cell)); - srslte_ue_ul_set_rnti(&ue_ul, rnti); // Init eNb TESTASSERT(!srslte_enb_ul_init(&enb_ul, buffer, cell.nof_prb)); TESTASSERT(!srslte_enb_ul_set_cell(&enb_ul, cell, &dmrs_pusch_cfg, NULL)); - TESTASSERT(!srslte_enb_ul_add_rnti(&enb_ul, rnti)); // The test itself starts here for (ul_sf.tti = 0; ul_sf.tti < (1U << (nof_carriers * 2U)); ul_sf.tti++) { diff --git a/lib/test/upper/CMakeLists.txt b/lib/test/upper/CMakeLists.txt index 24ed5c6e8..50db4bbfc 100644 --- a/lib/test/upper/CMakeLists.txt +++ b/lib/test/upper/CMakeLists.txt @@ -57,7 +57,7 @@ target_link_libraries(rlc_common_test srslte_upper srslte_phy) add_test(rlc_common_test rlc_common_test) add_executable(rlc_um_nr_pdu_test rlc_um_nr_pdu_test.cc) -target_link_libraries(rlc_um_nr_pdu_test srslte_upper srslte_phy) +target_link_libraries(rlc_um_nr_pdu_test srslte_upper srslte_mac srslte_phy) add_nr_test(rlc_um_nr_pdu_test rlc_um_nr_pdu_test) add_executable(rlc_um_nr_test rlc_um_nr_test.cc) diff --git a/lib/test/upper/pdcp_base_test.h b/lib/test/upper/pdcp_base_test.h index c2c64a532..803da7c95 100644 --- a/lib/test/upper/pdcp_base_test.h +++ b/lib/test/upper/pdcp_base_test.h @@ -27,7 +27,9 @@ #include "srslte/common/security.h" #include "srslte/common/test_common.h" #include "srslte/interfaces/pdcp_interface_types.h" +#include "srslte/interfaces/ue_gw_interfaces.h" #include "srslte/interfaces/ue_interfaces.h" +#include "srslte/interfaces/ue_rlc_interfaces.h" #include int compare_two_packets(const srslte::unique_byte_buffer_t& msg1, const srslte::unique_byte_buffer_t& msg2) diff --git a/lib/test/upper/pdcp_lte_test_status_report.cc b/lib/test/upper/pdcp_lte_test_status_report.cc index 6b4889570..c415d9d97 100644 --- a/lib/test/upper/pdcp_lte_test_status_report.cc +++ b/lib/test/upper/pdcp_lte_test_status_report.cc @@ -96,11 +96,92 @@ int test_tx_status_report(const srslte::pdcp_lte_state_t& init_state, srslog::ba TESTASSERT(out_pdu->N_bytes == 4); TESTASSERT(out_pdu->msg[0] == 0b00000001); TESTASSERT(out_pdu->msg[1] == 0b00000001); - TESTASSERT(out_pdu->msg[2] == 0b11000000); - TESTASSERT(out_pdu->msg[3] == 0b00000011); + TESTASSERT(out_pdu->msg[2] == 0b10000000); + TESTASSERT(out_pdu->msg[3] == 0b00000110); return 0; } +/* + * Test correct transmission of FMS and Bitmap in status report + */ +int test_tx_wraparound_status_report(const srslte::pdcp_lte_state_t& init_state, srslog::basic_logger& logger) +{ + srslte::pdcp_config_t cfg = {1, + srslte::PDCP_RB_IS_DRB, + srslte::SECURITY_DIRECTION_UPLINK, + srslte::SECURITY_DIRECTION_DOWNLINK, + srslte::PDCP_SN_LEN_12, + srslte::pdcp_t_reordering_t::ms500, + srslte::pdcp_discard_timer_t::ms500, + true}; + + pdcp_lte_test_helper pdcp_hlp(cfg, sec_cfg, logger); + srslte::pdcp_entity_lte* pdcp = &pdcp_hlp.pdcp; + rlc_dummy* rlc = &pdcp_hlp.rlc; + srsue::stack_test_dummy* stack = &pdcp_hlp.stack; + + pdcp_hlp.set_pdcp_initial_state(init_state); + srslte::unique_byte_buffer_t out_pdu = srslte::make_byte_buffer(); + + // Write 256 SDUs and notify imediatly -> FMS 1111 1111 0000 + for (uint32_t i = 0; i < 4080; i++) { + srslte::unique_byte_buffer_t sdu = srslte::make_byte_buffer(); + sdu->append_bytes(sdu1, sizeof(sdu1)); + pdcp->write_sdu(std::move(sdu)); + pdcp->notify_delivery({i}); + } + + // Check undelivered SDUs queue size + TESTASSERT(pdcp->nof_discard_timers() == 0); // 0 timers should be running + + // Generate the status report + pdcp->send_status_report(); + rlc->get_last_sdu(out_pdu); + logger.debug(out_pdu->msg, out_pdu->N_bytes, "Status PDU:"); + + // Check status PDU + /* + * | D/C | TYPE | FMS | -> | 0 | 000 | 1111 | + * | FMS | -> | 11110000 | + */ + TESTASSERT(out_pdu->msg[0] == 15); + TESTASSERT(out_pdu->msg[1] == 240); + TESTASSERT(out_pdu->N_bytes == 2); + + // Write another 32 SDUs but don't notify SN=4080, SN=4081, SN=14 and SN=15 + for (uint32_t i = 4080; i < 4112; i++) { + srslte::unique_byte_buffer_t sdu = srslte::make_byte_buffer(); + sdu->append_bytes(sdu1, sizeof(sdu1)); + pdcp->write_sdu(std::move(sdu)); + if (i != 4080 && i != 4081 && i != 4110 && i != 4111) { + pdcp->notify_delivery({i % 4096}); + } + } + + // Check undelivered SDUs queue size + TESTASSERT(pdcp->nof_discard_timers() == 4); + + // Generate the status report + pdcp->send_status_report(); + rlc->get_last_sdu(out_pdu); + logger.debug(out_pdu->msg, out_pdu->N_bytes, "Status PDU:"); + + // Check status PDU + /* + * | D/C | TYPE | FMS | -> | 0 | 0 | 0001 | + * | FMS | -> | 00000001 | + * | bitmap | -> | 11000000 | + * | bitmap (cont.) | -> | 00000011 | + */ + TESTASSERT(out_pdu->N_bytes == 6); + TESTASSERT(out_pdu->msg[0] == 0b00001111); + TESTASSERT(out_pdu->msg[1] == 0b11110000); + TESTASSERT(out_pdu->msg[2] == 0b10000000); + TESTASSERT(out_pdu->msg[3] == 0b00000000); + TESTASSERT(out_pdu->msg[4] == 0b00000000); + TESTASSERT(out_pdu->msg[5] == 0b00000110); + return 0; +} /* * Test reception of status report */ @@ -190,7 +271,7 @@ int run_all_tests() srslte::pdcp_lte_state_t normal_init_state = {}; TESTASSERT(test_tx_status_report(normal_init_state, logger) == 0); - + TESTASSERT(test_tx_wraparound_status_report(normal_init_state, logger) == 0); TESTASSERT(test_rx_status_report(normal_init_state, logger) == 0); return 0; } diff --git a/lib/test/upper/rlc_am_control_test.cc b/lib/test/upper/rlc_am_control_test.cc index a85cb3943..47b6f694d 100644 --- a/lib/test/upper/rlc_am_control_test.cc +++ b/lib/test/upper/rlc_am_control_test.cc @@ -42,6 +42,7 @@ int simple_status_pdu_test1() for (uint32_t i = 0; i < b2.N_bytes; i++) { TESTASSERT(b2.msg[i] == b1.msg[i]); } + TESTASSERT(rlc_am_is_valid_status_pdu(s1)); return SRSLTE_SUCCESS; } @@ -68,6 +69,22 @@ int status_pdu_with_nacks_test1() for (uint32_t i = 0; i < b2.N_bytes; i++) { TESTASSERT(b2.msg[i] == b1.msg[i]); } + + TESTASSERT(rlc_am_is_valid_status_pdu(s2)); + return SRSLTE_SUCCESS; +} + +int malformed_status_pdu_test() +{ + uint8_t pdu[] = {0x0b, 0x77, 0x6d, 0xd6, 0xe5, 0x6f, 0x56, 0xf8}; + + srslte::rlc_status_pdu_t s1; + srslte::byte_buffer_t b1, b2; + + memcpy(b1.msg, pdu, sizeof(pdu)); + b1.N_bytes = sizeof(pdu); + rlc_am_read_status_pdu(&b1, &s1); + TESTASSERT(rlc_am_is_valid_status_pdu(s1) == false); return SRSLTE_SUCCESS; } @@ -77,6 +94,7 @@ int main(int argc, char** argv) TESTASSERT(simple_status_pdu_test1() == SRSLTE_SUCCESS); TESTASSERT(status_pdu_with_nacks_test1() == SRSLTE_SUCCESS); + TESTASSERT(malformed_status_pdu_test() == SRSLTE_SUCCESS); return SRSLTE_SUCCESS; } diff --git a/lib/test/upper/rlc_am_test.cc b/lib/test/upper/rlc_am_test.cc index ac4ab983a..03d68f446 100644 --- a/lib/test/upper/rlc_am_test.cc +++ b/lib/test/upper/rlc_am_test.cc @@ -23,8 +23,10 @@ #include "srslte/common/rlc_pcap.h" #include "srslte/common/test_common.h" #include "srslte/common/threads.h" +#include "srslte/interfaces/ue_pdcp_interfaces.h" +#include "srslte/interfaces/ue_rrc_interfaces.h" #include "srslte/upper/rlc_am_lte.h" -#include + #define NBUFS 5 #define HAVE_PCAP 0 #define SDU_SIZE 500 @@ -47,17 +49,13 @@ bool rx_is_tx(const rlc_bearer_metrics_t& rlc1_metrics, const rlc_bearer_metrics class rlc_am_tester : public pdcp_interface_rlc, public rrc_interface_rlc { public: - rlc_am_tester(rlc_pcap* pcap_ = NULL) - { - n_sdus = 0; - pcap = pcap_; - } + rlc_am_tester(rlc_pcap* pcap_ = NULL) : pcap(pcap_) {} // PDCP interface void write_pdu(uint32_t lcid, unique_byte_buffer_t sdu) { assert(lcid == 1); - sdus[n_sdus++] = std::move(sdu); + sdus.push_back(std::move(sdu)); } void write_pdu_bcch_bch(unique_byte_buffer_t sdu) {} void write_pdu_bcch_dlsch(unique_byte_buffer_t sdu) {} @@ -80,12 +78,13 @@ public: } // RRC interface - void max_retx_attempted() {} + void max_retx_attempted() { max_retx_triggered = true; } + std::string get_rb_name(uint32_t lcid) { return std::string(""); } - unique_byte_buffer_t sdus[10]; - int n_sdus; - rlc_pcap* pcap; + std::vector sdus; + rlc_pcap* pcap = nullptr; + bool max_retx_triggered = false; std::map notified_counts; // Map of PDCP SNs to number of notifications }; @@ -204,7 +203,7 @@ int basic_test() // Check PDCP notifications TESTASSERT(tester.notified_counts.size() == 5); - for (uint16_t i = 0; i < tester.n_sdus; i++) { + for (uint16_t i = 0; i < tester.sdus.size(); i++) { TESTASSERT(tester.sdus[i]->N_bytes == 1); TESTASSERT(*(tester.sdus[i]->msg) == i); TESTASSERT(tester.notified_counts[i] == 1); @@ -270,15 +269,15 @@ int concat_test() // Write status PDU to RLC1 rlc1.write_pdu(status_buf.msg, status_buf.N_bytes); - TESTASSERT(tester.n_sdus == 5); - for (int i = 0; i < tester.n_sdus; i++) { + TESTASSERT(tester.sdus.size() == 5); + for (uint32_t i = 0; i < tester.sdus.size(); i++) { TESTASSERT(tester.sdus[i]->N_bytes == 1); TESTASSERT(*(tester.sdus[i]->msg) == i); } // Check PDCP notifications TESTASSERT(tester.notified_counts.size() == 5); - for (uint16_t i = 0; i < tester.n_sdus; i++) { + for (uint32_t i = 0; i < tester.sdus.size(); i++) { TESTASSERT(tester.sdus[i]->N_bytes == 1); TESTASSERT(*(tester.sdus[i]->msg) == i); TESTASSERT(tester.notified_counts[i] == 1); @@ -371,11 +370,12 @@ int segment_test(bool in_seq_rx) TESTASSERT(0 == rlc2.get_buffer_state()); - TESTASSERT(tester.n_sdus == 5); - for (int i = 0; i < tester.n_sdus; i++) { + TESTASSERT(tester.sdus.size() == 5); + for (uint32_t i = 0; i < tester.sdus.size(); i++) { TESTASSERT(tester.sdus[i]->N_bytes == 10); - for (int j = 0; j < 10; j++) + for (int j = 0; j < 10; j++) { TESTASSERT(tester.sdus[i]->msg[j] == j); + } } // Check statistics @@ -424,8 +424,9 @@ int retx_test() // Write PDUs into RLC2 (skip SN 1) for (int i = 0; i < NBUFS; i++) { - if (i != 1) + if (i != 1) { rlc2.write_pdu(pdu_bufs[i].msg, pdu_bufs[i].N_bytes); + } } // check buffered bytes at receiver, 3 PDUs with one 1 B each (SN=0 has been delivered already) @@ -480,8 +481,8 @@ int retx_test() // Write the retx PDU to RLC2 rlc2.write_pdu(retx.msg, retx.N_bytes); - TESTASSERT(tester.n_sdus == 5); - for (int i = 0; i < tester.n_sdus; i++) { + TESTASSERT(tester.sdus.size() == 5); + for (uint32_t i = 0; i < tester.sdus.size(); i++) { if (tester.sdus[i]->N_bytes != 1) return -1; if (*(tester.sdus[i]->msg) != i) @@ -518,6 +519,69 @@ int retx_test() return 0; } +// Test correct upper layer signaling when maxRetx (default 4) have been reached +int max_retx_test() +{ + rlc_am_tester tester; + timer_handler timers(8); + int len = 0; + + rlc_am_lte rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); + + const rlc_config_t rlc_cfg = rlc_config_t::default_rlc_am_config(); + if (not rlc1.configure(rlc_cfg)) { + return -1; + } + + // Push 2 SDUs into RLC1 + const uint32_t n_sdus = 2; + unique_byte_buffer_t sdu_bufs[n_sdus]; + for (uint32_t i = 0; i < n_sdus; i++) { + sdu_bufs[i] = srslte::make_byte_buffer(); + sdu_bufs[i]->msg[0] = i; // Write the index into the buffer + sdu_bufs[i]->N_bytes = 1; // Give each buffer a size of 1 byte + sdu_bufs[i]->md.pdcp_sn = i; // PDCP SN for notifications + rlc1.write_sdu(std::move(sdu_bufs[i])); + } + + // Read 2 PDUs from RLC1 (1 byte each) + const uint32_t n_pdus = 2; + 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()); + + // Fake status PDU that ack SN=1 + rlc_status_pdu_t fake_status = {}; + fake_status.ack_sn = 2; // delivered up to SN=1 + fake_status.N_nack = 1; // one SN was lost + fake_status.nacks[0].nack_sn = 0; // it was SN=0 that was lost + + // pack into PDU + byte_buffer_t status_pdu; + rlc_am_write_status_pdu(&fake_status, &status_pdu); + + // We've Tx'ed once already, loop until the max is reached + for (uint32_t retx_count = 0; retx_count < rlc_cfg.am.max_retx_thresh; ++retx_count) { + // we've not yet reached max attempts + TESTASSERT(tester.max_retx_triggered == false); + + // Write status PDU to RLC1 + rlc1.write_pdu(status_pdu.msg, status_pdu.N_bytes); + + byte_buffer_t pdu_buf; + len = rlc1.read_pdu(pdu_buf.msg, 3); + } + + // Now maxRetx should have been triggered + TESTASSERT(tester.max_retx_triggered == true); + + return SRSLTE_SUCCESS; +} + // Purpose: test correct retx of lost segment and pollRetx timer expiration int segment_retx_test() { @@ -626,8 +690,8 @@ int segment_retx_test() TESTASSERT(tester.notified_counts.size() == 1); TESTASSERT(tester.notified_counts.find(0) != tester.notified_counts.end() && tester.notified_counts[0] == 1); - TESTASSERT(tester.n_sdus == nof_sdus); - for (int i = 0; i < tester.n_sdus; i++) { + TESTASSERT(tester.sdus.size() == nof_sdus); + for (uint32_t i = 0; i < tester.sdus.size(); i++) { if (tester.sdus[i]->N_bytes != 10) { return SRSLTE_ERROR; } @@ -759,8 +823,8 @@ int resegment_test_1() // Write the retx PDU to RLC2 rlc2.write_pdu(retx2.msg, retx2.N_bytes); - TESTASSERT(tester.n_sdus == 5); - for (int i = 0; i < tester.n_sdus; i++) { + TESTASSERT(tester.sdus.size() == 5); + for (uint32_t i = 0; i < tester.sdus.size(); i++) { if (tester.sdus[i]->N_bytes != 10) return -1; for (int j = 0; j < 10; j++) @@ -886,7 +950,7 @@ int resegment_test_2() // Write the retx PDU to RLC2 rlc2.write_pdu(retx1.msg, retx1.N_bytes); - TESTASSERT(18 == rlc1.get_buffer_state()); + TESTASSERT(16 == rlc1.get_buffer_state()); // Read the remaining segment byte_buffer_t retx2; @@ -895,8 +959,8 @@ int resegment_test_2() // Write the retx PDU to RLC2 rlc2.write_pdu(retx2.msg, retx2.N_bytes); - TESTASSERT(tester.n_sdus == 5); - for (int i = 0; i < tester.n_sdus; i++) { + TESTASSERT(tester.sdus.size() == 5); + for (uint32_t i = 0; i < tester.sdus.size(); i++) { if (tester.sdus[i]->N_bytes != 10) return -1; for (int j = 0; j < 10; j++) @@ -1024,8 +1088,8 @@ int resegment_test_3() // Write the retx PDU to RLC2 rlc2.write_pdu(retx2.msg, retx2.N_bytes); - TESTASSERT(tester.n_sdus == 5); - for (int i = 0; i < tester.n_sdus; i++) { + TESTASSERT(tester.sdus.size() == 5); + for (uint32_t i = 0; i < tester.sdus.size(); i++) { if (tester.sdus[i]->N_bytes != 10) return -1; for (int j = 0; j < 10; j++) @@ -1147,17 +1211,17 @@ int resegment_test_4() // Write the retx PDU to RLC2 rlc2.write_pdu(retx1.msg, retx1.N_bytes); - TESTASSERT(23 == rlc1.get_buffer_state()); + TESTASSERT(21 == rlc1.get_buffer_state()); // Read the remaining segment byte_buffer_t retx2; - retx2.N_bytes = rlc1.read_pdu(retx2.msg, 23); // 6 byte header + 18 data + retx2.N_bytes = rlc1.read_pdu(retx2.msg, 21); // Write the retx PDU to RLC2 rlc2.write_pdu(retx2.msg, retx2.N_bytes); - TESTASSERT(tester.n_sdus == 5); - for (int i = 0; i < tester.n_sdus; i++) { + TESTASSERT(tester.sdus.size() == 5); + for (uint32_t i = 0; i < tester.sdus.size(); i++) { if (tester.sdus[i]->N_bytes != 10) return -1; for (int j = 0; j < 10; j++) @@ -1215,8 +1279,9 @@ int resegment_test_5() unique_byte_buffer_t sdu_bufs[NBUFS]; for (int i = 0; i < NBUFS; i++) { sdu_bufs[i] = srslte::make_byte_buffer(); - for (int j = 0; j < 10; j++) - sdu_bufs[i]->msg[j] = j; + for (int j = 0; j < 10; j++) { + sdu_bufs[i]->msg[j] = i; + } sdu_bufs[i]->N_bytes = 10; // Give each buffer a size of 10 bytes sdu_bufs[i]->md.pdcp_sn = i; rlc1.write_sdu(std::move(sdu_bufs[i])); @@ -1272,22 +1337,21 @@ int resegment_test_5() // Write the retx PDU to RLC2 rlc2.write_pdu(retx1.msg, retx1.N_bytes); - TESTASSERT(31 == rlc1.get_buffer_state()); + TESTASSERT(32 == rlc1.get_buffer_state()); // Read the remaining segment byte_buffer_t retx2; - retx2.N_bytes = rlc1.read_pdu(retx2.msg, 34); // 7 byte header + 24 data + retx2.N_bytes = rlc1.read_pdu(retx2.msg, 40); // Write the retx PDU to RLC2 rlc2.write_pdu(retx2.msg, retx2.N_bytes); - TESTASSERT(tester.n_sdus == 5); - for (int i = 0; i < tester.n_sdus; i++) { - if (tester.sdus[i]->N_bytes != 10) - return -1; - for (int j = 0; j < 10; j++) - if (tester.sdus[i]->msg[j] != j) - return -1; + TESTASSERT(tester.sdus.size() == 5); + for (uint32_t i = 0; i < tester.sdus.size(); i++) { + TESTASSERT(tester.sdus[i]->N_bytes == 10); + for (int j = 0; j < 10; j++) { + TESTASSERT(tester.sdus[i]->msg[j] == i); + } } // Get status from RLC 2 @@ -1422,30 +1486,29 @@ int resegment_test_6() // Write the retx PDU to RLC2 rlc2.write_pdu(retx1.msg, retx1.N_bytes); - TESTASSERT(159 == rlc1.get_buffer_state()); + TESTASSERT(169 == rlc1.get_buffer_state()); // Read the remaining segment byte_buffer_t retx2; - len = rlc1.read_pdu(retx2.msg, 162); + len = rlc1.read_pdu(retx2.msg, 169); retx2.N_bytes = len; // Write the retx PDU to RLC2 rlc2.write_pdu(retx2.msg, retx2.N_bytes); - TESTASSERT(tester.n_sdus == 9); + TESTASSERT(tester.sdus.size() == 9); for (int i = 0; i < 3; i++) { TESTASSERT(tester.sdus[i]->N_bytes == 10); for (int j = 0; j < 10; j++) TESTASSERT(tester.sdus[i]->msg[j] == j); } - for (int i = 3; i < 9; i++) { - if (i >= tester.n_sdus) - return -1; - if (tester.sdus[i]->N_bytes != 54) - return -1; + for (uint32_t i = 3; i < 9; i++) { + if (i >= tester.sdus.size()) { + return SRSLTE_ERROR; + } + TESTASSERT(tester.sdus[i]->N_bytes == 54); for (int j = 0; j < 54; j++) { - if (tester.sdus[i]->msg[j] != j) - return -1; + TESTASSERT(tester.sdus[i]->msg[j] == j); } } @@ -1490,7 +1553,7 @@ int resegment_test_7() #if HAVE_PCAP rlc_pcap pcap; - pcap.open("rlc_am_test7.pcap", 0); + pcap.open("rlc_am_test7.pcap", rlc_config_t::default_rlc_am_config()); rlc_am_tester tester(&pcap); #else rlc_am_tester tester(NULL); @@ -1543,7 +1606,7 @@ int resegment_test_7() if (i != 2) { rlc2.write_pdu(pdu_bufs[i].msg, pdu_bufs[i].N_bytes); #if HAVE_PCAP - pcap.write_dl_am_ccch(pdu_bufs[i].msg, pdu_bufs[i].N_bytes); + pcap.write_dl_ccch(pdu_bufs[i].msg, pdu_bufs[i].N_bytes); #endif } } @@ -1568,7 +1631,7 @@ int resegment_test_7() if (i > 1) { rlc2.write_pdu(retx[i].msg, retx[i].N_bytes); #if HAVE_PCAP - pcap.write_dl_am_ccch(retx[i].msg, retx[i].N_bytes); + pcap.write_dl_ccch(retx[i].msg, retx[i].N_bytes); #endif } } @@ -1588,7 +1651,7 @@ int resegment_test_7() // Write status PDU to RLC1 rlc1.write_pdu(status_buf.msg, status_buf.N_bytes); #if HAVE_PCAP - pcap.write_ul_am_ccch(status_buf.msg, status_buf.N_bytes); + pcap.write_ul_ccch(status_buf.msg, status_buf.N_bytes); #endif TESTASSERT(15 == rlc1.get_buffer_state()); @@ -1605,7 +1668,7 @@ int resegment_test_7() rlc2.write_pdu(retx2[i].msg, retx2[i].N_bytes); #if HAVE_PCAP - pcap.write_dl_am_ccch(retx[i].msg, retx[i].N_bytes); + pcap.write_dl_ccch(retx[i].msg, retx[i].N_bytes); #endif } @@ -1631,7 +1694,7 @@ int resegment_test_7() // Write status PDU to RLC1 rlc1.write_pdu(status_buf.msg, status_buf.N_bytes); #if HAVE_PCAP - pcap.write_ul_am_ccch(status_buf.msg, status_buf.N_bytes); + pcap.write_ul_ccch(status_buf.msg, status_buf.N_bytes); #endif // check status again @@ -1639,13 +1702,11 @@ int resegment_test_7() TESTASSERT(0 == rlc2.get_buffer_state()); // Check number of SDUs and their content - TESTASSERT(tester.n_sdus == N_SDU_BUFS); - for (int i = 0; i < tester.n_sdus; i++) { - if (tester.sdus[i]->N_bytes != sdu_size) - return -1; + TESTASSERT(tester.sdus.size() == N_SDU_BUFS); + for (uint32_t i = 0; i < tester.sdus.size(); i++) { + TESTASSERT(tester.sdus[i]->N_bytes == sdu_size); for (uint32_t j = 0; j < N_SDU_BUFS; j++) { - if (tester.sdus[i]->msg[j] != i) - return -1; + TESTASSERT(tester.sdus[i]->msg[j] == i); } } @@ -1677,7 +1738,7 @@ int resegment_test_8() #if HAVE_PCAP rlc_pcap pcap; - pcap.open("rlc_am_test8.pcap", 0); + pcap.open("rlc_am_test8.pcap", rlc_config_t::default_rlc_am_config()); rlc_am_tester tester(&pcap); #else rlc_am_tester tester(NULL); @@ -1723,7 +1784,7 @@ int resegment_test_8() if (i < 1 || i > 2) { rlc2.write_pdu(pdu_bufs[i].msg, pdu_bufs[i].N_bytes); #if HAVE_PCAP - pcap.write_dl_am_ccch(pdu_bufs[i].msg, pdu_bufs[i].N_bytes); + pcap.write_dl_ccch(pdu_bufs[i].msg, pdu_bufs[i].N_bytes); #endif } } @@ -1748,7 +1809,7 @@ int resegment_test_8() if (i > 1) { rlc2.write_pdu(retx[i].msg, retx[i].N_bytes); #if HAVE_PCAP - pcap.write_dl_am_ccch(retx[i].msg, retx[i].N_bytes); + pcap.write_dl_ccch(retx[i].msg, retx[i].N_bytes); #endif } } @@ -1767,7 +1828,7 @@ int resegment_test_8() // Write status PDU to RLC1 rlc1.write_pdu(status_buf.msg, status_buf.N_bytes); #if HAVE_PCAP - pcap.write_ul_am_ccch(status_buf.msg, status_buf.N_bytes); + pcap.write_ul_ccch(status_buf.msg, status_buf.N_bytes); #endif TESTASSERT(15 == rlc1.get_buffer_state()); @@ -1780,7 +1841,7 @@ int resegment_test_8() TESTASSERT(retx2[i].N_bytes != 0); rlc2.write_pdu(retx2[i].msg, retx2[i].N_bytes); #if HAVE_PCAP - pcap.write_dl_am_ccch(retx[i].msg, retx[i].N_bytes); + pcap.write_dl_ccch(retx[i].msg, retx[i].N_bytes); #endif } @@ -1790,7 +1851,7 @@ int resegment_test_8() // Write status PDU to RLC1 rlc1.write_pdu(status_buf.msg, status_buf.N_bytes); #if HAVE_PCAP - pcap.write_ul_am_ccch(status_buf.msg, status_buf.N_bytes); + pcap.write_ul_ccch(status_buf.msg, status_buf.N_bytes); #endif // check buffer states @@ -1802,8 +1863,8 @@ int resegment_test_8() }; // Check number of SDUs and their content - TESTASSERT(tester.n_sdus == N_SDU_BUFS); - for (int i = 0; i < tester.n_sdus; i++) { + TESTASSERT(tester.sdus.size() == N_SDU_BUFS); + for (uint32_t i = 0; i < tester.sdus.size(); i++) { if (tester.sdus[i]->N_bytes != sdu_size) return -1; for (uint32_t j = 0; j < N_SDU_BUFS; j++) { @@ -1819,6 +1880,1211 @@ int resegment_test_8() return 0; } +// Resegmentation with 1 B segments +int resegment_test_9() +{ + // SDUs: | 10 | 10 | 10 | + // PDUs: | 9 | x | + // Retx PDU segments: |2| 9 | + + const rlc_config_t config = rlc_config_t::default_rlc_am_config(); +#if HAVE_PCAP + rlc_pcap pcap; + pcap.open("rlc_resegment_test_9.pcap", config); + rlc_am_tester tester(&pcap); +#else + rlc_am_tester tester(NULL); +#endif + srslte::timer_handler timers(8); + + 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(config)) { + return SRSLTE_ERROR; + } + + if (not rlc2.configure(config)) { + return SRSLTE_ERROR; + } + + // Push 3 SDUs into RLC1 + const uint32_t n_bufs = 3; + unique_byte_buffer_t sdu_bufs[n_bufs]; + for (uint32_t i = 0; i < n_bufs; i++) { + sdu_bufs[i] = srslte::make_byte_buffer(); + for (uint32_t j = 0; j < 10; j++) { + sdu_bufs[i]->msg[j] = i; + } + sdu_bufs[i]->N_bytes = 10; // Give each buffer a size of 10 bytes + sdu_bufs[i]->md.pdcp_sn = i; + rlc1.write_sdu(std::move(sdu_bufs[i])); + } + + // Read 5 PDUs from RLC1 (2 bytes, 3 bytes, 40 bytes, 3 bytes, 2 bytes) + byte_buffer_t pdu_bufs[n_bufs]; + pdu_bufs[0].N_bytes = rlc1.read_pdu(pdu_bufs[0].msg, 11); // 2 byte header + 9 byte payload + pdu_bufs[1].N_bytes = rlc1.read_pdu(pdu_bufs[1].msg, 15); // 4 byte header + 11 byte payload + pdu_bufs[2].N_bytes = rlc1.read_pdu(pdu_bufs[2].msg, 12); // 2 byte header + 10 byte payload + + TESTASSERT(0 == rlc1.get_buffer_state()); + + // Write PDUs into RLC2 (skip SN 0) + for (uint32_t i = 0; i < n_bufs; i++) { + if (i != 1) { + rlc2.write_pdu(pdu_bufs[i].msg, pdu_bufs[i].N_bytes); +#if HAVE_PCAP + pcap.write_dl_ccch(pdu_bufs[i].msg, pdu_bufs[i].N_bytes); +#endif + } + } + + // Step timers until reordering timeout expires + int cnt = 5; + while (cnt--) { + timers.step_all(); + } + + // Read status PDU from RLC2 + byte_buffer_t status_buf; + status_buf.N_bytes = rlc2.read_pdu(status_buf.msg, 10); // 10 bytes is enough to hold the status + + // Write status PDU to RLC1 + rlc1.write_pdu(status_buf.msg, status_buf.N_bytes); +#if HAVE_PCAP + pcap.write_ul_ccch(status_buf.msg, status_buf.N_bytes); +#endif + + // Read the retx PDU from RLC1 and force resegmentation + byte_buffer_t retx1; + byte_buffer_t retx2; + retx1.N_bytes = rlc1.read_pdu(retx1.msg, 8); // 6 byte header + 2 data + + // Write the retx PDU to RLC2 + rlc2.write_pdu(retx1.msg, retx1.N_bytes); +#if HAVE_PCAP + pcap.write_dl_ccch(retx1.msg, retx1.N_bytes); +#endif + + // Read 2nd with a big enough grant to fit remaining content + retx2.N_bytes = rlc1.read_pdu(retx2.msg, 40); + + // Write the retx PDU to RLC2 + rlc2.write_pdu(retx2.msg, retx2.N_bytes); +#if HAVE_PCAP + pcap.write_dl_ccch(retx2.msg, retx2.N_bytes); +#endif + // goto exit; + + TESTASSERT(tester.sdus.size() == n_bufs); + for (uint32_t i = 0; i < tester.sdus.size(); i++) { + TESTASSERT(tester.sdus[i]->N_bytes == 10); + for (int j = 0; j < 10; j++) { + TESTASSERT(tester.sdus[i]->msg[j] == i); + } + } + + // Get status from RLC 2 + for (int i = 0; i < 5; i++) { + timers.step_all(); + } + + // Read status PDU from RLC2 + status_buf.N_bytes = rlc2.read_pdu(status_buf.msg, 10); // 10 bytes is enough to hold the status + + // Write status PDU to RLC1 + rlc1.write_pdu(status_buf.msg, status_buf.N_bytes); + + // Check final notifications + TESTASSERT(tester.notified_counts.size() == n_bufs); + for (uint32_t i = 0; i < n_bufs; i++) { + auto it = tester.notified_counts.find(i); + TESTASSERT(it != tester.notified_counts.end() && tester.notified_counts[i] == 1); + } + + // exit: + +#if HAVE_PCAP + pcap.close(); +#endif + + return 0; +} + +// Retransmission of segment Resegmentation with 1 B segments +int resegment_test_10() +{ + /// 21:35:17.369012 [RLC_1] [I] DRB1 Tx PDU SN=520 (20 B) + /// 0000: 9e 08 80 40 0a 34 34 34 34 35 35 35 35 35 35 35 + /// 0010: 35 35 35 36 + /// 21:35:17.369016 [RLC_1] [D] [Data PDU, RF=0, P=0, FI=1, SN=520, LSF=0, SO=0, N_li=2 (4, 10, )] + + /// 21:35:17.369703 [RLC_1] [I] DRB1 Retx PDU segment SN=520 [so=0] (10 B) (attempt 2/16) + /// 0000: fe 08 00 00 00 40 34 34 34 34 + /// 21:35:17.369712 [RLC_2] [I] DRB1 Rx data PDU segment of SN=520 (4 B), SO=0, N_li=1 + /// 0000: 34 34 34 34 + /// 21:35:17.369718 [RLC_2] [D] [Data PDU, RF=1, P=1, FI=1, SN=520, LSF=0, SO=0, N_li=1 (4, )] + + // SDUs: | 10 | 10 | 10 | 10 | + // PDUs: | 6 | 25(x) | 9 | + // Retx PDU segments: |4| 50 | + + const rlc_config_t config = rlc_config_t::default_rlc_am_config(); +#if HAVE_PCAP + rlc_pcap pcap; + pcap.open("rlc_resegment_test_10.pcap", config); + rlc_am_tester tester(&pcap); +#else + rlc_am_tester tester(NULL); +#endif + srslte::timer_handler timers(8); + + 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(config)) { + return SRSLTE_ERROR; + } + + if (not rlc2.configure(config)) { + return SRSLTE_ERROR; + } + + // Push 3 SDUs into RLC1 + const uint32_t n_sdus = 4; + unique_byte_buffer_t sdu_bufs[n_sdus]; + for (uint32_t i = 0; i < n_sdus; i++) { + sdu_bufs[i] = srslte::make_byte_buffer(); + for (uint32_t j = 0; j < 10; j++) { + sdu_bufs[i]->msg[j] = i; + } + sdu_bufs[i]->N_bytes = 10; // Give each buffer a size of 10 bytes + sdu_bufs[i]->md.pdcp_sn = i; + rlc1.write_sdu(std::move(sdu_bufs[i])); + } + + // Read 5 PDUs from RLC1 (2 bytes, 3 bytes, 40 bytes, 3 bytes, 2 bytes) + const uint32_t n_pdus = 3; + byte_buffer_t pdu_bufs[n_pdus]; + pdu_bufs[0].N_bytes = rlc1.read_pdu(pdu_bufs[0].msg, 8); // 2 byte header + 6 byte payload + pdu_bufs[1].N_bytes = rlc1.read_pdu(pdu_bufs[1].msg, 32); // 4 byte header + 25 byte payload + pdu_bufs[2].N_bytes = rlc1.read_pdu(pdu_bufs[2].msg, 11); // 2 byte header + 9 byte payload + + TESTASSERT(0 == rlc1.get_buffer_state()); + + // Write PDUs into RLC2 (skip SN 0) + for (uint32_t i = 0; i < n_pdus; i++) { + if (i != 1) { + rlc2.write_pdu(pdu_bufs[i].msg, pdu_bufs[i].N_bytes); + } +#if HAVE_PCAP + // write to PCAP even if its lost in the TC + pcap.write_dl_ccch(pdu_bufs[i].msg, pdu_bufs[i].N_bytes); +#endif + } + + // Step timers until reordering timeout expires + int cnt = 5; + while (cnt--) { + timers.step_all(); + } + + // Read status PDU from RLC2 + byte_buffer_t status_buf; + status_buf.N_bytes = rlc2.read_pdu(status_buf.msg, 10); // 10 bytes is enough to hold the status + + // Write status PDU to RLC1 + rlc1.write_pdu(status_buf.msg, status_buf.N_bytes); +#if HAVE_PCAP + pcap.write_ul_ccch(status_buf.msg, status_buf.N_bytes); +#endif + + // Read the retx PDU from RLC1 and force resegmentation + byte_buffer_t retx1; + byte_buffer_t retx2; + retx1.N_bytes = rlc1.read_pdu(retx1.msg, 13); // 6 byte header + 4 data ( +2 B MAC) + + // Write the retx PDU to RLC2 + rlc2.write_pdu(retx1.msg, retx1.N_bytes); +#if HAVE_PCAP + pcap.write_dl_ccch(retx1.msg, retx1.N_bytes); +#endif + + // Read 2nd with a big enough grant to fit remaining content + retx2.N_bytes = rlc1.read_pdu(retx2.msg, 32); + rlc2.write_pdu(retx2.msg, retx2.N_bytes); +#if HAVE_PCAP + pcap.write_dl_ccch(retx2.msg, retx2.N_bytes); +#endif + + TESTASSERT(tester.sdus.size() == n_sdus); + for (uint32_t i = 0; i < tester.sdus.size(); i++) { + TESTASSERT(tester.sdus[i]->N_bytes == 10); + for (int j = 0; j < 10; j++) { + TESTASSERT(tester.sdus[i]->msg[j] == i); + } + } + + // Get status from RLC 2 + for (int i = 0; i < 5; i++) { + timers.step_all(); + } + + // Read status PDU from RLC2 + status_buf.N_bytes = rlc2.read_pdu(status_buf.msg, 10); // 10 bytes is enough to hold the status + + // Write status PDU to RLC1 + rlc1.write_pdu(status_buf.msg, status_buf.N_bytes); + + // Check final notifications + TESTASSERT(tester.notified_counts.size() == n_sdus); + for (uint32_t i = 0; i < n_sdus; i++) { + auto it = tester.notified_counts.find(i); + TESTASSERT(it != tester.notified_counts.end() && tester.notified_counts[i] == 1); + } + + return SRSLTE_SUCCESS; +} + +// Custom resegmentation test of a orignal PDU with N_li=2 +// Because the provided MAC grant is relativly small, the retx segment +// can only accomodate 2 B of the original PDU. +// The test verifies the correct PDU packing, specifically the LI value +int resegment_test_11() +{ + /// Original PDU: + /// 11:29:16.065008 [RLC_1] [I] DRB1 Tx PDU SN=419 (21 B) + /// 0000: bd a3 80 50 0a aa aa aa aa aa ab ab ab ab ab ab + /// 0010: ab ab ab ab ac + /// 11:29:16.065013 [RLC_1] [D] [Data PDU, RF=0, P=1, FI=1, SN=419, LSF=0, SO=0, N_li=2 (5, 10, )] + + /// Log messages with the restoration bug: + /// 11:29:16.065688 [RLC_1] [D] MAC opportunity - 10 bytes + /// 11:29:16.065695 [RLC_1] [D] DRB1 build_retx_pdu - resegmentation required + /// 11:29:16.065702 [RLC_1] [D] retx.so_start=2, retx.so_end=6 + /// 11:29:16.065703 [RLC_1] [D] new_header head_len=4 + /// 11:29:16.065706 [RLC_1] [D] old_header.li[0], head_len=6, pdu_space=4 + /// 11:29:16.065710 [RLC_1] [D] new_header head_len=6 + /// 11:29:16.065713 [RLC_1] [D] old_header.li[1], head_len=8, pdu_space=2 + /// 11:29:16.065716 [RLC_1] [D] DRB1 vt_a = 419, vt_ms = 931, vt_s = 426, poll_sn = 424 + /// 11:29:16.065718 [RLC_1] [I] DRB1 Retx PDU segment SN=419 [so=2] (8 B) (attempt 2/16) + /// 0000: dd a3 00 02 00 30 aa aa + /// 11:29:16.065723 [RLC_2] [I] DRB1 Rx data PDU segment of SN=419 (2 B), SO=2, N_li=1 + /// 0000: aa aa + /// 11:29:16.065730 [RLC_2] [D] [Data PDU, RF=1, P=0, FI=1, SN=419, LSF=0, SO=2, N_li=1 (3, )] + /// NOTE: this segment is malformed, it has 2 B data and a larger LI field of 3 B + + // SDUs: | 10 | 10 | 10 | 10 | + // PDUs: | 15 | 16(x) | 9 | + // Retx PDU segments: |4| 50 | + + const rlc_config_t config = rlc_config_t::default_rlc_am_config(); +#if HAVE_PCAP + rlc_pcap pcap; + pcap.open("rlc_resegment_test_11.pcap", config); + rlc_am_tester tester(&pcap); +#else + rlc_am_tester tester(NULL); +#endif + srslte::timer_handler timers(8); + + 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(config)) { + return SRSLTE_ERROR; + } + + if (not rlc2.configure(config)) { + return SRSLTE_ERROR; + } + + // Push 4 SDUs into RLC1 + const uint32_t n_sdus = 4; + unique_byte_buffer_t sdu_bufs[n_sdus]; + for (uint32_t i = 0; i < n_sdus; i++) { + sdu_bufs[i] = srslte::make_byte_buffer(); + for (uint32_t j = 0; j < 10; j++) { + sdu_bufs[i]->msg[j] = i; + } + sdu_bufs[i]->N_bytes = 10; // Give each buffer a size of 10 bytes + sdu_bufs[i]->md.pdcp_sn = i; + rlc1.write_sdu(std::move(sdu_bufs[i])); + } + + // Read 3 PDUs from RLC1 (MAC opportunities are taken from logs) + const uint32_t n_pdus = 3; + byte_buffer_t pdu_bufs[n_pdus]; + pdu_bufs[0].N_bytes = rlc1.read_pdu(pdu_bufs[0].msg, 19); + pdu_bufs[1].N_bytes = rlc1.read_pdu(pdu_bufs[1].msg, 21); + pdu_bufs[2].N_bytes = rlc1.read_pdu(pdu_bufs[2].msg, 12); + + TESTASSERT(0 == rlc1.get_buffer_state()); + + // Write PDUs into RLC2 (skip SN 1) + for (uint32_t i = 0; i < n_pdus; i++) { + if (i != 1) { + rlc2.write_pdu(pdu_bufs[i].msg, pdu_bufs[i].N_bytes); + } +#if HAVE_PCAP + // write to PCAP even if its lost in the TC + pcap.write_dl_ccch(pdu_bufs[i].msg, pdu_bufs[i].N_bytes); +#endif + } + + // Step timers until reordering timeout expires + int cnt = 5; + while (cnt--) { + timers.step_all(); + } + + // Read status PDU from RLC2 + byte_buffer_t status_buf; + status_buf.N_bytes = rlc2.read_pdu(status_buf.msg, 10); // 10 bytes is enough to hold the status + + // Write status PDU to RLC1 + rlc1.write_pdu(status_buf.msg, status_buf.N_bytes); +#if HAVE_PCAP + pcap.write_ul_ccch(status_buf.msg, status_buf.N_bytes); +#endif + + // Read the retx PDU from RLC1 and force resegmentation + byte_buffer_t retx1; + retx1.N_bytes = rlc1.read_pdu(retx1.msg, 8); + rlc2.write_pdu(retx1.msg, retx1.N_bytes); +#if HAVE_PCAP + pcap.write_dl_ccch(retx1.msg, retx1.N_bytes); +#endif + + // Read 2nd with a small grant to trigger the original segmentation bug + byte_buffer_t retx2; + retx2.N_bytes = rlc1.read_pdu(retx2.msg, 10); + + // Write the retx PDU to RLC2 + rlc2.write_pdu(retx2.msg, retx2.N_bytes); +#if HAVE_PCAP + pcap.write_dl_ccch(retx2.msg, retx2.N_bytes); +#endif + + // Read 3nd with a big enough grant to fit remaining content + byte_buffer_t retx3; + retx3.N_bytes = rlc1.read_pdu(retx3.msg, 20); + rlc2.write_pdu(retx3.msg, retx3.N_bytes); +#if HAVE_PCAP + pcap.write_dl_ccch(retx3.msg, retx3.N_bytes); +#endif + + TESTASSERT(tester.sdus.size() == n_sdus); + for (uint32_t i = 0; i < tester.sdus.size(); i++) { + TESTASSERT(tester.sdus[i]->N_bytes == 10); + for (int j = 0; j < 10; j++) { + TESTASSERT(tester.sdus[i]->msg[j] == i); + } + } + + // Get status from RLC 2 + for (int i = 0; i < 5; i++) { + timers.step_all(); + } + + // Read status PDU from RLC2 + status_buf.N_bytes = rlc2.read_pdu(status_buf.msg, 10); // 10 bytes is enough to hold the status + + // Write status PDU to RLC1 + rlc1.write_pdu(status_buf.msg, status_buf.N_bytes); + +#if HAVE_PCAP + pcap.close(); +#endif + + return SRSLTE_SUCCESS; +} + +// Custom resegmentation test of a orignal PDU with N_li=2 +// The test triggered a bug in the packing and was creating a too large +// PDU +int resegment_test_12() +{ + /// Original PDU: + /// 17:19:51.296653 [RLC_1] [I] DRB1 Tx PDU SN=728 (21 B) + /// 0000: be d8 80 10 0a d1 d2 d2 d2 d2 d2 d2 d2 d2 d2 d2 + /// 0010: d3 d3 d3 d3 d3 + /// 17:19:51.296659 [RLC_1] [D] [Data PDU, RF=0, P=1, FI=1, SN=728, LSF=0, SO=0, N_li=2 (1, 10, )] + + /// Log messages with the segmentation bug: + /// 17:19:51.297485 [RLC_1] [D] MAC opportunity - 18 bytes + /// 17:19:51.297487 [RLC_1] [D] tx_window size - 2 PDUs + /// 17:19:51.297489 [RLC_1] [D] DRB1 build_retx_pdu - resegmentation required + /// 17:19:51.297498 [RLC_1] [I] DRB1 pdu_without_poll: 4 + /// 17:19:51.297499 [RLC_1] [I] DRB1 byte_without_poll: 67 + /// 17:19:51.297501 [RLC_1] [D] retx.so_start=0, retx.so_end=12 + /// 17:19:51.297502 [RLC_1] [D] new_header head_len=4 + /// 17:19:51.297504 [RLC_1] [D] old_header.li[0], head_len=4, pdu_space=14 + /// 17:19:51.297505 [RLC_1] [D] new_header head_len=6 + /// 17:19:51.297506 [RLC_1] [D] old_header.li[1], head_len=6, pdu_space=12 + /// 17:19:51.297509 [RLC_1] [D] DRB1 vt_a = 724, vt_ms = 212, vt_s = 736, poll_sn = 733 + /// 17:19:51.297513 [RLC_1] [E] DRB1 Retx PDU segment length error. Available: 18, Used: 19 + /// 17:19:51.297522 [RLC_1] [D] DRB1 Retx PDU segment length error. Header len: 7, Payload len: 12, N_li: 2 + /// 17:19:51.297527 [RLC_1] [I] DRB1 Retx PDU segment SN=728 [so=0] (19 B) (attempt 2/16) + /// 0000: de d8 00 00 80 10 0a d1 d2 d2 d2 d2 d2 d2 d2 d2 + /// 0010: d2 d2 d3 + /// 17:19:51.297531 [RLC_2] [I] DRB1 Rx data PDU segment of SN=728 (12 B), SO=0, N_li=2 + /// 0000: d1 d2 d2 d2 d2 d2 d2 d2 d2 d2 d2 d3 + /// 17:19:51.297538 [RLC_2] [D] [Data PDU, RF=1, P=0, FI=1, SN=728, LSF=0, SO=0, N_li=2 (1, 10, )] + + // SDUs: | 10 | 10 | 10 | 10 | + // PDUs: | 9 | 16(x) | 9 | + // Retx PDU segments: |4| 50 | + + const rlc_config_t config = rlc_config_t::default_rlc_am_config(); +#if HAVE_PCAP + rlc_pcap pcap; + pcap.open("rlc_resegment_test_12.pcap", config); + rlc_am_tester tester(&pcap); +#else + rlc_am_tester tester(NULL); +#endif + srslte::timer_handler timers(8); + + 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(config)) { + return SRSLTE_ERROR; + } + + if (not rlc2.configure(config)) { + return SRSLTE_ERROR; + } + + // Push 4 SDUs into RLC1 + const uint32_t n_sdus = 4; + unique_byte_buffer_t sdu_bufs[n_sdus]; + for (uint32_t i = 0; i < n_sdus; i++) { + sdu_bufs[i] = srslte::make_byte_buffer(); + for (uint32_t j = 0; j < 10; j++) { + sdu_bufs[i]->msg[j] = i; + } + sdu_bufs[i]->N_bytes = 10; // Give each buffer a size of 10 bytes + sdu_bufs[i]->md.pdcp_sn = i; + rlc1.write_sdu(std::move(sdu_bufs[i])); + } + + // Read 3 PDUs from RLC1 (MAC opportunities are taken from logs) + const uint32_t n_pdus = 3; + byte_buffer_t pdu_bufs[n_pdus]; + pdu_bufs[0].N_bytes = rlc1.read_pdu(pdu_bufs[0].msg, 11); + pdu_bufs[1].N_bytes = rlc1.read_pdu(pdu_bufs[1].msg, 21); + pdu_bufs[2].N_bytes = rlc1.read_pdu(pdu_bufs[2].msg, 19); + + TESTASSERT(0 == rlc1.get_buffer_state()); + + // Write PDUs into RLC2 (skip SN 1) + for (uint32_t i = 0; i < n_pdus; i++) { + if (i != 1) { + rlc2.write_pdu(pdu_bufs[i].msg, pdu_bufs[i].N_bytes); + } +#if HAVE_PCAP + // write to PCAP even if its lost in the TC + pcap.write_dl_ccch(pdu_bufs[i].msg, pdu_bufs[i].N_bytes); +#endif + } + + // Step timers until reordering timeout expires + int cnt = 5; + while (cnt--) { + timers.step_all(); + } + + // Read status PDU from RLC2 + byte_buffer_t status_buf; + status_buf.N_bytes = rlc2.read_pdu(status_buf.msg, 10); // 10 bytes is enough to hold the status + + // Write status PDU to RLC1 + rlc1.write_pdu(status_buf.msg, status_buf.N_bytes); +#if HAVE_PCAP + pcap.write_ul_ccch(status_buf.msg, status_buf.N_bytes); +#endif + + // Read the retx PDU from RLC1 and force resegmentation + byte_buffer_t retx1; + retx1.N_bytes = rlc1.read_pdu(retx1.msg, 18); + rlc2.write_pdu(retx1.msg, retx1.N_bytes); +#if HAVE_PCAP + pcap.write_dl_ccch(retx1.msg, retx1.N_bytes); +#endif + + // Read 2nd to trigger the original segmentation bug + byte_buffer_t retx2; + retx2.N_bytes = rlc1.read_pdu(retx2.msg, 18); + rlc2.write_pdu(retx2.msg, retx2.N_bytes); +#if HAVE_PCAP + pcap.write_dl_ccch(retx2.msg, retx2.N_bytes); +#endif + + // Read 3nd with a big enough grant to fit remaining content + byte_buffer_t retx3; + retx3.N_bytes = rlc1.read_pdu(retx3.msg, 20); + rlc2.write_pdu(retx3.msg, retx3.N_bytes); +#if HAVE_PCAP + pcap.write_dl_ccch(retx3.msg, retx3.N_bytes); +#endif + + TESTASSERT(tester.sdus.size() == n_sdus); + for (uint32_t i = 0; i < tester.sdus.size(); i++) { + TESTASSERT(tester.sdus[i]->N_bytes == 10); + for (int j = 0; j < 10; j++) { + TESTASSERT(tester.sdus[i]->msg[j] == i); + } + } + + // Get status from RLC 2 + for (int i = 0; i < 5; i++) { + timers.step_all(); + } + + // Read status PDU from RLC2 + status_buf.N_bytes = rlc2.read_pdu(status_buf.msg, 10); // 10 bytes is enough to hold the status + + // Write status PDU to RLC1 + rlc1.write_pdu(status_buf.msg, status_buf.N_bytes); + +#if HAVE_PCAP + pcap.close(); +#endif + + return SRSLTE_SUCCESS; +} + +// Series of header reconstruction tests that all used canned TV generated with the rlc_stress_test +// In this particular case, check correct reconstruction of headers after 2 segment retx +int header_reconstruction_test(srslte::log_sink_message_spy& spy) +{ + /// Original SN=277 with 3 segments, including full SDU with 24 + /// 13:35:16.337011 [RLC_1] [I] DRB1 Tx PDU SN=277 (20 B) + /// 0000: 9d 15 80 20 0a 23 23 24 24 24 24 24 24 24 24 24 + /// 0010: 24 25 25 25 + /// 13:35:16.337016 [RLC_1] [D] [Data PDU, RF=0, P=0, FI=1, SN=277, LSF=0, SO=0, N_li=2 (2, 10, )] + + // 2nd retransmission with SO=9 + std::array tv2 = {0xdd, 0x15, 0x80, 0x09, 0x00, 0x30, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25}; + + // 3rd retransmission with S0=0 + std::array tv3 = { + 0xdd, 0x15, 0x00, 0x00, 0x00, 0x20, 0x23, 0x23, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24}; + + byte_buffer_t pdu_tv2; + memcpy(pdu_tv2.msg, tv2.data(), tv2.size()); + pdu_tv2.N_bytes = tv2.size(); + + byte_buffer_t pdu_tv3; + memcpy(pdu_tv3.msg, tv3.data(), tv3.size()); + pdu_tv3.N_bytes = tv3.size(); + +#if HAVE_PCAP + rlc_pcap pcap; + pcap.open("rlc_am_header_reconstruction_test.pcap", rlc_config_t::default_rlc_am_config()); + rlc_am_tester tester(&pcap); +#else + rlc_am_tester tester(NULL); +#endif + srslte::timer_handler timers(8); + + rlc_am_lte rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); + + if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) { + return -1; + } + +#if HAVE_PCAP + pcap.write_dl_ccch(pdu_tv2.msg, pdu_tv2.N_bytes); + pcap.write_dl_ccch(pdu_tv3.msg, pdu_tv3.N_bytes); +#endif + + rlc1.write_pdu(pdu_tv2.msg, pdu_tv2.N_bytes); + rlc1.write_pdu(pdu_tv3.msg, pdu_tv3.N_bytes); + + // Check RLC re-assembled message header + TESTASSERT(spy.has_message("[Data PDU, RF=0, P=0, FI=1, SN=277, LSF=0, SO=0, N_li=2 (2, 10, )]")); + +#if HAVE_PCAP + pcap.close(); +#endif + + return 0; +} + +// Check correct reconstruction of headers after 3 segment retx +int header_reconstruction_test2(srslte::log_sink_message_spy& spy) +{ + /// Original SN=199 with 3 segments, including full SDU with d4 + /// 15:19:19.148272 [RLC_1] [I] DRB1 Tx PDU SN=199 (19 B) + /// 0000: 9c c7 80 30 0a d3 d3 d3 d4 d4 d4 d4 d4 d4 d4 d4 + /// 0010: d4 d4 d5 + /// 15:19:19.148278 [RLC_1] [D] [Data PDU, RF=0, P=0, FI=1, SN=199, LSF=0, SO=0, N_li=2 (3, 10, )] + + // 2nd retransmission with SO=0 + std::array tv1 = {0xd8, 0xc7, 0x00, 0x00, 0xd3, 0xd3}; + + // 3rd retransmission with S0=2 + std::array tv2 = { + 0xdc, 0xc7, 0x00, 0x02, 0x00, 0x10, 0xd3, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4}; + + std::array tv3 = {0xdc, 0xc7, 0x80, 0x0c, 0x00, 0x10, 0xd4, 0xd5}; + + byte_buffer_t pdu_tv1; + memcpy(pdu_tv1.msg, tv1.data(), tv1.size()); + pdu_tv1.N_bytes = tv1.size(); + + byte_buffer_t pdu_tv2; + memcpy(pdu_tv2.msg, tv2.data(), tv2.size()); + pdu_tv2.N_bytes = tv2.size(); + + byte_buffer_t pdu_tv3; + memcpy(pdu_tv3.msg, tv3.data(), tv3.size()); + pdu_tv3.N_bytes = tv3.size(); + +#if HAVE_PCAP + rlc_pcap pcap; + pcap.open("rlc_am_header_reconstruction_test2.pcap", rlc_config_t::default_rlc_am_config()); + rlc_am_tester tester(&pcap); +#else + rlc_am_tester tester(NULL); +#endif + srslte::timer_handler timers(8); + + rlc_am_lte rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); + if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) { + return -1; + } + +#if HAVE_PCAP + pcap.write_dl_ccch(pdu_tv1.msg, pdu_tv1.N_bytes); + pcap.write_dl_ccch(pdu_tv2.msg, pdu_tv2.N_bytes); + pcap.write_dl_ccch(pdu_tv3.msg, pdu_tv3.N_bytes); +#endif + + rlc1.write_pdu(pdu_tv1.msg, pdu_tv1.N_bytes); + rlc1.write_pdu(pdu_tv2.msg, pdu_tv2.N_bytes); + rlc1.write_pdu(pdu_tv3.msg, pdu_tv3.N_bytes); + + // Check RLC re-assembled message header + TESTASSERT(spy.has_message("[Data PDU, RF=0, P=0, FI=1, SN=199, LSF=0, SO=0, N_li=2 (3, 10, )]")); + +#if HAVE_PCAP + pcap.close(); +#endif + + return SRSLTE_SUCCESS; +} + +// TC with 3 segment retx +int header_reconstruction_test3(srslte::log_sink_message_spy& spy) +{ + // Original PDU + // 11:13:25.994566 [RLC_1] [I] DRB1 Tx PDU SN=206 (18 B) + // 0000: 8c ce 00 a0 db db db db db db db db db db dc dc + // 0010: dc dc + // 11:13:25.994571 [RLC_1] [D] [Data PDU, RF=0, P=0, FI=1, SN=206, LSF=0, SO=0, N_li=1 (10, )] + + // 11:13:25.995744 [RLC_1] [I] DRB1 Retx PDU segment SN=206 [so=8] (12 B) (attempt 2/16) + // 0000: dc ce 80 08 00 20 db db dc dc dc dc + // 11:13:25.995752 [RLC_2] [I] DRB1 Rx data PDU segment of SN=206 (6 B), SO=8, N_li=1 + // 0000: db db dc dc dc dc + std::array tv0 = {0xdc, 0xce, 0x80, 0x08, 0x00, 0x20, 0xdb, 0xdb, 0xdc, 0xdc, 0xdc, 0xdc}; + + // 11:13:25.996267 [RLC_1] [I] DRB1 Retx PDU segment SN=206 [so=0] (14 B) (attempt 3/16) + // 0000: c0 ce 00 00 db db db db db db db db db db + // 11:13:25.996272 [RLC_2] [I] DRB1 Rx data PDU segment of SN=206 (10 B), SO=0, N_li=0 + // 0000: db db db db db db db db db db + std::array tv1 = {0xc0, 0xce, 0x00, 0x00, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb}; + + byte_buffer_t pdu_tv0; + memcpy(pdu_tv0.msg, tv0.data(), tv0.size()); + pdu_tv0.N_bytes = tv0.size(); + + byte_buffer_t pdu_tv1; + memcpy(pdu_tv1.msg, tv1.data(), tv1.size()); + pdu_tv1.N_bytes = tv1.size(); + +#if HAVE_PCAP + rlc_pcap pcap; + pcap.open("rlc_am_header_reconstruction_test3.pcap", rlc_config_t::default_rlc_am_config()); + rlc_am_tester tester(&pcap); +#else + rlc_am_tester tester(NULL); +#endif + srslte::timer_handler timers(8); + + // configure RLC + rlc_am_lte rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); + if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) { + return -1; + } + +#if HAVE_PCAP + pcap.write_dl_ccch(pdu_tv0.msg, pdu_tv0.N_bytes); + pcap.write_dl_ccch(pdu_tv1.msg, pdu_tv1.N_bytes); +#endif + + rlc1.write_pdu(pdu_tv0.msg, pdu_tv0.N_bytes); + rlc1.write_pdu(pdu_tv1.msg, pdu_tv1.N_bytes); + + // Check RLC re-assembled message header + TESTASSERT(spy.has_message("[Data PDU, RF=0, P=0, FI=1, SN=206, LSF=0, SO=0, N_li=1 (10, )]")); + +#if HAVE_PCAP + pcap.close(); +#endif + + return SRSLTE_SUCCESS; +} + +int header_reconstruction_test4(srslte::log_sink_message_spy& spy) +{ + // Original PDU + // 15:32:20.667043 [RLC_1] [I] DRB1 Tx PDU SN=172 (22 B) + // 0000: 9c ac 80 10 0a af b0 b0 b0 b0 b0 b0 b0 b0 b0 b0 + // 0010: b1 b1 b1 b1 b1 b1 + // 15:32:20.667048 [RLC_1] [D] [Data PDU, RF=0, P=0, FI=1, SN=172, LSF=0, SO=0, N_li=2 (1, 10, )] + + // 15:32:20.668094 [RLC_1] [I] DRB1 Retx PDU segment SN=172 [so=0] (14 B) (attempt 2/16) + // 0000: dc ac 00 00 00 10 af b0 b0 b0 b0 b0 b0 b0 + // 15:32:20.668100 [RLC_2] [I] DRB1 Rx data PDU segment of SN=172 (8 B), SO=0, N_li=1 + // 0000: af b0 b0 b0 b0 b0 b0 b0 + // 15:32:20.668105 [RLC_2] [D] [Data PDU, RF=1, P=0, FI=1, SN=172, LSF=0, SO=0, N_li=1 (1, )] + std::array tv1 = {0xdc, 0xac, 0x00, 0x00, 0x00, 0x10, 0xaf, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0}; + + // 15:32:20.668497 [RLC_1] [I] DRB1 Retx PDU segment SN=172 [so=0] (12 B) (attempt 3/16) + // 0000: fc ac 00 00 00 10 af b0 b0 b0 b0 b0 + // 15:32:20.668502 [RLC_2] [I] DRB1 Rx data PDU segment of SN=172 (6 B), SO=0, N_li=1 + // 0000: af b0 b0 b0 b0 b0 + // 15:32:20.668507 [RLC_2] [D] [Data PDU, RF=1, P=1, FI=1, SN=172, LSF=0, SO=0, N_li=1 (1, )] + std::array tv2 = {0xfc, 0xac, 0x00, 0x00, 0x00, 0x10, 0xaf, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0}; + + // 15:32:20.668575 [RLC_1] [I] DRB1 Retx PDU segment SN=172 [so=6] (7 B) (attempt 3/16) + // 0000: d8 ac 00 06 b0 b0 b0 + // 15:32:20.668581 [RLC_1] [I] DRB1 Tx SDU (10 B, tx_sdu_queue_len=33) + // 0000: d8 d8 d8 d8 d8 d8 d8 d8 d8 d8 + // 15:32:20.668582 [RLC_2] [I] DRB1 Rx data PDU segment of SN=172 (3 B), SO=6, N_li=0 + // 0000: b0 b0 b0 + std::array tv3 = {0xd8, 0xac, 0x00, 0x06, 0xb0, 0xb0, 0xb0}; + + // 15:32:20.668665 [RLC_1] [I] DRB1 Retx PDU segment SN=172 [so=9] (14 B) (attempt 3/16) + // 0000: dc ac 80 09 00 20 b0 b0 b1 b1 b1 b1 b1 b1 + // 15:32:20.668671 [RLC_2] [I] DRB1 Rx data PDU segment of SN=172 (8 B), SO=9, N_li=1 + // 0000: b0 b0 b1 b1 b1 b1 b1 b1 + // 15:32:20.668675 [RLC_2] [D] [Data PDU, RF=1, P=0, FI=1, SN=172, LSF=1, SO=9, N_li=1 (2, )] + std::array tv4 = {0xdc, 0xac, 0x80, 0x09, 0x00, 0x20, 0xb0, 0xb0, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1}; + + byte_buffer_t pdu_tv1; + memcpy(pdu_tv1.msg, tv1.data(), tv1.size()); + pdu_tv1.N_bytes = tv1.size(); + + byte_buffer_t pdu_tv2; + memcpy(pdu_tv2.msg, tv2.data(), tv2.size()); + pdu_tv2.N_bytes = tv2.size(); + + byte_buffer_t pdu_tv3; + memcpy(pdu_tv3.msg, tv3.data(), tv3.size()); + pdu_tv3.N_bytes = tv3.size(); + + byte_buffer_t pdu_tv4; + memcpy(pdu_tv4.msg, tv4.data(), tv4.size()); + pdu_tv4.N_bytes = tv4.size(); + +#if HAVE_PCAP + rlc_pcap pcap; + pcap.open("rlc_am_header_reconstruction_test4.pcap", rlc_config_t::default_rlc_am_config()); + rlc_am_tester tester(&pcap); +#else + rlc_am_tester tester(NULL); +#endif + srslte::timer_handler timers(8); + + // configure RLC + rlc_am_lte rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); + if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) { + return -1; + } + +#if HAVE_PCAP + pcap.write_dl_ccch(pdu_tv1.msg, pdu_tv1.N_bytes); + pcap.write_dl_ccch(pdu_tv2.msg, pdu_tv2.N_bytes); + pcap.write_dl_ccch(pdu_tv3.msg, pdu_tv3.N_bytes); + pcap.write_dl_ccch(pdu_tv4.msg, pdu_tv4.N_bytes); +#endif + + rlc1.write_pdu(pdu_tv1.msg, pdu_tv1.N_bytes); + rlc1.write_pdu(pdu_tv2.msg, pdu_tv2.N_bytes); + rlc1.write_pdu(pdu_tv3.msg, pdu_tv3.N_bytes); + rlc1.write_pdu(pdu_tv4.msg, pdu_tv4.N_bytes); + + // Check RLC re-assembled message header + TESTASSERT(spy.has_message("[Data PDU, RF=0, P=0, FI=1, SN=172, LSF=0, SO=0, N_li=2 (1, 10, )]")); + +#if HAVE_PCAP + pcap.close(); +#endif + + return SRSLTE_SUCCESS; +} + +int header_reconstruction_test5(srslte::log_sink_message_spy& spy) +{ + // Original PDU: + // 18:46:22.372858 [RLC_1] [I] DRB1 Tx PDU SN=222 (22 B) + // 0000: bc de 80 30 0a ee ee ee ef ef ef ef ef ef ef ef + // 0010: ef ef f0 f0 f0 f0 + // 18:46:22.372863 [RLC_1] [D] [Data PDU, RF=0, P=1, FI=1, SN=222, LSF=0, SO=0, N_li=2 (3, 10, )] + + // 18:46:22.373623 [RLC_1] [I] DRB1 Retx PDU segment SN=222 [so=0] (7 B) (attempt 2/16) + // 0000: d0 de 00 00 ee ee ee + // 18:46:22.373629 [RLC_2] [I] DRB1 Rx data PDU segment of SN=222 (3 B), SO=0, N_li=0 + // 0000: ee ee ee + std::array tv0 = {0xd0, 0xde, 0x00, 0x00, 0xee, 0xee, 0xee}; + + // 18:46:22.373707 [RLC_1] [I] DRB1 Retx PDU segment SN=222 [so=3] (19 B) (attempt 2/16) + // 0000: cc de 00 03 00 a0 ef ef ef ef ef ef ef ef ef ef + // 0010: f0 f0 f0 + // 18:46:22.373714 [RLC_2] [I] DRB1 Rx data PDU segment of SN=222 (13 B), SO=3, N_li=1 + // 0000: ef ef ef ef ef ef ef ef ef ef f0 f0 f0 + std::array tv1 = { + 0xcc, 0xde, 0x00, 0x03, 0x00, 0xa0, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xf0, 0xf0, 0xf0}; + + // 18:46:22.373793 [RLC_1] [I] DRB1 Retx PDU segment SN=222 [so=16] (5 B) (attempt 2/16) + // 0000: d8 de 80 10 f0 + // 18:46:22.373798 [RLC_2] [I] DRB1 Rx data PDU segment of SN=222 (1 B), SO=16, N_li=0 + // 0000: f0 + std::array tv2 = {0xd8, 0xde, 0x80, 0x10, 0xf0}; + + byte_buffer_t pdu_tv0; + memcpy(pdu_tv0.msg, tv0.data(), tv0.size()); + pdu_tv0.N_bytes = tv0.size(); + + byte_buffer_t pdu_tv1; + memcpy(pdu_tv1.msg, tv1.data(), tv1.size()); + pdu_tv1.N_bytes = tv1.size(); + + byte_buffer_t pdu_tv2; + memcpy(pdu_tv2.msg, tv2.data(), tv2.size()); + pdu_tv2.N_bytes = tv2.size(); + +#if HAVE_PCAP + rlc_pcap pcap; + pcap.open("rlc_am_header_reconstruction_test5.pcap", rlc_config_t::default_rlc_am_config()); + rlc_am_tester tester(&pcap); +#else + rlc_am_tester tester(NULL); +#endif + srslte::timer_handler timers(8); + + // configure RLC + rlc_am_lte rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); + if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) { + return -1; + } + +#if HAVE_PCAP + pcap.write_dl_ccch(pdu_tv0.msg, pdu_tv0.N_bytes); + pcap.write_dl_ccch(pdu_tv1.msg, pdu_tv1.N_bytes); + pcap.write_dl_ccch(pdu_tv2.msg, pdu_tv2.N_bytes); +#endif + + // don't write original PDU + rlc1.write_pdu(pdu_tv0.msg, pdu_tv0.N_bytes); + rlc1.write_pdu(pdu_tv1.msg, pdu_tv1.N_bytes); + rlc1.write_pdu(pdu_tv2.msg, pdu_tv2.N_bytes); + + // Check RLC re-assembled message header + TESTASSERT(spy.has_message("[Data PDU, RF=0, P=0, FI=1, SN=222, LSF=0, SO=0, N_li=2 (3, 10, )]")); + +#if HAVE_PCAP + pcap.close(); +#endif + + return SRSLTE_SUCCESS; +} + +int header_reconstruction_test6(srslte::log_sink_message_spy& spy) +{ + // Original PDU: + // 21:50:12.709646 [RLC_1] [I] DRB1 Tx PDU SN=509 (20 B) + // 0000: 9d fd 80 40 0a b1 b1 b1 b1 b2 b2 b2 b2 b2 b2 b2 + // 0010: b2 b2 b2 b3 + // 21:50:12.709653 [RLC_1] [D] [Data PDU, RF=0, P=0, FI=1, SN=509, LSF=0, SO=0, N_li=2 (4, 10, )]] + + // 21:50:12.711022 [RLC_1] [I] DRB1 Retx PDU segment SN=509 [so=0] (5 B) (attempt 3/16) + // 0000: d9 fd 00 00 b1 + // 21:50:12.711029 [RLC_2] [I] DRB1 Rx data PDU segment of SN=509 (1 B), SO=0, N_li=0 + // 0000: b1 + // 21:50:12.711034 [RLC_2] [D] [Data PDU, RF=1, P=0, FI=1, SN=509, LSF=0, SO=0, N_li=0] + std::array tv0 = {0xd9, 0xfd, 0x00, 0x00, 0xb1}; + + // 21:50:12.711104 [RLC_1] [I] DRB1 Retx PDU segment SN=509 [so=1] (7 B) (attempt 3/16) + // 0000: d1 fd 00 01 b1 b1 b1 + // 21:50:12.711110 [RLC_2] [I] DRB1 Rx data PDU segment of SN=509 (3 B), SO=1, N_li=0 + // 0000: b1 b1 b1 + // 21:50:12.711115 [RLC_2] [D] [Data PDU, RF=1, P=0, FI=1, SN=509, LSF=0, SO=1, N_li=0] + std::array tv1 = {0xd1, 0xfd, 0x00, 0x01, 0xb1, 0xb1, 0xb1}; + + // 21:50:12.711201 [RLC_1] [I] DRB1 Retx PDU segment SN=509 [so=4] (17 B) (attempt 3/16) + // 0000: ed fd 80 04 00 a0 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 + // 0010: b3 + // 21:50:12.711210 [RLC_2] [I] DRB1 Rx data PDU segment of SN=509 (11 B), SO=4, N_li=1 + // 0000: b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b3 + // 21:50:12.711216 [RLC_2] [D] [Data PDU, RF=1, P=1, FI=1, SN=509, LSF=1, SO=4, N_li=1 (10, )] + std::array tv2 = { + 0xed, 0xfd, 0x80, 0x04, 0x00, 0xa0, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb3}; + + byte_buffer_t pdu_tv0; + memcpy(pdu_tv0.msg, tv0.data(), tv0.size()); + pdu_tv0.N_bytes = tv0.size(); + + byte_buffer_t pdu_tv1; + memcpy(pdu_tv1.msg, tv1.data(), tv1.size()); + pdu_tv1.N_bytes = tv1.size(); + + byte_buffer_t pdu_tv2; + memcpy(pdu_tv2.msg, tv2.data(), tv2.size()); + pdu_tv2.N_bytes = tv2.size(); + +#if HAVE_PCAP + rlc_pcap pcap; + pcap.open("rlc_am_header_reconstruction_test6.pcap", rlc_config_t::default_rlc_am_config()); + rlc_am_tester tester(&pcap); +#else + rlc_am_tester tester(NULL); +#endif + srslte::timer_handler timers(8); + + // configure RLC + rlc_am_lte rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); + if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) { + return -1; + } + +#if HAVE_PCAP + pcap.write_dl_ccch(pdu_tv0.msg, pdu_tv0.N_bytes); + pcap.write_dl_ccch(pdu_tv1.msg, pdu_tv1.N_bytes); + pcap.write_dl_ccch(pdu_tv2.msg, pdu_tv2.N_bytes); +#endif + + // don't write original PDU + rlc1.write_pdu(pdu_tv0.msg, pdu_tv0.N_bytes); + rlc1.write_pdu(pdu_tv1.msg, pdu_tv1.N_bytes); + rlc1.write_pdu(pdu_tv2.msg, pdu_tv2.N_bytes); + + // Check RLC re-assembled message header + TESTASSERT(spy.has_message("[Data PDU, RF=0, P=1, FI=1, SN=509, LSF=0, SO=0, N_li=2 (4, 10, )]")); + +#if HAVE_PCAP + pcap.close(); +#endif + + return SRSLTE_SUCCESS; +} + +int header_reconstruction_test7(srslte::log_sink_message_spy& spy) +{ + // Original PDU: + // 22:14:54.646530 [RLC_1] [I] DRB1 Tx PDU SN=282 (19 B) + // 0000: 9d 1a 80 10 0a 28 29 29 29 29 29 29 29 29 29 29 + // 0010: 2a 2a 2a + // 22:14:54.646535 [RLC_1] [D] [Data PDU, RF=0, P=0, FI=1, SN=282, LSF=0, SO=0, N_li=2 (1, 10, )] + + // 22:14:54.648484 [RLC_1] [I] DRB1 Retx PDU segment SN=282 [so=2] (6 B) (attempt 2/16) + // 0000: f9 1a 00 02 29 29 + // 22:14:54.648490 [RLC_2] [I] DRB1 Rx data PDU segment of SN=282 (2 B), SO=2, N_li=0 + // 0000: 29 29 + // 22:14:54.648495 [RLC_2] [D] [Data PDU, RF=1, P=1, FI=1, SN=282, LSF=0, SO=2, N_li=0] + std::array tv0 = {0xf9, 0x1a, 0x00, 0x02, 0x29, 0x29}; + + // 22:14:54.648576 [RLC_1] [I] DRB1 Retx PDU segment SN=282 [so=4] (11 B) (attempt 2/16) + // 0000: d1 1a 00 04 29 29 29 29 29 29 29 + // 22:14:54.648583 [RLC_2] [I] DRB1 Rx data PDU segment of SN=282 (7 B), SO=4, N_li=0 + // 0000: 29 29 29 29 29 29 29 + // 22:14:54.648588 [RLC_2] [D] [Data PDU, RF=1, P=0, FI=1, SN=282, LSF=0, SO=4, N_li=0] + std::array tv1 = {0xd1, 0x1a, 0x00, 0x04, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29}; + + // 22:14:54.648701 [RLC_1] [I] DRB1 Retx PDU segment SN=282 [so=11] (7 B) (attempt 2/16) + // 0000: d9 1a 80 0b 2a 2a 2a + // 22:14:54.648707 [RLC_2] [I] DRB1 Rx data PDU segment of SN=282 (3 B), SO=11, N_li=0 + // 0000: 2a 2a 2a + // 22:14:54.648713 [RLC_2] [D] [Data PDU, RF=1, P=0, FI=1, SN=282, LSF=1, SO=11, N_li=0] + std::array tv2 = {0xd9, 0x1a, 0x80, 0x0b, 0x2a, 0x2a, 0x2a}; + + // 22:14:54.648860 [RLC_1] [I] DRB1 Retx PDU segment SN=282 [so=0] (5 B) (attempt 3/16) + // 0000: d1 1a 00 00 28 + // 22:14:54.648866 [RLC_2] [I] DRB1 Rx data PDU segment of SN=282 (1 B), SO=0, N_li=0 + // 0000: 28 + // 22:14:54.648871 [RLC_2] [D] [Data PDU, RF=1, P=0, FI=1, SN=282, LSF=0, SO=0, N_li=0] + std::array tv3 = {0xd1, 0x1a, 0x00, 0x00, 0x28}; + + // 22:14:54.648948 [RLC_1] [I] DRB1 Retx PDU segment SN=282 [so=1] (8 B) (attempt 3/16) + // 0000: c9 1a 00 01 29 29 29 29 + // 22:14:54.648957 [RLC_2] [I] DRB1 Rx data PDU segment of SN=282 (4 B), SO=1, N_li=0 + // 0000: 29 29 29 29 + // 22:14:54.648962 [RLC_2] [D] [Data PDU, RF=1, P=0, FI=1, SN=282, LSF=0, SO=1, N_li=0] + std::array tv4 = {0xc9, 0x1a, 0x00, 0x01, 0x29, 0x29, 0x29, 0x29}; + + byte_buffer_t pdu_tv0; + memcpy(pdu_tv0.msg, tv0.data(), tv0.size()); + pdu_tv0.N_bytes = tv0.size(); + + byte_buffer_t pdu_tv1; + memcpy(pdu_tv1.msg, tv1.data(), tv1.size()); + pdu_tv1.N_bytes = tv1.size(); + + byte_buffer_t pdu_tv2; + memcpy(pdu_tv2.msg, tv2.data(), tv2.size()); + pdu_tv2.N_bytes = tv2.size(); + + byte_buffer_t pdu_tv3; + memcpy(pdu_tv3.msg, tv3.data(), tv3.size()); + pdu_tv3.N_bytes = tv3.size(); + + byte_buffer_t pdu_tv4; + memcpy(pdu_tv4.msg, tv4.data(), tv4.size()); + pdu_tv4.N_bytes = tv4.size(); + +#if HAVE_PCAP + rlc_pcap pcap; + pcap.open("rlc_am_header_reconstruction_test7.pcap", rlc_config_t::default_rlc_am_config()); + rlc_am_tester tester(&pcap); +#else + rlc_am_tester tester(NULL); +#endif + srslte::timer_handler timers(8); + + // configure RLC + rlc_am_lte rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); + if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) { + return -1; + } + +#if HAVE_PCAP + pcap.write_dl_ccch(pdu_tv0.msg, pdu_tv0.N_bytes); + pcap.write_dl_ccch(pdu_tv1.msg, pdu_tv1.N_bytes); + pcap.write_dl_ccch(pdu_tv2.msg, pdu_tv2.N_bytes); + pcap.write_dl_ccch(pdu_tv3.msg, pdu_tv3.N_bytes); + pcap.write_dl_ccch(pdu_tv4.msg, pdu_tv4.N_bytes); +#endif + + // don't write original PDU + rlc1.write_pdu(pdu_tv0.msg, pdu_tv0.N_bytes); + rlc1.write_pdu(pdu_tv1.msg, pdu_tv1.N_bytes); + rlc1.write_pdu(pdu_tv2.msg, pdu_tv2.N_bytes); + rlc1.write_pdu(pdu_tv3.msg, pdu_tv3.N_bytes); + rlc1.write_pdu(pdu_tv4.msg, pdu_tv4.N_bytes); + + // Check RLC re-assembled message header + TESTASSERT(spy.has_message("[Data PDU, RF=0, P=0, FI=1, SN=282, LSF=0, SO=0, N_li=2 (1, 10, )]")); + +#if HAVE_PCAP + pcap.close(); +#endif + + return SRSLTE_SUCCESS; +} + +int header_reconstruction_test8(srslte::log_sink_message_spy& spy) +{ + // Original PDU: + // 21:23:34.407718 [RLC_1] [I] DRB1 Tx PDU SN=423 (40 B) + // 0000: b5 a7 80 38 0a 00 a0 77 77 77 78 78 78 78 78 78 + // 0010: 78 78 78 78 79 79 79 79 79 79 79 79 79 79 7a 7a + // 0020: 7a 7a 7a 7a 7a 7a 7a 7a + // 21:23:34.407724 [RLC_1] [D] [Data PDU, RF=0, P=1, FI=1, SN=423, LSF=0, SO=0, N_li=3 (3, 10, 10, )] + + // 21:23:34.408815 [RLC_1] [I] DRB1 Retx PDU segment SN=423 [so=0] (18 B) (attempt 2/8) + // 0000: fd a7 00 00 00 30 77 77 77 78 78 78 78 78 78 78 + // 0010: 78 78 + // 21:23:34.408822 [RLC_2] [I] DRB1 Rx data PDU segment of SN=423 (12 B), SO=0, N_li=1 + // 0000: 77 77 77 78 78 78 78 78 78 78 78 78 + // 21:23:34.408828 [RLC_2] [D] [Data PDU, RF=1, P=1, FI=1, SN=423, LSF=0, SO=0, N_li=1 (3, )] + std::array tv0 = { + 0xfd, 0xa7, 0x00, 0x00, 0x00, 0x30, 0x77, 0x77, 0x77, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78}; + + // 21:23:34.408913 [RLC_1] [I] DRB1 Retx PDU segment SN=423 [so=12] (17 B) (attempt 2/8) + // 0000: f5 a7 00 0c 00 10 78 79 79 79 79 79 79 79 79 79 + // 0010: 79 + // 21:23:34.408919 [RLC_2] [I] DRB1 Rx data PDU segment of SN=423 (11 B), SO=12, N_li=1 + // 0000: 78 79 79 79 79 79 79 79 79 79 79 + // 21:23:34.408925 [RLC_2] [D] [Data PDU, RF=1, P=1, FI=1, SN=423, LSF=0, SO=12, N_li=1 (1, )] + std::array tv1 = { + 0xf5, 0xa7, 0x00, 0x0c, 0x00, 0x10, 0x78, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79}; + + // 21:23:34.409421 [RLC_1] [I] DRB1 Retx PDU segment SN=423 [so=0] (19 B) (attempt 3/8) + // 0000: f5 a7 00 00 00 30 77 77 77 78 78 78 78 78 78 78 + // 0010: 78 78 78 + // 21:23:34.409433 [RLC_2] [I] DRB1 Rx data PDU segment of SN=423 (13 B), SO=0, N_li=1 + // 0000: 77 77 77 78 78 78 78 78 78 78 78 78 78 + // 21:23:34.409440 [RLC_2] [D] [Data PDU, RF=1, P=1, FI=1, SN=423, LSF=0, SO=0, N_li=1 (3, )] + std::array tv2 = { + 0xf5, 0xa7, 0x00, 0x00, 0x00, 0x30, 0x77, 0x77, 0x77, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78}; + + // 21:23:34.409524 [RLC_1] [I] DRB1 Retx PDU segment SN=423 [so=13] (26 B) (attempt 3/8) + // 0000: e5 a7 80 0d 00 a0 79 79 79 79 79 79 79 79 79 79 + // 0010: 7a 7a 7a 7a 7a 7a 7a 7a 7a 7a + // 21:23:34.409531 [RLC_2] [I] DRB1 Rx data PDU segment of SN=423 (20 B), SO=13, N_li=1 + // 0000: 79 79 79 79 79 79 79 79 79 79 7a 7a 7a 7a 7a 7a + // 0010: 7a 7a 7a 7a + // 21:23:34.409537 [RLC_2] [D] [Data PDU, RF=1, P=1, FI=0, SN=423, LSF=1, SO=13, N_li=1 (10, )] + std::array tv3 = {0xe5, 0xa7, 0x80, 0x0d, 0x00, 0xa0, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, + 0x79, 0x79, 0x79, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a}; + + byte_buffer_t pdu_tv0; + memcpy(pdu_tv0.msg, tv0.data(), tv0.size()); + pdu_tv0.N_bytes = tv0.size(); + + byte_buffer_t pdu_tv1; + memcpy(pdu_tv1.msg, tv1.data(), tv1.size()); + pdu_tv1.N_bytes = tv1.size(); + + byte_buffer_t pdu_tv2; + memcpy(pdu_tv2.msg, tv2.data(), tv2.size()); + pdu_tv2.N_bytes = tv2.size(); + + byte_buffer_t pdu_tv3; + memcpy(pdu_tv3.msg, tv3.data(), tv3.size()); + pdu_tv3.N_bytes = tv3.size(); + +#if HAVE_PCAP + rlc_pcap pcap; + pcap.open("rlc_am_header_reconstruction_test8.pcap", rlc_config_t::default_rlc_am_config()); + rlc_am_tester tester(&pcap); +#else + rlc_am_tester tester(NULL); +#endif + srslte::timer_handler timers(8); + + // configure RLC + rlc_am_lte rlc1(srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); + if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) { + return -1; + } + +#if HAVE_PCAP + pcap.write_dl_ccch(pdu_tv0.msg, pdu_tv0.N_bytes); + pcap.write_dl_ccch(pdu_tv1.msg, pdu_tv1.N_bytes); + pcap.write_dl_ccch(pdu_tv2.msg, pdu_tv2.N_bytes); + pcap.write_dl_ccch(pdu_tv3.msg, pdu_tv3.N_bytes); + pcap.close(); +#endif + + // don't write original PDU + rlc1.write_pdu(pdu_tv0.msg, pdu_tv0.N_bytes); + rlc1.write_pdu(pdu_tv1.msg, pdu_tv1.N_bytes); + rlc1.write_pdu(pdu_tv2.msg, pdu_tv2.N_bytes); + rlc1.write_pdu(pdu_tv3.msg, pdu_tv3.N_bytes); + + // Check RLC re-assembled message header + TESTASSERT(spy.has_message("[Data PDU, RF=0, P=1, FI=1, SN=423, LSF=0, SO=0, N_li=3 (3, 10, 10, )]")); + + return SRSLTE_SUCCESS; +} + bool reset_test() { rlc_am_tester tester; @@ -1947,28 +3213,28 @@ bool status_pdu_test() } // Push 5 SDUs into RLC1 - unique_byte_buffer_t sdu_bufs[NBUFS]; - for (int i = 0; i < NBUFS; i++) { + 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] = srslte::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])); } - TESTASSERT(13 == rlc1.get_buffer_state()); - // Read 5 PDUs from RLC1 (1 byte each) - byte_buffer_t pdu_bufs[NBUFS]; - for (int i = 0; i < NBUFS; i++) { - len = rlc1.read_pdu(pdu_bufs[i].msg, 4); // 2 byte header + 1 byte payload + 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()); - // Only pass last PDUs to RLC2 - for (int i = 0; i < NBUFS; i++) { - if (i == 4) { + // Only pass 2nd and last PDUs to RLC2 + for (uint32_t i = 0; i < n_pdus; ++i) { + if (i == 0 || i == 2 || i == n_pdus - 1) { rlc2.write_pdu(pdu_bufs[i].msg, pdu_bufs[i].N_bytes); } } @@ -1980,27 +3246,20 @@ bool status_pdu_test() } uint32_t buffer_state = rlc2.get_buffer_state(); - TESTASSERT(8 == buffer_state); // Read status PDU from RLC2 byte_buffer_t status_buf; len = rlc2.read_pdu(status_buf.msg, 5); // provide only small grant status_buf.N_bytes = len; - TESTASSERT(status_buf.N_bytes != 0); - // check status PDU doesn't contain ACK_SN in NACK list rlc_status_pdu_t status_pdu = {}; rlc_am_read_status_pdu(status_buf.msg, status_buf.N_bytes, &status_pdu); - if (rlc_am_is_valid_status_pdu(status_pdu) == false) { - return -1; - } + TESTASSERT(rlc_am_is_valid_status_pdu(status_pdu)); // Write status PDU to RLC1 rlc1.write_pdu(status_buf.msg, status_buf.N_bytes); - TESTASSERT(3 == rlc1.get_buffer_state()); // 2 byte header + 1 byte payload - // Read the retx PDU from RLC1 byte_buffer_t retx; len = rlc1.read_pdu(retx.msg, 10); @@ -2017,7 +3276,7 @@ bool status_pdu_test() // get buffer state and status PDU again status_buf.clear(); - len = rlc2.read_pdu(status_buf.msg, 10); // big enough grant to fit full status PDU + len = rlc2.read_pdu(status_buf.msg, 20); // big enough grant to fit full status PDU status_buf.N_bytes = len; TESTASSERT(status_buf.N_bytes != 0); @@ -2025,7 +3284,7 @@ bool status_pdu_test() rlc1.write_pdu(status_buf.msg, status_buf.N_bytes); // retransmission of remaining PDUs - for (int i = 0; i < 3; i++) { + for (int i = 0; i < 10; i++) { retx.clear(); len = rlc1.read_pdu(retx.msg, 3); retx.N_bytes = len; @@ -2034,27 +3293,161 @@ bool status_pdu_test() rlc2.write_pdu(retx.msg, retx.N_bytes); } - TESTASSERT(tester.n_sdus == NBUFS); - for (int i = 0; i < tester.n_sdus; i++) { - if (tester.sdus[i]->N_bytes != 1) - return -1; - if (*(tester.sdus[i]->msg) != i) - return -1; + TESTASSERT(tester.sdus.size() == n_sdus); + for (uint32_t i = 0; i < tester.sdus.size(); i++) { + TESTASSERT(tester.sdus[i]->N_bytes == 1); } - return 0; + return SRSLTE_SUCCESS; +} + +// This test checks the correct functioning of RLC reestablishment +// after maxRetx attempt. +bool reestablish_test() +{ + const rlc_config_t config = rlc_config_t::default_rlc_am_config(); +#if HAVE_PCAP + rlc_pcap pcap; + pcap.open("rlc_am_reestablish_test.pcap", config); + rlc_am_tester tester(&pcap); +#else + rlc_am_tester tester(NULL); +#endif + + srslte::timer_handler timers(8); + + 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); + + srslog::fetch_basic_logger("RLC_AM_1").set_hex_dump_max_size(100); + srslog::fetch_basic_logger("RLC_AM_2").set_hex_dump_max_size(100); + srslog::fetch_basic_logger("RLC").set_hex_dump_max_size(100); + + if (not rlc1.configure(config)) { + return -1; + } + + if (not rlc2.configure(config)) { + return -1; + } + + bool reetablished_once = false; + + // Generate 40 SDUs/PDUs + const uint32_t total_num_tx_pdus = config.am.max_retx_thresh * 10; + uint32_t num_tx_pdus = 0; + + // Create a few SDUs and write to RLC1 to make sure buffers aren't empty after tx one PDU + for (uint32_t i = num_tx_pdus; i < 5; ++i) { + // Write SDU + unique_byte_buffer_t sdu = srslte::make_byte_buffer(); + TESTASSERT(sdu != nullptr); + sdu->N_bytes = 5; // Give each buffer a size of 1 byte + for (uint32_t k = 0; k < sdu->N_bytes; ++k) { + sdu->msg[k] = i; // Write the index into the buffer + } + sdu->md.pdcp_sn = i; + rlc1.write_sdu(std::move(sdu)); + } + + for (uint32_t i = num_tx_pdus; i < total_num_tx_pdus; i++) { + // Write SDU + unique_byte_buffer_t sdu = srslte::make_byte_buffer(); + TESTASSERT(sdu != nullptr); + sdu->N_bytes = 5; // Give each buffer a size of 1 byte + for (uint32_t k = 0; k < sdu->N_bytes; ++k) { + sdu->msg[k] = i; // Write the index into the buffer + } + sdu->md.pdcp_sn = i; + rlc1.write_sdu(std::move(sdu)); + + // Read PDU + unique_byte_buffer_t pdu = srslte::make_byte_buffer(); + pdu->N_bytes = rlc1.read_pdu(pdu->msg, 7); // 2 byte header + 5 byte payload; + + // Find SN=0 PDU + bool is_data_pdu_sn0 = false; + if (not rlc_am_is_control_pdu(pdu->msg)) { + // After reestablishment after maxretx, also SN=0 is delivered + if (not reetablished_once) { + rlc_amd_pdu_header_t header = {}; + rlc_am_read_data_pdu_header(pdu.get(), &header); + if (header.sn == 0) { + is_data_pdu_sn0 = true; + } + } + } + + // Deliver all PDUs but SN=0 to RLC2 + if (not is_data_pdu_sn0) { + rlc2.write_pdu(pdu->msg, pdu->N_bytes); +#if HAVE_PCAP + pcap.write_dl_ccch(pdu->msg, pdu->N_bytes); +#endif + } + + // Check if RLC2 has something to send + if (rlc2.get_buffer_state() > 0) { + byte_buffer_t status_buf; + status_buf.N_bytes = rlc2.read_pdu(status_buf.msg, 5); // provide only small grant + TESTASSERT(status_buf.N_bytes != 0); + + // Write status PDU to RLC1 + rlc1.write_pdu(status_buf.msg, status_buf.N_bytes); +#if HAVE_PCAP + pcap.write_ul_ccch(status_buf.msg, status_buf.N_bytes); +#endif + } + + // each interation is one TTI + timers.step_all(); + + // Reestablish if max retx have been reached + if (tester.max_retx_triggered and !reetablished_once) { + rlc1.reestablish(); + rlc2.reestablish(); + // make sure we only reesablish once + reetablished_once = true; + } + } + + TESTASSERT(tester.sdus.size() == 17); + + srslog::fetch_basic_logger("TEST").info("Received %zd SDUs", tester.sdus.size()); + +#if HAVE_PCAP + pcap.close(); +#endif + + return SRSLTE_SUCCESS; } int main(int argc, char** argv) { - srslog::init(); + srslte::logmap::set_default_log_level(srslte::LOG_LEVEL_DEBUG); + srslte::logmap::set_default_hex_limit(4096); + TESTASSERT(srslte::logmap::get("RLC_AM_1")->get_level() == srslte::LOG_LEVEL_DEBUG); - auto& logger_rrc1 = srslog::fetch_basic_logger("RLC_AM_1", false); - logger_rrc1.set_level(srslog::basic_levels::debug); - logger_rrc1.set_hex_dump_max_size(-1); - auto& logger_rrc2 = srslog::fetch_basic_logger("RLC_AM_2", false); - logger_rrc2.set_level(srslog::basic_levels::debug); - logger_rrc2.set_hex_dump_max_size(-1); + // Setup the log message spy to intercept error and warning log entries from RLC + if (!srslog::install_custom_sink(srslte::log_sink_message_spy::name(), + std::unique_ptr( + new srslte::log_sink_message_spy(srslog::get_default_log_formatter())))) { + return SRSLTE_ERROR; + } + + auto* spy = static_cast(srslog::find_sink(srslte::log_sink_message_spy::name())); + if (!spy) { + return SRSLTE_ERROR; + } + srslog::set_default_sink(*spy); + + auto& logger_rrc1 = srslog::fetch_basic_logger("RLC_AM_1", *spy, false); + auto& logger_rrc2 = srslog::fetch_basic_logger("RLC_AM_2", *spy, false); + logger_rrc1.set_hex_dump_max_size(100); + logger_rrc2.set_hex_dump_max_size(100); + + // start log backend + srslog::init(); if (basic_test()) { printf("basic_test failed\n"); @@ -2081,6 +3474,16 @@ int main(int argc, char** argv) exit(-1); }; + if (max_retx_test()) { + printf("max_retx_test failed\n"); + exit(-1); + }; + + if (reestablish_test()) { + printf("reestablish_test failed\n"); + exit(-1); + }; + if (segment_retx_test()) { printf("segment_retx_test failed\n"); exit(-1); @@ -2130,6 +3533,67 @@ int main(int argc, char** argv) logger_rrc1.set_hex_dump_max_size(-1); logger_rrc2.set_hex_dump_max_size(-1); + if (resegment_test_9()) { + printf("resegment_test_9 failed\n"); + exit(-1); + }; + + if (resegment_test_10()) { + printf("resegment_test_10 failed\n"); + exit(-1); + }; + + if (resegment_test_11()) { + printf("resegment_test_11 failed\n"); + exit(-1); + }; + + if (resegment_test_12()) { + printf("resegment_test_12 failed\n"); + exit(-1); + }; + + // Set of unique header reconstruction tests using the logspy + if (header_reconstruction_test(*spy)) { + printf("header_reconstruction_test failed\n"); + exit(-1); + } + + if (header_reconstruction_test2(*spy)) { + printf("header_reconstruction_test2 failed\n"); + exit(-1); + } + + if (header_reconstruction_test3(*spy)) { + printf("header_reconstruction_test3 failed\n"); + exit(-1); + } + + if (header_reconstruction_test4(*spy)) { + printf("header_reconstruction_test4 failed\n"); + exit(-1); + } + + if (header_reconstruction_test5(*spy)) { + printf("header_reconstruction_test5 failed\n"); + exit(-1); + } + + if (header_reconstruction_test6(*spy)) { + printf("header_reconstruction_test6 failed\n"); + exit(-1); + } + + if (header_reconstruction_test7(*spy)) { + printf("header_reconstruction_test7 failed\n"); + exit(-1); + } + + if (header_reconstruction_test8(*spy)) { + printf("header_reconstruction_test8 failed\n"); + exit(-1); + } + if (reset_test()) { printf("reset_test failed\n"); exit(-1); @@ -2150,5 +3614,5 @@ int main(int argc, char** argv) exit(-1); }; - return 0; -} + return SRSLTE_SUCCESS; +} \ No newline at end of file diff --git a/lib/test/upper/rlc_stress_test.cc b/lib/test/upper/rlc_stress_test.cc index 213d8f0e6..0386f37a7 100644 --- a/lib/test/upper/rlc_stress_test.cc +++ b/lib/test/upper/rlc_stress_test.cc @@ -35,34 +35,29 @@ #define LOG_HEX_LIMIT (-1) -#define PCAP 0 #define PCAP_CRNTI (0x1001) #define PCAP_TTI (666) -#if PCAP -#include "srslte/common/mac_nr_pcap.h" -#include "srslte/mac/mac_nr_pdu.h" -static std::unique_ptr pcap_handle = nullptr; -#endif +#include "srslte/common/mac_pcap.h" +#include "srslte/mac/mac_sch_pdu_nr.h" +static std::unique_ptr pcap_handle = nullptr; int write_pdu_to_pcap(const bool is_dl, const uint32_t lcid, const uint8_t* payload, const uint32_t len) { -#if PCAP if (pcap_handle) { srslte::byte_buffer_t tx_buffer; - srslte::mac_nr_sch_pdu tx_pdu; + srslte::mac_sch_pdu_nr tx_pdu; tx_pdu.init_tx(&tx_buffer, len + 10); tx_pdu.add_sdu(lcid, payload, len); tx_pdu.pack(); if (is_dl) { - pcap_handle->write_dl_crnti(tx_buffer.msg, tx_buffer.N_bytes, PCAP_CRNTI, true, PCAP_TTI); + pcap_handle->write_dl_crnti_nr(tx_buffer.msg, tx_buffer.N_bytes, PCAP_CRNTI, true, PCAP_TTI); } else { - pcap_handle->write_ul_crnti(tx_buffer.msg, tx_buffer.N_bytes, PCAP_CRNTI, true, PCAP_TTI); + pcap_handle->write_ul_crnti_nr(tx_buffer.msg, tx_buffer.N_bytes, PCAP_CRNTI, true, PCAP_TTI); } return SRSLTE_SUCCESS; } -#endif return SRSLTE_ERROR; } @@ -71,25 +66,27 @@ using namespace srsue; using namespace srslte; namespace bpo = boost::program_options; +#define MIN_SDU_SIZE (5) +#define MAX_SDU_SIZE (1500) + typedef struct { std::string rat; std::string mode; - uint32_t sdu_size; + int32_t sdu_size; uint32_t test_duration_sec; float pdu_drop_rate; float pdu_cut_rate; float pdu_duplicate_rate; uint32_t sdu_gen_delay_usec; uint32_t pdu_tx_delay_usec; - bool reestablish; uint32_t log_level; bool single_tx; bool write_pcap; uint32_t avg_opp_size; bool random_opp; bool zero_seed; - bool pedantic_sdu_check; uint32_t nof_pdu_tti; + uint32_t max_retx; } stress_test_args_t; void parse_args(stress_test_args_t* args, int argc, char* argv[]) @@ -107,20 +104,19 @@ void parse_args(stress_test_args_t* args, int argc, char* argv[]) ("rat", bpo::value(&args->rat)->default_value("LTE"), "The RLC version to use (LTE/NR)") ("mode", bpo::value(&args->mode)->default_value("AM"), "Whether to test RLC acknowledged or unacknowledged mode (AM/UM)") ("duration", bpo::value(&args->test_duration_sec)->default_value(5), "Duration (sec)") - ("sdu_size", bpo::value(&args->sdu_size)->default_value(1500), "Size of SDUs") - ("avg_opp_size", bpo::value(&args->avg_opp_size)->default_value(1505), "Size of the MAC opportunity (if not random)") + ("sdu_size", bpo::value(&args->sdu_size)->default_value(-1), "Size of SDUs (-1 means random)") ("random_opp", bpo::value(&args->random_opp)->default_value(true), "Whether to generate random MAC opportunities") + ("avg_opp_size", bpo::value(&args->avg_opp_size)->default_value(1505), "Size of the MAC opportunity (if not random)") ("sdu_gen_delay", bpo::value(&args->sdu_gen_delay_usec)->default_value(0), "SDU generation delay (usec)") ("pdu_tx_delay", bpo::value(&args->pdu_tx_delay_usec)->default_value(0), "Delay in MAC for transfering PDU from tx'ing RLC to rx'ing RLC (usec)") ("pdu_drop_rate", bpo::value(&args->pdu_drop_rate)->default_value(0.1), "Rate at which RLC PDUs are dropped") ("pdu_cut_rate", bpo::value(&args->pdu_cut_rate)->default_value(0.0), "Rate at which RLC PDUs are chopped in length") ("pdu_duplicate_rate", bpo::value(&args->pdu_duplicate_rate)->default_value(0.0), "Rate at which RLC PDUs are duplicated") - ("reestablish", bpo::value(&args->reestablish)->default_value(false), "Mimic RLC reestablish during execution") ("loglevel", bpo::value(&args->log_level)->default_value(srslte::LOG_LEVEL_DEBUG), "Log level (1=Error,2=Warning,3=Info,4=Debug)") ("singletx", bpo::value(&args->single_tx)->default_value(false), "If set to true, only one node is generating data") ("pcap", bpo::value(&args->write_pcap)->default_value(false), "Whether to write all RLC PDU to PCAP file") ("zeroseed", bpo::value(&args->zero_seed)->default_value(false), "Whether to initialize random seed to zero") - ("pedantic", bpo::value(&args->pedantic_sdu_check)->default_value(false), "Whether to check SDU length and exit on error") + ("max_retx", bpo::value(&args->max_retx)->default_value(8), "Maximum number of RLC retransmission attempts") ("nof_pdu_tti", bpo::value(&args->nof_pdu_tti)->default_value(1), "Number of PDUs processed in a TTI"); // clang-format on @@ -144,9 +140,14 @@ void parse_args(stress_test_args_t* args, int argc, char* argv[]) args->log_level = 4; printf("Set log level to %d (%s)\n", args->log_level, srslte::log_level_text[args->log_level]); } + + // convert mode to upper case + for (auto& c : args->mode) { + c = toupper(c); + } } -class mac_dummy : public thread +class mac_dummy : public srslte::thread { public: mac_dummy(rlc_interface_mac* rlc1_, @@ -154,7 +155,8 @@ public: stress_test_args_t args_, uint32_t lcid_, timer_handler* timers_, - rlc_pcap* pcap_ = NULL) : + rlc_pcap* pcap_, + uint32_t seed_) : run_enable(true), rlc1(rlc1_), rlc2(rlc2_), @@ -165,8 +167,7 @@ public: logger(srslog::fetch_basic_logger("MAC", false)), thread("MAC_DUMMY"), real_dist(0.0, 1.0), - mt19937(1234), - pool(byte_buffer_pool::get_instance()) + mt19937(seed_) { logger.set_level(static_cast(args.log_level)); logger.set_hex_dump_max_size(LOG_HEX_LIMIT); @@ -218,7 +219,7 @@ private: { // Sleep if necessary if (args.pdu_tx_delay_usec > 0) { - usleep(args.pdu_tx_delay_usec); + std::this_thread::sleep_for(std::chrono::microseconds(args.pdu_tx_delay_usec)); } auto it = pdu_list.begin(); // PDU iterator @@ -302,13 +303,13 @@ private: } } - rlc_interface_mac* rlc1; - rlc_interface_mac* rlc2; + rlc_interface_mac* rlc1 = nullptr; + rlc_interface_mac* rlc2 = nullptr; - bool run_enable; - stress_test_args_t args; - rlc_pcap* pcap; - uint32_t lcid; + bool run_enable = false; + stress_test_args_t args = {}; + rlc_pcap* pcap = nullptr; + uint32_t lcid = 0; srslog::basic_logger& logger; srslte::timer_handler* timers = nullptr; @@ -316,22 +317,24 @@ private: std::mt19937 mt19937; std::uniform_real_distribution real_dist; - byte_buffer_pool* pool = nullptr; }; -class rlc_tester : public pdcp_interface_rlc, public rrc_interface_rlc, public thread +class rlc_tester : public pdcp_interface_rlc, public rrc_interface_rlc, public srslte::thread { public: - rlc_tester(rlc_interface_pdcp* rlc_, std::string name_, stress_test_args_t args_, uint32_t lcid_) : - log("TEST"), - logger(srslog::fetch_basic_logger("TEST", false)), - rlc(rlc_), - run_enable(true), - rx_pdus(), + rlc_tester(rlc_interface_pdcp* rlc_pdcp_, + std::string name_, + stress_test_args_t args_, + uint32_t lcid_, + uint32_t seed_) : + logger(srslog::fetch_basic_logger(name_.c_str(), false)), + rlc_pdcp(rlc_pdcp_), name(name_), args(args_), lcid(lcid_), - thread("RLC_TESTER") + thread("RLC_TESTER"), + int_dist(MIN_SDU_SIZE, MAX_SDU_SIZE), + mt19937(seed_) { logger.set_level(srslog::basic_levels::error); logger.set_hex_dump_max_size(LOG_HEX_LIMIT); @@ -347,13 +350,26 @@ public: void write_pdu(uint32_t rx_lcid, unique_byte_buffer_t sdu) { assert(rx_lcid == lcid); - if (sdu->N_bytes != args.sdu_size) { - logger.error(sdu->msg, sdu->N_bytes, "Received SDU with size %d, expected %d.", sdu->N_bytes, args.sdu_size); - if (args.pedantic_sdu_check) { + if (args.mode != "AM") { + // Only AM will guarantee to deliver SDUs, take first byte as reference for other modes + next_expected_sdu = sdu->msg[0]; + } + + // check SDU content (consider faster alternative) + for (uint32_t i = 0; i < sdu->N_bytes; ++i) { + if (sdu->msg[i] != next_expected_sdu) { + logger.error(sdu->msg, + sdu->N_bytes, + "Received malformed SDU with size %d, expected data 0x%X", + sdu->N_bytes, + next_expected_sdu); + fprintf(stderr, "Received malformed SDU with size %d\n", sdu->N_bytes); + fprintf(stdout, "Received malformed SDU with size %d\n", sdu->N_bytes); + std::this_thread::sleep_for(std::chrono::seconds(1)); // give some time to flush logs exit(-1); } } - + next_expected_sdu += 1; rx_pdus++; } void write_pdu_bcch_bch(unique_byte_buffer_t sdu) {} @@ -364,48 +380,76 @@ public: void notify_failure(uint32_t lcid, const std::vector& pdcp_sns) {} // RRC interface - void max_retx_attempted() {} + void max_retx_attempted() + { + logger.error( + "Maximum number of RLC retransmission reached. Consider increasing threshold or lowering channel drop rate."); + std::this_thread::sleep_for(std::chrono::seconds(1)); + exit(1); + } std::string get_rb_name(uint32_t rx_lcid) { return std::string("DRB1"); } int get_nof_rx_pdus() { return rx_pdus; } private: - void run_thread() + const static size_t max_pdcp_sn = 262143u; // 18bit SN + void run_thread() { - uint32_t pdcp_sn = 0; - byte_buffer_pool* pool = byte_buffer_pool::get_instance(); + uint32_t pdcp_sn = 0; + uint32_t sdu_size = 0; + uint8_t payload = 0x0; // increment for each SDU while (run_enable) { + // SDU queue is full, don't assign PDCP SN + if (rlc_pdcp->sdu_queue_is_full(lcid)) { + continue; + } + unique_byte_buffer_t pdu = srslte::make_byte_buffer(); if (pdu == NULL) { printf("Error: Could not allocate PDU in rlc_tester::run_thread\n\n\n"); // backoff for a bit - usleep(1000); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); continue; } pdu->md.pdcp_sn = pdcp_sn; - for (uint32_t i = 0; i < args.sdu_size; i++) { - pdu->msg[i] = pdcp_sn & 0xFF; + + // random or fixed SDU size + if (args.sdu_size < 1) { + sdu_size = int_dist(mt19937); + } else { + sdu_size = args.sdu_size; } - pdcp_sn++; - pdu->N_bytes = args.sdu_size; - rlc->write_sdu(lcid, std::move(pdu)); + + for (uint32_t i = 0; i < sdu_size; i++) { + pdu->msg[i] = payload; + } + pdu->N_bytes = sdu_size; + payload++; + + rlc_pdcp->write_sdu(lcid, std::move(pdu)); + pdcp_sn = (pdcp_sn + 1) % max_pdcp_sn; if (args.sdu_gen_delay_usec > 0) { - usleep(args.sdu_gen_delay_usec); + std::this_thread::sleep_for(std::chrono::microseconds(args.sdu_gen_delay_usec)); } } } - bool run_enable; - uint64_t rx_pdus; - uint32_t lcid; + bool run_enable = true; + /// Tx uses thread-local PDCP SN to set SDU content, the Rx uses this variable to check received SDUs + uint8_t next_expected_sdu = 0; + uint64_t rx_pdus = 0; + uint32_t lcid = 0; srslte::log_filter log; srslog::basic_logger& logger; std::string name; - stress_test_args_t args; + stress_test_args_t args = {}; - rlc_interface_pdcp* rlc; + rlc_interface_pdcp* rlc_pdcp = nullptr; // used by run_thread to push PDCP SDUs to RLC + + std::mt19937 mt19937; + std::uniform_int_distribution<> int_dist; }; void stress_test(stress_test_args_t args) @@ -424,22 +468,11 @@ void stress_test(stress_test_args_t args) if (args.rat == "LTE") { if (args.mode == "AM") { // config RLC AM bearer - cnfg_.rlc_mode = rlc_mode_t::am; - cnfg_.am.max_retx_thresh = 4; - cnfg_.am.poll_byte = 25 * 1000; - cnfg_.am.poll_pdu = 4; - cnfg_.am.t_poll_retx = 5; - cnfg_.am.t_reordering = 5; - cnfg_.am.t_status_prohibit = 5; + cnfg_ = rlc_config_t::default_rlc_am_config(); + cnfg_.am.max_retx_thresh = args.max_retx; } else if (args.mode == "UM") { // config UM bearer - cnfg_.rlc_mode = rlc_mode_t::um; - cnfg_.um.t_reordering = 5; - cnfg_.um.rx_mod = 32; - cnfg_.um.rx_sn_field_length = rlc_umd_sn_size_t::size5bits; - cnfg_.um.rx_window_size = 16; - cnfg_.um.tx_sn_field_length = rlc_umd_sn_size_t::size5bits; - cnfg_.um.tx_mod = 32; + cnfg_ = rlc_config_t::default_rlc_um_config(); } else if (args.mode == "TM") { // use default LCID in TM lcid = 0; @@ -448,12 +481,9 @@ void stress_test(stress_test_args_t args) exit(-1); } -#if PCAP if (args.write_pcap) { pcap.open("rlc_stress_test.pcap", cnfg_); } -#endif - } else if (args.rat == "NR") { if (args.mode == "UM") { cnfg_ = rlc_config_t::default_rlc_um_nr_config(6); @@ -462,25 +492,30 @@ void stress_test(stress_test_args_t args) exit(-1); } -#if PCAP if (args.write_pcap) { - pcap_handle = std::unique_ptr(new srslte::mac_nr_pcap()); + pcap_handle = std::unique_ptr(new srslte::mac_pcap()); pcap_handle->open("rlc_stress_test_nr.pcap"); } -#endif } else { cout << "Unsupported RAT mode " << args.rat << ", exiting." << endl; exit(-1); } + // generate random seed if needed + uint32_t seed = 0; + if (not args.zero_seed) { + std::random_device rd; + seed = rd(); + } + srslte::timer_handler timers(8); rlc rlc1(log1.id().c_str()); rlc rlc2(log2.id().c_str()); - rlc_tester tester1(&rlc1, "tester1", args, lcid); - rlc_tester tester2(&rlc2, "tester2", args, lcid); - mac_dummy mac(&rlc1, &rlc2, args, lcid, &timers, &pcap); + rlc_tester tester1(&rlc1, "tester1", args, lcid, seed); + rlc_tester tester2(&rlc2, "tester2", args, lcid, seed); + mac_dummy mac(&rlc1, &rlc2, args, lcid, &timers, &pcap, seed); rlc1.init(&tester1, &tester1, &timers, 0); rlc2.init(&tester2, &tester2, &timers, 0); @@ -491,24 +526,16 @@ void stress_test(stress_test_args_t args) rlc2.add_bearer(lcid, cnfg_); } + printf("Starting test ..\n"); + tester1.start(7); if (!args.single_tx) { tester2.start(7); } mac.start(); - if (args.test_duration_sec < 1) { - args.test_duration_sec = 1; - } - - for (uint32_t i = 0; i < args.test_duration_sec; i++) { - // if enabled, mimic reestablishment every second - if (args.reestablish) { - rlc1.reestablish(); - rlc2.reestablish(); - } - usleep(1e6); - } + // wait until test is over + std::this_thread::sleep_for(std::chrono::seconds(args.test_duration_sec)); printf("Test finished, tearing down ..\n"); @@ -561,12 +588,6 @@ int main(int argc, char** argv) srslog::init(); - if (args.zero_seed) { - srand(0); - } else { - srand(time(NULL)); - } - stress_test(args); exit(0); diff --git a/lib/test/upper/rlc_test_common.h b/lib/test/upper/rlc_test_common.h index d4cb5367f..97d6dd530 100644 --- a/lib/test/upper/rlc_test_common.h +++ b/lib/test/upper/rlc_test_common.h @@ -22,7 +22,9 @@ #ifndef SRSLTE_RLC_TEST_COMMON_H #define SRSLTE_RLC_TEST_COMMON_H -#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/common/byte_buffer.h" +#include "srslte/interfaces/ue_pdcp_interfaces.h" +#include "srslte/interfaces/ue_rrc_interfaces.h" #include namespace srslte { diff --git a/lib/test/upper/rlc_um_nr_pdu_test.cc b/lib/test/upper/rlc_um_nr_pdu_test.cc index b9cae4150..9ee49b510 100644 --- a/lib/test/upper/rlc_um_nr_pdu_test.cc +++ b/lib/test/upper/rlc_um_nr_pdu_test.cc @@ -36,16 +36,16 @@ } \ } -#define PCAP 0 +#define PCAP 1 #define PCAP_CRNTI (0x1001) #define PCAP_TTI (666) using namespace srslte; #if PCAP -#include "srslte/common/mac_nr_pcap.h" -#include "srslte/mac/mac_nr_pdu.h" -static std::unique_ptr pcap_handle = nullptr; +#include "srslte/common/mac_pcap.h" +#include "srslte/mac/mac_sch_pdu_nr.h" +static std::unique_ptr pcap_handle = nullptr; #endif int write_pdu_to_pcap(const uint32_t lcid, const uint8_t* payload, const uint32_t len) @@ -53,11 +53,11 @@ int write_pdu_to_pcap(const uint32_t lcid, const uint8_t* payload, const uint32_ #if PCAP if (pcap_handle) { byte_buffer_t tx_buffer; - srslte::mac_nr_sch_pdu tx_pdu; + srslte::mac_sch_pdu_nr tx_pdu; tx_pdu.init_tx(&tx_buffer, len + 10); tx_pdu.add_sdu(lcid, payload, len); tx_pdu.pack(); - pcap_handle->write_dl_crnti(tx_buffer.msg, tx_buffer.N_bytes, PCAP_CRNTI, true, PCAP_TTI); + pcap_handle->write_dl_crnti_nr(tx_buffer.msg, tx_buffer.N_bytes, PCAP_CRNTI, true, PCAP_TTI); return SRSLTE_SUCCESS; } #endif @@ -204,10 +204,34 @@ int rlc_um_nr_pdu_unpack_test5() return SRSLTE_SUCCESS; } +// Unpack RLC UM 12bit SN PDU with PDCP and ICMP +int rlc_um_nr_pdu_unpack_test6() +{ + std::array tv = { + 0x00, 0x80, 0x00, 0x01, 0x45, 0x00, 0x00, 0x54, 0x34, 0xee, 0x40, 0x00, 0x40, 0x01, 0x80, 0x67, 0xc0, 0xa8, + 0x02, 0x01, 0xc0, 0xa8, 0x02, 0x02, 0x08, 0x00, 0xf0, 0x38, 0x56, 0x9b, 0x00, 0x02, 0x74, 0x40, 0x35, 0x60, + 0x00, 0x00, 0x00, 0x00, 0x3e, 0xb6, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37}; + srslte::byte_buffer_t pdu = make_pdu_and_log(tv); + + // unpack PDU + rlc_um_nr_pdu_header_t header = {}; + TESTASSERT(rlc_um_nr_read_data_pdu_header(&pdu, srslte::rlc_um_nr_sn_size_t::size12bits, &header) != 0); + + TESTASSERT(header.si == rlc_nr_si_field_t::full_sdu); + TESTASSERT(header.so == 0); + TESTASSERT(header.sn == 0); + + TESTASSERT(rlc_um_nr_packed_length(header) == 1); + + return SRSLTE_SUCCESS; +} + int main(int argc, char** argv) { #if PCAP - pcap_handle = std::unique_ptr(new srslte::mac_nr_pcap()); + pcap_handle = std::unique_ptr(new srslte::mac_pcap()); pcap_handle->open("rlc_um_nr_pdu_test.pcap"); #endif @@ -238,5 +262,14 @@ int main(int argc, char** argv) return SRSLTE_ERROR; } + if (rlc_um_nr_pdu_unpack_test6()) { + fprintf(stderr, "rlc_um_nr_pdu_unpack_test6() failed.\n"); + return SRSLTE_ERROR; + } + +#if PCAP + pcap_handle->close(); +#endif + return SRSLTE_SUCCESS; } diff --git a/lib/test/upper/rlc_um_nr_test.cc b/lib/test/upper/rlc_um_nr_test.cc index 7403fd489..52531f7f3 100644 --- a/lib/test/upper/rlc_um_nr_test.cc +++ b/lib/test/upper/rlc_um_nr_test.cc @@ -22,12 +22,12 @@ #include "rlc_test_common.h" #include "srslte/common/log_filter.h" #include "srslte/config.h" +#include "srslte/interfaces/ue_pdcp_interfaces.h" #include "srslte/upper/rlc.h" #include "srslte/upper/rlc_um_nr.h" #include #include -#include #include #define TESTASSERT(cond) \ @@ -188,7 +188,7 @@ int rlc_um_nr_test2(bool reverse_rx = false) // Read PDUs from RLC1 with grant of 25 Bytes each const uint32_t max_num_pdus = 10; - uint32 num_pdus = 0; + uint32_t num_pdus = 0; unique_byte_buffer_t pdu_bufs[max_num_pdus]; while (ctxt.rlc1.get_buffer_state() != 0 && num_pdus < max_num_pdus) { @@ -257,7 +257,7 @@ int rlc_um_nr_test4() // Read PDUs from RLC1 with grant of 25 Bytes each const uint32_t max_num_pdus = 20; - uint32 num_pdus = 0; + uint32_t num_pdus = 0; unique_byte_buffer_t pdu_bufs[max_num_pdus]; while (ctxt.rlc1.get_buffer_state() != 0 && num_pdus < max_num_pdus) { @@ -332,7 +332,7 @@ int rlc_um_nr_test5(const uint32_t last_sn) // Read PDUs from RLC1 with grant of 25 Bytes each const uint32_t max_num_pdus = 10; - uint32 num_pdus = 0; + uint32_t num_pdus = 0; unique_byte_buffer_t pdu_bufs[max_num_pdus]; while (ctxt.rlc1.get_buffer_state() != 0 && num_pdus < max_num_pdus) { @@ -399,7 +399,7 @@ int rlc_um_nr_test6() // Read PDUs from RLC1 with grant of 8 Bytes each const uint32_t max_num_pdus = num_sdus * 2; // we need 2 PDUs for each SDU - uint32 num_pdus = 0; + uint32_t num_pdus = 0; unique_byte_buffer_t pdu_bufs[max_num_pdus]; while (ctxt.rlc1.get_buffer_state() != 0 && num_pdus < max_num_pdus) { @@ -459,7 +459,7 @@ int rlc_um_nr_test7() // Read PDUs from RLC1 with grant of 8 Bytes each const uint32_t max_num_pdus = num_sdus * 2; // we need 2 PDUs for each SDU - uint32 num_pdus = 0; + uint32_t num_pdus = 0; unique_byte_buffer_t pdu_bufs[max_num_pdus]; while (ctxt.rlc1.get_buffer_state() != 0 && num_pdus < max_num_pdus) { @@ -523,7 +523,7 @@ int rlc_um_nr_test8() // Read PDUs from RLC1 with grant of 8 Bytes each const uint32_t max_num_pdus = 20 * 2; // we need 2 PDUs for each SDU - uint32 num_pdus = 0; + uint32_t num_pdus = 0; unique_byte_buffer_t pdu_bufs[max_num_pdus]; while (ctxt.rlc1.get_buffer_state() != 0 && num_pdus < max_num_pdus) { diff --git a/srsenb/enb.conf.example b/srsenb/enb.conf.example index c6098856e..7b700858f 100644 --- a/srsenb/enb.conf.example +++ b/srsenb/enb.conf.example @@ -83,11 +83,15 @@ rx_gain = 40 ##################################################################### # Packet capture configuration # -# MAC Packets are captured to file in the compact format decoded by -# the Wireshark mac-lte-framed dissector and with DLT 147. -# To use the dissector, edit the preferences for DLT_USER to -# add an entry with DLT=147, Payload Protocol=mac-lte-framed. +# MAC-layer packets are captured to file a the compact format decoded +# by the Wireshark. For decoding, use the UDP dissector and the UDP +# heuristic dissection. Edit the preferences (Edit > Preferences > +# Protocols > DLT_USER) for DLT_USER to add an entry for DLT=149 with +# Protocol=udp. Further, enable the heuristic dissection in UDP under: +# Analyze > Enabled Protocols > MAC-LTE > mac_lte_udp and MAC-NR > mac_nr_udp # For more information see: https://wiki.wireshark.org/MAC-LTE +# Configuring this Wireshark preferences is needed for decoding the MAC PCAP +# files as well as for the live network capture option. # # Please note that this setting will by default only capture MAC # frames on dedicated channels, and not SIB. You have to build with @@ -104,6 +108,11 @@ rx_gain = 40 # s1ap_enable: Enable or disable the PCAP. # s1ap_filename: File name where to save the PCAP. # +# mac_net_enable: Enable MAC layer packet captures sent over the network (true/false default: false) +# bind_ip: Bind IP address for MAC network trace (default: "0.0.0.0") +# bind_port: Bind port for MAC network trace (default: 5687) +# client_ip: Client IP address for MAC network trace (default "127.0.0.1") +# client_port Client IP address for MAC network trace (default: 5847) ##################################################################### [pcap] enable = false @@ -111,6 +120,12 @@ filename = /tmp/enb.pcap s1ap_enable = false s1ap_filename = /tmp/enb_s1ap.pcap +mac_net_enable = false +bind_ip = 0.0.0.0 +bind_port = 5687 +client_ip = 127.0.0.1 +client_port = 5847 + ##################################################################### # Log configuration # diff --git a/srsenb/hdr/enb.h b/srsenb/hdr/enb.h index 8840862f3..f4089a559 100644 --- a/srsenb/hdr/enb.h +++ b/srsenb/hdr/enb.h @@ -40,6 +40,7 @@ #include "srsenb/hdr/stack/enb_stack_base.h" #include "srsenb/hdr/stack/rrc/rrc_config.h" +#include "srslte/system/sys_metrics_processor.h" #include "srslte/common/bcd_helpers.h" #include "srslte/common/buffer_pool.h" #include "srslte/common/interfaces_common.h" @@ -159,6 +160,9 @@ private: std::unique_ptr radio = nullptr; std::unique_ptr phy = nullptr; + // System metrics processor. + srslte::sys_metrics_processor sys_proc; + srslte::LOG_LEVEL_ENUM level(std::string l); std::string get_build_mode(); diff --git a/srsenb/hdr/phy/lte/cc_worker.h b/srsenb/hdr/phy/lte/cc_worker.h index 19a2e5f4f..6af8769d9 100644 --- a/srsenb/hdr/phy/lte/cc_worker.h +++ b/srsenb/hdr/phy/lte/cc_worker.h @@ -46,7 +46,6 @@ public: int add_rnti(uint16_t rnti); void rem_rnti(uint16_t rnti); - int pregen_sequences(uint16_t rnti); uint32_t get_nof_rnti(); /* These are used by the GUI plotting tools */ diff --git a/srsenb/hdr/phy/lte/sf_worker.h b/srsenb/hdr/phy/lte/sf_worker.h index 9535967d5..8cc8ab5cf 100644 --- a/srsenb/hdr/phy/lte/sf_worker.h +++ b/srsenb/hdr/phy/lte/sf_worker.h @@ -45,7 +45,6 @@ public: int add_rnti(uint16_t rnti, uint32_t cc_idx); void rem_rnti(uint16_t rnti); - int pregen_sequences(uint16_t rnti); uint32_t get_nof_rnti(); /* These are used by the GUI plotting tools */ diff --git a/srsenb/hdr/phy/phy.h b/srsenb/hdr/phy/phy.h index 711f9de46..3bff23aa0 100644 --- a/srsenb/hdr/phy/phy.h +++ b/srsenb/hdr/phy/phy.h @@ -52,7 +52,6 @@ public: /* MAC->PHY interface */ void rem_rnti(uint16_t rnti) final; - int pregen_sequences(uint16_t rnti) override; void set_mch_period_stop(uint32_t stop) final; void set_activation_deactivation_scell(uint16_t rnti, const std::array& activation) override; diff --git a/srsenb/hdr/phy/phy_ue_db.h b/srsenb/hdr/phy/phy_ue_db.h index ce19aad8a..407eacad7 100644 --- a/srsenb/hdr/phy/phy_ue_db.h +++ b/srsenb/hdr/phy/phy_ue_db.h @@ -28,7 +28,6 @@ #include #include #include -#include namespace srsenb { diff --git a/srsenb/hdr/stack/enb_stack_base.h b/srsenb/hdr/stack/enb_stack_base.h index 7db3b69cf..271f840ce 100644 --- a/srsenb/hdr/stack/enb_stack_base.h +++ b/srsenb/hdr/stack/enb_stack_base.h @@ -35,6 +35,14 @@ typedef struct { std::string filename; } pcap_args_t; +typedef struct { + bool enable; + std::string client_ip; + std::string bind_ip; + uint16_t client_port; + uint16_t bind_port; +} pcap_net_args_t; + typedef struct { bool enable; std::string m1u_multiaddr; @@ -74,6 +82,7 @@ typedef struct { mac_args_t mac; s1ap_args_t s1ap; pcap_args_t mac_pcap; + pcap_net_args_t mac_pcap_net; pcap_args_t s1ap_pcap; stack_log_args_t log; embms_args_t embms; diff --git a/srsenb/hdr/stack/enb_stack_lte.h b/srsenb/hdr/stack/enb_stack_lte.h index 4fc8586f6..3649a68ba 100644 --- a/srsenb/hdr/stack/enb_stack_lte.h +++ b/srsenb/hdr/stack/enb_stack_lte.h @@ -36,6 +36,7 @@ #include "upper/s1ap.h" #include "enb_stack_base.h" +#include "srslte/common/mac_pcap_net.h" #include "srslte/interfaces/enb_interfaces.h" #include "srslte/srslog/srslog.h" @@ -134,6 +135,11 @@ private: srslog::basic_logger& gtpu_logger; srslog::basic_logger& stack_logger; + // PCAP and trace option + srslte::mac_pcap mac_pcap; + srslte::mac_pcap_net mac_pcap_net; + srslte::s1ap_pcap s1ap_pcap; + // task handling srslte::task_scheduler task_sched; srslte::task_queue_handle enb_task_queue, gtpu_task_queue, mme_task_queue, sync_task_queue; @@ -141,14 +147,12 @@ private: // components that layers depend on (need to be destroyed after layers) std::unique_ptr rx_sockets; - srsenb::mac mac; - srslte::mac_pcap mac_pcap; - srsenb::rlc rlc; - srsenb::pdcp pdcp; - srsenb::rrc rrc; - srsenb::gtpu gtpu; - srsenb::s1ap s1ap; - srslte::s1ap_pcap s1ap_pcap; + srsenb::mac mac; + srsenb::rlc rlc; + srsenb::pdcp pdcp; + srsenb::rrc rrc; + srsenb::gtpu gtpu; + srsenb::s1ap s1ap; srslte::logger* logger = nullptr; diff --git a/srsenb/hdr/stack/gnb_stack_nr.h b/srsenb/hdr/stack/gnb_stack_nr.h index d9e3ed5f9..6cccc98ce 100644 --- a/srsenb/hdr/stack/gnb_stack_nr.h +++ b/srsenb/hdr/stack/gnb_stack_nr.h @@ -54,7 +54,7 @@ class gnb_stack_nr final : public srsenb::enb_stack_base, public srslte::thread { public: - explicit gnb_stack_nr(srslte::logger* logger_); + explicit gnb_stack_nr(); ~gnb_stack_nr() final; int init(const srsenb::stack_args_t& args_, const rrc_nr_cfg_t& rrc_cfg_, phy_interface_stack_nr* phy_); @@ -87,9 +87,8 @@ private: void run_tti_impl(uint32_t tti); // args - srsenb::stack_args_t args = {}; - srslte::logger* logger = nullptr; - phy_interface_stack_nr* phy = nullptr; + srsenb::stack_args_t args = {}; + phy_interface_stack_nr* phy = nullptr; // task scheduling static const int STACK_MAIN_THREAD_PRIO = 4; diff --git a/srsenb/hdr/stack/mac/mac.h b/srsenb/hdr/stack/mac/mac.h index b155e35fc..57e6c6030 100644 --- a/srsenb/hdr/stack/mac/mac.h +++ b/srsenb/hdr/stack/mac/mac.h @@ -26,6 +26,7 @@ #include "srsenb/hdr/stack/mac/schedulers/sched_time_rr.h" #include "srslte/common/log.h" #include "srslte/common/mac_pcap.h" +#include "srslte/common/mac_pcap_net.h" #include "srslte/common/task_scheduler.h" #include "srslte/common/threads.h" #include "srslte/common/tti_sync_cv.h" @@ -54,6 +55,7 @@ public: void stop(); void start_pcap(srslte::mac_pcap* pcap_); + void start_pcap_net(srslte::mac_pcap_net* pcap_net_); /******** Interface from PHY (PHY -> MAC) ****************/ int sr_detected(uint32_t tti, uint16_t rnti) final; @@ -183,7 +185,8 @@ private: uint8_t mtch_payload_buffer[mtch_payload_len] = {}; // pointer to MAC PCAP object - srslte::mac_pcap* pcap = nullptr; + srslte::mac_pcap* pcap = nullptr; + srslte::mac_pcap_net* pcap_net = nullptr; // Number of rach preambles detected for a cc. std::vector detected_rachs; diff --git a/srsenb/hdr/stack/mac/sched_common.h b/srsenb/hdr/stack/mac/sched_common.h index b58a0cdb1..f953d4424 100644 --- a/srsenb/hdr/stack/mac/sched_common.h +++ b/srsenb/hdr/stack/mac/sched_common.h @@ -68,9 +68,10 @@ public: uint32_t get_dl_lb_nof_re(tti_point tti_tx_dl, uint32_t nof_prbs_alloc) const; uint32_t get_dl_nof_res(srslte::tti_point tti_tx_dl, const srslte_dci_dl_t& dci, uint32_t cfi) const; - uint32_t enb_cc_idx = 0; - sched_interface::cell_cfg_t cfg = {}; - const sched_interface::sched_args_t* sched_cfg = nullptr; + uint32_t enb_cc_idx = 0; + sched_interface::cell_cfg_t cfg = {}; + srslte_pucch_cfg_t pucch_cfg_common = {}; + const sched_interface::sched_args_t* sched_cfg = nullptr; std::unique_ptr regs; cce_sf_position_table common_locations = {}; cce_frame_position_table rar_locations = {}; diff --git a/srsenb/hdr/stack/mac/sched_grid.h b/srsenb/hdr/stack/mac/sched_grid.h index 095197f9f..f43506e01 100644 --- a/srsenb/hdr/stack/mac/sched_grid.h +++ b/srsenb/hdr/stack/mac/sched_grid.h @@ -111,10 +111,11 @@ public: void init(const sched_cell_params_t& cell_params_); void new_tti(tti_point tti_rx); dl_ctrl_alloc_t alloc_dl_ctrl(uint32_t aggr_lvl, alloc_type_t alloc_type); - alloc_outcome_t alloc_dl_data(sched_ue* user, const rbgmask_t& user_mask); + alloc_outcome_t alloc_dl_data(sched_ue* user, const rbgmask_t& user_mask, bool has_pusch_grant); bool reserve_dl_rbgs(uint32_t start_rbg, uint32_t end_rbg); alloc_outcome_t alloc_ul_data(sched_ue* user, prb_interval alloc, bool needs_pdcch); - bool reserve_ul_prbs(const prbmask_t& prbmask, bool strict); + alloc_outcome_t reserve_ul_prbs(const prbmask_t& prbmask, bool strict); + alloc_outcome_t reserve_ul_prbs(prb_interval alloc, bool strict); bool find_ul_alloc(uint32_t L, prb_interval* alloc) const; // getters @@ -122,15 +123,22 @@ public: const prbmask_t& get_ul_mask() const { return ul_mask; } uint32_t get_cfi() const { return pdcch_alloc.get_cfi(); } const sf_cch_allocator& get_pdcch_grid() const { return pdcch_alloc; } + uint32_t get_pucch_width() const { return pucch_nrb; } private: - alloc_outcome_t alloc_dl(uint32_t aggr_lvl, alloc_type_t alloc_type, rbgmask_t alloc_mask, sched_ue* user = nullptr); + alloc_outcome_t alloc_dl(uint32_t aggr_lvl, + alloc_type_t alloc_type, + rbgmask_t alloc_mask, + sched_ue* user = nullptr, + bool has_pusch_grant = false); // consts const sched_cell_params_t* cc_cfg = nullptr; srslog::basic_logger& logger; uint32_t nof_rbgs = 0; uint32_t si_n_rbg = 0, rar_n_rbg = 0; + uint32_t pucch_nrb = 0; + prbmask_t pucch_mask; // derived sf_cch_allocator pdcch_alloc = {}; @@ -175,7 +183,7 @@ public: uint32_t pid; }; struct ul_alloc_t { - enum type_t { NEWTX, NOADAPT_RETX, ADAPT_RETX, MSG3 }; + enum type_t { NEWTX, NOADAPT_RETX, ADAPT_RETX, MSG3, MSG3_RETX }; size_t dci_idx; type_t type; uint16_t rnti; @@ -252,7 +260,6 @@ private: const sched_cell_params_t* cc_cfg = nullptr; srslog::basic_logger& logger; sf_sched_result* cc_results; ///< Results of other CCs for the same Subframe - prbmask_t pucch_mask; // internal state sf_grid_t tti_alloc; diff --git a/srsenb/hdr/stack/mac/sched_phy_ch/sched_dci.h b/srsenb/hdr/stack/mac/sched_phy_ch/sched_dci.h new file mode 100644 index 000000000..e5aa7fa72 --- /dev/null +++ b/srsenb/hdr/stack/mac/sched_phy_ch/sched_dci.h @@ -0,0 +1,64 @@ +/** + * + * \section copyright + * + * copyright 2013-2020 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 SRSLTE_SCHED_DCI_H +#define SRSLTE_SCHED_DCI_H + +#include + +namespace srsenb { + +struct tbs_info { + int tbs_bytes = -1; + int mcs = 0; + tbs_info() = default; + tbs_info(int tbs_bytes_, int mcs_) : tbs_bytes(tbs_bytes_), mcs(mcs_) {} +}; +inline bool operator==(const tbs_info& lhs, const tbs_info& rhs) +{ + return lhs.mcs == rhs.mcs and lhs.tbs_bytes == rhs.tbs_bytes; +} +inline bool operator!=(const tbs_info& lhs, const tbs_info& rhs) +{ + return not(lhs == rhs); +} + +/** + * Compute MCS, TBS based on CQI, 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, + uint32_t cqi, + 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 + * \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_min_mcs_and_tbs_from_required_bytes(uint32_t nof_prb, + uint32_t nof_re, + uint32_t cqi, + uint32_t max_mcs, + uint32_t req_bytes, + bool is_ul, + bool ulqam64_enabled, + bool use_tbs_index_alt); + +} // namespace srsenb + +#endif // SRSLTE_SCHED_DCI_H diff --git a/srsenb/hdr/stack/mac/sched_phy_ch/sf_cch_allocator.h b/srsenb/hdr/stack/mac/sched_phy_ch/sf_cch_allocator.h index d745cee0e..1936b177f 100644 --- a/srsenb/hdr/stack/mac/sched_phy_ch/sf_cch_allocator.h +++ b/srsenb/hdr/stack/mac/sched_phy_ch/sf_cch_allocator.h @@ -34,10 +34,12 @@ class sf_cch_allocator public: const static uint32_t MAX_CFI = 3; struct alloc_t { + int8_t pucch_n_prb; ///< this PUCCH resource identifier uint16_t rnti = 0; srslte_dci_location_t dci_pos = {0, 0}; - pdcch_mask_t current_mask; ///< this PDCCH alloc mask - pdcch_mask_t total_mask; ///< Accumulation of all PDCCH masks for the current solution (tree route) + pdcch_mask_t current_mask; ///< this allocation PDCCH mask + pdcch_mask_t total_mask; ///< Accumulation of all PDCCH masks for the current solution (tree route) + prbmask_t total_pucch_mask; ///< Accumulation of all PUCCH masks for the current solution/tree route }; using alloc_result_t = std::vector; @@ -45,8 +47,15 @@ public: void init(const sched_cell_params_t& cell_params_); void new_tti(tti_point tti_rx_); - bool alloc_dci(alloc_type_t alloc_type, uint32_t aggr_idx, sched_ue* user = nullptr); - bool set_cfi(uint32_t cfi); + /** + * Allocates DCI space in PDCCH and PUCCH, avoiding in the process collisions with other users + * @param alloc_type allocation type (e.g. DL data, UL data, ctrl) + * @param aggr_idx Aggregation level index (0..3) + * @param user UE object or null in case of broadcast/RAR/paging allocation + * @param has_pusch_grant If the UE has already an PUSCH grant for UCI allocated + * @return if the allocation was successful + */ + bool alloc_dci(alloc_type_t alloc_type, uint32_t aggr_idx, sched_ue* user = nullptr, bool has_pusch_grant = false); // getters uint32_t get_cfi() const { return current_cfix + 1; } @@ -57,41 +66,52 @@ public: std::string result_to_string(bool verbose = false) const; private: + /// DCI allocation parameters + struct alloc_record_t { + sched_ue* user; + uint32_t aggr_idx; + alloc_type_t alloc_type; + bool pusch_uci; + }; + /// Tree-based data structure to store possible DCI allocation decisions struct alloc_tree_t { struct node_t { int parent_idx; alloc_t node; node_t(int i, const alloc_t& a) : parent_idx(i), node(a) {} }; + + // args + size_t nof_cces; + const sched_cell_params_t* cc_cfg = nullptr; + srslte_pucch_cfg_t* pucch_cfg = nullptr; + uint32_t cfi; // state - size_t nof_cces; std::vector dci_alloc_tree; size_t prev_start = 0, prev_end = 0; - explicit alloc_tree_t(size_t nof_cces_) : nof_cces(nof_cces_) {} - size_t nof_leaves() const { return prev_end - prev_start; } - void reset(); - }; - struct alloc_record_t { - sched_ue* user; - uint32_t aggr_idx; - alloc_type_t alloc_type; + explicit alloc_tree_t(uint32_t this_cfi, const sched_cell_params_t& cc_params, srslte_pucch_cfg_t& pucch_cfg); + size_t nof_leaves() const { return prev_end - prev_start; } + void reset(); + void get_allocs(alloc_result_t* vec, pdcch_mask_t* tot_mask, size_t idx) const; + bool add_tree_node_leaves(int node_idx, + const alloc_record_t& dci_record, + const cce_cfi_position_table& dci_locs, + tti_point tti_rx); + std::string result_to_string(bool verbose) const; }; const alloc_tree_t& get_alloc_tree() const { return alloc_trees[current_cfix]; } const cce_cfi_position_table* get_cce_loc_table(alloc_type_t alloc_type, sched_ue* user, uint32_t cfix) const; // PDCCH allocation algorithm - bool alloc_dci_record(const alloc_record_t& record, uint32_t cfix); - static bool add_tree_node_leaves(alloc_tree_t& tree, - int node_idx, - const alloc_record_t& dci_record, - const cce_cfi_position_table& dci_locs, - tti_point tti_tx_dl); + bool set_cfi(uint32_t cfi); + bool alloc_dci_record(const alloc_record_t& record, uint32_t cfix); // consts const sched_cell_params_t* cc_cfg = nullptr; srslog::basic_logger& logger; + srslte_pucch_cfg_t pucch_cfg_common = {}; // tti vars tti_point tti_rx; diff --git a/srsenb/hdr/stack/mac/sched_ue.h b/srsenb/hdr/stack/mac/sched_ue.h index a97c196d5..0747bf967 100644 --- a/srsenb/hdr/stack/mac/sched_ue.h +++ b/srsenb/hdr/stack/mac/sched_ue.h @@ -144,7 +144,6 @@ public: uint32_t get_max_retx(); - bool pucch_sr_collision(tti_point tti_tx_dl, uint32_t n_cce); 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; @@ -167,6 +166,12 @@ private: bool needs_cqi(uint32_t tti, uint32_t enb_cc_idx, bool will_send = false); + int generate_format1_common(uint32_t pid, + sched_interface::dl_sched_data_t* data, + tti_point tti_tx_dl, + uint32_t enb_cc_idx, + uint32_t cfi, + const rbgmask_t& user_mask); int generate_format1(uint32_t pid, sched_interface::dl_sched_data_t* data, tti_point tti_tx_dl, 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 5a27f8c37..c1e039f87 100644 --- a/srsenb/hdr/stack/mac/sched_ue_ctrl/sched_harq.h +++ b/srsenb/hdr/stack/mac/sched_ue_ctrl/sched_harq.h @@ -94,13 +94,14 @@ private: class ul_harq_proc : public harq_proc { public: - void new_tx(srslte::tti_point tti, int mcs, int tbs, prb_interval alloc, uint32_t max_retx_); + void new_tx(srslte::tti_point tti, int mcs, int tbs, prb_interval alloc, uint32_t max_retx_, bool is_msg3); void new_retx(srslte::tti_point tti_, int* mcs, int* tbs, prb_interval alloc); bool set_ack(uint32_t tb_idx, bool ack); bool retx_requires_pdcch(srslte::tti_point tti_, prb_interval alloc) const; prb_interval get_alloc() const; bool has_pending_retx() const; + bool is_msg3() const { return is_msg3_; } void reset_pending_data(); uint32_t get_pending_data() const; @@ -111,6 +112,7 @@ private: prb_interval allocation; int pending_data; bool pending_phich = false; + bool is_msg3_ = false; }; class harq_entity 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 35d849464..98c0acac9 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 @@ -24,17 +24,13 @@ #include "../sched_common.h" #include "sched_harq.h" +#include "srsenb/hdr/stack/mac/sched_phy_ch/sched_dci.h" #include "tpc.h" namespace srsenb { enum class cc_st { active, idle, activating, deactivating }; -struct tbs_info { - int tbs_bytes = -1; - int mcs = 0; -}; - struct sched_ue_cell { using ue_cc_cfg = sched_interface::ue_cfg_t::cc_cfg_t; const static int SCHED_MAX_HARQ_PROC = FDD_HARQ_DELAY_UL_MS + FDD_HARQ_DELAY_DL_MS; @@ -102,14 +98,18 @@ private: * TBS/MCS derivation ************************************************************/ -/// Compute TBS and MCS based on cell state and grant -tbs_info cqi_to_tbs(const sched_ue_cell& cell, uint32_t nof_prb, uint32_t nof_re, bool is_ul); - -tbs_info alloc_tbs_dl(const sched_ue_cell& cell, uint32_t nof_prb, uint32_t nof_re, uint32_t req_bytes); +tbs_info cqi_to_tbs_dl(const sched_ue_cell& cell, + uint32_t nof_prb, + uint32_t nof_re, + srslte_dci_format_t dci_format, + int req_bytes = -1); tbs_info -alloc_tbs_ul(const sched_ue_cell& cell, uint32_t nof_prb, uint32_t nof_re, uint32_t req_bytes, int explicit_mcs = -1); +cqi_to_tbs_ul(const sched_ue_cell& cell, uint32_t nof_prb, uint32_t nof_re, int req_bytes = -1, int explicit_mcs = -1); -int get_required_prb_dl(const sched_ue_cell& cell, tti_point tti_tx_dl, uint32_t req_bytes); +int get_required_prb_dl(const sched_ue_cell& cell, + tti_point tti_tx_dl, + srslte_dci_format_t dci_format, + uint32_t req_bytes); uint32_t get_required_prb_ul(const sched_ue_cell& cell, uint32_t req_bytes); } // namespace srsenb diff --git a/srsenb/hdr/stack/mac/ue.h b/srsenb/hdr/stack/mac/ue.h index f5be2f378..435233be4 100644 --- a/srsenb/hdr/stack/mac/ue.h +++ b/srsenb/hdr/stack/mac/ue.h @@ -27,6 +27,7 @@ #include "srslte/common/block_queue.h" #include "srslte/common/log.h" #include "srslte/common/mac_pcap.h" +#include "srslte/common/mac_pcap_net.h" #include "srslte/interfaces/sched_interface.h" #include "srslte/mac/pdu.h" #include "srslte/mac/pdu_queue.h" @@ -41,6 +42,48 @@ class rrc_interface_mac; class rlc_interface_mac; class phy_interface_stack_lte; +class cc_buffer_handler +{ +public: + // List of Tx softbuffers for all HARQ processes of one carrier + using cc_softbuffer_tx_list_t = std::vector; + // List of Rx softbuffers for all HARQ processes of one carrier + using cc_softbuffer_rx_list_t = std::vector; + + cc_buffer_handler(); + ~cc_buffer_handler(); + + void reset(); + void allocate_cc(uint32_t nof_prb, uint32_t nof_rx_harq_proc, uint32_t nof_tx_harq_proc); + void deallocate_cc(); + + bool empty() const { return softbuffer_tx_list.empty() and softbuffer_rx_list.empty(); } + srslte_softbuffer_tx_t& get_tx_softbuffer(uint32_t pid, uint32_t tb_idx) + { + return softbuffer_tx_list.at(pid * SRSLTE_MAX_TB + tb_idx); + } + srslte_softbuffer_rx_t& get_rx_softbuffer(uint32_t tti) { return softbuffer_rx_list.at(tti % nof_rx_harq_proc); } + srslte::byte_buffer_t* get_tx_payload_buffer(size_t harq_pid, size_t tb) + { + return tx_payload_buffer[harq_pid][tb].get(); + } + std::map& get_rx_used_buffers() { return rx_used_buffers; } + +private: + // args + uint32_t nof_prb; + uint32_t nof_rx_harq_proc; + uint32_t nof_tx_harq_proc; + + // buffers + cc_softbuffer_tx_list_t softbuffer_tx_list; ///< List of softbuffer lists for Tx + cc_softbuffer_rx_list_t softbuffer_rx_list; ///< List of softbuffer lists for Rx + std::map rx_used_buffers; + + // One buffer per TB per HARQ process and per carrier is needed for each UE. + std::array, SRSLTE_FDD_NOF_HARQ> tx_payload_buffer; +}; + class ue : public srslte::read_pdu_interface, public srslte::pdu_queue::process_callback, public mac_ta_ue_interface { public: @@ -54,30 +97,25 @@ public: srslog::basic_logger& logger, uint32_t nof_cells_, uint32_t nof_rx_harq_proc = SRSLTE_FDD_NOF_HARQ, - uint32_t nof_tx_harq_proc = SRSLTE_FDD_NOF_HARQ * SRSLTE_MAX_TB); + uint32_t nof_tx_harq_proc = SRSLTE_FDD_NOF_HARQ); + virtual ~ue(); - - void reset(); - - void start_pcap(srslte::mac_pcap* pcap_); - - void set_tti(uint32_t tti); - + void reset(); + void start_pcap(srslte::mac_pcap* pcap_); + void start_pcap_net(srslte::mac_pcap_net* pcap_net_); + void set_tti(uint32_t tti); uint16_t get_rnti() { 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); }; + void tic(); - void tic(); - - uint8_t* generate_pdu(uint32_t ue_cc_idx, - uint32_t harq_pid, - uint32_t tb_idx, - sched_interface::dl_sched_pdu_t pdu[sched_interface::MAX_RLC_PDU_LIST], - uint32_t nof_pdu_elems, - uint32_t grant_size); + uint8_t* generate_pdu(uint32_t ue_cc_idx, + uint32_t harq_pid, + uint32_t tb_idx, + const sched_interface::dl_sched_pdu_t pdu[sched_interface::MAX_RLC_PDU_LIST], + uint32_t nof_pdu_elems, + uint32_t grant_size); 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); @@ -101,12 +139,9 @@ public: void metrics_dl_cqi(uint32_t dl_cqi); void metrics_cnt(); - bool is_phy_added = false; - int read_pdu(uint32_t lcid, uint8_t* payload, uint32_t requested_bytes) final; + int read_pdu(uint32_t lcid, uint8_t* payload, uint32_t requested_bytes) final; private: - uint32_t allocate_cc_buffers(const uint32_t num_cc = 1); ///< Add and initialize softbuffers for CC - void allocate_sdu(srslte::sch_pdu* pdu, uint32_t lcid, uint32_t sdu_len); bool process_ce(srslte::sch_subh* subh); void allocate_ce(srslte::sch_pdu* pdu, uint32_t lcid); @@ -117,29 +152,19 @@ private: uint32_t dl_pmi_counter = 0; mac_ue_metrics_t ue_metrics = {}; - srslte::mac_pcap* pcap = nullptr; - uint64_t conres_id = 0; - uint16_t rnti = 0; - uint32_t nof_prb = 0; - uint32_t last_tti = 0; - uint32_t nof_failures = 0; - int nof_rx_harq_proc = 0; - int nof_tx_harq_proc = 0; + srslte::mac_pcap* pcap = nullptr; + srslte::mac_pcap_net* pcap_net = nullptr; + uint64_t conres_id = 0; + uint16_t rnti = 0; + uint32_t nof_prb = 0; + uint32_t last_tti = 0; + uint32_t nof_failures = 0; + int nof_rx_harq_proc = 0; + int nof_tx_harq_proc = 0; - typedef std::vector - cc_softbuffer_tx_list_t; ///< List of Tx softbuffers for all HARQ processes of one carrier - std::vector softbuffer_tx; ///< List of softbuffer lists for Tx + std::vector cc_buffers; - typedef std::vector - cc_softbuffer_rx_list_t; ///< List of Rx softbuffers for all HARQ processes of one carrier - std::vector softbuffer_rx; ///< List of softbuffer lists for Rx - - // One buffer per TB per HARQ process and per carrier is needed for each UE. - std::vector, SRSLTE_FDD_NOF_HARQ> > - tx_payload_buffer; - - std::mutex rx_buffers_mutex; - std::vector > rx_used_buffers; + std::mutex rx_buffers_mutex; srslte::block_queue pending_ta_commands; ta ta_fsm; diff --git a/srsenb/hdr/stack/rrc/mac_controller.h b/srsenb/hdr/stack/rrc/mac_controller.h index 6e8104bc6..5f1fd81a0 100644 --- a/srsenb/hdr/stack/rrc/mac_controller.h +++ b/srsenb/hdr/stack/rrc/mac_controller.h @@ -65,6 +65,7 @@ public: void handle_ho_prep(const asn1::rrc::ho_prep_info_r8_ies_s& ho_prep); const ue_cfg_t& get_ue_sched_cfg() const { return current_sched_ue_cfg; } + bool is_crnti_set() const { return crnti_set; } void set_scell_activation(const std::bitset& scell_mask); void set_drb_activation(bool active); diff --git a/srsenb/hdr/stack/rrc/rrc.h b/srsenb/hdr/stack/rrc/rrc.h index ea8f92adc..5a46ad861 100644 --- a/srsenb/hdr/stack/rrc/rrc.h +++ b/srsenb/hdr/stack/rrc/rrc.h @@ -180,6 +180,7 @@ private: void config_mac(); void parse_ul_dcch(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t pdu); void parse_ul_ccch(uint16_t rnti, srslte::unique_byte_buffer_t pdu); + void send_rrc_connection_reject(uint16_t rnti); uint32_t paging_tti = INVALID_TTI; srslte::byte_buffer_t byte_buf_paging; @@ -196,6 +197,7 @@ private: const static uint32_t LCID_REM_USER = 0xffff0001; const static uint32_t LCID_REL_USER = 0xffff0002; const static uint32_t LCID_ACT_USER = 0xffff0004; + const static uint32_t LCID_RTX_USER = 0xffff0005; bool running = false; srslte::block_queue rx_pdu_queue; diff --git a/srsenb/hdr/stack/rrc/rrc_bearer_cfg.h b/srsenb/hdr/stack/rrc/rrc_bearer_cfg.h index 1099bea1f..b27c4ec97 100644 --- a/srsenb/hdr/stack/rrc/rrc_bearer_cfg.h +++ b/srsenb/hdr/stack/rrc/rrc_bearer_cfg.h @@ -116,7 +116,7 @@ public: std::map erabs; private: - srslog::basic_logger& logger; + srslog::basic_logger* logger; uint16_t rnti = 0; const rrc_cfg_t* cfg = nullptr; gtpu_interface_rrc* gtpu = nullptr; diff --git a/srsenb/hdr/stack/rrc/rrc_nr.h b/srsenb/hdr/stack/rrc/rrc_nr.h index 0a7448620..203100e25 100644 --- a/srsenb/hdr/stack/rrc/rrc_nr.h +++ b/srsenb/hdr/stack/rrc/rrc_nr.h @@ -30,6 +30,7 @@ #include "srslte/common/buffer_pool.h" #include "srslte/common/common.h" #include "srslte/common/logmap.h" +#include "srslte/common/task_scheduler.h" #include "srslte/common/threads.h" #include "srslte/common/timeout.h" #include "srslte/interfaces/gnb_interfaces.h" diff --git a/srsenb/hdr/stack/rrc/rrc_ue.h b/srsenb/hdr/stack/rrc/rrc_ue.h index 3ad2a1a09..2a82e0366 100644 --- a/srsenb/hdr/stack/rrc/rrc_ue.h +++ b/srsenb/hdr/stack/rrc/rrc_ue.h @@ -41,14 +41,16 @@ public: 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 + 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) + UE_REESTABLISH_TIMEOUT, ///< Maximum timeout in which UE reestablishment is expected 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 activity_timer_expired(); + void max_retx_reached(); rrc_state_t get_state(); void get_metrics(rrc_ue_metrics_t& ue_metrics) const; @@ -105,6 +107,7 @@ public: int get_cqi(uint16_t* pmi_idx, uint16_t* n_pucch, uint32_t ue_cc_idx); int get_ri(uint32_t m_ri, uint16_t* ri_idx); bool is_allocated() const; + bool is_crnti_set() const { return mac_ctrl.is_crnti_set(); } void send_dl_ccch(asn1::rrc::dl_ccch_msg_s* dl_ccch_msg); bool send_dl_dcch(const asn1::rrc::dl_dcch_msg_s* dl_dcch_msg, diff --git a/srsenb/hdr/stack/upper/gtpu.h b/srsenb/hdr/stack/upper/gtpu.h index bae7f12da..b29e29a56 100644 --- a/srsenb/hdr/stack/upper/gtpu.h +++ b/srsenb/hdr/stack/upper/gtpu.h @@ -27,8 +27,10 @@ #include "srslte/common/logmap.h" #include "srslte/common/threads.h" #include "srslte/interfaces/enb_gtpu_interfaces.h" +#include "srslte/phy/common/phy_common.h" #include "srslte/srslog/srslog.h" -#include "srslte/srslte.h" + +#include #ifndef SRSENB_GTPU_H #define SRSENB_GTPU_H diff --git a/srsenb/hdr/stack/upper/pdcp.h b/srsenb/hdr/stack/upper/pdcp.h index 55fcda413..3635cdd8d 100644 --- a/srsenb/hdr/stack/upper/pdcp.h +++ b/srsenb/hdr/stack/upper/pdcp.h @@ -22,7 +22,8 @@ #include "srslte/common/timers.h" #include "srslte/interfaces/enb_metrics_interface.h" #include "srslte/interfaces/enb_pdcp_interfaces.h" -#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/interfaces/ue_gw_interfaces.h" +#include "srslte/interfaces/ue_rlc_interfaces.h" #include "srslte/srslog/srslog.h" #include "srslte/upper/pdcp.h" #include diff --git a/srsenb/hdr/stack/upper/pdcp_nr.h b/srsenb/hdr/stack/upper/pdcp_nr.h index 4a03c959e..523493fd9 100644 --- a/srsenb/hdr/stack/upper/pdcp_nr.h +++ b/srsenb/hdr/stack/upper/pdcp_nr.h @@ -23,6 +23,8 @@ #include "srslte/common/log_filter.h" #include "srslte/common/logger.h" #include "srslte/interfaces/gnb_interfaces.h" +#include "srslte/interfaces/ue_gw_interfaces.h" +#include "srslte/interfaces/ue_rlc_interfaces.h" #include "srslte/upper/pdcp.h" #include diff --git a/srsenb/hdr/stack/upper/sdap.h b/srsenb/hdr/stack/upper/sdap.h index 3e8b09967..8e4c89332 100644 --- a/srsenb/hdr/stack/upper/sdap.h +++ b/srsenb/hdr/stack/upper/sdap.h @@ -26,7 +26,7 @@ #include "srslte/common/common.h" #include "srslte/common/logmap.h" #include "srslte/interfaces/gnb_interfaces.h" -#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/interfaces/ue_gw_interfaces.h" namespace srsenb { diff --git a/srsenb/rr.conf.example b/srsenb/rr.conf.example index 944cb033f..a78d5e11b 100644 --- a/srsenb/rr.conf.example +++ b/srsenb/rr.conf.example @@ -37,7 +37,7 @@ phy_cnfg = dsr_trans_max = 64; period = 20; // in ms //subframe = [1, 11]; // Optional vector of subframe indices allowed for SR transmissions (default uses all) - nof_prb = 2; // number of PRBs on each extreme used for SR (total prb is twice this number) + nof_prb = 1; // number of PRBs on each extreme used for SR (total prb is twice this number) }; cqi_report_cnfg = { @@ -45,7 +45,7 @@ phy_cnfg = simultaneousAckCQI = true; period = 40; // in ms //subframe = [0, 10, 20, 30]; // Optional vector of subframe indices every period where CQI resources will be allocated (default uses all) - nof_prb = 2; + nof_prb = 1; m_ri = 8; // RI period in CQI period }; }; diff --git a/srsenb/sib.conf.example b/srsenb/sib.conf.example index 52f5a348a..0d4e60aa4 100644 --- a/srsenb/sib.conf.example +++ b/srsenb/sib.conf.example @@ -47,7 +47,7 @@ sib2 = { high_speed_flag = false; prach_config_index = 3; - prach_freq_offset = 2; + prach_freq_offset = 4; zero_correlation_zone_config = 5; }; }; @@ -74,8 +74,8 @@ sib2 = }; pucch_cnfg = { - delta_pucch_shift = 2; - n_rb_cqi = 2; + delta_pucch_shift = 1; + n_rb_cqi = 1; n_cs_an = 0; n1_pucch_an = 12; }; diff --git a/srsenb/src/CMakeLists.txt b/srsenb/src/CMakeLists.txt index d8c7b24a7..8db2e9fe8 100644 --- a/srsenb/src/CMakeLists.txt +++ b/srsenb/src/CMakeLists.txt @@ -37,8 +37,8 @@ target_link_libraries(enb_cfg_parser ${LIBCONFIGPP_LIBRARIES}) add_executable(srsenb main.cc enb.cc metrics_stdout.cc metrics_csv.cc metrics_json.cc) -set(SRSENB_SOURCES srsenb_phy srsenb_stack srsenb_upper srsenb_mac srsenb_rrc srslog) -set(SRSLTE_SOURCES srslte_common srslte_mac srslte_phy srslte_upper srslte_radio rrc_asn1 s1ap_asn1 enb_cfg_parser srslog) +set(SRSENB_SOURCES srsenb_phy srsenb_stack srsenb_upper srsenb_mac srsenb_rrc srslog system) +set(SRSLTE_SOURCES srslte_common srslte_mac srslte_phy srslte_upper srslte_radio rrc_asn1 s1ap_asn1 enb_cfg_parser srslog system) set(SRSENB_SOURCES ${SRSENB_SOURCES} srsgnb_phy srsgnb_stack srsgnb_upper srsgnb_mac srsgnb_rrc) set(SRSLTE_SOURCES ${SRSLTE_SOURCES} rrc_nr_asn1 ngap_nr_asn1) diff --git a/srsenb/src/enb.cc b/srsenb/src/enb.cc index 879ddd407..0280e1c34 100644 --- a/srsenb/src/enb.cc +++ b/srsenb/src/enb.cc @@ -108,7 +108,7 @@ int enb::init(const all_args_t& args_, srslte::logger* logger_) radio = std::move(lte_radio); } else if (args.stack.type == "nr") { - std::unique_ptr nr_stack(new srsenb::gnb_stack_nr(logger)); + std::unique_ptr nr_stack(new srsenb::gnb_stack_nr); std::unique_ptr nr_radio(new srslte::radio_null); std::unique_ptr nr_phy(new srsenb::vnf_phy_nr); @@ -209,6 +209,7 @@ bool enb::get_metrics(enb_metrics_t* m) phy->get_metrics(m->phy); stack->get_metrics(&m->stack); m->running = started; + m->sys = sys_proc.get_metrics(); return true; } diff --git a/srsenb/src/enb_cfg_parser.cc b/srsenb/src/enb_cfg_parser.cc index 9a4bee553..e6a731b91 100644 --- a/srsenb/src/enb_cfg_parser.cc +++ b/srsenb/src/enb_cfg_parser.cc @@ -20,12 +20,10 @@ */ #include "enb_cfg_parser.h" -#include "srsenb/hdr/cfg_parser.h" #include "srsenb/hdr/enb.h" #include "srslte/asn1/rrc_utils.h" #include "srslte/common/multiqueue.h" #include "srslte/phy/common/phy_common.h" -#include "srslte/srslte.h" #include #define HANDLEPARSERCODE(cond) \ @@ -1114,16 +1112,6 @@ int set_derived_args(all_args_t* args_, rrc_cfg_t* rrc_cfg_, phy_cfg_t* phy_cfg_ rrc_cfg_->sibs[1].sib2().rr_cfg_common.prach_cfg.prach_cfg_info.prach_freq_offset = 0; phy_cfg_->prach_cnfg.prach_cfg_info.prach_freq_offset = 0; } - if (nrb_pucch > 1) { - fprintf(stderr, - "ERROR: Invalid PUCCH configuration - \"cqi_report_cnfg=%d\" and \"sched_request_cnfg.nof_prb=%d\"" - " in rr.conf for 6 PRBs.\n Consider decreasing these values to 1 to leave enough space for the " - "transmission of Msg3.\n", - rrc_cfg_->cqi_cfg.nof_prb, - rrc_cfg_->sr_cfg.nof_prb); - rrc_cfg_->cqi_cfg.nof_prb = 1; - rrc_cfg_->sr_cfg.nof_prb = 1; - } } // Patch certain args that are not exposed yet diff --git a/srsenb/src/main.cc b/srsenb/src/main.cc index 1ab6dd31d..e09e35e6f 100644 --- a/srsenb/src/main.cc +++ b/srsenb/src/main.cc @@ -29,6 +29,7 @@ #include "srslte/common/config_file.h" #include "srslte/common/crash_handler.h" #include "srslte/common/logger_srslog_wrapper.h" +#include "srslte/common/logmap.h" #include "srslte/common/signal_handler.h" #include "srslte/srslog/srslog.h" @@ -139,6 +140,11 @@ void parse_args(all_args_t* args, int argc, char* argv[]) ("pcap.filename", bpo::value(&args->stack.mac_pcap.filename)->default_value("enb_mac.pcap"), "MAC layer capture filename") ("pcap.s1ap_enable", bpo::value(&args->stack.s1ap_pcap.enable)->default_value(false), "Enable S1AP packet captures for wireshark") ("pcap.s1ap_filename", bpo::value(&args->stack.s1ap_pcap.filename)->default_value("enb_s1ap.pcap"), "S1AP layer capture filename") + ("pcap.mac_net_enable", bpo::value(&args->stack.mac_pcap_net.enable)->default_value(false), "Enable MAC network captures") + ("pcap.bind_ip", bpo::value(&args->stack.mac_pcap_net.bind_ip)->default_value("0.0.0.0"), "Bind IP address for MAC network trace") + ("pcap.bind_port", bpo::value(&args->stack.mac_pcap_net.bind_port)->default_value(5687), "Bind port for MAC network trace") + ("pcap.client_ip", bpo::value(&args->stack.mac_pcap_net.client_ip)->default_value("127.0.0.1"), "Client IP address for MAC network trace") + ("pcap.client_port", bpo::value(&args->stack.mac_pcap_net.client_port)->default_value(5847), "Enable MAC network captures") /* Scheduling section */ ("scheduler.policy", bpo::value(&args->stack.mac.sched.sched_policy)->default_value("time_pf"), "DL and UL data scheduling policy (E.g. time_rr, time_pf)") @@ -150,6 +156,8 @@ void parse_args(all_args_t* args, int argc, char* argv[]) ("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.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") + /* Downlink Channel emulator section */ ("channel.dl.enable", bpo::value(&args->phy.dl_channel_args.enable)->default_value(false), "Enable/Disable internal Downlink channel emulator") diff --git a/srsenb/src/metrics_csv.cc b/srsenb/src/metrics_csv.cc index 4ef163c1a..87376a5c5 100644 --- a/srsenb/src/metrics_csv.cc +++ b/srsenb/src/metrics_csv.cc @@ -64,7 +64,8 @@ void metrics_csv::set_metrics(const enb_metrics_t& metrics, const uint32_t perio { if (file.is_open() && enb != NULL) { if (n_reports == 0) { - file << "time;nof_ue;dl_brate;ul_brate\n"; + file << "time;nof_ue;dl_brate;ul_brate;" + "proc_rmem;proc_rmem_kB;proc_vmem;proc_vmem_kB;sys_mem;proc_cpu;thread_count\n"; } // Time @@ -89,11 +90,21 @@ void metrics_csv::set_metrics(const enb_metrics_t& metrics, const uint32_t perio // UL rate if (ul_rate_sum > 0) { - file << float_to_string(SRSLTE_MAX(0.1, (float)ul_rate_sum), 2, false); + file << float_to_string(SRSLTE_MAX(0.1, (float)ul_rate_sum), 2); } else { - file << float_to_string(0, 2, false); + file << float_to_string(0, 2); } + // Write system metrics. + const srslte::sys_metrics_t& m = metrics.sys; + file << float_to_string(m.process_realmem, 2); + file << std::to_string(m.process_realmem_kB) << ";"; + file << float_to_string(m.process_virtualmem, 2); + file << std::to_string(m.process_virtualmem_kB) << ";"; + file << float_to_string(m.system_mem, 2); + file << float_to_string(m.process_cpu_usage, 2); + file << std::to_string(m.thread_count); + file << "\n"; n_reports++; diff --git a/srsenb/src/phy/CMakeLists.txt b/srsenb/src/phy/CMakeLists.txt index f7191a81b..05da4a8ff 100644 --- a/srsenb/src/phy/CMakeLists.txt +++ b/srsenb/src/phy/CMakeLists.txt @@ -36,4 +36,4 @@ add_library(srsgnb_phy STATIC vnf_phy_nr.cc) if(ENABLE_GUI AND SRSGUI_FOUND) target_link_libraries(srsenb_phy ${SRSGUI_LIBRARIES}) -endif(ENABLE_GUI AND SRSGUI_FOUND) +endif() diff --git a/srsenb/src/phy/lte/cc_worker.cc b/srsenb/src/phy/lte/cc_worker.cc index 95acb0f5b..2a9820d55 100644 --- a/srsenb/src/phy/lte/cc_worker.cc +++ b/srsenb/src/phy/lte/cc_worker.cc @@ -180,17 +180,6 @@ void cc_worker::set_tti(uint32_t tti_) tti_tx_ul = TTI_RX_ACK(tti_rx); } -int cc_worker::pregen_sequences(uint16_t rnti) -{ - if (srslte_enb_dl_add_rnti(&enb_dl, rnti)) { - return -1; - } - if (srslte_enb_ul_add_rnti(&enb_ul, rnti)) { - return -1; - } - return SRSLTE_SUCCESS; -} - int cc_worker::add_rnti(uint16_t rnti) { std::unique_lock lock(mutex); @@ -208,11 +197,9 @@ 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); } - - // Always try to remove from PHY-lib - srslte_enb_dl_rem_rnti(&enb_dl, rnti); - srslte_enb_ul_rem_rnti(&enb_ul, rnti); } uint32_t cc_worker::get_nof_rnti() @@ -542,7 +529,6 @@ int cc_worker::encode_pmch(stack_interface_phy_lte::dl_sched_grant_t* grant, srs int cc_worker::encode_pdsch(stack_interface_phy_lte::dl_sched_grant_t* grants, uint32_t nof_grants) { - /* Scales the Resources Elements affected by the power allocation (p_b) */ // srslte_enb_dl_prepare_power_allocation(&enb_dl); for (uint32_t i = 0; i < nof_grants; i++) { diff --git a/srsenb/src/phy/lte/sf_worker.cc b/srsenb/src/phy/lte/sf_worker.cc index 71db441ab..9226c2704 100644 --- a/srsenb/src/phy/lte/sf_worker.cc +++ b/srsenb/src/phy/lte/sf_worker.cc @@ -129,16 +129,6 @@ void sf_worker::set_time(uint32_t tti_, uint32_t tx_worker_cnt_, const srslte::r } } -int sf_worker::pregen_sequences(uint16_t rnti) -{ - for (auto& w : cc_workers) { - if (w->pregen_sequences(rnti)) { - return SRSLTE_ERROR; - } - } - return SRSLTE_SUCCESS; -} - int sf_worker::add_rnti(uint16_t rnti, uint32_t cc_idx) { int ret = SRSLTE_ERROR; @@ -440,7 +430,6 @@ void* plot_thread_run(void* arg) void init_plots(srsenb::lte::sf_worker* worker) { - if (sem_init(&plot_sem, 0, 0)) { perror("sem_init"); exit(-1); diff --git a/srsenb/src/phy/phy.cc b/srsenb/src/phy/phy.cc index 0aa025a62..4d7f25c38 100644 --- a/srsenb/src/phy/phy.cc +++ b/srsenb/src/phy/phy.cc @@ -184,16 +184,6 @@ void phy::rem_rnti(uint16_t rnti) } } -int phy::pregen_sequences(uint16_t rnti) -{ - for (uint32_t i = 0; i < nof_workers; i++) { - if (lte_workers[i]->pregen_sequences(rnti) != SRSLTE_SUCCESS) { - return SRSLTE_ERROR; - } - } - return SRSLTE_SUCCESS; -} - void phy::set_mch_period_stop(uint32_t stop) { workers_common.set_mch_period_stop(stop); diff --git a/srsenb/src/stack/enb_stack_lte.cc b/srsenb/src/stack/enb_stack_lte.cc index 4357a548b..097eaf30d 100644 --- a/srsenb/src/stack/enb_stack_lte.cc +++ b/srsenb/src/stack/enb_stack_lte.cc @@ -22,8 +22,7 @@ #include "srsenb/hdr/stack/enb_stack_lte.h" #include "srsenb/hdr/enb.h" #include "srslte/common/network_utils.h" -#include "srslte/srslte.h" -#include +#include "srslte/interfaces/enb_metrics_interface.h" using namespace srslte; @@ -38,7 +37,7 @@ enb_stack_lte::enb_stack_lte(srslte::logger* logger_, srslog::sink& log_sink) : s1ap_logger(srslog::fetch_basic_logger("S1AP", log_sink, false)), gtpu_logger(srslog::fetch_basic_logger("GTPU", log_sink, false)), stack_logger(srslog::fetch_basic_logger("STCK", log_sink, false)), - task_sched(512, 0, 128), + task_sched(512, 128), pdcp(&task_sched, pdcp_logger), mac(&task_sched, mac_logger), rlc(rlc_logger), @@ -46,8 +45,9 @@ enb_stack_lte::enb_stack_lte(srslte::logger* logger_, srslog::sink& log_sink) : s1ap(&task_sched, s1ap_logger), rrc(&task_sched), logger(logger_), - mac_pcap(srslte_rat_t::lte) + mac_pcap() { + get_background_workers().set_nof_workers(2); enb_task_queue = task_sched.make_task_queue(); mme_task_queue = task_sched.make_task_queue(); gtpu_task_queue = task_sched.make_task_queue(); @@ -118,6 +118,15 @@ int enb_stack_lte::init(const stack_args_t& args_, const rrc_cfg_t& rrc_cfg_) mac_pcap.open(args.mac_pcap.filename.c_str()); mac.start_pcap(&mac_pcap); } + + if (args.mac_pcap_net.enable) { + mac_pcap_net.open(args.mac_pcap_net.client_ip, + args.mac_pcap_net.bind_ip, + args.mac_pcap_net.client_port, + args.mac_pcap_net.bind_port); + mac.start_pcap_net(&mac_pcap_net); + } + if (args.s1ap_pcap.enable) { s1ap_pcap.open(args.s1ap_pcap.filename.c_str()); s1ap.start_pcap(&s1ap_pcap); @@ -191,11 +200,17 @@ void enb_stack_lte::stop_impl() if (args.mac_pcap.enable) { mac_pcap.close(); } + + if (args.mac_pcap_net.enable) { + mac_pcap_net.close(); + } + if (args.s1ap_pcap.enable) { s1ap_pcap.close(); } task_sched.stop(); + get_background_workers().stop(); started = false; } diff --git a/srsenb/src/stack/gnb_stack_nr.cc b/srsenb/src/stack/gnb_stack_nr.cc index aeac6f5ec..173562a1f 100644 --- a/srsenb/src/stack/gnb_stack_nr.cc +++ b/srsenb/src/stack/gnb_stack_nr.cc @@ -25,7 +25,7 @@ namespace srsenb { -gnb_stack_nr::gnb_stack_nr(srslte::logger* logger_) : logger(logger_), task_sched{512, 1, 128}, thread("gNB") +gnb_stack_nr::gnb_stack_nr() : task_sched{512, 128}, thread("gNB") { m_mac.reset(new mac_nr()); m_rlc.reset(new rlc_nr("RLC")); @@ -92,7 +92,7 @@ int gnb_stack_nr::init(const srsenb::stack_args_t& args_, const rrc_nr_cfg_t& rr m_sdap->init(m_pdcp.get(), nullptr, m_gw.get()); - m_gw->init(args.coreless.gw_args, logger, this); + m_gw->init(args.coreless.gw_args, this); char* err_str = nullptr; if (m_gw->setup_if_addr(5, args.coreless.drb_lcid, @@ -124,6 +124,7 @@ void gnb_stack_nr::stop() m_pdcp->stop(); m_mac->stop(); + srslte::get_background_workers().stop(); running = false; } } diff --git a/srsenb/src/stack/mac/CMakeLists.txt b/srsenb/src/stack/mac/CMakeLists.txt index 90a46c042..00c108205 100644 --- a/srsenb/src/stack/mac/CMakeLists.txt +++ b/srsenb/src/stack/mac/CMakeLists.txt @@ -21,7 +21,7 @@ add_subdirectory(schedulers) set(SOURCES mac.cc ue.cc sched.cc sched_carrier.cc sched_grid.cc sched_ue_ctrl/sched_harq.cc sched_ue.cc - sched_ue_ctrl/sched_lch.cc sched_ue_ctrl/sched_ue_cell.cc sched_phy_ch/sf_cch_allocator.cc sched_helpers.cc) + sched_ue_ctrl/sched_lch.cc sched_ue_ctrl/sched_ue_cell.cc sched_phy_ch/sf_cch_allocator.cc sched_phy_ch/sched_dci.cc sched_helpers.cc) add_library(srsenb_mac STATIC ${SOURCES} $) set(SOURCES mac_nr.cc) diff --git a/srsenb/src/stack/mac/mac.cc b/srsenb/src/stack/mac/mac.cc index 287e495fc..b01d8331f 100644 --- a/srsenb/src/stack/mac/mac.cc +++ b/srsenb/src/stack/mac/mac.cc @@ -30,7 +30,7 @@ #include "srslte/interfaces/enb_rlc_interfaces.h" #include "srslte/interfaces/enb_rrc_interfaces.h" -//#define WRITE_SIB_PCAP +// #define WRITE_SIB_PCAP using namespace asn1::rrc; namespace srsenb { @@ -131,6 +131,15 @@ void mac::start_pcap(srslte::mac_pcap* pcap_) } } +void mac::start_pcap_net(srslte::mac_pcap_net* pcap_net_) +{ + pcap_net = pcap_net_; + // Set pcap in all UEs for UL messages + for (auto& u : ue_db) { + u.second->start_pcap_net(pcap_net); + } +} + /******************************************************** * * RLC interface @@ -202,17 +211,6 @@ int mac::ue_cfg(uint16_t rnti, sched_interface::ue_cfg_t* cfg) // Start TA FSM in UE entity ue_ptr->start_ta(); - // Add RNTI to the PHY (pregenerate signals) now instead of after PRACH - if (not ue_ptr->is_phy_added) { - logger.info("Registering RNTI=0x%X to PHY...", rnti); - // Register new user in PHY with first CC index - if (phy_h->pregen_sequences(rnti) == SRSLTE_ERROR) { - logger.error("Generating sequences for UE RNTI=0x%X", rnti); - } - logger.info("Done registering RNTI=0x%X to PHY...", rnti); - ue_ptr->is_phy_added = true; - } - // Update Scheduler configuration if (cfg != nullptr and scheduler.ue_cfg(rnti, *cfg) == SRSLTE_ERROR) { logger.error("Registering new UE rnti=0x%x to SCHED", rnti); @@ -299,7 +297,7 @@ int mac::ack_info(uint32_t tti_rx, uint16_t rnti, uint32_t enb_cc_idx, uint32_t return SRSLTE_ERROR; } - uint32_t nof_bytes = scheduler.dl_ack_info(tti_rx, rnti, enb_cc_idx, tb_idx, ack); + int nof_bytes = scheduler.dl_ack_info(tti_rx, rnti, enb_cc_idx, tb_idx, ack); ue_db[rnti]->metrics_tx(ack, nof_bytes); if (ack) { @@ -480,11 +478,17 @@ uint16_t mac::allocate_ue() ue_ptr->start_pcap(pcap); } + if (pcap_net != nullptr) { + ue_ptr->start_pcap_net(pcap_net); + } + { srslte::rwlock_write_guard lock(rwlock); ue_db[rnti] = std::move(ue_ptr); } + // Allocate one new UE object in advance + srslte::get_background_workers().push_task([this]() { prealloc_ue(1); }); return rnti; } @@ -495,11 +499,6 @@ uint16_t mac::reserve_new_crnti(const sched_interface::ue_cfg_t& ue_cfg) return rnti; } - task_sched.enqueue_background_task([this](uint32_t wid) { - // Allocate one new UE object in advance - prealloc_ue(1); - }); - // Add new user to the scheduler so that it can RX/TX SRB0 if (scheduler.ue_cfg(rnti, ue_cfg) != SRSLTE_SUCCESS) { logger.error("Registering new user rnti=0x%x to SCHED", rnti); @@ -565,9 +564,6 @@ void mac::rach_detected(uint32_t tti, uint32_t enb_cc_idx, uint32_t preamble_idx time_adv, rnti); }); - - // Allocate one new UE object in advance - prealloc_ue(1); } void mac::prealloc_ue(uint32_t nof_ue) @@ -639,6 +635,10 @@ int mac::get_dl_sched(uint32_t tti_tx_dl, dl_sched_list_t& dl_sched_res_list) pcap->write_dl_crnti( dl_sched_res->pdsch[n].data[tb], sched_result.data[i].tbs[tb], rnti, true, tti_tx_dl, enb_cc_idx); } + if (pcap_net) { + pcap_net->write_dl_crnti( + dl_sched_res->pdsch[n].data[tb], sched_result.data[i].tbs[tb], rnti, true, tti_tx_dl, enb_cc_idx); + } } else { /* TB not enabled OR no data to send: set pointers to NULL */ dl_sched_res->pdsch[n].data[tb] = nullptr; @@ -683,7 +683,14 @@ int mac::get_dl_sched(uint32_t tti_tx_dl, dl_sched_list_t& dl_sched_res_list) tti_tx_dl, enb_cc_idx); } - + if (pcap_net) { + pcap_net->write_dl_ranti(dl_sched_res->pdsch[n].data[0], + sched_result.rar[i].tbs, + dl_sched_res->pdsch[n].dci.rnti, + true, + tti_tx_dl, + enb_cc_idx); + } n++; } @@ -701,6 +708,10 @@ int mac::get_dl_sched(uint32_t tti_tx_dl, dl_sched_list_t& dl_sched_res_list) if (pcap) { pcap->write_dl_sirnti(dl_sched_res->pdsch[n].data[0], sched_result.bc[i].tbs, true, tti_tx_dl, enb_cc_idx); } + if (pcap_net) { + pcap_net->write_dl_sirnti( + dl_sched_res->pdsch[n].data[0], sched_result.bc[i].tbs, true, tti_tx_dl, enb_cc_idx); + } #endif } else { dl_sched_res->pdsch[n].softbuffer_tx[0] = &common_buffers[enb_cc_idx].pcch_softbuffer_tx; @@ -710,6 +721,9 @@ int mac::get_dl_sched(uint32_t tti_tx_dl, dl_sched_list_t& dl_sched_res_list) if (pcap) { pcap->write_dl_pch(dl_sched_res->pdsch[n].data[0], sched_result.bc[i].tbs, true, tti_tx_dl, enb_cc_idx); } + if (pcap_net) { + pcap_net->write_dl_pch(dl_sched_res->pdsch[n].data[0], sched_result.bc[i].tbs, true, tti_tx_dl, enb_cc_idx); + } } n++; diff --git a/srsenb/src/stack/mac/mac_nr.cc b/srsenb/src/stack/mac/mac_nr.cc index b2419949c..9cccea54f 100644 --- a/srsenb/src/stack/mac/mac_nr.cc +++ b/srsenb/src/stack/mac/mac_nr.cc @@ -63,7 +63,7 @@ int mac_nr::init(const mac_nr_args_t& args_, log_h->set_hex_limit(args.log_hex_limit); if (args.pcap.enable) { - pcap = std::unique_ptr(new srslte::mac_pcap(srslte::srslte_rat_t::nr)); + pcap = std::unique_ptr(new srslte::mac_pcap()); pcap->open(args.pcap.filename); } diff --git a/srsenb/src/stack/mac/sched.cc b/srsenb/src/stack/mac/sched.cc index 39e3ef31c..9fbb3b995 100644 --- a/srsenb/src/stack/mac/sched.cc +++ b/srsenb/src/stack/mac/sched.cc @@ -27,7 +27,6 @@ #include "srsenb/hdr/stack/mac/sched_helpers.h" #include "srslte/common/logmap.h" #include "srslte/srslog/srslog.h" -#include "srslte/srslte.h" #define Console(fmt, ...) srslte::console(fmt, ##__VA_ARGS__) #define Error(fmt, ...) srslog::fetch_basic_logger("MAC").error(fmt, ##__VA_ARGS__) diff --git a/srsenb/src/stack/mac/sched_grid.cc b/srsenb/src/stack/mac/sched_grid.cc index 1a76d8035..f5c59db96 100644 --- a/srsenb/src/stack/mac/sched_grid.cc +++ b/srsenb/src/stack/mac/sched_grid.cc @@ -121,10 +121,6 @@ cc_sched_result* sched_result_list::get_cc(srslte::tti_point tti_rx, uint32_t en return res != nullptr ? res->get_cc(enb_cc_idx) : nullptr; } -/******************************************************* - * PDCCH Allocation Methods - *******************************************************/ - /******************************************************* * TTI resource Scheduling Methods *******************************************************/ @@ -140,6 +136,17 @@ void sf_grid_t::init(const sched_cell_params_t& cell_params_) ul_mask.resize(cc_cfg->nof_prb()); pdcch_alloc.init(*cc_cfg); + + // Compute reserved PRBs for CQI, SR and HARQ-ACK, and store it in a bitmask + pucch_mask.resize(cc_cfg->nof_prb()); + pucch_nrb = (cc_cfg->cfg.nrb_pucch > 0) ? (uint32_t)cc_cfg->cfg.nrb_pucch : 0; + srslte_pucch_cfg_t pucch_cfg = cell_params_.pucch_cfg_common; + pucch_cfg.n_pucch = cc_cfg->nof_cce_table[SRSLTE_NOF_CFI - 1] - 1 + cc_cfg->cfg.n1pucch_an; + pucch_nrb = std::max(pucch_nrb, srslte_pucch_m(&pucch_cfg, cc_cfg->cfg.cell.cp) / 2 + 1); + if (pucch_nrb > 0) { + pucch_mask.fill(0, pucch_nrb); + pucch_mask.fill(cc_cfg->nof_prb() - pucch_nrb, cc_cfg->nof_prb()); + } } void sf_grid_t::new_tti(tti_point tti_rx_) @@ -150,12 +157,29 @@ void sf_grid_t::new_tti(tti_point tti_rx_) ul_mask.reset(); avail_rbg = nof_rbgs; + // Reserve PRBs for PUCCH + ul_mask |= pucch_mask; + + // Reserve PRBs for PRACH + if (srslte_prach_tti_opportunity_config_fdd(cc_cfg->cfg.prach_config, to_tx_ul(tti_rx).to_uint(), -1)) { + prbmask_t prach_mask{cc_cfg->nof_prb()}; + prach_mask.fill(cc_cfg->cfg.prach_freq_offset, cc_cfg->cfg.prach_freq_offset + 6); + reserve_ul_prbs(prach_mask, false); // TODO: set to true once test sib.conf files are updated + logger.debug("SCHED: Allocated PRACH RBs for tti_tx_ul=%d. Mask: 0x%s", + to_tx_ul(tti_rx).to_uint(), + prach_mask.to_hex().c_str()); + } + // internal state pdcch_alloc.new_tti(tti_rx); } //! Allocates CCEs and RBs for the given mask and allocation type (e.g. data, BC, RAR, paging) -alloc_outcome_t sf_grid_t::alloc_dl(uint32_t aggr_idx, alloc_type_t alloc_type, rbgmask_t alloc_mask, sched_ue* user) +alloc_outcome_t sf_grid_t::alloc_dl(uint32_t aggr_idx, + alloc_type_t alloc_type, + rbgmask_t alloc_mask, + sched_ue* user, + bool has_pusch_grant) { // Check RBG collision if ((dl_mask & alloc_mask).any()) { @@ -163,7 +187,7 @@ alloc_outcome_t sf_grid_t::alloc_dl(uint32_t aggr_idx, alloc_type_t alloc_type, } // Allocate DCI in PDCCH - if (not pdcch_alloc.alloc_dci(alloc_type, aggr_idx, user)) { + if (not pdcch_alloc.alloc_dci(alloc_type, aggr_idx, user, has_pusch_grant)) { if (user != nullptr) { if (logger.debug.enabled()) { logger.debug("No space in PDCCH for rnti=0x%x DL tx. Current PDCCH allocation: %s", @@ -204,12 +228,12 @@ sf_grid_t::dl_ctrl_alloc_t sf_grid_t::alloc_dl_ctrl(uint32_t aggr_idx, alloc_typ } //! Allocates CCEs and RBs for a user DL data alloc. -alloc_outcome_t sf_grid_t::alloc_dl_data(sched_ue* user, const rbgmask_t& user_mask) +alloc_outcome_t sf_grid_t::alloc_dl_data(sched_ue* user, const rbgmask_t& user_mask, bool has_pusch_grant) { srslte_dci_format_t dci_format = user->get_dci_format(); uint32_t nof_bits = srslte_dci_format_sizeof(&cc_cfg->cfg.cell, nullptr, nullptr, dci_format); uint32_t aggr_idx = user->get_aggr_level(cc_cfg->enb_cc_idx, nof_bits); - alloc_outcome_t ret = alloc_dl(aggr_idx, alloc_type_t::DL_DATA, user_mask, user); + alloc_outcome_t ret = alloc_dl(aggr_idx, alloc_type_t::DL_DATA, user_mask, user, has_pusch_grant); return ret; } @@ -251,14 +275,25 @@ bool sf_grid_t::reserve_dl_rbgs(uint32_t start_rbg, uint32_t end_rbg) return true; } -bool sf_grid_t::reserve_ul_prbs(const prbmask_t& prbmask, bool strict) +alloc_outcome_t sf_grid_t::reserve_ul_prbs(prb_interval alloc, bool strict) { - bool ret = true; + if (alloc.stop() > ul_mask.size()) { + return alloc_outcome_t::ERROR; + } + + prbmask_t newmask(ul_mask.size()); + newmask.fill(alloc.start(), alloc.stop()); + return reserve_ul_prbs(newmask, strict); +} + +alloc_outcome_t sf_grid_t::reserve_ul_prbs(const prbmask_t& prbmask, bool strict) +{ + alloc_outcome_t ret = alloc_outcome_t::SUCCESS; if (strict and (ul_mask & prbmask).any()) { logger.error("There was a collision in UL channel. current mask=0x%s, new alloc mask=0x%s", ul_mask.to_hex().c_str(), prbmask.to_hex().c_str()); - ret = false; + ret = alloc_outcome_t::ERROR; } ul_mask |= prbmask; return ret; @@ -309,13 +344,7 @@ void sf_sched::init(const sched_cell_params_t& cell_params_) { cc_cfg = &cell_params_; tti_alloc.init(*cc_cfg); - max_msg3_prb = std::max(6u, cc_cfg->cfg.cell.nof_prb - (uint32_t)cc_cfg->cfg.nrb_pucch); - - pucch_mask.resize(cc_cfg->nof_prb()); - if (cc_cfg->cfg.nrb_pucch > 0) { - pucch_mask.fill(0, (uint32_t)cc_cfg->cfg.nrb_pucch); - pucch_mask.fill(cc_cfg->nof_prb() - cc_cfg->cfg.nrb_pucch, cc_cfg->nof_prb()); - } + max_msg3_prb = std::max(6u, cc_cfg->cfg.cell.nof_prb - tti_alloc.get_pucch_width()); } void sf_sched::new_tti(tti_point tti_rx_, sf_sched_result* cc_results_) @@ -330,21 +359,8 @@ void sf_sched::new_tti(tti_point tti_rx_, sf_sched_result* cc_results_) tti_alloc.new_tti(tti_rx_); cc_results = cc_results_; - // Reserve PRBs for PUCCH - reserve_ul_prbs(pucch_mask, true); - - // Reserve PRBs for PRACH - if (srslte_prach_tti_opportunity_config_fdd(cc_cfg->cfg.prach_config, to_tx_ul(tti_rx).to_uint(), -1)) { - prbmask_t prach_mask{cc_cfg->nof_prb()}; - prach_mask.fill(cc_cfg->cfg.prach_freq_offset, cc_cfg->cfg.prach_freq_offset + 6); - reserve_ul_prbs(prach_mask, cc_cfg->nof_prb() != 6); - logger.debug("SCHED: Allocated PRACH RBs for tti_tx_ul=%d. Mask: 0x%s", - to_tx_ul(tti_rx).to_uint(), - prach_mask.to_hex().c_str()); - } - // setup first prb to be used for msg3 alloc. Account for potential PRACH alloc - last_msg3_prb = cc_cfg->cfg.nrb_pucch; + last_msg3_prb = tti_alloc.get_pucch_width(); tti_point tti_msg3_alloc = to_tx_ul(tti_rx) + MSG3_DELAY_MS; if (srslte_prach_tti_opportunity_config_fdd(cc_cfg->cfg.prach_config, tti_msg3_alloc.to_uint(), -1)) { last_msg3_prb = std::max(last_msg3_prb, cc_cfg->cfg.prach_freq_offset + 6); @@ -547,28 +563,40 @@ alloc_outcome_t sf_sched::alloc_dl_user(sched_ue* user, const rbgmask_t& user_ma return alloc_outcome_t::INVALID_PRBMASK; } + bool has_pusch_grant = is_ul_alloc(user->get_rnti()) or cc_results->is_ul_alloc(user->get_rnti()); + // Check if there is space in the PUCCH for HARQ ACKs const sched_interface::ue_cfg_t& ue_cfg = user->get_ue_cfg(); std::bitset scells = user->scell_activation_mask(); uint32_t ue_cc_idx = cc->get_ue_cc_idx(); if (user->nof_carriers_configured() > 1 and (ue_cc_idx == 0 or scells[ue_cc_idx]) and - is_periodic_cqi_expected(ue_cfg, get_tti_tx_ul())) { - bool has_pusch_grant = is_ul_alloc(user->get_rnti()) or cc_results->is_ul_alloc(user->get_rnti()); - if (not has_pusch_grant) { - // Try to allocate small PUSCH grant, if there are no allocated PUSCH grants for this TTI yet - prb_interval alloc = {}; - uint32_t L = user->get_required_prb_ul(cc_cfg->enb_cc_idx, srslte::ceil_div(SRSLTE_UCI_CQI_CODED_PUCCH_B + 2, 8)); - tti_alloc.find_ul_alloc(L, &alloc); - bool ul_alloc_success = alloc.length() > 0 and alloc_ul_user(user, alloc); - if (ue_cc_idx != 0 and not ul_alloc_success) { - // For SCells, if we can't allocate small PUSCH grant, abort DL allocation - return alloc_outcome_t::PUCCH_COLLISION; - } + is_periodic_cqi_expected(ue_cfg, get_tti_tx_ul()) and not has_pusch_grant and + user->get_ul_harq(get_tti_tx_ul(), get_enb_cc_idx())->is_empty()) { + // Try to allocate small PUSCH grant, if there are no allocated PUSCH grants for this TTI yet + prb_interval alloc = {}; + uint32_t L = user->get_required_prb_ul(cc_cfg->enb_cc_idx, srslte::ceil_div(SRSLTE_UCI_CQI_CODED_PUCCH_B + 2, 8)); + tti_alloc.find_ul_alloc(L, &alloc); + has_pusch_grant = alloc.length() > 0 and alloc_ul_user(user, alloc); + if (ue_cc_idx != 0 and not has_pusch_grant) { + // For SCells, if we can't allocate small PUSCH grant, abort DL allocation + return alloc_outcome_t::PUCCH_COLLISION; } } - // Try to allocate RBGs and DCI - alloc_outcome_t ret = tti_alloc.alloc_dl_data(user, user_mask); + // Try to allocate RBGs, PDCCH, and PUCCH + alloc_outcome_t ret = tti_alloc.alloc_dl_data(user, user_mask, has_pusch_grant); + + if (ret == alloc_outcome_t::DCI_COLLISION and not has_pusch_grant and not data_allocs.empty() and + user->get_ul_harq(get_tti_tx_ul(), get_enb_cc_idx())->is_empty()) { + // PUCCH may be too full. Attempt small UL grant allocation for UCI-PUSCH + uint32_t L = user->get_required_prb_ul(cc_cfg->enb_cc_idx, srslte::ceil_div(SRSLTE_UCI_CQI_CODED_PUCCH_B + 2, 8)); + prb_interval alloc = {}; + tti_alloc.find_ul_alloc(L, &alloc); + has_pusch_grant = alloc.length() > 0 and alloc_ul_user(user, alloc); + if (has_pusch_grant) { + ret = tti_alloc.alloc_dl_data(user, user_mask, has_pusch_grant); + } + } if (ret != alloc_outcome_t::SUCCESS) { return ret; } @@ -604,7 +632,13 @@ alloc_outcome_t sf_sched::alloc_ul(sched_ue* user, prb_interval alloc, ul_alloc_ } // Allocate RBGs and DCI space - alloc_outcome_t ret = tti_alloc.alloc_ul_data(user, alloc, needs_pdcch); + alloc_outcome_t ret; + if (alloc_type != ul_alloc_t::MSG3 and alloc_type != ul_alloc_t::MSG3_RETX) { + ret = tti_alloc.alloc_ul_data(user, alloc, needs_pdcch); + } else { + // allow collisions between Msg3 and PUCCH for 6 PRBs + ret = tti_alloc.reserve_ul_prbs(alloc, cc_cfg->nof_prb() != 6); + } if (ret != alloc_outcome_t::SUCCESS) { return ret; } @@ -626,14 +660,14 @@ alloc_outcome_t sf_sched::alloc_ul_user(sched_ue* user, prb_interval alloc) ul_alloc_t::type_t alloc_type; ul_harq_proc* h = user->get_ul_harq(get_tti_tx_ul(), cc_cfg->enb_cc_idx); bool has_retx = h->has_pending_retx(); - if (has_retx) { - if (h->retx_requires_pdcch(tti_point{get_tti_tx_ul()}, alloc)) { - alloc_type = ul_alloc_t::ADAPT_RETX; - } else { - alloc_type = ul_alloc_t::NOADAPT_RETX; - } - } else { + if (not has_retx) { alloc_type = ul_alloc_t::NEWTX; + } else if (h->is_msg3()) { + alloc_type = ul_alloc_t::MSG3_RETX; + } else if (h->retx_requires_pdcch(tti_point{get_tti_tx_ul()}, alloc)) { + alloc_type = ul_alloc_t::ADAPT_RETX; + } else { + alloc_type = ul_alloc_t::NOADAPT_RETX; } return alloc_ul(user, alloc, alloc_type); diff --git a/srsenb/src/stack/mac/sched_helpers.cc b/srsenb/src/stack/mac/sched_helpers.cc index fc383abc1..9c1ca20d9 100644 --- a/srsenb/src/stack/mac/sched_helpers.cc +++ b/srsenb/src/stack/mac/sched_helpers.cc @@ -230,11 +230,14 @@ sched_cell_params_t::dl_lb_nof_re_table get_lb_nof_re_x_prb(const sched_cell_par srslte::bounded_vector re_prb_vec(table.size()); for (uint32_t p = 0; p < table.size(); ++p) { for (uint32_t s = 0; s < SRSLTE_NOF_SLOTS_PER_SF; ++s) { + // assume max CFI to compute lower bound re_prb_vec[p] += table[p][sf_idx][s][SRSLTE_NOF_CFI - 1]; } } + srslte::bounded_vector re_prb_vec2(re_prb_vec.size()); std::copy(re_prb_vec.begin(), re_prb_vec.end(), re_prb_vec2.begin()); + // pick intervals of PRBs with the lowest sum of REs ret[sf_idx][0] = *std::min_element(re_prb_vec2.begin(), re_prb_vec2.end()); for (uint32_t p = 1; p < table.size(); ++p) { std::transform(re_prb_vec2.begin(), @@ -332,6 +335,13 @@ bool sched_cell_params_t::set_cfg(uint32_t enb_cc_id nof_cce_table[cfix] = (uint32_t)ret; } + // PUCCH config struct for PUCCH position derivation + pucch_cfg_common.format = SRSLTE_PUCCH_FORMAT_1; + pucch_cfg_common.delta_pucch_shift = cfg.delta_pucch_shift; + pucch_cfg_common.n_rb_2 = cfg.nrb_cqi; + pucch_cfg_common.N_cs = cfg.ncs_an; + pucch_cfg_common.N_pucch_1 = cfg.n1pucch_an; + P = srslte_ra_type0_P(cfg.cell.nof_prb); nof_rbgs = srslte::ceil_div(cfg.cell.nof_prb, P); @@ -358,6 +368,7 @@ uint32_t sched_cell_params_t::get_dl_lb_nof_re(tti_point tti_tx_dl, uint32_t nof uint32_t sched_cell_params_t::get_dl_nof_res(srslte::tti_point tti_tx_dl, const srslte_dci_dl_t& dci, uint32_t cfi) const { + assert(cfi > 0 && "CFI has to be within (1..3)"); srslte_pdsch_grant_t grant = {}; srslte_dl_sf_cfg_t dl_sf = {}; dl_sf.cfi = cfi; diff --git a/srsenb/src/stack/mac/sched_phy_ch/sched_dci.cc b/srsenb/src/stack/mac/sched_phy_ch/sched_dci.cc new file mode 100644 index 000000000..cdd5b7c9d --- /dev/null +++ b/srsenb/src/stack/mac/sched_phy_ch/sched_dci.cc @@ -0,0 +1,164 @@ +/** + * + * \section copyright + * + * copyright 2013-2020 software radio systems limited + * + * by using this file, you agree to the terms and conditions set + * forth in the license file which can be found at the top level of + * the distribution. + * + */ + +#include "srsenb/hdr/stack/mac/sched_phy_ch/sched_dci.h" +#include "srsenb/hdr/stack/mac/sched_common.h" +#include +#include + +namespace srsenb { + +/// Compute max TBS based on max coderate +int coderate_to_tbs(float max_coderate, uint32_t nof_re) +{ + return floorf(nof_re * max_coderate - 24); +} + +/// Compute {mcs, tbs_idx} based on {max_tbs, nof_prb} +int compute_mcs_from_max_tbs(uint32_t nof_prb, + uint32_t max_tbs, + uint32_t max_mcs, + bool is_ul, + bool use_tbs_index_alt, + int& mcs, + int& tbs_idx) +{ + constexpr static std::array forbidden_tbs_idx_alt{1, 3, 5, 7, 9, 26}; + + // Compute I_TBS based on max TBS + uint32_t max_tbs_idx = (use_tbs_index_alt) ? 33 : 26; + tbs_idx = srslte_ra_tbs_to_table_idx(max_tbs, nof_prb, max_tbs_idx); + if (tbs_idx <= 0) { + return SRSLTE_ERROR; + } + --tbs_idx; // get TBS index lower bound + if (use_tbs_index_alt and + std::find(forbidden_tbs_idx_alt.begin(), forbidden_tbs_idx_alt.end(), tbs_idx) != forbidden_tbs_idx_alt.end()) { + // some tbs_idx are invalid for 256QAM. See TS 36.213 - Table 7.1.7.1-1A + --tbs_idx; + } + + // Compute I_mcs based on I_TBS. Reverse of TS 36.213 - Table 7.1.7.1-1/1A + mcs = srslte_ra_mcs_from_tbs_idx(tbs_idx, use_tbs_index_alt, is_ul); + if (mcs < 0) { + return SRSLTE_ERROR; + } + if (mcs > (int)max_mcs) { + // bound mcs + mcs = max_mcs; + tbs_idx = srslte_ra_tbs_idx_from_mcs(mcs, use_tbs_index_alt, is_ul); + } + + return SRSLTE_SUCCESS; +} + +tbs_info compute_mcs_and_tbs(uint32_t nof_prb, + uint32_t nof_re, + uint32_t cqi, + 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 = srslte_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.930f * max_Qm); + + int mcs = 0; + float prev_max_coderate = 0; + do { + // update max TBS based on max coderate + int max_tbs = coderate_to_tbs(max_coderate, nof_re); + if (max_tbs < 16) { + return tbs_info{}; + } + + // Compute max {MCS,I_TBS} based on given max_tbs, nof_prb + int tbs_idx = 0; + if (compute_mcs_from_max_tbs(nof_prb, max_tbs, max_mcs, is_ul, use_tbs_index_alt, mcs, tbs_idx) != SRSLTE_SUCCESS) { + return tbs_info{}; + } + + if (mcs == 6 and nof_prb == 1) { + // Avoid the unusual case n_prb=1, mcs=6 tbs=328 (used in voip) + max_mcs = mcs - 1; + continue; + } + + // compute real TBS and coderate based on maximum achievable MCS + int tbs = srslte_ra_tbs_from_idx(tbs_idx, nof_prb); + float coderate = srslte_coderate(tbs, nof_re); + + // update max coderate based on mcs + srslte_mod_t mod = (is_ul) ? srslte_ra_ul_mod_from_mcs(mcs) : srslte_ra_dl_mod_from_mcs(mcs, use_tbs_index_alt); + uint32_t Qm = srslte_mod_bits_x_symbol(mod); + max_coderate = std::min(0.930f * Qm, max_coderate); + + if (coderate <= max_coderate) { + // solution was found + tbs_info tb; + tb.tbs_bytes = tbs / 8u; + tb.mcs = mcs; + return tb; + } + + // start with smaller max mcs in next iteration + max_mcs = mcs - 1; + } while (mcs > 0 and max_coderate != prev_max_coderate); + + return tbs_info{}; +} + +tbs_info compute_min_mcs_and_tbs_from_required_bytes(uint32_t nof_prb, + uint32_t nof_re, + uint32_t cqi, + uint32_t max_mcs, + uint32_t req_bytes, + bool is_ul, + bool ulqam64_enabled, + bool use_tbs_index_alt) +{ + // get max MCS/TBS that meets max coderate requirements + tbs_info tb_max = compute_mcs_and_tbs(nof_prb, nof_re, cqi, max_mcs, is_ul, ulqam64_enabled, use_tbs_index_alt); + if (tb_max.tbs_bytes + 8 <= (int)req_bytes or tb_max.mcs == 0 or req_bytes <= 0) { + // if mcs cannot be lowered or a decrease in TBS index won't meet req_bytes requirement + return tb_max; + } + + // get maximum MCS that leads to tbs < req_bytes (used as max_tbs argument) + int mcs_min = 0, tbs_idx_min = 0; + // Note: we subtract -1 to required data to get an exclusive lower bound for maximum MCS. This works ok because + // req_bytes * 8 is always even + if (compute_mcs_from_max_tbs(nof_prb, req_bytes * 8u - 1, max_mcs, is_ul, use_tbs_index_alt, mcs_min, tbs_idx_min) != + SRSLTE_SUCCESS) { + // Failed to compute maximum MCS that leads to TBS < req bytes. MCS=0 is likely a valid solution + tbs_info tb2 = compute_mcs_and_tbs(nof_prb, nof_re, cqi, 0, is_ul, ulqam64_enabled, use_tbs_index_alt); + if (tb2.tbs_bytes >= (int)req_bytes) { + return tb2; + } + return tb_max; + } + + // Iterate from min to max MCS until a solution is found + for (int mcs = mcs_min + 1; mcs < tb_max.mcs; ++mcs) { + tbs_info tb2 = compute_mcs_and_tbs(nof_prb, nof_re, cqi, mcs, is_ul, ulqam64_enabled, use_tbs_index_alt); + if (tb2.tbs_bytes >= (int)req_bytes) { + return tb2; + } + } + return tb_max; +} + +} // namespace srsenb diff --git a/srsenb/src/stack/mac/sched_phy_ch/sf_cch_allocator.cc b/srsenb/src/stack/mac/sched_phy_ch/sf_cch_allocator.cc index bc52a8a95..4f0de3b81 100644 --- a/srsenb/src/stack/mac/sched_phy_ch/sf_cch_allocator.cc +++ b/srsenb/src/stack/mac/sched_phy_ch/sf_cch_allocator.cc @@ -21,24 +21,19 @@ #include "srsenb/hdr/stack/mac/sched_phy_ch/sf_cch_allocator.h" #include "srsenb/hdr/stack/mac/sched_grid.h" +#include "srslte/srslog/bundled/fmt/format.h" namespace srsenb { -void sf_cch_allocator::alloc_tree_t::reset() -{ - prev_start = 0; - prev_end = 0; - dci_alloc_tree.clear(); -} - void sf_cch_allocator::init(const sched_cell_params_t& cell_params_) { - cc_cfg = &cell_params_; + cc_cfg = &cell_params_; + pucch_cfg_common = cc_cfg->pucch_cfg_common; // init alloc trees alloc_trees.reserve(cc_cfg->sched_cfg->max_nof_ctrl_symbols); for (uint32_t i = 0; i < cc_cfg->sched_cfg->max_nof_ctrl_symbols; ++i) { - alloc_trees.emplace_back(cc_cfg->nof_cce_table[i]); + alloc_trees.emplace_back(i + 1, *cc_cfg, pucch_cfg_common); } } @@ -74,10 +69,10 @@ sf_cch_allocator::get_cce_loc_table(alloc_type_t alloc_type, sched_ue* user, uin return nullptr; } -bool sf_cch_allocator::alloc_dci(alloc_type_t alloc_type, uint32_t aggr_idx, sched_ue* user) +bool sf_cch_allocator::alloc_dci(alloc_type_t alloc_type, uint32_t aggr_idx, sched_ue* user, bool has_pusch_grant) { // TODO: Make the alloc tree update lazy - alloc_record_t record{.user = user, .aggr_idx = aggr_idx, .alloc_type = alloc_type}; + alloc_record_t record{.user = user, .aggr_idx = aggr_idx, .alloc_type = alloc_type, .pusch_uci = has_pusch_grant}; // Try to allocate user in PDCCH for given CFI. If it fails, increment CFI. uint32_t first_cfi = get_cfi(); @@ -112,10 +107,10 @@ bool sf_cch_allocator::alloc_dci_record(const alloc_record_t& record, uint32_t c if (tree.prev_end > 0) { for (size_t j = tree.prev_start; j < tree.prev_end; ++j) { - ret |= add_tree_node_leaves(tree, (int)j, record, *dci_locs, to_tx_dl(tti_rx)); + ret |= tree.add_tree_node_leaves((int)j, record, *dci_locs, tti_rx); } } else { - ret = add_tree_node_leaves(tree, -1, record, *dci_locs, to_tx_dl(tti_rx)); + ret = tree.add_tree_node_leaves(-1, record, *dci_locs, tti_rx); } if (ret) { @@ -126,66 +121,6 @@ bool sf_cch_allocator::alloc_dci_record(const alloc_record_t& record, uint32_t c return ret; } -//! Algorithm to compute a valid PDCCH allocation -bool sf_cch_allocator::add_tree_node_leaves(alloc_tree_t& tree, - int parent_node_idx, - const alloc_record_t& dci_record, - const cce_cfi_position_table& dci_locs, - tti_point tti_tx_dl) -{ - bool ret = false; - - alloc_t alloc; - alloc.rnti = (dci_record.user != nullptr) ? dci_record.user->get_rnti() : (uint16_t)0u; - alloc.dci_pos.L = dci_record.aggr_idx; - - // get cumulative pdcch mask - pdcch_mask_t cum_mask; - if (parent_node_idx >= 0) { - cum_mask = tree.dci_alloc_tree[parent_node_idx].node.total_mask; - } else { - cum_mask.resize(tree.nof_cces); - } - - for (uint32_t i = 0; i < dci_locs[dci_record.aggr_idx].size(); ++i) { - uint32_t startpos = dci_locs[dci_record.aggr_idx][i]; - - if (dci_record.alloc_type == alloc_type_t::DL_DATA and dci_record.user->pucch_sr_collision(tti_tx_dl, startpos)) { - // will cause a collision in the PUCCH - continue; - } - - pdcch_mask_t alloc_mask(tree.nof_cces); - alloc_mask.fill(startpos, startpos + (1u << dci_record.aggr_idx)); - if ((cum_mask & alloc_mask).any()) { - // there is collision. Try another mask - continue; - } - - // Allocation successful - alloc.current_mask = alloc_mask; - alloc.total_mask = cum_mask | alloc_mask; - alloc.dci_pos.ncce = startpos; - - // Prune if repetition - uint32_t j = tree.prev_end; - for (; j < tree.dci_alloc_tree.size(); ++j) { - if (tree.dci_alloc_tree[j].node.total_mask == alloc.total_mask) { - break; - } - } - if (j < tree.dci_alloc_tree.size()) { - continue; - } - - // Register allocation - tree.dci_alloc_tree.emplace_back(parent_node_idx, alloc); - ret = true; - } - - return ret; -} - bool sf_cch_allocator::set_cfi(uint32_t cfi) { if (cfi < cc_cfg->sched_cfg->min_nof_ctrl_symbols or cfi > cc_cfg->sched_cfg->max_nof_ctrl_symbols) { @@ -218,20 +153,131 @@ bool sf_cch_allocator::set_cfi(uint32_t cfi) } current_cfix = new_cfix; - // TODO: The estimation of the number of required prbs in metric depends on CFI. Analyse the consequences return true; } void sf_cch_allocator::get_allocs(alloc_result_t* vec, pdcch_mask_t* tot_mask, size_t idx) const { - auto& tree = alloc_trees[current_cfix]; + alloc_trees[current_cfix].get_allocs(vec, tot_mask, idx); +} + +std::string sf_cch_allocator::result_to_string(bool verbose) const +{ + return alloc_trees[current_cfix].result_to_string(verbose); +} + +sf_cch_allocator::alloc_tree_t::alloc_tree_t(uint32_t this_cfi, + const sched_cell_params_t& cc_params, + srslte_pucch_cfg_t& pucch_cfg) : + cfi(this_cfi), cc_cfg(&cc_params), pucch_cfg(&pucch_cfg), nof_cces(cc_params.nof_cce_table[this_cfi - 1]) +{ + dci_alloc_tree.reserve(8); +} + +void sf_cch_allocator::alloc_tree_t::reset() +{ + prev_start = 0; + prev_end = 0; + dci_alloc_tree.clear(); +} + +bool is_pucch_sr_collision(const srslte_pucch_cfg_t& pucch_cfg, tti_point tti_tx_dl, uint32_t n1_pucch) +{ + if (pucch_cfg.sr_configured && srslte_ue_ul_sr_send_tti(&pucch_cfg, tti_tx_dl.to_uint())) { + return n1_pucch == pucch_cfg.n_pucch_sr; + } + return false; +} + +/// Algorithm to compute a valid PDCCH allocation +bool sf_cch_allocator::alloc_tree_t::add_tree_node_leaves(int parent_node_idx, + const alloc_record_t& dci_record, + const cce_cfi_position_table& dci_locs, + tti_point tti_rx_) +{ + bool ret = false; + + alloc_t alloc; + alloc.rnti = (dci_record.user != nullptr) ? dci_record.user->get_rnti() : SRSLTE_INVALID_RNTI; + alloc.dci_pos.L = dci_record.aggr_idx; + + // get cumulative pdcch & pucch masks + pdcch_mask_t parent_total_mask; + prbmask_t parent_pucch_mask; + if (parent_node_idx >= 0) { + parent_total_mask = dci_alloc_tree[parent_node_idx].node.total_mask; + parent_pucch_mask = dci_alloc_tree[parent_node_idx].node.total_pucch_mask; + } else { + parent_total_mask.resize(nof_cces); + parent_pucch_mask.resize(cc_cfg->nof_prb()); + } + + for (uint32_t i = 0; i < dci_locs[dci_record.aggr_idx].size(); ++i) { + int8_t pucch_prbidx = -1; + uint32_t ncce_pos = dci_locs[dci_record.aggr_idx][i]; + + if (dci_record.alloc_type == alloc_type_t::DL_DATA and not dci_record.pusch_uci) { + // The UE needs to allocate space in PUCCH for HARQ-ACK + pucch_cfg->n_pucch = ncce_pos + pucch_cfg->N_pucch_1; + + if (is_pucch_sr_collision(*pucch_cfg, to_tx_dl_ack(tti_rx_), pucch_cfg->n_pucch)) { + // avoid collision of HARQ-ACK with own SR n(1)_pucch + continue; + } + + pucch_prbidx = srslte_pucch_n_prb(&cc_cfg->cfg.cell, pucch_cfg, 0); + if (not cc_cfg->sched_cfg->pucch_mux_enabled and parent_pucch_mask.test(pucch_prbidx)) { + // PUCCH allocation would collide with other PUCCH/PUSCH grants. Try another CCE position + continue; + } + } + + pdcch_mask_t alloc_mask(nof_cces); + alloc_mask.fill(ncce_pos, ncce_pos + (1u << dci_record.aggr_idx)); + if ((parent_total_mask & alloc_mask).any()) { + // there is a PDCCH collision. Try another CCE position + continue; + } + + // Allocation successful + alloc.current_mask = alloc_mask; + alloc.total_mask = parent_total_mask | alloc_mask; + alloc.dci_pos.ncce = ncce_pos; + alloc.pucch_n_prb = pucch_prbidx; + alloc.total_pucch_mask = parent_pucch_mask; + if (pucch_prbidx >= 0) { + alloc.total_pucch_mask.set(pucch_prbidx); + } + + // Prune if repetition of total_masks + uint32_t j = prev_end; + for (; j < dci_alloc_tree.size(); ++j) { + if (dci_alloc_tree[j].node.total_mask == alloc.total_mask) { + // leave nested for-loop + break; + } + } + if (j < dci_alloc_tree.size()) { + continue; + } + + // Register allocation + dci_alloc_tree.emplace_back(parent_node_idx, alloc); + ret = true; + } + + return ret; +} + +void sf_cch_allocator::alloc_tree_t::get_allocs(alloc_result_t* vec, pdcch_mask_t* tot_mask, size_t idx) const +{ // if alloc tree is empty - if (tree.prev_start == tree.prev_end) { + if (prev_start == prev_end) { if (vec != nullptr) { vec->clear(); } if (tot_mask != nullptr) { - tot_mask->resize(nof_cces()); + tot_mask->resize(nof_cces); tot_mask->reset(); } return; @@ -240,50 +286,52 @@ void sf_cch_allocator::get_allocs(alloc_result_t* vec, pdcch_mask_t* tot_mask, s // set vector of allocations if (vec != nullptr) { vec->clear(); - size_t i = tree.prev_start + idx; - while (tree.dci_alloc_tree[i].parent_idx >= 0) { - vec->push_back(&tree.dci_alloc_tree[i].node); - i = (size_t)tree.dci_alloc_tree[i].parent_idx; + size_t i = prev_start + idx; + while (dci_alloc_tree[i].parent_idx >= 0) { + vec->push_back(&dci_alloc_tree[i].node); + i = (size_t)dci_alloc_tree[i].parent_idx; } - vec->push_back(&tree.dci_alloc_tree[i].node); + vec->push_back(&dci_alloc_tree[i].node); std::reverse(vec->begin(), vec->end()); } // set final cce mask if (tot_mask != nullptr) { - *tot_mask = tree.dci_alloc_tree[tree.prev_start + idx].node.total_mask; + *tot_mask = dci_alloc_tree[prev_start + idx].node.total_mask; } } -std::string sf_cch_allocator::result_to_string(bool verbose) const +std::string sf_cch_allocator::alloc_tree_t::result_to_string(bool verbose) const { - auto& tree = alloc_trees[current_cfix]; - std::stringstream ss; - ss << "cfi=" << get_cfi() << ", mask_size=" << nof_cces() << ", " << tree.prev_end - tree.prev_start - << " DCI allocation combinations:\n"; - // get all the possible combinations of DCI allocations + // get all the possible combinations of DCI pos allocations + fmt::basic_memory_buffer strbuf; + fmt::format_to(strbuf, + "SCHED: PDCCH allocations cfi={}, nof_cce={}, {} possible combinations:\n", + cfi, + nof_cces, + prev_end - prev_start); uint32_t count = 0; - for (size_t i = tree.prev_start; i < tree.prev_end; ++i) { + for (size_t i = prev_start; i < prev_end; ++i) { alloc_result_t vec; pdcch_mask_t tot_mask; - get_allocs(&vec, &tot_mask, i - tree.prev_start); + get_allocs(&vec, &tot_mask, i - prev_start); - ss << " combination " << count << ": mask=0x" << tot_mask.to_hex().c_str(); + fmt::format_to(strbuf, "[{}]: total mask=0x{}", count, tot_mask.to_hex().c_str()); if (verbose) { - ss << ", DCI allocs:\n"; + fmt::format_to(strbuf, ", allocations:\n"); for (const auto& dci_alloc : vec) { - char hex[5]; - sprintf(hex, "%x", dci_alloc->rnti); - ss << " > rnti=0x" << hex << ": " << dci_alloc->current_mask.to_hex().c_str() << " / " - << dci_alloc->total_mask.to_hex().c_str() << "\n"; + fmt::format_to(strbuf, + " > rnti=0x{:0x}: 0x{} / 0x{}\n", + dci_alloc->rnti, + dci_alloc->current_mask.to_hex().c_str(), + dci_alloc->total_mask.to_hex().c_str()); } } else { - ss << "\n"; + fmt::format_to(strbuf, "\n"); } count++; } - - return ss.str(); + return fmt::to_string(strbuf); } -} // namespace srsenb \ No newline at end of file +} // namespace srsenb diff --git a/srsenb/src/stack/mac/sched_ue.cc b/srsenb/src/stack/mac/sched_ue.cc index bdccc4f5e..b326152a0 100644 --- a/srsenb/src/stack/mac/sched_ue.cc +++ b/srsenb/src/stack/mac/sched_ue.cc @@ -26,7 +26,6 @@ #include "srsenb/hdr/stack/mac/sched_ue.h" #include "srslte/common/log_helper.h" #include "srslte/common/logmap.h" -#include "srslte/srslte.h" using srslte::tti_interval; @@ -186,17 +185,6 @@ void sched_ue::unset_sr() sr = false; } -bool sched_ue::pucch_sr_collision(tti_point tti_tx_dl, uint32_t n_cce) -{ - if (!phy_config_dedicated_enabled) { - return false; - } - if (cfg.pucch_cfg.sr_configured && srslte_ue_ul_sr_send_tti(&cfg.pucch_cfg, tti_tx_dl.to_uint())) { - return (n_cce + cfg.pucch_cfg.N_pucch_1) == cfg.pucch_cfg.n_pucch_sr; - } - return false; -} - tti_point prev_meas_gap_start(tti_point tti, uint32_t period, uint32_t offset) { return tti_point{static_cast(floor(static_cast((tti - offset).to_uint()) / period)) * period + @@ -391,6 +379,13 @@ int sched_ue::generate_dl_dci_format(uint32_t pid, srslte_dci_format_t dci_format = get_dci_format(); int tbs_bytes = 0; + // Set common DCI fields + srslte_dci_dl_t* dci = &data->dci; + dci->rnti = rnti; + dci->pid = pid; + dci->ue_cc_idx = cells[enb_cc_idx].get_ue_cc_idx(); + dci->format = dci_format; + switch (dci_format) { case SRSLTE_DCI_FORMAT1A: tbs_bytes = generate_format1a(pid, data, tti_tx_dl, enb_cc_idx, cfi, user_mask); @@ -408,14 +403,9 @@ int sched_ue::generate_dl_dci_format(uint32_t pid, logger.error("DCI format (%d) not implemented", dci_format); } - // Set common DCI fields + // If allocation successful, encode TPC if (tbs_bytes > 0) { - srslte_dci_dl_t* dci = &data->dci; - dci->rnti = rnti; - dci->pid = pid; - dci->ue_cc_idx = cells[enb_cc_idx].get_ue_cc_idx(); - data->dci.format = dci_format; - dci->tpc_pucch = cells[enb_cc_idx].tpc_fsm.encode_pucch_tpc(); + dci->tpc_pucch = cells[enb_cc_idx].tpc_fsm.encode_pucch_tpc(); } return tbs_bytes; @@ -428,8 +418,6 @@ int sched_ue::generate_format1a(uint32_t pid, uint32_t cfi, const rbgmask_t& user_mask) { - int tbs_bytes = generate_format1(pid, data, tti_tx_dl, enb_cc_idx, cfi, user_mask); - srslte_dci_dl_t* dci = &data->dci; dci->alloc_type = SRSLTE_RA_ALLOC_TYPE2; @@ -444,28 +432,24 @@ int sched_ue::generate_format1a(uint32_t pid, logger.warning("SCHED: Can't use distributed RA due to DCI size ambiguity"); } - return tbs_bytes; + return generate_format1_common(pid, data, tti_tx_dl, enb_cc_idx, cfi, user_mask); } -// > return 0 if allocation is invalid -int sched_ue::generate_format1(uint32_t pid, - sched_interface::dl_sched_data_t* data, - tti_point tti_tx_dl, - uint32_t enb_cc_idx, - uint32_t cfi, - const rbgmask_t& user_mask) +int sched_ue::generate_format1_common(uint32_t pid, + sched_interface::dl_sched_data_t* data, + tti_point tti_tx_dl, + uint32_t enb_cc_idx, + uint32_t cfi, + const rbgmask_t& user_mask) { dl_harq_proc* h = &cells[enb_cc_idx].harq_ent.dl_harq_procs()[pid]; srslte_dci_dl_t* dci = &data->dci; - dci->alloc_type = SRSLTE_RA_ALLOC_TYPE0; - dci->type0_alloc.rbg_bitmask = (uint32_t)user_mask.to_uint64(); - tbs_info tbinfo; if (h->is_empty(0)) { tbinfo = allocate_new_dl_mac_pdu(data, h, user_mask, tti_tx_dl, enb_cc_idx, cfi, 0); } else { - h->new_retx(user_mask, 0, tti_tx_dl, &tbinfo.mcs, &tbinfo.tbs_bytes, data->dci.location.ncce); + h->new_retx(user_mask, 0, tti_tx_dl, &tbinfo.mcs, &tbinfo.tbs_bytes, dci->location.ncce); logger.debug("SCHED: Alloc format1 previous mcs=%d, tbs=%d", tbinfo.mcs, tbinfo.tbs_bytes); } @@ -480,6 +464,21 @@ int sched_ue::generate_format1(uint32_t pid, return tbinfo.tbs_bytes; } +int sched_ue::generate_format1(uint32_t pid, + sched_interface::dl_sched_data_t* data, + tti_point tti_tx_dl, + uint32_t enb_cc_idx, + uint32_t cfi, + const rbgmask_t& user_mask) +{ + srslte_dci_dl_t* dci = &data->dci; + + dci->alloc_type = SRSLTE_RA_ALLOC_TYPE0; + dci->type0_alloc.rbg_bitmask = (uint32_t)user_mask.to_uint64(); + + return generate_format1_common(pid, data, tti_tx_dl, enb_cc_idx, cfi, user_mask); +} + /** * Based on the amount of tx data, allocated PRBs, DCI params, etc. compute a valid MCS and resulting TBS * @param enb_cc_idx user carrier index @@ -502,7 +501,7 @@ tbs_info sched_ue::compute_mcs_and_tbs(uint32_t enb_cc_idx, uint32_t nof_re = cells[enb_cc_idx].cell_cfg->get_dl_nof_res(tti_tx_dl, dci, cfi); // Compute MCS+TBS - tbs_info tb = alloc_tbs_dl(cells[enb_cc_idx], nof_alloc_prbs, nof_re, req_bytes.stop()); + tbs_info tb = cqi_to_tbs_dl(cells[enb_cc_idx], nof_alloc_prbs, nof_re, dci.format, req_bytes.stop()); if (tb.tbs_bytes > 0 and tb.tbs_bytes < (int)req_bytes.start()) { logger.info("SCHED: Could not get PRB allocation that avoids MAC CE or RLC SRB0 PDU segmentation"); @@ -626,11 +625,6 @@ int sched_ue::generate_format0(sched_interface::ul_sched_data_t* data, bool is_newtx = h->is_empty(0); if (is_newtx) { - uint32_t nof_retx; - - // If Msg3 set different nof retx - nof_retx = (data->needs_pdcch) ? get_max_retx() : max_msg3retx; - if (tbinfo.mcs >= 0) { tbinfo.tbs_bytes = get_tbs_bytes(tbinfo.mcs, alloc.length(), false, true); } else { @@ -639,7 +633,7 @@ int sched_ue::generate_format0(sched_interface::ul_sched_data_t* data, uint32_t N_srs = 0; uint32_t nof_symb = 2 * (SRSLTE_CP_NSYMB(cell.cp) - 1) - N_srs; uint32_t nof_re = nof_symb * alloc.length() * SRSLTE_NRE; - tbinfo = alloc_tbs_ul(cells[enb_cc_idx], alloc.length(), nof_re, req_bytes); + tbinfo = cqi_to_tbs_ul(cells[enb_cc_idx], alloc.length(), nof_re, req_bytes); // Reduce MCS to fit UCI if transmitted in this grant if (uci_type != UCI_PUSCH_NONE) { @@ -658,12 +652,14 @@ int sched_ue::generate_format0(sched_interface::ul_sched_data_t* data, } // Recompute again the MCS and TBS with the new spectral efficiency (based on the available RE for data) if (nof_re >= nof_uci_re) { - tbinfo = alloc_tbs_ul(cells[enb_cc_idx], alloc.length(), nof_re - nof_uci_re, req_bytes); + tbinfo = cqi_to_tbs_ul(cells[enb_cc_idx], alloc.length(), nof_re - nof_uci_re, req_bytes); } // NOTE: if (nof_re < nof_uci_re) we should set TBS=0 } } - h->new_tx(tti_tx_ul, tbinfo.mcs, tbinfo.tbs_bytes, alloc, nof_retx); + // If Msg3 set different nof retx + uint32_t nof_retx = (data->needs_pdcch) ? get_max_retx() : max_msg3retx; + h->new_tx(tti_tx_ul, tbinfo.mcs, tbinfo.tbs_bytes, alloc, nof_retx, not data->needs_pdcch); // Un-trigger the SR if data is allocated if (tbinfo.tbs_bytes > 0) { unset_sr(); @@ -762,7 +758,7 @@ rbg_interval sched_ue::get_required_dl_rbgs(uint32_t enb_cc_idx) if (req_bytes == srslte::interval{0, 0}) { return {0, 0}; } - int pending_prbs = get_required_prb_dl(cells[enb_cc_idx], to_tx_dl(current_tti), req_bytes.start()); + int pending_prbs = get_required_prb_dl(cells[enb_cc_idx], to_tx_dl(current_tti), get_dci_format(), req_bytes.start()); if (pending_prbs < 0) { // Cannot fit allocation in given PRBs logger.error("SCHED: DL CQI=%d does now allow fitting %d non-segmentable DL tx bytes into the cell bandwidth. " @@ -772,8 +768,8 @@ rbg_interval sched_ue::get_required_dl_rbgs(uint32_t enb_cc_idx) return {cellparams->nof_prb(), cellparams->nof_prb()}; } uint32_t min_pending_rbg = cellparams->nof_prbs_to_rbgs(pending_prbs); - pending_prbs = get_required_prb_dl(cells[enb_cc_idx], to_tx_dl(current_tti), req_bytes.stop()); - pending_prbs = (pending_prbs < 0) ? cellparams->nof_prb() : pending_prbs; + pending_prbs = get_required_prb_dl(cells[enb_cc_idx], to_tx_dl(current_tti), get_dci_format(), req_bytes.stop()); + pending_prbs = (pending_prbs < 0) ? cellparams->nof_prb() : pending_prbs; uint32_t max_pending_rbg = cellparams->nof_prbs_to_rbgs(pending_prbs); return {min_pending_rbg, max_pending_rbg}; } 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 cff21188a..425b3eecd 100644 --- a/srsenb/src/stack/mac/sched_ue_ctrl/sched_harq.cc +++ b/srsenb/src/stack/mac/sched_ue_ctrl/sched_harq.cc @@ -24,7 +24,6 @@ #include "srsenb/hdr/stack/mac/sched.h" #include "srslte/common/log_helper.h" #include "srslte/mac/pdu.h" -#include "srslte/srslte.h" using srslte::tti_point; @@ -245,12 +244,13 @@ bool ul_harq_proc::has_pending_retx() const return has_pending_retx_common(0); } -void ul_harq_proc::new_tx(tti_point tti_, int mcs, int tbs, prb_interval alloc, uint32_t max_retx_) +void ul_harq_proc::new_tx(tti_point tti_, int mcs, int tbs, prb_interval alloc, uint32_t max_retx_, bool is_msg3) { allocation = alloc; new_tx_common(0, tti_point{tti_}, mcs, tbs, max_retx_); pending_data = tbs; pending_phich = true; + is_msg3_ = is_msg3; } void ul_harq_proc::new_retx(tti_point tti_, int* mcs, int* tbs, prb_interval alloc) 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 924e5d645..6826f6228 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 @@ -21,6 +21,7 @@ #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 namespace srsenb { @@ -229,130 +230,52 @@ std::tuple false_position_method(int x1, int x2, YType y return false_position_method(x1, x2, y0, f, [](int x) { return false; }); } -float diff_coderate_maxcoderate(int mcs, - uint32_t nof_prb, - uint32_t nof_re, - uint32_t max_Qm, - float max_coderate, - bool use_tbs_index_alt, - bool is_ul) +tbs_info cqi_to_tbs_dl(const sched_ue_cell& cell, + uint32_t nof_prb, + uint32_t nof_re, + srslte_dci_format_t dci_format, + int req_bytes) { - uint32_t tbs_idx = srslte_ra_tbs_idx_from_mcs(mcs, use_tbs_index_alt, is_ul); - int tbs = srslte_ra_tbs_from_idx(tbs_idx, nof_prb); - float coderate = srslte_coderate(tbs, nof_re); - srslte_mod_t mod = (is_ul) ? srslte_ra_ul_mod_from_mcs(mcs) : srslte_ra_dl_mod_from_mcs(mcs, use_tbs_index_alt); - uint32_t Qm = std::min(max_Qm, srslte_mod_bits_x_symbol(mod)); - return coderate - std::min(max_coderate, 0.930f * Qm); -} + bool use_tbs_index_alt = cell.get_ue_cfg()->use_tbs_index_alt and dci_format != SRSLTE_DCI_FORMAT1A; -tbs_info cqi_to_tbs(const sched_ue_cell& cell, uint32_t nof_prb, uint32_t nof_re, bool is_ul) -{ - using ul64qam_cap = sched_interface::ue_cfg_t::ul64qam_cap; - uint32_t max_Qm; - int max_mcs; - float max_coderate; - if (is_ul) { - max_mcs = cell.max_mcs_ul; - max_Qm = cell.get_ue_cfg()->support_ul64qam == ul64qam_cap::enabled ? 6 : 4; - max_coderate = srslte_cqi_to_coderate(std::min(cell.ul_cqi + 1u, 15u), false); - } else { - max_mcs = cell.max_mcs_dl; - max_Qm = cell.get_ue_cfg()->use_tbs_index_alt ? 8 : 6; - max_coderate = srslte_cqi_to_coderate(std::min(cell.dl_cqi + 1u, 15u), cell.get_ue_cfg()->use_tbs_index_alt); - } - - // function with sign-flip at solution - auto test_mcs = [&](int sel_mcs) -> float { - return diff_coderate_maxcoderate( - sel_mcs, nof_prb, nof_re, max_Qm, max_coderate, cell.get_ue_cfg()->use_tbs_index_alt, is_ul); - }; - - std::tuple ret; - if (nof_prb > 1) { - // for non-voip case - ret = false_position_method(0, max_mcs, 0.0f, test_mcs); - } else { - // avoid 6 prbs (voip case), where function is not monotonic - ret = false_position_method(7, max_mcs, 0.0f, test_mcs); - if (std::get<1>(ret) > 0) { - ret = false_position_method(0, 5, 0.0f, test_mcs); - } - } - tbs_info ret2; - ret2.mcs = std::get<0>(ret); - ret2.tbs_bytes = get_tbs_bytes(ret2.mcs, nof_prb, cell.get_ue_cfg()->use_tbs_index_alt, is_ul); - - // If coderate > SRSLTE_MIN(max_coderate, 0.930 * 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 - - return ret2; -} - -/* In this scheduler we tend to use all the available bandwidth and select the MCS - * that approximates the minimum between the capacity and the requested rate - */ -tbs_info alloc_tbs(const sched_ue_cell& cell, uint32_t nof_prb, uint32_t nof_re, uint32_t req_bytes, bool is_ul) -{ - // TODO: Compute real spectral efficiency based on PUSCH-UCI configuration - tbs_info ret = cqi_to_tbs(cell, nof_prb, nof_re, is_ul); - - /* If less bytes are requested, lower the MCS */ - if (ret.tbs_bytes > (int)req_bytes && req_bytes > 0) { - int req_tbs_idx = srslte_ra_tbs_to_table_idx(req_bytes * 8, nof_prb); - int req_mcs = srslte_ra_mcs_from_tbs_idx(req_tbs_idx, cell.get_ue_cfg()->use_tbs_index_alt, is_ul); - while (cell.get_ue_cfg()->use_tbs_index_alt and req_mcs < 0 and req_tbs_idx < 33) { - // some tbs_idx are invalid for 256QAM. See TS 36.213 - Table 7.1.7.1-1A - req_mcs = srslte_ra_mcs_from_tbs_idx(++req_tbs_idx, cell.get_ue_cfg()->use_tbs_index_alt, is_ul); - } - - if (req_mcs >= 0 and req_mcs < (int)ret.mcs) { - uint32_t max_Qm = - (is_ul) ? (cell.get_ue_cfg()->support_ul64qam == sched_interface::ue_cfg_t::ul64qam_cap::enabled ? 6 : 4) - : (cell.get_ue_cfg()->use_tbs_index_alt ? 8 : 6); - float max_coderate = - (is_ul) ? srslte_cqi_to_coderate(std::min(cell.ul_cqi + 1u, 15u), false) - : srslte_cqi_to_coderate(std::min(cell.dl_cqi + 1u, 15u), cell.get_ue_cfg()->use_tbs_index_alt); - if (diff_coderate_maxcoderate( - req_mcs, nof_prb, nof_re, max_Qm, max_coderate, cell.get_ue_cfg()->use_tbs_index_alt, is_ul) < 0) { - ret.mcs = req_mcs; - ret.tbs_bytes = srslte_ra_tbs_from_idx(req_tbs_idx, nof_prb) / 8; - } - } - } - // Avoid the unusual case n_prb=1, mcs=6 tbs=328 (used in voip) - if (nof_prb == 1 && ret.mcs == 6) { - ret.mcs--; - ret.tbs_bytes = get_tbs_bytes(ret.mcs, nof_prb, cell.get_ue_cfg()->use_tbs_index_alt, is_ul); - } - - return ret; -} - -tbs_info alloc_tbs_dl(const sched_ue_cell& cell, uint32_t nof_prb, uint32_t nof_re, uint32_t req_bytes) -{ tbs_info ret; - - // Use a higher MCS for the Msg4 to fit in the 6 PRB case if (cell.fixed_mcs_dl < 0 or not cell.dl_cqi_rx) { // Dynamic MCS - ret = alloc_tbs(cell, nof_prb, nof_re, req_bytes, false); + ret = compute_min_mcs_and_tbs_from_required_bytes( + nof_prb, nof_re, cell.dl_cqi, cell.max_mcs_dl, req_bytes, false, false, use_tbs_index_alt); + + // If coderate > SRSLTE_MIN(max_coderate, 0.930 * 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 + if (ret.tbs_bytes < 0) { + ret.mcs = 0; + ret.tbs_bytes = get_tbs_bytes((uint32_t)ret.mcs, nof_prb, use_tbs_index_alt, false); + } } else { // Fixed MCS ret.mcs = cell.fixed_mcs_dl; - ret.tbs_bytes = get_tbs_bytes((uint32_t)cell.fixed_mcs_dl, nof_prb, cell.get_ue_cfg()->use_tbs_index_alt, false); + ret.tbs_bytes = get_tbs_bytes((uint32_t)cell.fixed_mcs_dl, nof_prb, use_tbs_index_alt, false); } return ret; } -tbs_info -alloc_tbs_ul(const sched_ue_cell& cell, uint32_t nof_prb, uint32_t nof_re, uint32_t req_bytes, int explicit_mcs) +tbs_info cqi_to_tbs_ul(const sched_ue_cell& cell, uint32_t nof_prb, uint32_t nof_re, int req_bytes, int explicit_mcs) { - tbs_info ret; - int mcs = explicit_mcs >= 0 ? explicit_mcs : cell.fixed_mcs_ul; + using ul64qam_cap = sched_interface::ue_cfg_t::ul64qam_cap; + int mcs = explicit_mcs >= 0 ? explicit_mcs : cell.fixed_mcs_ul; + bool ulqam64_enabled = cell.get_ue_cfg()->support_ul64qam == ul64qam_cap::enabled; + tbs_info ret; if (mcs < 0) { // Dynamic MCS - ret = alloc_tbs(cell, nof_prb, nof_re, req_bytes, true); + 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); + + // If coderate > SRSLTE_MIN(max_coderate, 0.930 * 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 + if (ret.tbs_bytes < 0) { + ret.mcs = 0; + ret.tbs_bytes = get_tbs_bytes((uint32_t)ret.mcs, nof_prb, false, true); + } } else { // Fixed MCS ret.mcs = mcs; @@ -362,11 +285,14 @@ alloc_tbs_ul(const sched_ue_cell& cell, uint32_t nof_prb, uint32_t nof_re, uint3 return ret; } -int get_required_prb_dl(const sched_ue_cell& cell, tti_point tti_tx_dl, uint32_t req_bytes) +int get_required_prb_dl(const sched_ue_cell& cell, + tti_point tti_tx_dl, + srslte_dci_format_t dci_format, + uint32_t req_bytes) { - auto compute_tbs_approx = [tti_tx_dl, &cell](uint32_t nof_prb) { + auto compute_tbs_approx = [tti_tx_dl, &cell, dci_format](uint32_t nof_prb) { uint32_t nof_re = cell.cell_cfg->get_dl_lb_nof_re(tti_tx_dl, nof_prb); - tbs_info tb = alloc_tbs_dl(cell, nof_prb, nof_re, 0); + tbs_info tb = cqi_to_tbs_dl(cell, nof_prb, nof_re, dci_format, -1); return tb.tbs_bytes; }; @@ -385,7 +311,7 @@ uint32_t get_required_prb_ul(const sched_ue_cell& cell, uint32_t req_bytes) auto compute_tbs_approx = [&cell](uint32_t nof_prb) { const uint32_t N_srs = 0; uint32_t nof_re = (2 * (SRSLTE_CP_NSYMB(cell.cell_cfg->cfg.cell.cp) - 1) - N_srs) * nof_prb * SRSLTE_NRE; - return alloc_tbs_ul(cell, nof_prb, nof_re, 0).tbs_bytes; + return cqi_to_tbs_ul(cell, nof_prb, nof_re, -1).tbs_bytes; }; // find nof prbs that lead to a tbs just above req_bytes diff --git a/srsenb/src/stack/mac/schedulers/sched_time_pf.cc b/srsenb/src/stack/mac/schedulers/sched_time_pf.cc index 16d546bb6..d1ee2f7ad 100644 --- a/srsenb/src/stack/mac/schedulers/sched_time_pf.cc +++ b/srsenb/src/stack/mac/schedulers/sched_time_pf.cc @@ -97,7 +97,7 @@ uint32_t sched_time_pf::try_dl_alloc(ue_ctxt& ue_ctxt, sched_ue& ue, sf_sched* t } } if (code == alloc_outcome_t::DCI_COLLISION) { - logger.info("SCHED: Couldn't find space in PDCCH for DL tx for rnti=0x%x", ue.get_rnti()); + logger.info("SCHED: Couldn't find space in PDCCH/PUCCH for DL tx for rnti=0x%x", ue.get_rnti()); } return 0; } diff --git a/srsenb/src/stack/mac/schedulers/sched_time_rr.cc b/srsenb/src/stack/mac/schedulers/sched_time_rr.cc index 702ea1e21..022db540d 100644 --- a/srsenb/src/stack/mac/schedulers/sched_time_rr.cc +++ b/srsenb/src/stack/mac/schedulers/sched_time_rr.cc @@ -61,7 +61,7 @@ void sched_time_rr::sched_dl_retxs(sched_ue_list& ue_db, sf_sched* tti_sched, si } alloc_outcome_t code = try_dl_retx_alloc(*tti_sched, user, *h); if (code == alloc_outcome_t::DCI_COLLISION) { - logger.info("SCHED: Couldn't find space in PDCCH for DL retx for rnti=0x%x", user.get_rnti()); + logger.info("SCHED: Couldn't find space in PDCCH/PUCCH for DL retx for rnti=0x%x", user.get_rnti()); } } } @@ -84,7 +84,7 @@ void sched_time_rr::sched_dl_newtxs(sched_ue_list& ue_db, sf_sched* tti_sched, s continue; } if (try_dl_newtx_alloc_greedy(*tti_sched, user, *h) == alloc_outcome_t::DCI_COLLISION) { - logger.info("SCHED: Couldn't find space in PDCCH for DL tx for rnti=0x%x", user.get_rnti()); + logger.info("SCHED: Couldn't find space in PDCCH/PUCCH for DL tx for rnti=0x%x", user.get_rnti()); } } } diff --git a/srsenb/src/stack/mac/ue.cc b/srsenb/src/stack/mac/ue.cc index eaa14c482..8127e3073 100644 --- a/srsenb/src/stack/mac/ue.cc +++ b/srsenb/src/stack/mac/ue.cc @@ -25,13 +25,80 @@ #include #include "srsenb/hdr/stack/mac/ue.h" -#include "srslte/common/log_helper.h" #include "srslte/interfaces/enb_phy_interfaces.h" #include "srslte/interfaces/enb_rlc_interfaces.h" #include "srslte/interfaces/enb_rrc_interfaces.h" namespace srsenb { +cc_buffer_handler::cc_buffer_handler() +{ + for (auto& harq_buffers : tx_payload_buffer) { + for (srslte::unique_byte_buffer_t& tb_buffer : harq_buffers) { + tb_buffer = srslte::make_byte_buffer(); + if (tb_buffer == nullptr) { + srslog::fetch_basic_logger("MAC").error("Failed to allocate HARQ buffers for UE"); + return; + } + } + } +} + +cc_buffer_handler::~cc_buffer_handler() +{ + deallocate_cc(); +} + +/** + * Allocate and initialize softbuffers for Tx and Rx. It uses the configured + * number of HARQ processes and cell width. + * + * @param num_cc Number of carriers to add buffers for (default 1) + * @return number of carriers + */ +void cc_buffer_handler::allocate_cc(uint32_t nof_prb_, uint32_t nof_rx_harq_proc_, uint32_t nof_tx_harq_proc_) +{ + assert(empty()); + nof_prb = nof_prb_; + nof_rx_harq_proc = nof_rx_harq_proc_; + nof_tx_harq_proc = nof_tx_harq_proc_; + + // Create and init Rx buffers + softbuffer_rx_list.resize(nof_rx_harq_proc); + for (srslte_softbuffer_rx_t& buffer : softbuffer_rx_list) { + srslte_softbuffer_rx_init(&buffer, nof_prb); + } + + // Create and init Tx buffers + softbuffer_tx_list.resize(nof_tx_harq_proc * SRSLTE_MAX_TB); + for (auto& buffer : softbuffer_tx_list) { + srslte_softbuffer_tx_init(&buffer, nof_prb); + } +} + +void cc_buffer_handler::deallocate_cc() +{ + for (auto& buffer : softbuffer_rx_list) { + srslte_softbuffer_rx_free(&buffer); + } + softbuffer_rx_list.clear(); + + for (auto& buffer : softbuffer_tx_list) { + srslte_softbuffer_tx_free(&buffer); + } + softbuffer_tx_list.clear(); +} + +void cc_buffer_handler::reset() +{ + for (auto& buffer : softbuffer_rx_list) { + srslte_softbuffer_rx_reset(&buffer); + } + for (auto& buffer : softbuffer_tx_list) { + srslte_softbuffer_tx_reset(&buffer); + } +} + ue::ue(uint16_t rnti_, uint32_t nof_prb_, sched_interface* sched_, @@ -57,45 +124,24 @@ ue::ue(uint16_t rnti_, pdus(logger, 128), nof_rx_harq_proc(nof_rx_harq_proc_), nof_tx_harq_proc(nof_tx_harq_proc_), - rx_used_buffers(nof_cells_), - ta_fsm(this) + ta_fsm(this), + cc_buffers(nof_cells_) { - tx_payload_buffer.resize(nof_cells_); - for (auto& carrier_buffers : tx_payload_buffer) { - for (auto& harq_buffers : carrier_buffers) { - for (srslte::unique_byte_buffer_t& tb_buffer : harq_buffers) { - tb_buffer = srslte::make_byte_buffer(); - } - } - } - pdus.init(this); // Allocate buffer for PCell - allocate_cc_buffers(); + cc_buffers[0].allocate_cc(nof_prb, nof_rx_harq_proc, nof_tx_harq_proc); } ue::~ue() { - // Free up all softbuffers for all CCs - for (auto cc : softbuffer_rx) { - for (auto buffer : cc) { - srslte_softbuffer_rx_free(&buffer); - } - } - - for (auto cc : softbuffer_tx) { - for (auto buffer : cc) { - srslte_softbuffer_tx_free(&buffer); - } - } { std::unique_lock lock(rx_buffers_mutex); - for (auto& rx_buffers_cc : rx_used_buffers) { - for (auto& q : rx_buffers_cc) { + for (auto& cc : cc_buffers) { + for (auto& q : cc.get_rx_used_buffers()) { pdus.deallocate(q.second); } - rx_buffers_cc.clear(); + cc.get_rx_used_buffers().clear(); } } } @@ -105,46 +151,14 @@ void ue::reset() ue_metrics = {}; nof_failures = 0; - for (auto cc : softbuffer_rx) { - for (auto buffer : cc) { - srslte_softbuffer_rx_reset(&buffer); - } - } - - for (auto cc : softbuffer_tx) { - for (auto buffer : cc) { - srslte_softbuffer_tx_reset(&buffer); - } + for (auto& cc : cc_buffers) { + cc.reset(); } } -/** - * Allocate and initialize softbuffers for Tx and Rx and - * append to current list of CC buffers. It uses the configured - * number of HARQ processes and cell width. - * - * @param num_cc Number of carriers to add buffers for (default 1) - * @return number of carriers - */ -uint32_t ue::allocate_cc_buffers(const uint32_t num_cc) +void ue::start_pcap_net(srslte::mac_pcap_net* pcap_net_) { - for (uint32_t i = 0; i < num_cc; ++i) { - // create and init Rx buffers for Pcell - softbuffer_rx.emplace_back(); - softbuffer_rx.back().resize(nof_rx_harq_proc); - for (auto& buffer : softbuffer_rx.back()) { - srslte_softbuffer_rx_init(&buffer, nof_prb); - } - - // Create and init Tx buffers for Pcell - softbuffer_tx.emplace_back(); - softbuffer_tx.back().resize(nof_tx_harq_proc); - for (auto& buffer : softbuffer_tx.back()) { - srslte_softbuffer_tx_init(&buffer, nof_prb); - } - // don't need to reset because just initiated the buffers - } - return softbuffer_tx.size(); + pcap_net = pcap_net_; } void ue::start_pcap(srslte::mac_pcap* pcap_) @@ -154,33 +168,23 @@ void ue::start_pcap(srslte::mac_pcap* pcap_) srslte_softbuffer_rx_t* ue::get_rx_softbuffer(const uint32_t ue_cc_idx, const uint32_t tti) { - if ((size_t)ue_cc_idx >= softbuffer_rx.size()) { - ERROR("UE CC Index (%d/%zd) out-of-range", ue_cc_idx, softbuffer_rx.size()); + if ((size_t)ue_cc_idx >= cc_buffers.size()) { + ERROR("UE CC Index (%d/%zd) out-of-range", ue_cc_idx, cc_buffers.size()); return nullptr; } - if ((size_t)nof_rx_harq_proc > softbuffer_rx.at(ue_cc_idx).size()) { - ERROR("HARQ process index (%d/%zd) out-of-range", nof_rx_harq_proc, softbuffer_rx.at(ue_cc_idx).size()); - return nullptr; - } - - return &softbuffer_rx.at(ue_cc_idx).at(tti % nof_rx_harq_proc); + return &cc_buffers.at(ue_cc_idx).get_rx_softbuffer(tti % nof_rx_harq_proc); } srslte_softbuffer_tx_t* ue::get_tx_softbuffer(const uint32_t ue_cc_idx, const uint32_t harq_process, const uint32_t tb_idx) { - if ((size_t)ue_cc_idx >= softbuffer_tx.size()) { - ERROR("UE CC Index (%d/%zd) out-of-range", ue_cc_idx, softbuffer_tx.size()); + if ((size_t)ue_cc_idx >= cc_buffers.size()) { + ERROR("UE CC Index (%d/%zd) out-of-range", ue_cc_idx, cc_buffers.size()); return nullptr; } - if ((size_t)nof_tx_harq_proc > softbuffer_tx.at(ue_cc_idx).size()) { - ERROR("HARQ process index (%d/%zd) out-of-range", harq_process, softbuffer_tx.at(ue_cc_idx).size()); - return nullptr; - } - - return &softbuffer_tx.at(ue_cc_idx).at((harq_process * SRSLTE_MAX_TB + tb_idx) % nof_tx_harq_proc); + return &cc_buffers[ue_cc_idx].get_tx_softbuffer(harq_process, tb_idx); } uint8_t* ue::request_buffer(uint32_t tti, uint32_t ue_cc_idx, const uint32_t len) @@ -189,10 +193,10 @@ uint8_t* ue::request_buffer(uint32_t tti, uint32_t ue_cc_idx, const uint32_t len uint8_t* pdu = nullptr; if (len > 0) { // Deallocate oldest buffer if we didn't deallocate it - if (!rx_used_buffers.at(ue_cc_idx).count(tti)) { + if (!cc_buffers.at(ue_cc_idx).get_rx_used_buffers().count(tti)) { pdu = pdus.request(len); if (pdu) { - rx_used_buffers.at(ue_cc_idx).emplace(tti, pdu); + cc_buffers.at(ue_cc_idx).get_rx_used_buffers().emplace(tti, pdu); } else { logger.error("UE buffers: Requesting buffer from pool"); } @@ -210,7 +214,8 @@ void ue::clear_old_buffers(uint32_t tti) std::unique_lock lock(rx_buffers_mutex); // remove old buffers - for (auto& rx_buffer_cc : rx_used_buffers) { + for (auto& cc : cc_buffers) { + auto& rx_buffer_cc = cc.get_rx_used_buffers(); for (auto it = rx_buffer_cc.begin(); it != rx_buffer_cc.end();) { if (srslte_tti_interval(tti, it->first) > 20 && srslte_tti_interval(tti, it->first) < 500) { logger.warning("UE buffers: Removing old buffer tti=%d, rnti=%d, now is %d, interval=%d", @@ -253,8 +258,6 @@ uint32_t ue::set_ta(int ta_) return nof_cmd; } -#include - void ue::process_pdu(uint8_t* pdu, uint32_t nof_bytes, srslte::pdu_queue::channel_t channel) { // Unpack ULSCH MAC PDU @@ -267,6 +270,10 @@ void ue::process_pdu(uint8_t* pdu, uint32_t nof_bytes, srslte::pdu_queue::channe pcap->write_ul_crnti(pdu, nof_bytes, 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); + } + pdus.deallocate(pdu); uint32_t lcid_most_data = 0; @@ -353,9 +360,9 @@ void ue::deallocate_pdu(uint32_t tti, uint32_t ue_cc_idx) { std::unique_lock lock(rx_buffers_mutex); - if (rx_used_buffers.at(ue_cc_idx).count(tti)) { - pdus.deallocate(rx_used_buffers.at(ue_cc_idx).at(tti)); - rx_used_buffers.at(ue_cc_idx).erase(tti); + if (cc_buffers.at(ue_cc_idx).get_rx_used_buffers().count(tti)) { + pdus.deallocate(cc_buffers.at(ue_cc_idx).get_rx_used_buffers().at(tti)); + cc_buffers.at(ue_cc_idx).get_rx_used_buffers().erase(tti); } else { logger.warning("UE buffers: Null RX PDU pointer in deallocate_pdu for rnti=0x%x pid=%d cc_idx=%d", rnti, @@ -367,13 +374,13 @@ 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) { std::unique_lock lock(rx_buffers_mutex); - if (rx_used_buffers.at(ue_cc_idx).count(tti)) { + if (cc_buffers.at(ue_cc_idx).get_rx_used_buffers().count(tti)) { if (len > 0) { - pdus.push(rx_used_buffers.at(ue_cc_idx).at(tti), len); + pdus.push(cc_buffers.at(ue_cc_idx).get_rx_used_buffers().at(tti), len); } else { logger.error("Error pushing PDU: null length"); } - rx_used_buffers.at(ue_cc_idx).erase(tti); + cc_buffers.at(ue_cc_idx).get_rx_used_buffers().erase(tti); } else { logger.warning("UE buffers: Null RX PDU pointer in push_pdu for rnti=0x%x pid=%d cc_idx=%d", rnti, @@ -491,7 +498,11 @@ void ue::allocate_ce(srslte::sch_pdu* pdu, uint32_t lcid) if (pdu->get()->set_scell_activation_cmd(active_scell_list)) { phy->set_activation_deactivation_scell(rnti, active_scell_list); // Allocate and initialize Rx/Tx softbuffers for new carriers (exclude PCell) - allocate_cc_buffers(active_scell_list.size() - 1); + for (size_t i = 0; i < std::min(active_scell_list.size(), cc_buffers.size()); ++i) { + if (active_scell_list[i] and cc_buffers[i].empty()) { + cc_buffers[i].allocate_cc(nof_prb, nof_rx_harq_proc, nof_tx_harq_proc); + } + } } else { logger.error("CE: Setting SCell Activation CE"); } @@ -505,19 +516,20 @@ void ue::allocate_ce(srslte::sch_pdu* pdu, uint32_t lcid) } } -uint8_t* ue::generate_pdu(uint32_t ue_cc_idx, - uint32_t harq_pid, - uint32_t tb_idx, - sched_interface::dl_sched_pdu_t pdu[sched_interface::MAX_RLC_PDU_LIST], - uint32_t nof_pdu_elems, - uint32_t grant_size) +uint8_t* ue::generate_pdu(uint32_t ue_cc_idx, + uint32_t harq_pid, + uint32_t tb_idx, + const sched_interface::dl_sched_pdu_t pdu[sched_interface::MAX_RLC_PDU_LIST], + uint32_t nof_pdu_elems, + uint32_t grant_size) { std::lock_guard lock(mutex); uint8_t* ret = nullptr; if (rlc) { if (ue_cc_idx < SRSLTE_MAX_CARRIERS && harq_pid < SRSLTE_FDD_NOF_HARQ && tb_idx < SRSLTE_MAX_TB) { - tx_payload_buffer[ue_cc_idx][harq_pid][tb_idx]->clear(); - mac_msg_dl.init_tx(tx_payload_buffer[ue_cc_idx][harq_pid][tb_idx].get(), grant_size, false); + srslte::byte_buffer_t* buffer = cc_buffers[ue_cc_idx].get_tx_payload_buffer(harq_pid, tb_idx); + buffer->clear(); + mac_msg_dl.init_tx(buffer, grant_size, false); for (uint32_t i = 0; i < nof_pdu_elems; i++) { if (pdu[i].lcid <= (uint32_t)srslte::ul_sch_lcid::PHR_REPORT) { allocate_sdu(&mac_msg_dl, pdu[i].lcid, pdu[i].nbytes); @@ -538,25 +550,26 @@ uint8_t* ue::generate_pdu(uint32_t ue_cc_idx, } uint8_t* ue::generate_mch_pdu(uint32_t harq_pid, - sched_interface::dl_pdu_mch_t sched, + sched_interface::dl_pdu_mch_t sched_, uint32_t nof_pdu_elems, uint32_t grant_size) { std::lock_guard lock(mutex); - uint8_t* ret = nullptr; - tx_payload_buffer[0][harq_pid][0]->clear(); - mch_mac_msg_dl.init_tx(tx_payload_buffer[0][harq_pid][0].get(), grant_size); + uint8_t* ret = nullptr; + srslte::byte_buffer_t* buffer = cc_buffers[0].get_tx_payload_buffer(harq_pid, 0); + buffer->clear(); + mch_mac_msg_dl.init_tx(buffer, grant_size); for (uint32_t i = 0; i < nof_pdu_elems; i++) { - if (sched.pdu[i].lcid == (uint32_t)srslte::mch_lcid::MCH_SCHED_INFO) { + if (sched_.pdu[i].lcid == (uint32_t)srslte::mch_lcid::MCH_SCHED_INFO) { mch_mac_msg_dl.new_subh(); - mch_mac_msg_dl.get()->set_next_mch_sched_info(sched.mtch_sched[i].lcid, sched.mtch_sched[i].stop); - } else if (sched.pdu[i].lcid == 0) { + mch_mac_msg_dl.get()->set_next_mch_sched_info(sched_.mtch_sched[i].lcid, sched_.mtch_sched[i].stop); + } else if (sched_.pdu[i].lcid == 0) { mch_mac_msg_dl.new_subh(); - mch_mac_msg_dl.get()->set_sdu(0, sched.pdu[i].nbytes, sched.mcch_payload); - } else if (sched.pdu[i].lcid <= (uint32_t)srslte::mch_lcid::MTCH_MAX_LCID) { + mch_mac_msg_dl.get()->set_sdu(0, sched_.pdu[i].nbytes, sched_.mcch_payload); + } else if (sched_.pdu[i].lcid <= (uint32_t)srslte::mch_lcid::MTCH_MAX_LCID) { mch_mac_msg_dl.new_subh(); - mch_mac_msg_dl.get()->set_sdu(sched.pdu[i].lcid, sched.pdu[i].nbytes, sched.mtch_sched[i].mtch_payload); + mch_mac_msg_dl.get()->set_sdu(sched_.pdu[i].lcid, sched_.pdu[i].nbytes, sched_.mtch_sched[i].mtch_payload); } } diff --git a/srsenb/src/stack/rrc/rrc.cc b/srsenb/src/stack/rrc/rrc.cc index e2ae401df..8fc404a7c 100644 --- a/srsenb/src/stack/rrc/rrc.cc +++ b/srsenb/src/stack/rrc/rrc.cc @@ -30,7 +30,6 @@ #include "srslte/interfaces/enb_pdcp_interfaces.h" #include "srslte/interfaces/enb_rlc_interfaces.h" #include "srslte/interfaces/sched_interface.h" -#include "srslte/srslte.h" using srslte::byte_buffer_t; using srslte::uint32_to_uint8; @@ -151,7 +150,11 @@ uint32_t rrc::get_nof_users() return users.size(); } -void rrc::max_retx_attempted(uint16_t rnti) {} +void rrc::max_retx_attempted(uint16_t rnti) +{ + rrc_pdu p = {rnti, LCID_RTX_USER, nullptr}; + rx_pdu_queue.push(std::move(p)); +} // 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) @@ -165,9 +168,6 @@ int rrc::add_user(uint16_t rnti, const sched_interface::ue_cfg_t& sched_ue_cfg) logger.error("Adding user rnti=0x%x - Failed to allocate user resources", rnti); return SRSLTE_ERROR; } - if (ue_pool.capacity() <= 4) { - task_sched.defer_task([]() { rrc::ue_pool.reserve(16); }); - } users.insert(std::make_pair(rnti, std::move(u))); } rlc->add_user(rnti); @@ -202,18 +202,48 @@ void rrc::upd_user(uint16_t new_rnti, uint16_t old_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()) { - auto ue_ptr = old_it->second.get(); - if (ue_ptr->mobility_handler->is_ho_running()) { - ue_ptr->mobility_handler->trigger(ue::rrc_mobility::user_crnti_upd_ev{old_rnti, new_rnti}); - } else if (ue_ptr->is_connected()) { + if (old_it == users.end()) { + send_rrc_connection_reject(old_rnti); + return; + } + ue* ue_ptr = old_it->second.get(); + + if (ue_ptr->mobility_handler->is_ho_running()) { + ue_ptr->mobility_handler->trigger(ue::rrc_mobility::user_crnti_upd_ev{old_rnti, new_rnti}); + } else { + logger.info("Resuming rnti=0x%x RRC connection due to received C-RNTI CE from rnti=0x%x.", old_rnti, new_rnti); + if (ue_ptr->is_connected()) { + // Send a new RRC Reconfiguration to overlay previous old_it->second->send_connection_reconf(); - } else { - old_it->second->send_connection_reject(); } } } +// Note: this method is not part of UE methods, because the UE context may not exist anymore when reject is sent +void rrc::send_rrc_connection_reject(uint16_t rnti) +{ + dl_ccch_msg_s dl_ccch_msg; + dl_ccch_msg.msg.set_c1().set_rrc_conn_reject().crit_exts.set_c1().set_rrc_conn_reject_r8().wait_time = 10; + + // Allocate a new PDU buffer, pack the message and send to PDCP + srslte::unique_byte_buffer_t pdu = srslte::make_byte_buffer(); + if (pdu == nullptr) { + logger.error("Allocating pdu"); + return; + } + asn1::bit_ref bref(pdu->msg, pdu->get_tailroom()); + if (dl_ccch_msg.pack(bref) != asn1::SRSASN_SUCCESS) { + logger.error(pdu->msg, bref.distance_bytes(), "Failed to pack DL-CCCH-Msg:"); + return; + } + pdu->N_bytes = bref.distance_bytes(); + + char buf[32] = {}; + sprintf(buf, "SRB0 - rnti=0x%x", rnti); + log_rrc_message(buf, Tx, pdu.get(), dl_ccch_msg, dl_ccch_msg.msg.c1().type().to_string()); + rlc->write_sdu(rnti, RB_ID_SRB0, std::move(pdu)); +} + /******************************************************************************* PDCP interface *******************************************************************************/ @@ -690,6 +720,10 @@ void rrc::config_mac() item.initial_dl_cqi = cfg.cell_list[ccidx].initial_dl_cqi; item.target_ul_sinr = cfg.cell_list[ccidx].target_ul_sinr_db; item.enable_phr_handling = cfg.cell_list[ccidx].enable_phr_handling; + 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; + item.nrb_cqi = cfg.sibs[1].sib2().rr_cfg_common.pucch_cfg_common.nrb_cqi; item.nrb_pucch = SRSLTE_MAX(cfg.sr_cfg.nof_prb, cfg.cqi_cfg.nof_prb); logger.info("Allocating %d PRBs for PUCCH", item.nrb_pucch); @@ -969,6 +1003,9 @@ void rrc::tti_clock() case LCID_ACT_USER: user_it->second->set_activity(); break; + case LCID_RTX_USER: + user_it->second->max_retx_reached(); + break; case LCID_EXIT: logger.info("Exiting thread"); break; diff --git a/srsenb/src/stack/rrc/rrc_bearer_cfg.cc b/srsenb/src/stack/rrc/rrc_bearer_cfg.cc index 23628b6cd..98bc37828 100644 --- a/srsenb/src/stack/rrc/rrc_bearer_cfg.cc +++ b/srsenb/src/stack/rrc/rrc_bearer_cfg.cc @@ -210,7 +210,7 @@ void security_cfg_handler::regenerate_keys_handover(uint32_t new_pci, uint32_t n ****************************/ bearer_cfg_handler::bearer_cfg_handler(uint16_t rnti_, const rrc_cfg_t& cfg_, gtpu_interface_rrc* gtpu_) : - rnti(rnti_), cfg(&cfg_), gtpu(gtpu_), logger(srslog::fetch_basic_logger("RRC")) + rnti(rnti_), cfg(&cfg_), gtpu(gtpu_), logger(&srslog::fetch_basic_logger("RRC")) {} int bearer_cfg_handler::add_erab(uint8_t erab_id, @@ -220,7 +220,7 @@ int bearer_cfg_handler::add_erab(uint8_t const asn1::unbounded_octstring* nas_pdu) { if (erab_id < 5) { - logger.error("ERAB id=%d is invalid", erab_id); + logger->error("ERAB id=%d is invalid", erab_id); return SRSLTE_ERROR; } uint8_t lcid = erab_id - 2; // Map e.g. E-RAB 5 to LCID 3 (==DRB1) @@ -228,11 +228,11 @@ int bearer_cfg_handler::add_erab(uint8_t auto qci_it = cfg->qci_cfg.find(qos.qci); if (qci_it == cfg->qci_cfg.end() or not qci_it->second.configured) { - logger.error("QCI=%d not configured", qos.qci); + logger->error("QCI=%d not configured", qos.qci); return SRSLTE_ERROR; } if (lcid < 3 or lcid > 10) { - logger.error("DRB logical channel ids must be within 3 and 10"); + logger->error("DRB logical channel ids must be within 3 and 10"); return SRSLTE_ERROR; } const rrc_cfg_qci_t& qci_cfg = qci_it->second; @@ -243,13 +243,13 @@ int bearer_cfg_handler::add_erab(uint8_t erabs[erab_id].teid_out = teid_out; if (addr.length() > 32) { - logger.error("Only addresses with length <= 32 are supported"); + logger->error("Only addresses with length <= 32 are supported"); return SRSLTE_ERROR; } if (nas_pdu != nullptr and nas_pdu->size() > 0) { erab_info_list[erab_id].assign(nas_pdu->data(), nas_pdu->data() + nas_pdu->size()); - logger.info( + logger->info( &erab_info_list[erab_id][0], erab_info_list[erab_id].size(), "setup_erab nas_pdu -> erab_info rnti 0x%x", rnti); } @@ -275,7 +275,7 @@ bool bearer_cfg_handler::release_erab(uint8_t erab_id) { auto it = erabs.find(erab_id); if (it == erabs.end()) { - logger.warning("The user rnti=0x%x does not contain ERAB-ID=%d", rnti, erab_id); + logger->warning("The user rnti=0x%x does not contain ERAB-ID=%d", rnti, erab_id); return false; } @@ -302,10 +302,10 @@ bool bearer_cfg_handler::modify_erab(uint8_t const asn1::s1ap::erab_level_qos_params_s& qos, const asn1::unbounded_octstring* nas_pdu) { - logger.info("Modifying E-RAB %d", erab_id); + logger->info("Modifying E-RAB %d", erab_id); std::map::iterator erab_it = erabs.find(erab_id); if (erab_it == erabs.end()) { - logger.error("Could not find E-RAB to modify"); + logger->error("Could not find E-RAB to modify"); return false; } auto address = erab_it->second.address; @@ -319,7 +319,7 @@ void bearer_cfg_handler::add_gtpu_bearer(uint32_t erab_id) { auto it = erabs.find(erab_id); if (it == erabs.end()) { - logger.error("Adding erab_id=%d to GTPU", erab_id); + logger->error("Adding erab_id=%d to GTPU", erab_id); return; } it->second.teid_in = add_gtpu_bearer(erab_id, it->second.teid_out, it->second.address.to_number(), nullptr); @@ -332,7 +332,7 @@ uint32_t bearer_cfg_handler::add_gtpu_bearer(uint32_t { auto it = erabs.find(erab_id); if (it == erabs.end()) { - logger.error("Adding erab_id=%d to GTPU", erab_id); + logger->error("Adding erab_id=%d to GTPU", erab_id); return 0; } @@ -353,7 +353,7 @@ void bearer_cfg_handler::rem_gtpu_bearer(uint32_t erab_id) // Map e.g. E-RAB 5 to LCID 3 (==DRB1) gtpu->rem_bearer(rnti, erab_id - 2); } else { - logger.error("Removing erab_id=%d to GTPU\n", erab_id); + logger->error("Removing erab_id=%d to GTPU\n", erab_id); } } @@ -375,12 +375,12 @@ void bearer_cfg_handler::fill_pending_nas_info(asn1::rrc::rrc_conn_recfg_r8_ies_ auto it = erab_info_list.find(erab_id); if (it != erab_info_list.end()) { const std::vector& erab_info = it->second; - logger.info(&erab_info[0], erab_info.size(), "connection_reconf erab_info -> nas_info rnti 0x%x", rnti); + logger->info(&erab_info[0], erab_info.size(), "connection_reconf erab_info -> nas_info rnti 0x%x", rnti); msg->ded_info_nas_list[idx].resize(erab_info.size()); memcpy(msg->ded_info_nas_list[idx].data(), &erab_info[0], erab_info.size()); erab_info_list.erase(it); } else { - logger.debug("Not adding NAS message to connection reconfiguration. E-RAB id %d", erab_id); + logger->debug("Not adding NAS message to connection reconfiguration. E-RAB id %d", erab_id); } idx++; } diff --git a/srsenb/src/stack/rrc/rrc_mobility.cc b/srsenb/src/stack/rrc/rrc_mobility.cc index 1372158cb..f996d6e32 100644 --- a/srsenb/src/stack/rrc/rrc_mobility.cc +++ b/srsenb/src/stack/rrc/rrc_mobility.cc @@ -751,7 +751,8 @@ void rrc::ue::rrc_mobility::handle_ho_requested(idle_st& s, const ho_req_rx_ev& // Set admitted E-RABs std::vector admitted_erabs; auto& fwd_tunnels = get_state()->pending_tunnels; - for (auto& erab : rrc_ue->bearer_list.get_erabs()) { + fwd_tunnels.clear(); + for (const auto& erab : rrc_ue->bearer_list.get_erabs()) { admitted_erabs.emplace_back(); asn1::s1ap::erab_admitted_item_s& admitted_erab = admitted_erabs.back(); admitted_erab.erab_id = erab.second.id; @@ -907,7 +908,7 @@ void rrc::ue::rrc_mobility::handle_status_transfer(s1_target_ho_st& s, const sta drb_state.next_pdcp_rx_sn = erab_item.ul_coun_tvalue.pdcp_sn; uint8_t sn_len = srslte::get_pdcp_drb_sn_len(drb_it->pdcp_cfg); uint32_t maximum_pdcp_sn = (1u << sn_len) - 1u; - drb_state.last_submitted_pdcp_rx_sn = std::max(erab_item.ul_coun_tvalue.pdcp_sn - 1u, maximum_pdcp_sn); + drb_state.last_submitted_pdcp_rx_sn = std::min(erab_item.ul_coun_tvalue.pdcp_sn - 1u, maximum_pdcp_sn); logger.info("Setting lcid=%d PDCP state to {Tx SN: %d, Rx SN: %d}", drb_it->lc_ch_id, drb_state.next_pdcp_tx_sn, @@ -915,7 +916,7 @@ void rrc::ue::rrc_mobility::handle_status_transfer(s1_target_ho_st& s, const sta rrc_enb->pdcp->set_bearer_state(rrc_ue->rnti, drb_it->lc_ch_id, drb_state); } - // Enable forwarding of GTPU SDUs to PDCP + // Enable forwarding of GTPU SDUs coming from Source eNB Tunnel to PDCP for (uint32_t teid : s.pending_tunnels) { rrc_enb->gtpu->set_tunnel_status(teid, true); } diff --git a/srsenb/src/stack/rrc/rrc_ue.cc b/srsenb/src/stack/rrc/rrc_ue.cc index 0a3099489..84f013060 100644 --- a/srsenb/src/stack/rrc/rrc_ue.cc +++ b/srsenb/src/stack/rrc/rrc_ue.cc @@ -74,7 +74,11 @@ int rrc::ue::init() void* rrc::ue::operator new(size_t sz) { assert(sz == sizeof(ue)); - return rrc::ue_pool.allocate_node(sz); + void* memchunk = rrc::ue_pool.allocate_node(sz); + if (ue_pool.capacity() <= 4) { + srslte::get_background_workers().push_task([]() { rrc::ue_pool.reserve(4); }); + } + return memchunk; } void rrc::ue::operator delete(void* ptr)noexcept { @@ -130,6 +134,16 @@ void rrc::ue::activity_timer_expired() state = RRC_STATE_RELEASE_REQUEST; } +void rrc::ue::max_retx_reached() +{ + if (parent) { + parent->logger.info("Max retx reached for rnti=0x%x", rnti); + + // Give UE time to start re-establishment + set_activity_timeout(UE_REESTABLISH_TIMEOUT); + } +} + void rrc::ue::set_activity_timeout(const activity_timeout_type_t type) { uint32_t deadline_s = 0; @@ -145,6 +159,13 @@ void rrc::ue::set_activity_timeout(const activity_timeout_type_t type) deadline_s = parent->cfg.inactivity_timeout_ms / 1000; deadline_ms = parent->cfg.inactivity_timeout_ms % 1000; break; + case UE_REESTABLISH_TIMEOUT: + deadline_ms = static_cast((get_ue_cc_cfg(UE_PCELL_CC_IDX)->sib2.ue_timers_and_consts.t310.to_number()) + + (get_ue_cc_cfg(UE_PCELL_CC_IDX)->sib2.ue_timers_and_consts.t311.to_number()) + + (get_ue_cc_cfg(UE_PCELL_CC_IDX)->sib2.ue_timers_and_consts.n310.to_number())); + deadline_s = deadline_ms / 1000; + deadline_ms = deadline_ms % 1000; + break; default: parent->logger.error("Unknown timeout type %d", type); } @@ -252,7 +273,7 @@ void rrc::ue::parse_ul_dcch(uint32_t lcid, srslte::unique_byte_buffer_t pdu) std::string rrc::ue::to_string(const activity_timeout_type_t& type) { - constexpr static const char* options[] = {"Msg3 reception", "UE response reception", "UE inactivity"}; + constexpr static const char* options[] = {"Msg3 reception", "UE inactivity", "UE reestablishment"}; return srslte::enum_to_text(options, (uint32_t)activity_timeout_type_t::nulltype, (uint32_t)type); } @@ -504,10 +525,7 @@ void rrc::ue::handle_rrc_con_reest_complete(rrc_conn_reest_complete_s* msg, srsl parent->pdcp->enable_encryption(rnti, RB_ID_SRB1); // Reestablish current DRBs during ConnectionReconfiguration - for (const auto& erab_pair : parent->users.at(old_reest_rnti)->bearer_list.get_erabs()) { - const bearer_cfg_handler::erab_t& erab = erab_pair.second; - bearer_list.add_erab(erab.id, erab.qos_params, erab.address, erab.teid_out, nullptr); - } + bearer_list = std::move(parent->users.at(old_reest_rnti)->bearer_list); // remove old RNTI parent->rem_user_thread(old_reest_rnti); diff --git a/srsenb/src/stack/upper/gtpu.cc b/srsenb/src/stack/upper/gtpu.cc index d23902679..47c7c24b3 100644 --- a/srsenb/src/stack/upper/gtpu.cc +++ b/srsenb/src/stack/upper/gtpu.cc @@ -151,22 +151,23 @@ void gtpu::send_pdu_to_tunnel(tunnel& tx_tun, srslte::unique_byte_buffer_t pdu, uint32_t gtpu::add_bearer(uint16_t rnti, uint32_t lcid, uint32_t addr, uint32_t teid_out, const bearer_props* props) { // Allocate a TEID for the incoming tunnel - uint32_t teid_in = ++next_teid_in; - tunnel& new_tun = tunnels[teid_in]; - new_tun.teid_in = teid_in; - new_tun.rnti = rnti; - new_tun.lcid = lcid; - new_tun.spgw_addr = addr; - new_tun.teid_out = teid_out; + uint32_t teid_in = ++next_teid_in; + auto insert_ret = tunnels.emplace(teid_in, tunnel{}); + tunnel& new_tun = insert_ret.first->second; + new_tun.teid_in = teid_in; + new_tun.rnti = rnti; + new_tun.lcid = lcid; + new_tun.spgw_addr = addr; + new_tun.teid_out = teid_out; ue_teidin_db[rnti][lcid].push_back(teid_in); - logger.info("Adding bearer for rnti: 0x%x, lcid: %d, addr: 0x%x, teid_out: 0x%x, teid_in: 0x%x", + logger.info("New tunnel teid_in=0x%x, teid_out=0x%x, rnti=0x%x, lcid=%d, addr=%s", + teid_in, + teid_out, rnti, lcid, - addr, - teid_out, - teid_in); + srslte::gtpu_ntoa(htonl(addr)).c_str()); if (props != nullptr) { if (props->flush_before_teidin_present) { @@ -200,6 +201,10 @@ void gtpu::set_tunnel_status(uint32_t teidin, bool dl_active) } tun_it->second.dl_enabled = dl_active; if (dl_active) { + logger.info("Activating GTPU tunnel rnti=0x%x,TEID=%d. %d SDUs currently buffered", + tun_it->second.rnti, + teidin, + tun_it->second.buffer.size()); for (auto& sdu_it : tun_it->second.buffer) { pdcp->write_sdu(tun_it->second.rnti, tun_it->second.lcid, diff --git a/srsenb/test/mac/CMakeLists.txt b/srsenb/test/mac/CMakeLists.txt index 674578f17..45de0240c 100644 --- a/srsenb/test/mac/CMakeLists.txt +++ b/srsenb/test/mac/CMakeLists.txt @@ -19,7 +19,7 @@ # add_library(sched_test_common STATIC sched_test_common.cc sched_common_test_suite.cc sched_ue_ded_test_suite.cc - sched_sim_ue.cc sched_sim_ue.cc) + sched_sim_ue.cc sched_sim_ue.cc) target_link_libraries(sched_test_common srslte_common srslte_mac srsenb_mac) # Scheduler subcomponent testing @@ -66,3 +66,7 @@ add_test(sched_lc_ch_test sched_lc_ch_test) add_executable(sched_tpc_test sched_tpc_test.cc) target_link_libraries(sched_tpc_test srslte_common srslte_mac sched_test_common) add_test(sched_tpc_test sched_tpc_test) + +add_executable(sched_dci_test sched_dci_test.cc) +target_link_libraries(sched_dci_test srslte_common srsenb_mac srslte_mac sched_test_common) +add_test(sched_dci_test sched_dci_test) diff --git a/srsenb/test/mac/sched_common_test_suite.cc b/srsenb/test/mac/sched_common_test_suite.cc index 03342fc3a..57bb0f4ce 100644 --- a/srsenb/test/mac/sched_common_test_suite.cc +++ b/srsenb/test/mac/sched_common_test_suite.cc @@ -20,7 +20,6 @@ */ #include "sched_common_test_suite.h" -#include "lib/include/srslte/phy/phch/prach.h" #include "srslte/common/test_common.h" #include @@ -56,11 +55,13 @@ int test_pusch_collisions(const sf_output_res_t& sf_out, uint32_t enb_cc_idx, co } /* TEST: check collisions in PUCCH */ - bool strict = nof_prb != 6 or (not is_prach_tti_tx_ul); // and not tti_data.ul_pending_msg3_present); - try_ul_fill({0, (uint32_t)cell_params.cfg.nrb_pucch}, "PUCCH", strict); - try_ul_fill({cell_params.cfg.cell.nof_prb - cell_params.cfg.nrb_pucch, (uint32_t)cell_params.cfg.cell.nof_prb}, - "PUCCH", - strict); + bool strict = nof_prb != 6 or (not is_prach_tti_tx_ul); // and not tti_data.ul_pending_msg3_present); + uint32_t pucch_nrb = (cell_params.cfg.nrb_pucch > 0) ? (uint32_t)cell_params.cfg.nrb_pucch : 0; + srslte_pucch_cfg_t pucch_cfg = cell_params.pucch_cfg_common; + pucch_cfg.n_pucch = cell_params.nof_cce_table[SRSLTE_NOF_CFI - 1] - 1 + cell_params.cfg.n1pucch_an; + pucch_nrb = std::max(pucch_nrb, srslte_pucch_m(&pucch_cfg, cell_params.cfg.cell.cp) / 2 + 1); + try_ul_fill({0, pucch_nrb}, "PUCCH", strict); + try_ul_fill({cell_params.cfg.cell.nof_prb - pucch_nrb, (uint32_t)cell_params.cfg.cell.nof_prb}, "PUCCH", strict); /* TEST: check collisions in the UL PUSCH */ for (uint32_t i = 0; i < ul_result.nof_dci_elems; ++i) { diff --git a/srsenb/test/mac/sched_dci_test.cc b/srsenb/test/mac/sched_dci_test.cc new file mode 100644 index 000000000..662ae3b4e --- /dev/null +++ b/srsenb/test/mac/sched_dci_test.cc @@ -0,0 +1,288 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2020 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 "sched_test_utils.h" +#include "srsenb/hdr/stack/mac/sched_common.h" +#include "srsenb/hdr/stack/mac/sched_phy_ch/sched_dci.h" +#include "srslte/common/test_common.h" + +namespace srsenb { + +struct tbs_test_args { + bool verbose = false; + bool is_ul = false; + bool use_tbs_index_alt = false; + bool ul64qam_enabled = false; + uint32_t cqi = 5; + uint32_t max_mcs = 28; + uint32_t prb_grant_size = 1; + int req_bytes = std::numeric_limits::max(); + tti_point tti_tx_dl{0}; + + uint32_t get_max_Qm() const + { + if (is_ul) { + return ul64qam_enabled ? 6 : 4; + } + return use_tbs_index_alt ? 8 : 6; + } + float get_max_coderate() const + { + if (is_ul) { + return srslte_cqi_to_coderate(std::min(cqi + 1u, 15u), false); + } + return srslte_cqi_to_coderate(std::min(cqi + 1u, 15u), use_tbs_index_alt); + } +}; + +bool lower_coderate(tbs_info tb, uint32_t nof_re, const tbs_test_args& args) +{ + float max_coderate = srslte_cqi_to_coderate(std::min(args.cqi + 1u, 15u), args.use_tbs_index_alt); + float coderate = srslte_coderate(tb.tbs_bytes * 8, nof_re); + if (coderate > max_coderate) { + return false; + } + srslte_mod_t mod = + (args.is_ul) ? srslte_ra_ul_mod_from_mcs(tb.mcs) : srslte_ra_dl_mod_from_mcs(tb.mcs, args.use_tbs_index_alt); + float Qm = std::min(args.get_max_Qm(), srslte_mod_bits_x_symbol(mod)); + return coderate <= 0.930f * Qm; +} + +int test_mcs_tbs_dl_helper(const sched_cell_params_t& cell_params, const tbs_test_args& args, tbs_info* result) +{ + srslte_dci_dl_t dci; + dci.format = SRSLTE_DCI_FORMAT1; + dci.alloc_type = SRSLTE_RA_ALLOC_TYPE0; + rbgmask_t rbgmask(cell_params.nof_rbgs); + rbgmask.fill(0, cell_params.nof_prbs_to_rbgs(args.prb_grant_size)); + dci.type0_alloc.rbg_bitmask = (uint32_t)rbgmask.to_uint64(); + uint32_t nof_re = cell_params.get_dl_nof_res(args.tti_tx_dl, dci, 1); + float max_coderate = args.get_max_coderate(); + + if (srslte_coderate(16, nof_re) > max_coderate) { + // no solution is possible + return SRSLTE_SUCCESS; + } + + // Verify MCS, TBS + tbs_info ret = compute_mcs_and_tbs( + args.prb_grant_size, nof_re, args.cqi, args.max_mcs, args.is_ul, args.ul64qam_enabled, args.use_tbs_index_alt); + if (ret.tbs_bytes < 0) { + return SRSLTE_SUCCESS; + } + if (result != nullptr) { + *result = ret; + } + CONDERROR(ret.mcs > (int)args.max_mcs, "Result mcs=%d is higher than stipulated max_mcs=%d", ret.mcs, args.max_mcs); + + // Verify TBS is a valid value in TS tables + uint32_t tbs_idx = srslte_ra_tbs_idx_from_mcs(ret.mcs, args.use_tbs_index_alt, args.is_ul); + int expected_tbs = srslte_ra_tbs_from_idx(tbs_idx, args.prb_grant_size); + CONDERROR(expected_tbs != ret.tbs_bytes * 8, + "The tbs=%d is not valid. For {mcs=%d,tbs_idx=%d,nof_re=%d,nof_prb=%d}, it should have been tbs=%d", + ret.tbs_bytes * 8, + ret.mcs, + tbs_idx, + nof_re, + args.prb_grant_size, + expected_tbs); + + // Verify coderate doesn't surpass maximum + CONDERROR(not lower_coderate(ret, nof_re, args), "Coderate is higher than maximum"); + + // Verify there were no better {mcs,tbs} solutions + tbs_info tb2; + for (tb2.mcs = ret.mcs + 1; tb2.mcs <= (int)args.max_mcs; ++tb2.mcs) { + int tbs_idx2 = srslte_ra_tbs_idx_from_mcs(tb2.mcs, args.use_tbs_index_alt, args.is_ul); + tb2.tbs_bytes = srslte_ra_tbs_from_idx(tbs_idx2, args.prb_grant_size) / 8u; + TESTASSERT(not lower_coderate(tb2, nof_re, args) or (args.prb_grant_size == 1 and tb2.mcs == 6)); + } + + // log results + if (args.verbose) { + printf("input={max_mcs=%d,cqi=%d,nof_prb=%d,nof_re=%d} -> output={mcs=%d, tbs=%d, tbs_index=%d}\n", + args.max_mcs, + args.cqi, + args.prb_grant_size, + nof_re, + ret.mcs, + ret.tbs_bytes * 8, + tbs_idx); + } + + return SRSLTE_SUCCESS; +} + +int test_mcs_lookup_specific() +{ + sched_cell_params_t cell_params = {}; + sched_interface::cell_cfg_t cell_cfg = generate_default_cell_cfg(6); + sched_interface::sched_args_t sched_args = {}; + cell_params.set_cfg(0, cell_cfg, sched_args); + tbs_test_args args; + args.verbose = true; + tbs_info expected_result; + + /* TEST CASE: DL, no 256-QAM */ + // cqi=5,Nprb=1 -> {mcs=3, tbs_idx=3, tbs=40} + TESTASSERT(test_mcs_tbs_dl_helper(cell_params, args, &expected_result) == SRSLTE_SUCCESS); + CONDERROR(expected_result != tbs_info(40 / 8, 3), + "TBS computation failure. {%d, %d}!={40, 3}", + expected_result.tbs_bytes * 8, + expected_result.mcs); + + // cqi=15,Nprb=1 -> {mcs=19, tbs_idx=17, tbs=336} + args.cqi = 15; + TESTASSERT(test_mcs_tbs_dl_helper(cell_params, args, &expected_result) == SRSLTE_SUCCESS); + CONDERROR(expected_result != tbs_info(336 / 8, 19), + "TBS computation failure. {%d, %d}!={336, 19}", + expected_result.tbs_bytes * 8, + expected_result.mcs); + + // cqi=9,Nprb=1,cell_nprb=100 -> {mcs=28, tbs_idx=17, tbs=712} + cell_params = {}; + cell_cfg = generate_default_cell_cfg(100); + cell_params.set_cfg(0, cell_cfg, sched_args); + args.cqi = 9; + TESTASSERT(test_mcs_tbs_dl_helper(cell_params, args, &expected_result) == SRSLTE_SUCCESS); + CONDERROR(expected_result != tbs_info(712 / 8, 28), + "TBS computation failure. {%d, %d}!={712, 28}", + expected_result.tbs_bytes * 8, + expected_result.mcs); + + // cqi=10,Nprb=10,cell_nprb=100 -> {mcs=28, tbs=5736} + args.prb_grant_size = 10; + args.cqi = 10; + TESTASSERT(test_mcs_tbs_dl_helper(cell_params, args, &expected_result) == SRSLTE_SUCCESS); + CONDERROR(expected_result != tbs_info(5736 / 8, 25), + "TBS computation failure. {%d, %d}!={5736, 25}", + expected_result.tbs_bytes * 8, + expected_result.mcs); + + // cqi=15,Nprb=1,256-QAM -> {mcs=26,tbs_idx=32,tbs=968} + args.prb_grant_size = 1; + args.use_tbs_index_alt = true; + args.max_mcs = 27; // limited to 27 for 256-QAM + args.cqi = 15; + TESTASSERT(test_mcs_tbs_dl_helper(cell_params, args, &expected_result) == SRSLTE_SUCCESS); + CONDERROR(expected_result != tbs_info(968 / 8, 27), + "TBS computation failure. {%d, %d}!={968, 27}", + expected_result.tbs_bytes * 8, + expected_result.mcs); + + return SRSLTE_SUCCESS; +} + +/// Verify consistency of MCS,TBS computation for different permutations of banwidths, grant sizes, cqi, max_mcs +int test_mcs_tbs_consistency_all() +{ + uint32_t prb_list[] = {6, 15, 25, 50, 75, 100}; + sched_interface::sched_args_t sched_args = {}; + + for (auto& nof_prb_cell : prb_list) { + sched_interface::cell_cfg_t cell_cfg = generate_default_cell_cfg(nof_prb_cell); + sched_cell_params_t cell_params = {}; + cell_params.set_cfg(0, cell_cfg, sched_args); + for (uint32_t prb_grant = 1; prb_grant < nof_prb_cell; ++prb_grant) { + for (uint32_t cqi = 1; cqi < 15; ++cqi) { + for (uint32_t max_mcs = 1; max_mcs <= 28; ++max_mcs) { + tbs_test_args args; + args.tti_tx_dl = tti_point{1}; + args.prb_grant_size = prb_grant; + args.cqi = cqi; + args.max_mcs = max_mcs; + TESTASSERT(test_mcs_tbs_dl_helper(cell_params, args, nullptr) == SRSLTE_SUCCESS); + } + } + } + } + return SRSLTE_SUCCESS; +} + +int test_min_mcs_tbs_dl_helper(const sched_cell_params_t& cell_params, const tbs_test_args& args, tbs_info* result) +{ + uint32_t nof_re = cell_params.get_dl_lb_nof_re(args.tti_tx_dl, args.prb_grant_size); + *result = compute_min_mcs_and_tbs_from_required_bytes(args.prb_grant_size, + nof_re, + args.cqi, + args.max_mcs, + args.req_bytes, + args.is_ul, + args.ul64qam_enabled, + args.use_tbs_index_alt); + tbs_info tb_max; + TESTASSERT(test_mcs_tbs_dl_helper(cell_params, args, &tb_max) == SRSLTE_SUCCESS); + CONDERROR(tb_max.mcs < result->mcs or tb_max.tbs_bytes < result->tbs_bytes, "Invalid min MCS calculation"); + + if (args.verbose) { + printf("Min: {tbs=%d, mcs=%d}. Max: {tbs=%d, mcs=%d}. Required tbs was %d\n", + result->tbs_bytes * 8, + result->mcs, + tb_max.tbs_bytes * 8, + tb_max.mcs, + args.req_bytes * 8); + } + + return SRSLTE_SUCCESS; +} + +/// Test search for minimum MCS/TBS in TS 36.213 table 7.1.7.2.1-1 that fulfills a TBS >= required bytes +int test_min_mcs_tbs_specific() +{ + printf("--- Min MCS test ---\n"); + sched_cell_params_t cell_params = {}; + sched_interface::cell_cfg_t cell_cfg = generate_default_cell_cfg(100); + sched_interface::sched_args_t sched_args = {}; + cell_params.set_cfg(0, cell_cfg, sched_args); + tbs_test_args args; + args.verbose = true; + tbs_info result; + + args.cqi = 10; + args.prb_grant_size = 5; + args.req_bytes = 10; + TESTASSERT(test_min_mcs_tbs_dl_helper(cell_params, args, &result) == SRSLTE_SUCCESS); + CONDERROR(result.tbs_bytes < (int)args.req_bytes, "Invalid MCS calculation"); + CONDERROR(result.tbs_bytes * 8 != 120, "Invalid min TBS calculation"); + + args.req_bytes = 50; + TESTASSERT(test_min_mcs_tbs_dl_helper(cell_params, args, &result) == SRSLTE_SUCCESS); + CONDERROR(result.tbs_bytes < (int)args.req_bytes, "Invalid MCS calculation"); + CONDERROR(result.tbs_bytes * 8 != 424, "Invalid min TBS calculation"); + + args.cqi = 15; + args.prb_grant_size = 10; + args.req_bytes = 100; + TESTASSERT(test_min_mcs_tbs_dl_helper(cell_params, args, &result) == SRSLTE_SUCCESS); + CONDERROR(result.tbs_bytes < (int)args.req_bytes, "Invalid MCS calculation"); + CONDERROR(result.tbs_bytes * 8 != 872, "Invalid min TBS calculation"); + + // Check equality case + args.req_bytes = 109; + TESTASSERT(test_min_mcs_tbs_dl_helper(cell_params, args, &result) == SRSLTE_SUCCESS); + CONDERROR(result.tbs_bytes < (int)args.req_bytes, "Invalid MCS calculation"); + CONDERROR(result.tbs_bytes * 8 != 872, "Invalid min TBS calculation"); + + return SRSLTE_SUCCESS; +} + +} // namespace srsenb + +int main() +{ + TESTASSERT(srsenb::test_mcs_lookup_specific() == SRSLTE_SUCCESS); + TESTASSERT(srsenb::test_mcs_tbs_consistency_all() == SRSLTE_SUCCESS); + TESTASSERT(srsenb::test_min_mcs_tbs_specific() == SRSLTE_SUCCESS); + + printf("Success\n"); + return 0; +} \ No newline at end of file diff --git a/srsenb/test/mac/sched_grid_test.cc b/srsenb/test/mac/sched_grid_test.cc index e4b7d4c22..a8ed38584 100644 --- a/srsenb/test/mac/sched_grid_test.cc +++ b/srsenb/test/mac/sched_grid_test.cc @@ -80,7 +80,7 @@ int test_pdcch_one_ue() const cce_cfi_position_table* dci_cce = sched_ue.get_locations(ENB_CC_IDX, prev_cfi, to_tx_dl(tti_rx).sf_idx()); uint32_t prev_nof_cce_locs = (*dci_cce)[aggr_idx].size(); - TESTASSERT(pdcch.alloc_dci(alloc_type_t::DL_DATA, aggr_idx, &sched_ue)); + TESTASSERT(pdcch.alloc_dci(alloc_type_t::DL_DATA, aggr_idx, &sched_ue, true)); TESTASSERT(pdcch.nof_allocs() == 1); if (prev_nof_cce_locs == pdcch.nof_allocs() - 1) { // CFI must be increased @@ -111,7 +111,7 @@ int test_pdcch_one_ue() } prev_nof_cce_locs = dci_locs.size(); prev_cfi = pdcch.get_cfi(); - TESTASSERT(pdcch.alloc_dci(alloc_type_t::UL_DATA, aggr_idx, &sched_ue)); + TESTASSERT(pdcch.alloc_dci(alloc_type_t::UL_DATA, aggr_idx, &sched_ue, true)); TESTASSERT(pdcch.nof_allocs() == 2); if (prev_nof_cce_locs == pdcch.nof_allocs() - 1) { // CFI must be increased diff --git a/srsenb/test/mac/sched_sim_ue.cc b/srsenb/test/mac/sched_sim_ue.cc index 73ce11d5d..b417d231f 100644 --- a/srsenb/test/mac/sched_sim_ue.cc +++ b/srsenb/test/mac/sched_sim_ue.cc @@ -360,7 +360,7 @@ int sched_sim_base::apply_tti_events(sim_ue_ctxt_t& ue_ctxt, const ue_tti_events } if (cc_feedback.ul_pid >= 0) { - auto& h = ue_ctxt.cc_list[cc_feedback.ue_cc_idx].ul_harqs[cc_feedback.dl_pid]; + auto& h = ue_ctxt.cc_list[cc_feedback.ue_cc_idx].ul_harqs[cc_feedback.ul_pid]; if (cc_feedback.ul_ack) { logger.info("UL ACK rnti=0x%x tti_ul_tx=%u pid=%d", diff --git a/srsenb/test/mac/sched_test_common.cc b/srsenb/test/mac/sched_test_common.cc index 694ea0d6a..715401e52 100644 --- a/srsenb/test/mac/sched_test_common.cc +++ b/srsenb/test/mac/sched_test_common.cc @@ -272,7 +272,7 @@ int common_sched_tester::run_tti(const tti_ev& tti_events) ul_sched(to_tx_ul(tti_rx).to_uint(), i, tti_info.ul_sched_result[i]); } - process_results(); + TESTASSERT(process_results() == SRSLTE_SUCCESS); tti_count++; return SRSLTE_SUCCESS; } diff --git a/srsenb/test/mac/sched_test_rand.cc b/srsenb/test/mac/sched_test_rand.cc index 2e0bf5ca7..0374eda00 100644 --- a/srsenb/test/mac/sched_test_rand.cc +++ b/srsenb/test/mac/sched_test_rand.cc @@ -26,7 +26,6 @@ #include #include #include -#include #include #include "srslte/common/log_filter.h" diff --git a/srsenb/test/mac/sched_test_utils.h b/srsenb/test/mac/sched_test_utils.h index 307831f8f..0d5f306dc 100644 --- a/srsenb/test/mac/sched_test_utils.h +++ b/srsenb/test/mac/sched_test_utils.h @@ -53,11 +53,15 @@ inline srsenb::sched_interface::cell_cfg_t generate_default_cell_cfg(uint32_t no cell_cfg.sibs[1].period_rf = 16; cell_cfg.si_window_ms = 40; cell_cfg.nrb_pucch = (cell_cfg_phy.nof_prb == 6) ? 1 : 2; - cell_cfg.prach_freq_offset = (cell_cfg_phy.nof_prb == 6) ? 0 : 2; + cell_cfg.prach_freq_offset = (cell_cfg_phy.nof_prb == 6) ? 0 : 4; cell_cfg.prach_rar_window = 3; cell_cfg.maxharq_msg3tx = 3; - cell_cfg.initial_dl_cqi = 5; + cell_cfg.initial_dl_cqi = 6; cell_cfg.target_ul_sinr = -1; + cell_cfg.nrb_cqi = 2; + cell_cfg.n1pucch_an = 12; + cell_cfg.delta_pucch_shift = 2; + cell_cfg.ncs_an = 0; return cell_cfg; } diff --git a/srsenb/test/phy/enb_phy_test.cc b/srsenb/test/phy/enb_phy_test.cc index 3589f8dfc..c227d74d1 100644 --- a/srsenb/test/phy/enb_phy_test.cc +++ b/srsenb/test/phy/enb_phy_test.cc @@ -19,6 +19,10 @@ * */ +#include "srslte/common/threads.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/utils/random.h" +#include "srslte/srslog/srslog.h" #include #include #include @@ -28,12 +32,7 @@ #include #include #include -#include -#include #include -#include -#include -#include static inline bool dl_ack_value(uint32_t ue_cc_idx, uint32_t tti) { @@ -831,9 +830,6 @@ public: ERROR("Setting UE DL cell"); } - // Set RNTI - srslte_ue_dl_set_rnti(ue_dl, rnti); - // Allocate UE UL auto* ue_ul = (srslte_ue_ul_t*)srslte_vec_malloc(sizeof(srslte_ue_ul_t)); if (not ue_ul) { @@ -850,9 +846,6 @@ public: if (srslte_ue_ul_set_cell(ue_ul, cell)) { ERROR("Setting UE DL cell"); } - - // Set RNTI - srslte_ue_ul_set_rnti(ue_ul, rnti); } // Initialise softbuffer diff --git a/srsenb/test/upper/rrc_mobility_test.cc b/srsenb/test/upper/rrc_mobility_test.cc index d2a43c472..77b11cafb 100644 --- a/srsenb/test/upper/rrc_mobility_test.cc +++ b/srsenb/test/upper/rrc_mobility_test.cc @@ -26,7 +26,6 @@ #include "srslte/common/test_common.h" #include "test_helpers.h" #include -#include using namespace asn1::rrc; diff --git a/srsue/hdr/phy/lte/cc_worker.h b/srsue/hdr/phy/lte/cc_worker.h index d4668f3bc..be2552c2c 100644 --- a/srsue/hdr/phy/lte/cc_worker.h +++ b/srsue/hdr/phy/lte/cc_worker.h @@ -51,7 +51,6 @@ public: void set_tdd_config_unlocked(srslte_tdd_config_t config); void set_config_unlocked(srslte::phy_cfg_t& phy_cfg); void upd_config_dci_unlocked(srslte_dci_cfg_t& dci_cfg); - void set_crnti_unlocked(uint16_t rnti); void enable_pregen_signals_unlocked(bool enabled); void set_uci_periodic_cqi(srslte_uci_data_t* uci_data); diff --git a/srsue/hdr/phy/lte/worker_pool.h b/srsue/hdr/phy/lte/worker_pool.h index f0bdcd84e..aae3485b7 100644 --- a/srsue/hdr/phy/lte/worker_pool.h +++ b/srsue/hdr/phy/lte/worker_pool.h @@ -37,7 +37,7 @@ public: sf_worker* operator[](std::size_t pos) { return workers.at(pos).get(); } worker_pool(uint32_t max_workers); - bool init(phy_common* common, srslog::sink& log_sink, int prio); + bool init(phy_common* common, int prio); sf_worker* wait_worker(uint32_t tti); sf_worker* wait_worker_id(uint32_t id); void start_worker(sf_worker* w); diff --git a/srsue/hdr/phy/nr/cc_worker.h b/srsue/hdr/phy/nr/cc_worker.h index e3ad27788..10e997291 100644 --- a/srsue/hdr/phy/nr/cc_worker.h +++ b/srsue/hdr/phy/nr/cc_worker.h @@ -60,9 +60,7 @@ private: srslog::basic_logger& logger; // Temporal attributes - srslte_softbuffer_tx_t softbuffer_tx = {}; srslte_softbuffer_rx_t softbuffer_rx = {}; - std::vector tx_data; // Methods for DL... void decode_pdcch_ul(); diff --git a/srsue/hdr/phy/nr/state.h b/srsue/hdr/phy/nr/state.h index 97183a124..c5185e446 100644 --- a/srsue/hdr/phy/nr/state.h +++ b/srsue/hdr/phy/nr/state.h @@ -56,11 +56,21 @@ private: srslte::circular_array pending_ack = {}; mutable std::mutex pending_ack_mutex; + /// Pending scheduling request identifiers + std::set pending_sr_id; + + /// CSI-RS measurements + std::array csi_measurements = {}; + public: mac_interface_phy_nr* stack = nullptr; srslte_carrier_nr_t carrier = {}; - srslte::phy_cfg_nr_t cfg; - phy_args_nr_t args; + + /// Physical layer user configuration + phy_args_nr_t args = {}; + + /// Physical layer higher layer configuration, provided by higher layers through configuration messages + srslte::phy_cfg_nr_t cfg = {}; uint16_t ra_rnti = 0; uint32_t rar_grant_tti = 0; @@ -70,6 +80,12 @@ public: carrier.id = 500; carrier.nof_prb = 100; carrier.max_mimo_layers = 1; + + // Hard-coded values, this should be set when the measurements take place + csi_measurements[0].K_csi_rs = 1; + csi_measurements[0].nof_ports = 1; + csi_measurements[1].K_csi_rs = 4; + csi_measurements[0].nof_ports = 1; } /** @@ -249,6 +265,59 @@ public: return true; } + + void reset() { pending_sr_id.clear(); } + + void set_pending_sr(uint32_t value) { pending_sr_id.insert(value); } + + void get_pending_sr(const uint32_t& tti, srslte_uci_data_nr_t& uci_data) + { + // Append fixed SR + pending_sr_id.insert(args.fixed_sr.begin(), args.fixed_sr.end()); + + // Calculate all SR opportunities in the given TTI + uint32_t sr_resource_id[SRSLTE_PUCCH_MAX_NOF_SR_RESOURCES] = {}; + int n = srslte_ue_ul_nr_sr_send_slot(cfg.pucch.sr_resources, tti, sr_resource_id); + if (n < SRSLTE_SUCCESS) { + ERROR("Calculating SR opportunities"); + return; + } + + // Initialise counters + uint32_t sr_count_all = (uint32_t)n; + uint32_t sr_count_positive = 0; + + // Iterate all opportunities and check if there is a pending SR + for (uint32_t i = 0; i < sr_count_all; i++) { + // Extract SR identifier + uint32_t sr_id = cfg.pucch.sr_resources[sr_resource_id[i]].sr_id; + + // Check if the SR resource ID is pending + if (pending_sr_id.count(sr_id) > 0) { + // Count it as present + sr_count_positive++; + + // Erase pending SR + pending_sr_id.erase(sr_id); + } + } + + // Configure SR fields in UCI data + uci_data.cfg.sr_resource_id = sr_resource_id[0]; + uci_data.cfg.o_sr = srslte_ra_ul_nr_nof_sr_bits(sr_count_all); + uci_data.cfg.sr_positive_present = sr_count_positive > 0; + uci_data.value.sr = sr_count_positive; + } + + void get_periodic_csi(const uint32_t& tti, srslte_uci_data_nr_t& uci_data) + { + int n = srslte_csi_generate_reports(&cfg.csi, tti, csi_measurements.data(), uci_data.cfg.csi, uci_data.value.csi); + if (n > SRSLTE_SUCCESS) { + uci_data.cfg.nof_csi = n; + } + + uci_data.cfg.rnti = stack->get_ul_sched_rnti_nr(tti).id; + } }; } // namespace nr } // namespace srsue diff --git a/srsue/hdr/phy/nr/worker_pool.h b/srsue/hdr/phy/nr/worker_pool.h index aa26904d9..7e2429151 100644 --- a/srsue/hdr/phy/nr/worker_pool.h +++ b/srsue/hdr/phy/nr/worker_pool.h @@ -32,7 +32,6 @@ namespace nr { class worker_pool { private: - srslog::sink& log_sink; srslog::basic_logger& logger; srslte::thread_pool pool; std::vector > workers; @@ -42,7 +41,7 @@ private: public: sf_worker* operator[](std::size_t pos) { return workers.at(pos).get(); } - worker_pool(uint32_t max_workers, srslog::sink& log_sink_); + worker_pool(uint32_t max_workers); bool init(const phy_args_nr_t& args_, phy_common* common, stack_interface_phy_nr* stack_, int prio); sf_worker* wait_worker(uint32_t tti); void start_worker(sf_worker* w); @@ -50,6 +49,7 @@ public: void send_prach(uint32_t prach_occasion, uint32_t preamble_index, int preamble_received_target_power); int set_ul_grant(std::array array, uint16_t rnti, srslte_rnti_type_t rnti_type); bool set_config(const srslte::phy_cfg_nr_t& cfg); + void sr_send(uint32_t sr_id); }; } // namespace nr diff --git a/srsue/hdr/phy/phy.h b/srsue/hdr/phy/phy.h index 9c02250be..ba7ecd6fc 100644 --- a/srsue/hdr/phy/phy.h +++ b/srsue/hdr/phy/phy.h @@ -24,13 +24,12 @@ #include "phy_common.h" #include "phy_metrics.h" -#include "prach.h" +#include "srslte/common/block_queue.h" #include "srslte/common/log_filter.h" #include "srslte/common/threads.h" #include "srslte/common/trace.h" #include "srslte/interfaces/phy_interface_types.h" #include "srslte/interfaces/radio_interfaces.h" -#include "srslte/interfaces/ue_interfaces.h" #include "srslte/radio/radio.h" #include "srslte/srslog/srslog.h" #include "srslte/srslte.h" @@ -75,17 +74,14 @@ private: srslte::block_queue > cmd_queue; }; -class phy final : public ue_lte_phy_base, - public ue_nr_phy_base, - public srslte::thread +class phy final : public ue_lte_phy_base, public ue_nr_phy_base, public srslte::thread { public: - explicit phy(srslog::sink& log_sink) : - log_sink(log_sink), - logger_phy(srslog::fetch_basic_logger("PHY", log_sink)), - logger_phy_lib(srslog::fetch_basic_logger("PHY_LIB", log_sink)), + explicit phy() : + logger_phy(srslog::fetch_basic_logger("PHY")), + logger_phy_lib(srslog::fetch_basic_logger("PHY_LIB")), lte_workers(MAX_WORKERS), - nr_workers(MAX_WORKERS, log_sink), + nr_workers(MAX_WORKERS), common(logger_phy), sfsync(logger_phy, logger_phy_lib), prach_buffer(logger_phy), @@ -145,9 +141,6 @@ public: bool cell_is_camping() final; /********** MAC INTERFACE ********************/ - // Precomputes sequences for the given RNTI. The computation is done in the background. - void set_crnti(uint16_t rnti) final; - /* Transmits PRACH in the next opportunity */ void prach_send(uint32_t preamble_idx, int allowed_subframe, float target_power_dbm, float ta_base_sec) final; prach_info_t prach_get_info() final; @@ -193,6 +186,7 @@ public: const float ta_base_sec = 0.0f) final; int tx_request(const tx_request_t& request) final; void set_earfcn(std::vector earfcns) final; + void sr_send(uint32_t sr_id) final; private: void run_thread() final; @@ -207,7 +201,6 @@ private: const static int WORKERS_THREAD_PRIO = 2; srslte::radio_interface_phy* radio = nullptr; - srslog::sink& log_sink; srslog::basic_logger& logger_phy; srslog::basic_logger& logger_phy_lib; diff --git a/srsue/hdr/phy/phy_common.h b/srsue/hdr/phy/phy_common.h index 2951638b5..62c3fe553 100644 --- a/srsue/hdr/phy/phy_common.h +++ b/srsue/hdr/phy/phy_common.h @@ -27,8 +27,10 @@ #include "srslte/common/gen_mch_tables.h" #include "srslte/common/log.h" #include "srslte/common/tti_sempahore.h" +#include "srslte/interfaces/phy_interface_types.h" #include "srslte/interfaces/radio_interfaces.h" -#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/interfaces/rrc_interface_types.h" +#include "srslte/interfaces/ue_phy_interfaces.h" #include "srslte/radio/radio.h" #include "srslte/srslog/srslog.h" #include "srslte/srslte.h" @@ -41,6 +43,8 @@ namespace srsue { +class stack_interface_phy_lte; + class rsrp_insync_itf { public: diff --git a/srsue/hdr/phy/prach.h b/srsue/hdr/phy/prach.h index bd28c4005..ba97544cb 100644 --- a/srsue/hdr/phy/prach.h +++ b/srsue/hdr/phy/prach.h @@ -23,7 +23,7 @@ #define SRSUE_PRACH_H #include "srslte/common/log.h" -#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/interfaces/ue_phy_interfaces.h" #include "srslte/radio/radio.h" #include "srslte/srslog/srslog.h" #include "srslte/srslte.h" diff --git a/srsue/hdr/phy/search.h b/srsue/hdr/phy/search.h index b1a0b5f2e..bb4e710b9 100644 --- a/srsue/hdr/phy/search.h +++ b/srsue/hdr/phy/search.h @@ -22,7 +22,6 @@ #ifndef SRSUE_SEARCH_H #define SRSUE_SEARCH_H -#include "srslte/interfaces/ue_interfaces.h" #include "srslte/radio/radio.h" #include "srslte/srslog/srslog.h" #include "srslte/srslte.h" diff --git a/srsue/hdr/phy/sfn_sync.h b/srsue/hdr/phy/sfn_sync.h index 0a5a30d22..c4dc60388 100644 --- a/srsue/hdr/phy/sfn_sync.h +++ b/srsue/hdr/phy/sfn_sync.h @@ -22,13 +22,14 @@ #ifndef SRSUE_SFN_SYNC_H #define SRSUE_SFN_SYNC_H -#include "srslte/interfaces/ue_interfaces.h" #include "srslte/radio/radio.h" #include "srslte/srslog/srslog.h" #include "srslte/srslte.h" namespace srsue { +struct phy_args_t; + // Class to synchronize system frame number class sfn_sync { diff --git a/srsue/hdr/phy/sync.h b/srsue/hdr/phy/sync.h index 9e5f2dafb..cf1f7e053 100644 --- a/srsue/hdr/phy/sync.h +++ b/srsue/hdr/phy/sync.h @@ -38,7 +38,6 @@ #include "srslte/common/threads.h" #include "srslte/common/tti_sync_cv.h" #include "srslte/interfaces/radio_interfaces.h" -#include "srslte/interfaces/ue_interfaces.h" #include "srslte/phy/channel/channel.h" #include "srslte/srslte.h" #include "srsue/hdr/phy/lte/worker_pool.h" diff --git a/srsue/hdr/phy/ue_lte_phy_base.h b/srsue/hdr/phy/ue_lte_phy_base.h index 1a63d903e..f037f85e6 100644 --- a/srsue/hdr/phy/ue_lte_phy_base.h +++ b/srsue/hdr/phy/ue_lte_phy_base.h @@ -33,6 +33,8 @@ namespace srsue { +class stack_interface_phy_lte; + class ue_lte_phy_base : public ue_phy_base, public phy_interface_stack_lte, public srslte::phy_interface_radio { public: diff --git a/srsue/hdr/phy/ue_phy_base.h b/srsue/hdr/phy/ue_phy_base.h index 05ff233fa..7397fe2e4 100644 --- a/srsue/hdr/phy/ue_phy_base.h +++ b/srsue/hdr/phy/ue_phy_base.h @@ -28,7 +28,7 @@ #define SRSUE_UE_PHY_BASE_H #include "srslte/common/logger.h" -#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/interfaces/ue_phy_interfaces.h" #include "srsue/hdr/phy/phy_metrics.h" namespace srsue { diff --git a/srsue/hdr/phy/vnf_phy_nr.h b/srsue/hdr/phy/vnf_phy_nr.h index d3a08e32e..4beab26b6 100644 --- a/srsue/hdr/phy/vnf_phy_nr.h +++ b/srsue/hdr/phy/vnf_phy_nr.h @@ -68,6 +68,7 @@ public: const int prach_occasion, const float target_power_dbm, const float ta_base_sec = 0.0f) override{}; + void sr_send(uint32_t sr_id) override; private: std::unique_ptr vnf; diff --git a/srsue/hdr/stack/mac/demux.h b/srsue/hdr/stack/mac/demux.h index 95a3a467f..1bdc1c25a 100644 --- a/srsue/hdr/stack/mac/demux.h +++ b/srsue/hdr/stack/mac/demux.h @@ -24,7 +24,8 @@ #include "srslte/common/log.h" #include "srslte/common/timers.h" -#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/interfaces/ue_mac_interfaces.h" +#include "srslte/interfaces/ue_rlc_interfaces.h" #include "srslte/mac/pdu.h" #include "srslte/mac/pdu_queue.h" #include "srslte/srslog/srslog.h" @@ -33,6 +34,9 @@ namespace srsue { +class rlc_interface_mac; +class phy_interface_mac_common; + class mac_interface_demux { public: diff --git a/srsue/hdr/stack/mac/dl_harq.h b/srsue/hdr/stack/mac/dl_harq.h index 9e3a24888..e23870476 100644 --- a/srsue/hdr/stack/mac/dl_harq.h +++ b/srsue/hdr/stack/mac/dl_harq.h @@ -28,8 +28,6 @@ #include "srslte/common/mac_pcap.h" #include "srslte/common/timers.h" -#include "srslte/interfaces/ue_interfaces.h" - /* Downlink HARQ entity as defined in 5.3.2 of 36.321 */ namespace srsue { diff --git a/srsue/hdr/stack/mac/mac.h b/srsue/hdr/stack/mac/mac.h index 2d6728468..a47ceb498 100644 --- a/srsue/hdr/stack/mac/mac.h +++ b/srsue/hdr/stack/mac/mac.h @@ -35,7 +35,7 @@ #include "srslte/common/threads.h" #include "srslte/common/timers.h" #include "srslte/common/tti_sync_cv.h" -#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/interfaces/ue_rrc_interfaces.h" #include "srslte/srslog/srslog.h" #include "ul_harq.h" #include diff --git a/srsue/hdr/stack/mac/mux.h b/srsue/hdr/stack/mac/mux.h index 787204431..e30e5b9ab 100644 --- a/srsue/hdr/stack/mac/mux.h +++ b/srsue/hdr/stack/mac/mux.h @@ -31,7 +31,6 @@ #include "srslte/common/common.h" #include "srslte/common/log.h" #include "srslte/interfaces/mac_interface_types.h" -#include "srslte/interfaces/ue_interfaces.h" #include "srslte/mac/pdu.h" #include "srslte/srslog/srslog.h" #include diff --git a/srsue/hdr/stack/mac/proc_bsr.h b/srsue/hdr/stack/mac/proc_bsr.h index 944663bbf..4f5076e6c 100644 --- a/srsue/hdr/stack/mac/proc_bsr.h +++ b/srsue/hdr/stack/mac/proc_bsr.h @@ -27,14 +27,15 @@ #include "proc_sr.h" #include "srslte/common/logmap.h" -#include "srslte/common/timers.h" -#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/common/task_scheduler.h" #include "srslte/srslog/srslog.h" /* Buffer status report procedure */ namespace srsue { +class rlc_interface_mac; + // BSR interface for MUX class bsr_interface_mux { diff --git a/srsue/hdr/stack/mac/proc_phr.h b/srsue/hdr/stack/mac/proc_phr.h index 40248ab52..fae65e989 100644 --- a/srsue/hdr/stack/mac/proc_phr.h +++ b/srsue/hdr/stack/mac/proc_phr.h @@ -23,8 +23,8 @@ #define SRSUE_PROC_PHR_H #include "srslte/common/logmap.h" -#include "srslte/common/timers.h" -#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/common/task_scheduler.h" +#include "srslte/interfaces/ue_mac_interfaces.h" #include "srslte/srslog/srslog.h" #include @@ -32,6 +32,8 @@ namespace srsue { +class phy_interface_mac_lte; + class phr_proc : public srslte::timer_callback { public: diff --git a/srsue/hdr/stack/mac/proc_ra.h b/srsue/hdr/stack/mac/proc_ra.h index f1fac0b0f..5360dc032 100644 --- a/srsue/hdr/stack/mac/proc_ra.h +++ b/srsue/hdr/stack/mac/proc_ra.h @@ -72,8 +72,6 @@ public: void start_pcap(srslte::mac_pcap* pcap); - void notify_ra_completed(uint32_t task_id); - bool is_idle() const { return state == IDLE; } private: @@ -81,7 +79,6 @@ private: void state_response_reception(uint32_t tti); void state_backoff_wait(uint32_t tti); void state_contention_resolution(); - void state_completition(); void process_timeadv_cmd(uint32_t ta_cmd); void initialization(); @@ -131,8 +128,6 @@ private: RESPONSE_RECEPTION, BACKOFF_WAIT, CONTENTION_RESOLUTION, - START_WAIT_COMPLETION, - WAITING_COMPLETION }; std::atomic state = {IDLE}; diff --git a/srsue/hdr/stack/mac/proc_sr.h b/srsue/hdr/stack/mac/proc_sr.h index 70e6e1aea..77c424f08 100644 --- a/srsue/hdr/stack/mac/proc_sr.h +++ b/srsue/hdr/stack/mac/proc_sr.h @@ -23,7 +23,7 @@ #define SRSUE_PROC_SR_H #include "srslte/common/logmap.h" -#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/interfaces/ue_mac_interfaces.h" #include "srslte/srslog/srslog.h" #include @@ -31,8 +31,9 @@ namespace srsue { -// Forward-declare ra_proc class ra_proc; +class phy_interface_mac_lte; +class rrc_interface_mac; class sr_proc { diff --git a/srsue/hdr/stack/mac/ul_harq.h b/srsue/hdr/stack/mac/ul_harq.h index 2531b8bcc..274e5b010 100644 --- a/srsue/hdr/stack/mac/ul_harq.h +++ b/srsue/hdr/stack/mac/ul_harq.h @@ -28,7 +28,6 @@ #include "srslte/common/log.h" #include "srslte/common/mac_pcap.h" #include "srslte/common/timers.h" -#include "srslte/interfaces/ue_interfaces.h" #include "ul_sps.h" using namespace srslte; diff --git a/srsue/hdr/stack/mac_nr/mac_nr.h b/srsue/hdr/stack/mac_nr/mac_nr.h index ae018ae0e..fd4acebdd 100644 --- a/srsue/hdr/stack/mac_nr/mac_nr.h +++ b/srsue/hdr/stack/mac_nr/mac_nr.h @@ -28,6 +28,7 @@ #include "srslte/common/mac_pcap.h" #include "srslte/interfaces/mac_interface_types.h" #include "srslte/interfaces/ue_nr_interfaces.h" +#include "srslte/interfaces/ue_rlc_interfaces.h" #include "srslte/mac/mac_sch_pdu_nr.h" #include "srslte/srslog/srslog.h" #include "srsue/hdr/stack/mac_nr/mux_nr.h" @@ -35,8 +36,9 @@ namespace srsue { +class rlc_interface_mac; + struct mac_nr_args_t { - srsue::pcap_args_t pcap; }; class mac_nr final : public mac_interface_phy_nr, public mac_interface_rrc_nr, public mac_interface_proc_ra_nr @@ -51,6 +53,8 @@ public: void reset(); void run_tti(const uint32_t tti); + void start_pcap(srslte::mac_pcap* pcap_); + void bch_decoded_ok(uint32_t tti, srslte::unique_byte_buffer_t payload); /// Interface for PHY @@ -59,7 +63,7 @@ public: 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, srslte::byte_buffer_t* tx_pdu); + void new_grant_ul(const uint32_t cc_idx, const mac_nr_grant_ul_t& grant, tb_action_ul_t* action); void prach_sent(const uint32_t tti, const uint32_t s_id, const uint32_t t_id, @@ -82,7 +86,7 @@ public: /// procedure ra nr interface uint64_t get_contention_id(); uint16_t get_c_rnti(); - void set_c_rnti(uint64_t c_rnti_); + void set_c_rnti(uint64_t c_rnti_); void msg3_flush() { mux.msg3_flush(); } bool msg3_is_transmitted() { return mux.msg3_is_transmitted(); } @@ -119,9 +123,9 @@ private: rlc_interface_mac* rlc = nullptr; srslte::ext_task_sched_handle task_sched; - std::unique_ptr pcap = nullptr; - srslog::basic_logger& logger; - mac_nr_args_t args = {}; + srslte::mac_pcap* pcap = nullptr; + srslog::basic_logger& logger; + mac_nr_args_t args = {}; bool started = false; @@ -141,8 +145,9 @@ private: /// Tx buffer srslte::mac_sch_pdu_nr tx_pdu; - srslte::unique_byte_buffer_t tx_buffer = nullptr; - srslte::unique_byte_buffer_t rlc_buffer = nullptr; + srslte::unique_byte_buffer_t tx_buffer = nullptr; + srslte::unique_byte_buffer_t rlc_buffer = nullptr; + srslte_softbuffer_tx_t softbuffer_tx = {}; /// UL HARQ (temporal) srslte::task_multiqueue::queue_handle stack_task_dispatch_queue; diff --git a/srsue/hdr/stack/rrc/phy_controller.h b/srsue/hdr/stack/rrc/phy_controller.h index 0e84b4523..cc9c5f1ca 100644 --- a/srsue/hdr/stack/rrc/phy_controller.h +++ b/srsue/hdr/stack/rrc/phy_controller.h @@ -25,7 +25,9 @@ #include "srslte/adt/observer.h" #include "srslte/common/fsm.h" #include "srslte/common/logmap.h" -#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/common/task_scheduler.h" +#include "srslte/interfaces/ue_phy_interfaces.h" +#include "srslte/interfaces/ue_rrc_interfaces.h" #include namespace srsue { diff --git a/srsue/hdr/stack/rrc/rrc.h b/srsue/hdr/stack/rrc/rrc.h index 5d3450d36..c0cf70439 100644 --- a/srsue/hdr/stack/rrc/rrc.h +++ b/srsue/hdr/stack/rrc/rrc.h @@ -67,6 +67,12 @@ using srslte::byte_buffer_t; namespace srsue { class phy_controller; +class usim_interface_rrc; +class gw_interface_rrc; +class pdcp_interface_rrc; +class rlc_interface_rrc; +class nas_interface_rrc; +class phy_interface_rrc_lte; class rrc : public rrc_interface_nas, public rrc_interface_phy_lte, @@ -87,8 +93,8 @@ public: nas_interface_rrc* nas_, usim_interface_rrc* usim_, gw_interface_rrc* gw_, - rrc_nr_interface_rrc* rrc_nr_, - const rrc_args_t& args_); + rrc_nr_interface_rrc* rrc_nr_, + const rrc_args_t& args_); void stop(); @@ -174,17 +180,17 @@ private: void process_pcch(srslte::unique_byte_buffer_t pdu); - stack_interface_rrc* stack = nullptr; - srslte::task_sched_handle task_sched; - srslog::basic_logger& logger; - phy_interface_rrc_lte* phy = nullptr; - mac_interface_rrc* mac = nullptr; - rlc_interface_rrc* rlc = nullptr; - pdcp_interface_rrc* pdcp = nullptr; - nas_interface_rrc* nas = nullptr; - usim_interface_rrc* usim = nullptr; - gw_interface_rrc* gw = nullptr; - rrc_nr_interface_rrc* rrc_nr = nullptr; + stack_interface_rrc* stack = nullptr; + srslte::task_sched_handle task_sched; + srslog::basic_logger& logger; + phy_interface_rrc_lte* phy = nullptr; + mac_interface_rrc* mac = nullptr; + rlc_interface_rrc* rlc = nullptr; + pdcp_interface_rrc* pdcp = nullptr; + nas_interface_rrc* nas = nullptr; + usim_interface_rrc* usim = nullptr; + gw_interface_rrc* gw = nullptr; + rrc_nr_interface_rrc* rrc_nr = nullptr; srslte::unique_byte_buffer_t dedicated_info_nas; void send_ul_ccch_msg(const asn1::rrc::ul_ccch_msg_s& msg); diff --git a/srsue/hdr/stack/rrc/rrc_cell.h b/srsue/hdr/stack/rrc/rrc_cell.h index d51f6819f..96fc34c34 100644 --- a/srsue/hdr/stack/rrc/rrc_cell.h +++ b/srsue/hdr/stack/rrc/rrc_cell.h @@ -23,15 +23,17 @@ #define SRSLTE_RRC_CELL_H #include "srslte/asn1/rrc.h" -#include "srslte/asn1/rrc_utils.h" #include "srslte/asn1/rrc_nr.h" #include "srslte/asn1/rrc_nr_utils.h" -#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/asn1/rrc_utils.h" +#include "srslte/common/task_scheduler.h" +#include "srslte/interfaces/ue_rrc_interfaces.h" #include "srslte/srslog/srslog.h" +#include namespace srsue { -inline std::string to_string(const srsue::phy_cell_t& c) +inline std::string to_string(const phy_cell_t& c) { char buffer[64]; snprintf(buffer, 64, "{earfcn=%d, pci=%d}\n", c.earfcn, c.pci); @@ -226,7 +228,6 @@ bool is_same_cell(const T& lhs, const U& rhs) template class meas_cell_list { - public: const static int NEIGHBOUR_TIMEOUT = 5; const static int MAX_NEIGHBOUR_CELLS = 8; diff --git a/srsue/hdr/stack/rrc/rrc_metrics.h b/srsue/hdr/stack/rrc/rrc_metrics.h index 8ee6e9529..bd40b078e 100644 --- a/srsue/hdr/stack/rrc/rrc_metrics.h +++ b/srsue/hdr/stack/rrc/rrc_metrics.h @@ -23,7 +23,7 @@ #define SRSUE_RRC_METRICS_H #include "rrc_common.h" -#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/interfaces/phy_interface_types.h" namespace srsue { diff --git a/srsue/hdr/stack/rrc/rrc_nr.h b/srsue/hdr/stack/rrc/rrc_nr.h index ff85577b8..7cb253e4e 100644 --- a/srsue/hdr/stack/rrc/rrc_nr.h +++ b/srsue/hdr/stack/rrc/rrc_nr.h @@ -26,13 +26,21 @@ #include "srslte/asn1/rrc_nr_utils.h" #include "srslte/common/block_queue.h" #include "srslte/common/buffer_pool.h" +#include "srslte/common/logmap.h" +#include "srslte/common/stack_procedure.h" +#include "srslte/common/task_scheduler.h" #include "srslte/interfaces/nr_common_interface_types.h" -#include "srslte/interfaces/ue_interfaces.h" #include "srslte/interfaces/ue_nr_interfaces.h" +#include "srslte/interfaces/ue_rrc_interfaces.h" #include "srsue/hdr/stack/upper/gw.h" namespace srsue { +class usim_interface_rrc_nr; +class pdcp_interface_rrc; +class rlc_interface_rrc; +class stack_interface_rrc; + // Expert arguments to create GW without proper RRC struct core_less_args_t { std::string ip_addr; diff --git a/srsue/hdr/stack/rrc/rrc_procedures.h b/srsue/hdr/stack/rrc/rrc_procedures.h index fc4749401..4afd37416 100644 --- a/srsue/hdr/stack/rrc/rrc_procedures.h +++ b/srsue/hdr/stack/rrc/rrc_procedures.h @@ -21,6 +21,7 @@ #include "phy_controller.h" #include "srslte/common/log.h" +#include "srslte/interfaces/ue_nas_interfaces.h" #include "srslte/srslog/srslog.h" #include "srsue/hdr/stack/rrc/rrc.h" #include @@ -173,7 +174,7 @@ private: srslog::basic_logger& logger; // state variables - found_plmn_t found_plmns[MAX_FOUND_PLMNS]; + nas_interface_rrc::found_plmn_t found_plmns[nas_interface_rrc::MAX_FOUND_PLMNS]; int nof_plmns = 0; srslte::proc_future_t cell_search_fut; }; diff --git a/srsue/hdr/stack/ue_stack_base.h b/srsue/hdr/stack/ue_stack_base.h index d6c87ffe1..9a42f8100 100644 --- a/srsue/hdr/stack/ue_stack_base.h +++ b/srsue/hdr/stack/ue_stack_base.h @@ -23,7 +23,6 @@ #define SRSUE_UE_STACK_BASE_H #include "srslte/common/logger.h" -#include "srslte/interfaces/ue_interfaces.h" #include "srsue/hdr/stack/upper/nas_config.h" #include "srsue/hdr/ue_metrics_interface.h" @@ -37,10 +36,15 @@ namespace srsue { typedef struct { bool enable; std::string filename; - bool nas_enable; - std::string nas_filename; } pcap_args_t; +typedef struct { + std::string enable; + pcap_args_t mac_pcap; + pcap_args_t mac_nr_pcap; + pcap_args_t nas_pcap; +} pkt_trace_args_t; + typedef struct { std::string mac_level; std::string rlc_level; @@ -63,7 +67,7 @@ typedef struct { typedef struct { std::string type; - pcap_args_t pcap; + pkt_trace_args_t pkt_trace; stack_log_args_t log; usim_args_t usim; rrc_args_t rrc; diff --git a/srsue/hdr/stack/ue_stack_lte.h b/srsue/hdr/stack/ue_stack_lte.h index 5e6881010..00dc3e408 100644 --- a/srsue/hdr/stack/ue_stack_lte.h +++ b/srsue/hdr/stack/ue_stack_lte.h @@ -43,16 +43,18 @@ #include "srslte/common/buffer_pool.h" #include "srslte/common/log_filter.h" #include "srslte/common/multiqueue.h" +#include "srslte/common/string_helpers.h" #include "srslte/common/task_scheduler.h" #include "srslte/common/thread_pool.h" -#include "srslte/interfaces/ue_interfaces.h" - #include "srslte/common/time_prof.h" +#include "srslte/interfaces/ue_interfaces.h" #include "srsue/hdr/ue_metrics_interface.h" #include "ue_stack_base.h" namespace srsue { +class phy_interface_stack_lte; + class ue_stack_lte final : public ue_stack_base, public stack_interface_phy_lte, public stack_interface_phy_nr, @@ -61,18 +63,17 @@ class ue_stack_lte final : public ue_stack_base, public srslte::thread { public: - explicit ue_stack_lte(srslog::sink& log_sink); + explicit ue_stack_lte(); ~ue_stack_lte(); std::string get_type() final; - int init(const stack_args_t& args_, srslte::logger* logger_); - int init(const stack_args_t& args_, srslte::logger* logger_, phy_interface_stack_lte* phy_, gw_interface_stack* gw_); - int init(const stack_args_t& args_, - srslte::logger* logger_, - phy_interface_stack_lte* phy_, - phy_interface_stack_nr* phy_nr_, - gw_interface_stack* gw_); + int init(const stack_args_t& args_); + int init(const stack_args_t& args_, phy_interface_stack_lte* phy_, gw_interface_stack* gw_); + int init(const stack_args_t& args_, + phy_interface_stack_lte* phy_, + phy_interface_stack_nr* phy_nr_, + gw_interface_stack* gw_); bool switch_on() final; bool switch_off() final; bool is_registered() final; @@ -100,7 +101,7 @@ public: sched_rnti_t get_dl_sched_rnti_nr(uint32_t tti) final { return mac_nr.get_dl_sched_rnti_nr(tti); } sched_rnti_t get_ul_sched_rnti_nr(uint32_t tti) final { return mac_nr.get_ul_sched_rnti_nr(tti); } - void new_grant_ul(uint32_t cc_idx, mac_grant_ul_t grant, tb_action_ul_t* action) final + void new_grant_ul(uint32_t cc_idx, mac_grant_ul_t grant, mac_interface_phy_lte::tb_action_ul_t* action) final { mac.new_grant_ul(cc_idx, grant, action); } @@ -135,7 +136,12 @@ public: int sf_indication(const uint32_t tti) final { return SRSLTE_SUCCESS; } void tb_decoded(const uint32_t cc_idx, mac_nr_grant_dl_t& grant) final { mac_nr.tb_decoded(cc_idx, grant); } - void new_grant_ul(const uint32_t cc_idx, const mac_nr_grant_ul_t& grant, srslte::byte_buffer_t* tx_pdu) final { mac_nr.new_grant_ul(cc_idx, grant, tx_pdu); } + void new_grant_ul(const uint32_t cc_idx, + const mac_nr_grant_ul_t& grant, + mac_interface_phy_nr::tb_action_ul_t* action) final + { + mac_nr.new_grant_ul(cc_idx, grant, action); + } void run_tti(const uint32_t tti) final { @@ -172,13 +178,6 @@ private: srslte::tti_point current_tti; // UE stack logging - srslte::logger* logger = nullptr; - srslte::log_ref mac_log{"MAC"}; - srslte::log_ref rlc_log{"RLC"}; - srslte::log_ref pdcp_log{"PDCP"}; - srslte::log_ref rrc_log{"RRC"}; - srslte::log_ref usim_log{"USIM"}; - srslte::log_ref nas_log{"NAS"}; srslog::basic_logger& stack_logger; srslog::basic_logger& mac_logger; srslog::basic_logger& rlc_logger; @@ -187,9 +186,14 @@ private: srslog::basic_logger& usim_logger; srslog::basic_logger& nas_logger; + // tracing + srslte::mac_pcap mac_pcap; + srslte::mac_pcap mac_nr_pcap; + srslte::nas_pcap nas_pcap; + // RAT-specific interfaces - phy_interface_stack_lte* phy = nullptr; - gw_interface_stack* gw = nullptr; + phy_interface_stack_lte* phy = nullptr; + gw_interface_stack* gw = nullptr; phy_interface_stack_nr* phy_nr = nullptr; // Thread @@ -202,14 +206,12 @@ private: srslte::tprof tti_tprof; // stack components - srsue::mac mac; - srslte::mac_pcap mac_pcap; - srslte::nas_pcap nas_pcap; - srslte::rlc rlc; - srslte::pdcp pdcp; - srsue::rrc rrc; - srsue::mac_nr mac_nr; - srsue::rrc_nr rrc_nr; + srsue::mac mac; + srslte::rlc rlc; + srslte::pdcp pdcp; + srsue::rrc rrc; + srsue::mac_nr mac_nr; + srsue::rrc_nr rrc_nr; srsue::nas nas; std::unique_ptr usim; diff --git a/srsue/hdr/stack/ue_stack_nr.h b/srsue/hdr/stack/ue_stack_nr.h index 3fef732c8..fd2c4f025 100644 --- a/srsue/hdr/stack/ue_stack_nr.h +++ b/srsue/hdr/stack/ue_stack_nr.h @@ -91,7 +91,10 @@ public: return SRSLTE_SUCCESS; } void tb_decoded(const uint32_t cc_idx, mac_nr_grant_dl_t& grant) final { mac->tb_decoded(cc_idx, grant); } - void new_grant_ul(const uint32_t cc_idx, const mac_nr_grant_ul_t& grant, srslte::byte_buffer_t* phy_tx_pdu) final { mac->new_grant_ul(cc_idx, grant, phy_tx_pdu); } + void new_grant_ul(const uint32_t cc_idx, const mac_nr_grant_ul_t& grant, tb_action_ul_t* action) final + { + mac->new_grant_ul(cc_idx, grant, action); + } void prach_sent(uint32_t tti, uint32_t s_id, uint32_t t_id, uint32_t f_id, uint32_t ul_carrier_id) { mac->prach_sent(tti, s_id, t_id, f_id, ul_carrier_id); diff --git a/srsue/hdr/stack/upper/gw.h b/srsue/hdr/stack/upper/gw.h index 46cd20cd9..47edc8547 100644 --- a/srsue/hdr/stack/upper/gw.h +++ b/srsue/hdr/stack/upper/gw.h @@ -29,13 +29,16 @@ #include "srslte/common/log.h" #include "srslte/common/log_filter.h" #include "srslte/common/threads.h" -#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/interfaces/ue_gw_interfaces.h" #include "srslte/srslog/srslog.h" #include "tft_packet_filter.h" #include +#include namespace srsue { +class stack_interface_gw; + struct gw_args_t { struct log_args_t { std::string gw_level; @@ -50,7 +53,7 @@ class gw : public gw_interface_stack, public srslte::thread { public: gw(); - int init(const gw_args_t& args_, srslte::logger* logger_, stack_interface_gw* stack); + int init(const gw_args_t& args_, stack_interface_gw* stack); void stop(); void get_metrics(gw_metrics_t& m, const uint32_t nof_tti); @@ -78,8 +81,7 @@ public: private: static const int GW_THREAD_PRIO = -1; - stack_interface_gw* stack = nullptr; - srslte::logger* old_logger = nullptr; + stack_interface_gw* stack = nullptr; gw_args_t args = {}; diff --git a/srsue/hdr/stack/upper/nas.h b/srsue/hdr/stack/upper/nas.h index 75414c9d7..fd235ae1e 100644 --- a/srsue/hdr/stack/upper/nas.h +++ b/srsue/hdr/stack/upper/nas.h @@ -30,7 +30,7 @@ #include "srslte/common/security.h" #include "srslte/common/stack_procedure.h" #include "srslte/common/task_scheduler.h" -#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/interfaces/ue_nas_interfaces.h" #include "srslte/srslog/srslog.h" #include "srsue/hdr/stack/upper/nas_config.h" #include "srsue/hdr/stack/upper/nas_emm_state.h" @@ -40,6 +40,10 @@ using srslte::byte_buffer_t; namespace srsue { +class usim_interface_nas; +class gw_interface_nas; +class rrc_interface_nas; + class nas : public nas_interface_rrc, public srslte::timer_callback { public: @@ -62,8 +66,7 @@ public: bool get_k_asme(uint8_t* k_asme_, uint32_t n) override; uint32_t get_ipv4_addr() override; bool get_ipv6_addr(uint8_t* ipv6_addr) override; - void plmn_search_completed(const rrc_interface_nas::found_plmn_t found_plmns[rrc_interface_nas::MAX_FOUND_PLMNS], - int nof_plmns) final; + void plmn_search_completed(const found_plmn_t found_plmns[MAX_FOUND_PLMNS], int nof_plmns) final; // Stack interface bool switch_on(); diff --git a/srsue/hdr/stack/upper/nas_idle_procedures.h b/srsue/hdr/stack/upper/nas_idle_procedures.h index c5c30caf1..536b952a1 100644 --- a/srsue/hdr/stack/upper/nas_idle_procedures.h +++ b/srsue/hdr/stack/upper/nas_idle_procedures.h @@ -35,9 +35,9 @@ class nas::plmn_search_proc { public: struct plmn_search_complete_t { - rrc_interface_nas::found_plmn_t found_plmns[rrc_interface_nas::MAX_FOUND_PLMNS]; + nas_interface_rrc::found_plmn_t found_plmns[nas_interface_rrc::MAX_FOUND_PLMNS]; int nof_plmns; - plmn_search_complete_t(const rrc_interface_nas::found_plmn_t* plmns_, int nof_plmns_) : nof_plmns(nof_plmns_) + plmn_search_complete_t(const nas_interface_rrc::found_plmn_t* plmns_, int nof_plmns_) : nof_plmns(nof_plmns_) { if (nof_plmns > 0) { std::copy(&plmns_[0], &plmns_[nof_plmns], found_plmns); diff --git a/srsue/hdr/stack/upper/pcsc_usim.h b/srsue/hdr/stack/upper/pcsc_usim.h index 4f4f52c9c..8a4afa967 100644 --- a/srsue/hdr/stack/upper/pcsc_usim.h +++ b/srsue/hdr/stack/upper/pcsc_usim.h @@ -25,7 +25,6 @@ #include "srslte/common/common.h" #include "srslte/common/log.h" #include "srslte/common/security.h" -#include "srslte/interfaces/ue_interfaces.h" #include "srsue/hdr/stack/upper/usim.h" #include #include diff --git a/srsue/hdr/stack/upper/usim.h b/srsue/hdr/stack/upper/usim.h index cc7cfc947..7fccdb879 100644 --- a/srsue/hdr/stack/upper/usim.h +++ b/srsue/hdr/stack/upper/usim.h @@ -25,7 +25,6 @@ #include "srslte/common/common.h" #include "srslte/common/log.h" #include "srslte/common/security.h" -#include "srslte/interfaces/ue_interfaces.h" #include "usim_base.h" #include diff --git a/srsue/hdr/stack/upper/usim_base.h b/srsue/hdr/stack/upper/usim_base.h index 1f76e9f93..f8a64ba89 100644 --- a/srsue/hdr/stack/upper/usim_base.h +++ b/srsue/hdr/stack/upper/usim_base.h @@ -25,7 +25,7 @@ #include "srslte/common/common.h" #include "srslte/common/log.h" #include "srslte/common/security.h" -#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/interfaces/ue_usim_interfaces.h" #include "srslte/srslog/srslog.h" #include diff --git a/srsue/hdr/ue.h b/srsue/hdr/ue.h index 7f7207b41..90d9a3758 100644 --- a/srsue/hdr/ue.h +++ b/srsue/hdr/ue.h @@ -35,9 +35,9 @@ #include "phy/ue_phy_base.h" #include "srslte/common/buffer_pool.h" #include "srslte/common/log_filter.h" -#include "srslte/interfaces/ue_interfaces.h" #include "srslte/radio/radio.h" #include "srslte/srslog/srslog.h" +#include "srslte/system/sys_metrics_processor.h" #include "stack/ue_stack_base.h" #include "ue_metrics_interface.h" @@ -93,7 +93,7 @@ typedef struct { class ue : public ue_metrics_interface { public: - ue(srslog::sink& log_sink); + ue(); ~ue(); int init(const all_args_t& args_, srslte::logger* logger_); @@ -116,9 +116,11 @@ private: // Generic logger members srslte::logger* old_logger = nullptr; - srslog::sink& log_sink; srslog::basic_logger& logger; + // System metrics processor. + srslte::sys_metrics_processor sys_proc; + all_args_t args; // Helper functions diff --git a/srsue/hdr/ue_metrics_interface.h b/srsue/hdr/ue_metrics_interface.h index 85d611076..f6bbd025e 100644 --- a/srsue/hdr/ue_metrics_interface.h +++ b/srsue/hdr/ue_metrics_interface.h @@ -27,6 +27,7 @@ #include "phy/phy_metrics.h" #include "srslte/common/metrics_hub.h" #include "srslte/radio/radio_metrics.h" +#include "srslte/system/sys_metrics.h" #include "srslte/upper/rlc_metrics.h" #include "stack/mac/mac_metrics.h" #include "stack/rrc/rrc_metrics.h" @@ -44,10 +45,11 @@ typedef struct { } stack_metrics_t; typedef struct { - srslte::rf_metrics_t rf; - phy_metrics_t phy; - gw_metrics_t gw; - stack_metrics_t stack; + srslte::rf_metrics_t rf; + phy_metrics_t phy; + gw_metrics_t gw; + stack_metrics_t stack; + srslte::sys_metrics_t sys; } ue_metrics_t; // UE interface diff --git a/srsue/src/CMakeLists.txt b/srsue/src/CMakeLists.txt index ad18a22d4..c39330267 100644 --- a/srsue/src/CMakeLists.txt +++ b/srsue/src/CMakeLists.txt @@ -32,8 +32,8 @@ endif (RPATH) add_executable(srsue main.cc ue.cc metrics_stdout.cc metrics_csv.cc) -set(SRSUE_SOURCES srsue_phy srsue_stack srsue_upper srsue_mac srsue_rrc srslog) -set(SRSLTE_SOURCES srslte_common srslte_mac srslte_phy srslte_radio srslte_upper rrc_asn1 srslog) +set(SRSUE_SOURCES srsue_phy srsue_stack srsue_upper srsue_mac srsue_rrc srslog system) +set(SRSLTE_SOURCES srslte_common srslte_mac srslte_phy srslte_radio srslte_upper rrc_asn1 srslog system) set(SRSUE_SOURCES ${SRSUE_SOURCES} srsue_nr_stack srsue_rrc_nr srsue_mac_nr) set(SRSLTE_SOURCES ${SRSLTE_SOURCES} rrc_nr_asn1 ngap_nr_asn1) diff --git a/srsue/src/main.cc b/srsue/src/main.cc index a503270a0..34b16c7a3 100644 --- a/srsue/src/main.cc +++ b/srsue/src/main.cc @@ -142,11 +142,11 @@ static int parse_args(all_args_t* args, int argc, char* argv[]) ("nas.eia", bpo::value(&args->stack.nas.eia)->default_value("1,2,3"), "List of integrity algorithms included in UE capabilities") ("nas.eea", bpo::value(&args->stack.nas.eea)->default_value("0,1,2,3"), "List of ciphering algorithms included in UE capabilities") - ("pcap.enable", bpo::value(&args->stack.pcap.enable)->default_value(false), "Enable MAC packet captures for wireshark") - ("pcap.filename", bpo::value(&args->stack.pcap.filename)->default_value("ue.pcap"), "MAC layer capture filename") - ("pcap.nas_enable", bpo::value(&args->stack.pcap.nas_enable)->default_value(false), "Enable NAS packet captures for wireshark") - ("pcap.nas_filename", bpo::value(&args->stack.pcap.nas_filename)->default_value("ue_nas.pcap"), "NAS layer capture filename (useful when NAS encryption is enabled)") - + ("pcap.enable", bpo::value(&args->stack.pkt_trace.enable)->default_value("none"), "Enable (MAC, MAC_NR, NAS) packet captures for wireshark") + ("pcap.mac_filename", bpo::value(&args->stack.pkt_trace.mac_pcap.filename)->default_value("/tmp/ue_mac.pcap"), "MAC layer capture filename") + ("pcap.mac_nr_filename", bpo::value(&args->stack.pkt_trace.mac_nr_pcap.filename)->default_value("/tmp/ue_mac_nr.pcap"), "MAC_NR layer capture filename") + ("pcap.nas_filename", bpo::value(&args->stack.pkt_trace.nas_pcap.filename)->default_value("/tmp/ue_nas.pcap"), "NAS layer capture filename") + ("gui.enable", bpo::value(&args->gui.enable)->default_value(false), "Enable GUI plots") ("log.rf_level", bpo::value(&args->rf.log_level), "RF log level") @@ -479,7 +479,6 @@ static int parse_args(all_args_t* args, int argc, char* argv[]) // if no config file given, check users home path if (!vm.count("config_file")) { - if (!config_exists(config_file, "ue.conf")) { cout << "Failed to read UE configuration file " << config_file << " - exiting" << endl; return SRSLTE_ERROR; @@ -661,7 +660,7 @@ int main(int argc, char* argv[]) srslte::check_scaling_governor(args.rf.device_name); // Create UE instance - srsue::ue ue(*log_sink); + srsue::ue ue; if (ue.init(args, &log_wrapper)) { ue.stop(); return SRSLTE_SUCCESS; diff --git a/srsue/src/metrics_csv.cc b/srsue/src/metrics_csv.cc index c2267b347..4504d5927 100644 --- a/srsue/src/metrics_csv.cc +++ b/srsue/src/metrics_csv.cc @@ -86,7 +86,8 @@ void metrics_csv::set_metrics(const ue_metrics_t& metrics, const uint32_t period "ul_ta;ul_mcs;ul_buff;ul_brate;ul_" "bler;" "rf_o;rf_" - "u;rf_l;is_attached\n"; + "u;rf_l;is_attached;" + "proc_rmem;proc_rmem_kB;proc_vmem;proc_vmem_kB;sys_mem;proc_cpu;thread_count\n"; } for (uint32_t r = 0; r < metrics.phy.nof_active_cc; r++) { @@ -159,7 +160,18 @@ void metrics_csv::set_metrics(const ue_metrics_t& metrics, const uint32_t period file << float_to_string(metrics.rf.rf_o, 2); file << float_to_string(metrics.rf.rf_u, 2); file << float_to_string(metrics.rf.rf_l, 2); - file << (metrics.stack.rrc.state == RRC_STATE_CONNECTED ? "1.0" : "0.0"); + file << (metrics.stack.rrc.state == RRC_STATE_CONNECTED ? "1.0" : "0.0") << ";"; + + // Write system metrics. + const srslte::sys_metrics_t &m = metrics.sys; + file << float_to_string(m.process_realmem, 2); + file << std::to_string(m.process_realmem_kB) << ";"; + file << float_to_string(m.process_virtualmem, 2); + file << std::to_string(m.process_virtualmem_kB) << ";" ; + file << float_to_string(m.system_mem, 2); + file << float_to_string(m.process_cpu_usage, 2); + file << std::to_string(m.thread_count); + file << "\n"; } diff --git a/srsue/src/phy/CMakeLists.txt b/srsue/src/phy/CMakeLists.txt index 867e17ea6..01d76747f 100644 --- a/srsue/src/phy/CMakeLists.txt +++ b/srsue/src/phy/CMakeLists.txt @@ -23,7 +23,7 @@ add_library(srsue_phy STATIC ${SOURCES}) if(ENABLE_GUI AND SRSGUI_FOUND) target_link_libraries(srsue_phy ${SRSGUI_LIBRARIES}) -endif(ENABLE_GUI AND SRSGUI_FOUND) +endif() set(SOURCES_NR "../phy/vnf_phy_nr.cc") add_library(srsue_phy_nr STATIC ${SOURCES_NR}) diff --git a/srsue/src/phy/lte/cc_worker.cc b/srsue/src/phy/lte/cc_worker.cc index 2b649c81a..843c2075a 100644 --- a/srsue/src/phy/lte/cc_worker.cc +++ b/srsue/src/phy/lte/cc_worker.cc @@ -189,12 +189,6 @@ float cc_worker::get_ref_cfo() const return ue_dl.chest_res.cfo; } -void cc_worker::set_crnti_unlocked(uint16_t rnti) -{ - srslte_ue_dl_set_rnti(&ue_dl, rnti); - srslte_ue_ul_set_rnti(&ue_ul, rnti); -} - void cc_worker::set_tdd_config_unlocked(srslte_tdd_config_t config) { sf_cfg_dl.tdd_config = config; @@ -242,7 +236,6 @@ bool cc_worker::work_dl_regular() // Blind search PHICH mi value for (uint32_t i = 0; i < mi_set_len && !found_dl_grant; i++) { - if (mi_set_len == 1) { srslte_ue_dl_set_mi_auto(&ue_dl); } else { @@ -269,7 +262,6 @@ bool cc_worker::work_dl_regular() // If found a dci for this carrier, generate a grant, pass it to MAC and decode the associated PDSCH if (has_dl_grant) { - // Read last TB from last retx for this pid for (uint32_t i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { ue_dl_cfg.cfg.pdsch.grant.last_tbs[i] = phy->last_dl_tbs[dci_dl.pid][cc_idx][i]; @@ -426,7 +418,6 @@ int cc_worker::decode_pdsch(srslte_pdsch_ack_resource_t ack_resource, mac_interface_phy_lte::tb_action_dl_t* action, bool mac_acks[SRSLTE_MAX_CODEWORDS]) { - srslte_pdsch_res_t pdsch_dec[SRSLTE_MAX_CODEWORDS] = {}; // See if at least 1 codeword needs to be decoded. If not need to be decode, resend ACK @@ -508,7 +499,6 @@ int cc_worker::decode_pmch(mac_interface_phy_lte::tb_action_dl_t* action, srslte pmch_dec.payload = action->tb[0].payload; if (action->tb[0].enabled) { - srslte_softbuffer_rx_reset_tbs(pmch_cfg.pdsch_cfg.softbuffers.rx[0], pmch_cfg.pdsch_cfg.grant.tb[0].tbs); if (srslte_ue_dl_decode_pmch(&ue_dl, &sf_cfg_dl, &pmch_cfg, &pmch_dec)) { @@ -610,7 +600,6 @@ bool cc_worker::work_ul(srslte_uci_data_t* uci_data) /* Send UL dci or HARQ information (from PHICH) to MAC and receive actions*/ if (ul_grant_available || ul_mac_grant.phich_available) { - // Read last TB info from last retx for this PID ue_ul_cfg.ul_cfg.pusch.grant.last_tb = phy->last_ul_tb[pid][cc_idx]; @@ -718,7 +707,6 @@ int cc_worker::decode_pdcch_ul() /* Convert every DCI message to UL dci */ for (int k = 0; k < nof_grants; k++) { - // If the DCI does not have Carrier Indicator Field then indicate in which carrier the dci was found uint32_t cc_idx_grant = dci[k].cif_present ? dci[k].cif : cc_idx; @@ -842,7 +830,6 @@ void cc_worker::set_uci_ack(srslte_uci_data_t* uci_data, uint32_t V_dai_ul, bool is_pusch_available) { - srslte_pdsch_ack_t ack_info = {}; uint32_t nof_configured_carriers = 0; diff --git a/srsue/src/phy/lte/sf_worker.cc b/srsue/src/phy/lte/sf_worker.cc index e11c8a025..c052caec8 100644 --- a/srsue/src/phy/lte/sf_worker.cc +++ b/srsue/src/phy/lte/sf_worker.cc @@ -19,12 +19,10 @@ * */ -#include "srslte/interfaces/ue_interfaces.h" #include "srslte/srslte.h" #include "srsue/hdr/phy/lte/sf_worker.h" #include -#include #define Error(fmt, ...) \ if (SRSLTE_DEBUG_ENABLED) \ @@ -140,13 +138,6 @@ void sf_worker::set_cfo_unlocked(const uint32_t& cc_idx, float cfo) cc_workers[cc_idx]->set_cfo_unlocked(cfo); } -void sf_worker::set_crnti_unlocked(uint16_t rnti) -{ - for (auto& cc_worker : cc_workers) { - cc_worker->set_crnti_unlocked(rnti); - } -} - void sf_worker::set_tdd_config_unlocked(srslte_tdd_config_t config) { for (auto& cc_worker : cc_workers) { @@ -177,7 +168,6 @@ void sf_worker::set_config_unlocked(uint32_t cc_idx, srslte::phy_cfg_t phy_cfg) void sf_worker::work_imp() { - srslte::rf_buffer_t tx_signal_ptr = {}; if (!cell_initiated) { phy->worker_end(this, false, tx_signal_ptr, tx_time, false); @@ -192,7 +182,6 @@ void sf_worker::work_imp() // Loop through all carriers. carrier_idx=0 is PCell for (uint32_t carrier_idx = 0; carrier_idx < cc_workers.size(); carrier_idx++) { - // Process all DL and special subframes if (srslte_sfidx_tdd_type(tdd_config, tti % 10) != SRSLTE_TDD_SF_U || cell.frame_type == SRSLTE_FDD) { srslte_mbsfn_cfg_t mbsfn_cfg; @@ -214,7 +203,6 @@ void sf_worker::work_imp() if ((srslte_sfidx_tdd_type(tdd_config, TTI_TX(tti) % 10) == SRSLTE_TDD_SF_U) || cell.frame_type == SRSLTE_FDD) { // Generate Uplink signal if no PRACH pending if (!prach_ptr) { - // Common UCI data object for all carriers srslte_uci_data_t uci_data; reset_uci(&uci_data); diff --git a/srsue/src/phy/lte/worker_pool.cc b/srsue/src/phy/lte/worker_pool.cc index e56dcdda7..c628881e6 100644 --- a/srsue/src/phy/lte/worker_pool.cc +++ b/srsue/src/phy/lte/worker_pool.cc @@ -25,16 +25,15 @@ namespace lte { worker_pool::worker_pool(uint32_t max_workers) : pool(max_workers) {} -bool worker_pool::init(phy_common* common, srslog::sink& log_sink, int prio) +bool worker_pool::init(phy_common* common, int prio) { // Add workers to workers pool and start threads for (uint32_t i = 0; i < common->args->nof_phy_threads; i++) { - srslog::basic_logger &log = srslog::fetch_basic_logger(fmt::format("PHY{}", i), log_sink); + srslog::basic_logger& log = srslog::fetch_basic_logger(fmt::format("PHY{}", i)); log.set_level(srslog::str_to_basic_level(common->args->log.phy_level)); log.set_hex_dump_max_size(common->args->log.phy_hex_limit); - auto w = - std::unique_ptr(new lte::sf_worker(SRSLTE_MAX_PRB, common, log)); + auto w = std::unique_ptr(new lte::sf_worker(SRSLTE_MAX_PRB, common, log)); pool.init_worker(i, w.get(), prio, common->args->worker_cpu_mask); workers.push_back(std::move(w)); } diff --git a/srsue/src/phy/nr/cc_worker.cc b/srsue/src/phy/nr/cc_worker.cc index 4bd5cd88a..35b7cdc98 100644 --- a/srsue/src/phy/nr/cc_worker.cc +++ b/srsue/src/phy/nr/cc_worker.cc @@ -47,23 +47,11 @@ cc_worker::cc_worker(uint32_t cc_idx_, srslog::basic_logger& log, state* phy_sta return; } - if (srslte_softbuffer_tx_init_guru(&softbuffer_tx, SRSLTE_SCH_NR_MAX_NOF_CB_LDPC, SRSLTE_LDPC_MAX_LEN_ENCODED_CB) < - SRSLTE_SUCCESS) { - ERROR("Error init soft-buffer"); - return; - } - if (srslte_softbuffer_rx_init_guru(&softbuffer_rx, SRSLTE_SCH_NR_MAX_NOF_CB_LDPC, SRSLTE_LDPC_MAX_LEN_ENCODED_CB) < SRSLTE_SUCCESS) { ERROR("Error init soft-buffer"); return; } - - // Initialise data with numbers - tx_data.resize(SRSLTE_SCH_NR_MAX_NOF_CB_LDPC * SRSLTE_LDPC_MAX_LEN_ENCODED_CB / 8); - for (uint32_t i = 0; i < SRSLTE_SCH_NR_MAX_NOF_CB_LDPC * SRSLTE_LDPC_MAX_LEN_ENCODED_CB / 8; i++) { - tx_data[i] = i % 255U; - } } cc_worker::~cc_worker() @@ -280,7 +268,7 @@ bool cc_worker::work_ul() srslte_sch_cfg_nr_t pusch_cfg = {}; bool has_pusch_grant = phy->get_ul_pending_grant(ul_slot_cfg.idx, pusch_cfg, pid); - // If PDSCH UL AKC is available, load into UCI + // If PDSCH UL ACK is available, load into UCI if (has_ul_ack) { pdsch_ack.use_pusch = has_pusch_grant; if (srslte_ue_dl_nr_gen_ack(&phy->cfg.harq_ack, &pdsch_ack, &uci_data) < SRSLTE_SUCCESS) { @@ -289,24 +277,28 @@ bool cc_worker::work_ul() } } + // Add SR to UCI data if available + phy->get_pending_sr(ul_slot_cfg.idx, uci_data); + + // Add CSI reports to UCI data if available + phy->get_periodic_csi(ul_slot_cfg.idx, uci_data); + if (has_pusch_grant) { // Notify MAC about PUSCH found grant + mac_interface_phy_nr::tb_action_ul_t ul_action = {}; mac_interface_phy_nr::mac_nr_grant_ul_t mac_ul_grant = {}; mac_ul_grant.pid = pid; mac_ul_grant.rnti = pusch_cfg.grant.rnti; mac_ul_grant.tti = ul_slot_cfg.idx; mac_ul_grant.tbs = pusch_cfg.grant.tb[0].tbs; - srslte::unique_byte_buffer_t tx_pdu = srslte::make_byte_buffer(); - phy->stack->new_grant_ul(0, mac_ul_grant, tx_pdu.get()); - // Provisional reset and assign Tx softbuffer - srslte_softbuffer_tx_reset(&softbuffer_tx); - pusch_cfg.grant.tb[0].softbuffer.tx = &softbuffer_tx; - // TODO: Use here PDU, after that, remove tx_data attribute - uint8_t* tx_data_ptr = tx_pdu.get()->msg; + phy->stack->new_grant_ul(0, mac_ul_grant, &ul_action); + + // Assignning MAC provided values to PUSCH config structs + pusch_cfg.grant.tb[0].softbuffer.tx = ul_action.tb.softbuffer; // Encode PUSCH transmission - if (srslte_ue_ul_nr_encode_pusch(&ue_ul, &ul_slot_cfg, &pusch_cfg, tx_data_ptr) < SRSLTE_SUCCESS) { + if (srslte_ue_ul_nr_encode_pusch(&ue_ul, &ul_slot_cfg, &pusch_cfg, ul_action.tb.payload->msg) < SRSLTE_SUCCESS) { ERROR("Encoding PUSCH"); return false; } @@ -315,7 +307,7 @@ bool cc_worker::work_ul() if (logger.info.enabled()) { std::array str; srslte_ue_ul_nr_pusch_info(&ue_ul, &pusch_cfg, str.data(), str.size()); - logger.info(tx_data_ptr, + logger.info(ul_action.tb.payload->msg, pusch_cfg.grant.tb[0].tbs / 8, "PUSCH (NR): cc=%d, %s, tti_tx=%d", cc_idx, diff --git a/srsue/src/phy/nr/state.cc b/srsue/src/phy/nr/state.cc deleted file mode 100644 index 0e849375f..000000000 --- a/srsue/src/phy/nr/state.cc +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Copyright 2013-2021 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/phy/nr/state.h" - -namespace srsue { -namespace nr {} -} // namespace srsue \ No newline at end of file diff --git a/srsue/src/phy/nr/worker_pool.cc b/srsue/src/phy/nr/worker_pool.cc index d465b20ea..df2598312 100644 --- a/srsue/src/phy/nr/worker_pool.cc +++ b/srsue/src/phy/nr/worker_pool.cc @@ -23,9 +23,7 @@ namespace srsue { namespace nr { -worker_pool::worker_pool(uint32_t max_workers, srslog::sink& log_sink_) : - pool(max_workers), log_sink(log_sink_), logger(srslog::fetch_basic_logger("NR-PHY", log_sink)) -{} +worker_pool::worker_pool(uint32_t max_workers) : pool(max_workers), logger(srslog::fetch_basic_logger("NR-PHY")) {} bool worker_pool::init(const phy_args_nr_t& args, phy_common* common, stack_interface_phy_nr* stack_, int prio) { @@ -47,7 +45,7 @@ bool worker_pool::init(const phy_args_nr_t& args, phy_common* common, stack_inte // Add workers to workers pool and start threads for (uint32_t i = 0; i < args.nof_phy_threads; i++) { - auto& log = srslog::fetch_basic_logger(fmt::format("PHY{}", i), log_sink); + auto& log = srslog::fetch_basic_logger(fmt::format("PHY{}", i)); log.set_level(srslog::str_to_basic_level(args.log.phy_level)); log.set_hex_dump_max_size(args.log.phy_hex_limit); @@ -61,7 +59,7 @@ bool worker_pool::init(const phy_args_nr_t& args, phy_common* common, stack_inte } // Initialise PRACH - auto& prach_log = srslog::fetch_basic_logger("NR-PRACH", log_sink); + auto& prach_log = srslog::fetch_basic_logger("NR-PRACH"); prach_log.set_level(srslog::str_to_basic_level(args.log.phy_level)); prach_buffer = std::unique_ptr(new prach(prach_log)); prach_buffer->init(phy_state.args.dl.nof_max_prb); @@ -143,5 +141,10 @@ bool worker_pool::set_config(const srslte::phy_cfg_nr_t& cfg) phy_state.cfg = cfg; return true; } + +void worker_pool::sr_send(uint32_t sr_id) +{ + phy_state.set_pending_sr(sr_id); +} } // namespace nr } // namespace srsue diff --git a/srsue/src/phy/phy.cc b/srsue/src/phy/phy.cc index 6a310b9ed..ccc4b62bf 100644 --- a/srsue/src/phy/phy.cc +++ b/srsue/src/phy/phy.cc @@ -156,7 +156,7 @@ void phy::run_thread() common.init(&args, radio, stack, &sfsync); // Initialise workers - lte_workers.init(&common, log_sink, WORKERS_THREAD_PRIO); + lte_workers.init(&common, WORKERS_THREAD_PRIO); // Warning this must be initialized after all workers have been added to the pool sfsync.init( @@ -411,23 +411,6 @@ void phy::set_rar_grant(uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN], uint16_t rn common.set_rar_grant(grant_payload, rnti, tdd_config); } -void phy::set_crnti(uint16_t rnti) -{ - // set_crnti() is an operation that takes time, run in background worker - cmd_worker.add_cmd([this, rnti]() { - logger_phy.info("Configuring sequences for C-RNTI=0x%x...", rnti); - for (uint32_t i = 0; i < args.nof_phy_threads; i++) { - // set_crnti is not protected so run when worker is finished - lte::sf_worker* w = lte_workers.wait_worker_id(i); - if (w) { - w->set_crnti_unlocked(rnti); - w->release(); - } - } - logger_phy.info("Finished configuring sequences for C-RNTI=0x%x.", rnti); - }); -} - // Start GUI void phy::start_plot() { @@ -653,4 +636,8 @@ bool phy::set_config(const srslte::phy_cfg_nr_t& cfg) return nr_workers.set_config(cfg); } +void phy::sr_send(uint32_t sr_id) +{ + nr_workers.sr_send(sr_id); +} } // namespace srsue diff --git a/srsue/src/phy/phy_common.cc b/srsue/src/phy/phy_common.cc index 831d4114a..709ff6f42 100644 --- a/srsue/src/phy/phy_common.cc +++ b/srsue/src/phy/phy_common.cc @@ -561,7 +561,7 @@ void phy_common::worker_end(void* tx_sem_id, if (nr_tx_buffer_ready) { // Load NR carrier base-band for (uint32_t i = 0; i < args->nof_nr_carriers * args->nof_rx_ant; i++) { - uint32 channel_idx = args->nof_lte_carriers * args->nof_rx_ant + i; + uint32_t channel_idx = args->nof_lte_carriers * args->nof_rx_ant + i; buffer.set(channel_idx, nr_tx_buffer.get(i)); } diff --git a/srsue/src/phy/prach.cc b/srsue/src/phy/prach.cc index 259ec5ac0..c2992a174 100644 --- a/srsue/src/phy/prach.cc +++ b/srsue/src/phy/prach.cc @@ -22,7 +22,6 @@ #include "srsue/hdr/phy/prach.h" #include "srslte/common/log.h" #include "srslte/interfaces/phy_interface_types.h" -#include "srslte/interfaces/ue_interfaces.h" #include "srslte/srslte.h" #define Error(fmt, ...) \ diff --git a/srsue/src/phy/sfn_sync.cc b/srsue/src/phy/sfn_sync.cc index 9667ddedf..32d783618 100644 --- a/srsue/src/phy/sfn_sync.cc +++ b/srsue/src/phy/sfn_sync.cc @@ -20,6 +20,7 @@ */ #include "srsue/hdr/phy/sfn_sync.h" +#include "srslte/interfaces/ue_phy_interfaces.h" #define Error(fmt, ...) \ if (SRSLTE_DEBUG_ENABLED) \ @@ -117,7 +118,6 @@ sfn_sync::ret_code sfn_sync::decode_mib(srslte_cell_t* } if (srslte_ue_sync_get_sfidx(ue_sync) == 0) { - // Skip MIB decoding if we are only interested in subframe 0 if (sfidx_only) { if (tti_cnt) { diff --git a/srsue/src/phy/vnf_phy_nr.cc b/srsue/src/phy/vnf_phy_nr.cc index 74fa792e8..652c0b70b 100644 --- a/srsue/src/phy/vnf_phy_nr.cc +++ b/srsue/src/phy/vnf_phy_nr.cc @@ -82,5 +82,6 @@ bool vnf_phy_nr::set_config(const srslte::phy_cfg_nr_t& cfg) { return false; } +void vnf_phy_nr::sr_send(uint32_t sr_id) {} } // namespace srsue \ No newline at end of file diff --git a/srsue/src/stack/mac/demux.cc b/srsue/src/stack/mac/demux.cc index bc89fa300..112f2d69f 100644 --- a/srsue/src/stack/mac/demux.cc +++ b/srsue/src/stack/mac/demux.cc @@ -25,8 +25,7 @@ #define Debug(fmt, ...) logger.debug(fmt, ##__VA_ARGS__) #include "srsue/hdr/stack/mac/demux.h" -#include "srslte/interfaces/ue_interfaces.h" -#include "srsue/hdr/stack/mac/mac.h" +#include "srslte/interfaces/ue_phy_interfaces.h" namespace srsue { diff --git a/srsue/src/stack/mac/dl_harq.cc b/srsue/src/stack/mac/dl_harq.cc index 9a9cb7849..09fb5b876 100644 --- a/srsue/src/stack/mac/dl_harq.cc +++ b/srsue/src/stack/mac/dl_harq.cc @@ -28,7 +28,6 @@ #include "srslte/common/log.h" #include "srslte/common/mac_pcap.h" #include "srslte/common/timers.h" -#include "srslte/interfaces/ue_interfaces.h" namespace srsue { @@ -238,7 +237,6 @@ void dl_harq_entity::dl_harq_process::dl_tb_process::reset_ndi() void dl_harq_entity::dl_harq_process::dl_tb_process::new_grant_dl(mac_interface_phy_lte::mac_grant_dl_t grant, mac_interface_phy_lte::tb_action_dl_t* action) { - mutex.lock(); // Compute RV for BCCH when not specified in PDCCH format @@ -272,7 +270,6 @@ void dl_harq_entity::dl_harq_process::dl_tb_process::new_grant_dl(mac_interface_ // If data has not yet been successfully decoded if (!ack) { - // Save dci cur_grant = grant; diff --git a/srsue/src/stack/mac/mac.cc b/srsue/src/stack/mac/mac.cc index 64b1ad599..f2b056643 100644 --- a/srsue/src/stack/mac/mac.cc +++ b/srsue/src/stack/mac/mac.cc @@ -24,13 +24,12 @@ #define Info(fmt, ...) logger.info(fmt, ##__VA_ARGS__) #define Debug(fmt, ...) logger.debug(fmt, ##__VA_ARGS__) -#include #include #include -#include #include "srslte/common/log.h" #include "srslte/common/pcap.h" +#include "srslte/interfaces/ue_phy_interfaces.h" #include "srsue/hdr/stack/mac/mac.h" namespace srsue { diff --git a/srsue/src/stack/mac/proc_bsr.cc b/srsue/src/stack/mac/proc_bsr.cc index 757b39e59..8d07ec57b 100644 --- a/srsue/src/stack/mac/proc_bsr.cc +++ b/srsue/src/stack/mac/proc_bsr.cc @@ -20,6 +20,7 @@ */ #include "srsue/hdr/stack/mac/proc_bsr.h" +#include "srslte/interfaces/ue_rlc_interfaces.h" #include "srsue/hdr/stack/mac/mux.h" namespace srsue { diff --git a/srsue/src/stack/mac/proc_phr.cc b/srsue/src/stack/mac/proc_phr.cc index 0b76958c4..8a0889ffa 100644 --- a/srsue/src/stack/mac/proc_phr.cc +++ b/srsue/src/stack/mac/proc_phr.cc @@ -25,9 +25,7 @@ #define Debug(fmt, ...) logger.debug(fmt, ##__VA_ARGS__) #include "srsue/hdr/stack/mac/proc_phr.h" -#include "srslte/interfaces/ue_interfaces.h" -#include "srsue/hdr/stack/mac/mac.h" -#include "srsue/hdr/stack/mac/mux.h" +#include "srslte/interfaces/ue_phy_interfaces.h" namespace srsue { @@ -140,7 +138,6 @@ void phr_proc::step() bool phr_proc::generate_phr_on_ul_grant(float* phr) { - if (phr_is_triggered) { if (phr) { *phr = phy_h->get_phr(); diff --git a/srsue/src/stack/mac/proc_ra.cc b/srsue/src/stack/mac/proc_ra.cc index 10d16fe3f..329c52d0d 100644 --- a/srsue/src/stack/mac/proc_ra.cc +++ b/srsue/src/stack/mac/proc_ra.cc @@ -20,7 +20,8 @@ */ #include "srsue/hdr/stack/mac/proc_ra.h" -#include "srslte/common/log_helper.h" +#include "srslte/interfaces/ue_phy_interfaces.h" +#include "srslte/interfaces/ue_rrc_interfaces.h" #include "srsue/hdr/stack/mac/mux.h" #include // for printing uint64_t #include @@ -149,12 +150,6 @@ void ra_proc::step(uint32_t tti_) case CONTENTION_RESOLUTION: state_contention_resolution(); break; - case START_WAIT_COMPLETION: - state_completition(); - break; - case WAITING_COMPLETION: - // do nothing, bc we are waiting for the phy to finish - break; } } @@ -228,36 +223,6 @@ void ra_proc::state_contention_resolution() } } -/* This step just configures the PHY to generate the C-RNTI. It is called from a state because it takes a long time to - * compute - */ -void ra_proc::state_completition() -{ - state = WAITING_COMPLETION; - uint16_t rnti = rntis->crnti; - uint32_t task_id = current_task_id; - - phy_h->set_crnti(rnti); - - // signal MAC RA proc to go back to idle - notify_ra_completed(task_id); -} - -void ra_proc::notify_ra_completed(uint32_t task_id) -{ - if (current_task_id == task_id) { - if (state != WAITING_COMPLETION) { - rError("Received unexpected notification of RA completion"); - } else { - rInfo("RA waiting procedure completed"); - } - state = IDLE; - } else { - rError( - "Received old notification of RA completition (old task_id=%d, current_task_id=%d)", task_id, current_task_id); - } -} - /* RA procedure initialization as defined in 5.1.1 */ void ra_proc::initialization() { @@ -419,7 +384,6 @@ void ra_proc::tb_decoded_ok(const uint8_t cc_idx, const uint32_t tti) while (rar_pdu_msg.next()) { if (rar_pdu_msg.get()->has_rapid() && rar_pdu_msg.get()->get_rapid() == sel_preamble) { - rar_received = true; process_timeadv_cmd(rar_pdu_msg.get()->get_ta_cmd()); @@ -446,7 +410,6 @@ void ra_proc::tb_decoded_ok(const uint8_t cc_idx, const uint32_t tti) // If this is the first successfully received RAR within this procedure, Msg3 is empty if (mux_unit->msg3_is_empty()) { - // Save transmitted C-RNTI (if any) transmitted_crnti = rntis->crnti; @@ -526,7 +489,7 @@ void ra_proc::complete() srslte::console("Random Access Complete. c-rnti=0x%x, ta=%d\n", rntis->crnti, current_ta); rInfo("Random Access Complete. c-rnti=0x%x, ta=%d", rntis->crnti, current_ta); - state = START_WAIT_COMPLETION; + state = IDLE; } void ra_proc::start_mac_order(uint32_t msg_len_bits) diff --git a/srsue/src/stack/mac/proc_sr.cc b/srsue/src/stack/mac/proc_sr.cc index 4c8c36006..7f617908d 100644 --- a/srsue/src/stack/mac/proc_sr.cc +++ b/srsue/src/stack/mac/proc_sr.cc @@ -25,6 +25,8 @@ #define Debug(fmt, ...) logger.debug(fmt, ##__VA_ARGS__) #include "srsue/hdr/stack/mac/proc_sr.h" +#include "srslte/interfaces/ue_phy_interfaces.h" +#include "srslte/interfaces/ue_rrc_interfaces.h" #include "srsue/hdr/stack/mac/proc_ra.h" namespace srsue { diff --git a/srsue/src/stack/mac/ul_harq.cc b/srsue/src/stack/mac/ul_harq.cc index fefd5c8d9..556271a8a 100644 --- a/srsue/src/stack/mac/ul_harq.cc +++ b/srsue/src/stack/mac/ul_harq.cc @@ -29,7 +29,6 @@ #include "srslte/common/log.h" #include "srslte/common/mac_pcap.h" #include "srslte/common/timers.h" -#include "srslte/interfaces/ue_interfaces.h" namespace srsue { diff --git a/srsue/src/stack/mac_nr/mac_nr.cc b/srsue/src/stack/mac_nr/mac_nr.cc index 4d80f143e..c62486f46 100644 --- a/srsue/src/stack/mac_nr/mac_nr.cc +++ b/srsue/src/stack/mac_nr/mac_nr.cc @@ -26,7 +26,11 @@ namespace srsue { mac_nr::mac_nr(srslte::ext_task_sched_handle task_sched_) : - task_sched(task_sched_), logger(srslog::fetch_basic_logger("MAC")), proc_ra(logger), mux(logger) + task_sched(task_sched_), + logger(srslog::fetch_basic_logger("MAC")), + proc_ra(logger), + mux(logger), + pcap(nullptr) { tx_buffer = srslte::make_byte_buffer(); rlc_buffer = srslte::make_byte_buffer(); @@ -46,30 +50,33 @@ int mac_nr::init(const mac_nr_args_t& args_, phy_interface_mac_nr* phy_, rlc_int // Create Stack task dispatch queue stack_task_dispatch_queue = task_sched.make_task_queue(); - // Set up pcap - if (args.pcap.enable) { - pcap.reset(new srslte::mac_pcap(srslte::srslte_rat_t::nr)); - pcap->open(args.pcap.filename.c_str()); - } - proc_ra.init(phy, this, &task_sched); mux.init(); + if (srslte_softbuffer_tx_init_guru(&softbuffer_tx, SRSLTE_SCH_NR_MAX_NOF_CB_LDPC, SRSLTE_LDPC_MAX_LEN_ENCODED_CB) < + SRSLTE_SUCCESS) { + ERROR("Error init soft-buffer"); + return SRSLTE_ERROR; + } + started = true; return SRSLTE_SUCCESS; } +void mac_nr::start_pcap(srslte::mac_pcap* pcap_) +{ + pcap = pcap_; +} + void mac_nr::stop() { if (started) { - if (pcap != nullptr) { - pcap->close(); - } - started = false; } + + srslte_softbuffer_tx_free(&softbuffer_tx); } // Implement Section 5.9 @@ -209,13 +216,22 @@ void mac_nr::tb_decoded(const uint32_t cc_idx, mac_nr_grant_dl_t& grant) stack_task_dispatch_queue.push([this]() { process_pdus(); }); } -void mac_nr::new_grant_ul(const uint32_t cc_idx, const mac_nr_grant_ul_t& grant, srslte::byte_buffer_t* phy_tx_pdu) +void mac_nr::new_grant_ul(const uint32_t cc_idx, const mac_nr_grant_ul_t& grant, tb_action_ul_t* action) { // if proc ra is in contention resolution and c_rnti == grant.c_rnti resolve contention resolution if (proc_ra.is_contention_resolution() && grant.rnti == c_rnti) { proc_ra.pdcch_to_crnti(); } - get_ul_data(grant, phy_tx_pdu); + + // fill TB action (goes into UL harq eventually) + action->tb.payload = tx_buffer.get(); + action->tb.enabled = true; + action->tb.rv = 0; + action->tb.softbuffer = &softbuffer_tx; + srslte_softbuffer_tx_reset(&softbuffer_tx); + + // Pack MAC PDU + get_ul_data(grant, action->tb.payload); metrics[cc_idx].tx_pkts++; } @@ -223,8 +239,8 @@ void mac_nr::new_grant_ul(const uint32_t cc_idx, const mac_nr_grant_ul_t& grant, void mac_nr::get_ul_data(const mac_nr_grant_ul_t& grant, srslte::byte_buffer_t* phy_tx_pdu) { // initialize MAC PDU - tx_buffer->clear(); - tx_pdu.init_tx(tx_buffer.get(), grant.tbs / 8U, true); + phy_tx_pdu->clear(); + tx_pdu.init_tx(phy_tx_pdu, grant.tbs / 8U, true); if (mux.msg3_is_pending()) { // If message 3 is pending pack message 3 for uplink transmission @@ -243,17 +259,17 @@ void mac_nr::get_ul_data(const mac_nr_grant_ul_t& grant, srslte::byte_buffer_t* rlc_buffer->clear(); uint8_t* rd = rlc_buffer->msg; int pdu_len = 0; - // pdu_len = rlc->read_pdu(args.drb_lcid, rd, tx_pdu.get_remaing_len() - 2); + pdu_len = rlc->read_pdu(4, rd, tx_pdu.get_remaing_len() - 2); // Add SDU if RLC has something to tx if (pdu_len > 0) { - // rlc_buffer->N_bytes = pdu_len; - // logger.info(rlc_buffer->msg, rlc_buffer->N_bytes, "Read %d B from RLC", rlc_buffer->N_bytes); + rlc_buffer->N_bytes = pdu_len; + logger.info(rlc_buffer->msg, rlc_buffer->N_bytes, "Read %d B from RLC", rlc_buffer->N_bytes); - // // add to MAC PDU and pack - // if (tx_pdu.add_sdu(args.drb_lcid, rlc_buffer->msg, rlc_buffer->N_bytes) != SRSLTE_SUCCESS) { - // logger.error("Error packing MAC PDU"); - // } + // add to MAC PDU and pack + if (tx_pdu.add_sdu(4, rlc_buffer->msg, rlc_buffer->N_bytes) != SRSLTE_SUCCESS) { + logger.error("Error packing MAC PDU"); + } } else { break; } @@ -263,13 +279,10 @@ void mac_nr::get_ul_data(const mac_nr_grant_ul_t& grant, srslte::byte_buffer_t* // Pack PDU tx_pdu.pack(); - logger.info(tx_buffer->msg, tx_buffer->N_bytes, "Generated MAC PDU (%d B)", tx_buffer->N_bytes); - - memcpy(phy_tx_pdu->msg, tx_buffer->msg, tx_buffer->N_bytes); - phy_tx_pdu->N_bytes = tx_buffer->N_bytes; + logger.info(phy_tx_pdu->msg, phy_tx_pdu->N_bytes, "Generated MAC PDU (%d B)", phy_tx_pdu->N_bytes); if (pcap) { - pcap->write_ul_crnti_nr(tx_buffer->msg, tx_buffer->N_bytes, grant.rnti, grant.pid, grant.tti); + pcap->write_ul_crnti_nr(phy_tx_pdu->msg, phy_tx_pdu->N_bytes, grant.rnti, grant.pid, grant.tti); } } @@ -359,14 +372,15 @@ void mac_nr::handle_pdu(srslte::unique_byte_buffer_t pdu) for (uint32_t i = 0; i < rx_pdu.get_num_subpdus(); ++i) { srslte::mac_sch_subpdu_nr subpdu = rx_pdu.get_subpdu(i); logger.info("Handling subPDU %d/%d: rnti=0x%x lcid=%d, sdu_len=%d", - i, + i + 1, rx_pdu.get_num_subpdus(), subpdu.get_c_rnti(), subpdu.get_lcid(), subpdu.get_sdu_length()); - - // rlc->write_pdu(subpdu.get_lcid(), subpdu.get_sdu(), subpdu.get_sdu_length()); - } + if (subpdu.get_lcid() == 4) { + rlc->write_pdu(subpdu.get_lcid(), subpdu.get_sdu(), subpdu.get_sdu_length()); + } + } } uint64_t mac_nr::get_contention_id() diff --git a/srsue/src/stack/rrc/rrc.cc b/srsue/src/stack/rrc/rrc.cc index 038237f63..c12b43420 100644 --- a/srsue/src/stack/rrc/rrc.cc +++ b/srsue/src/stack/rrc/rrc.cc @@ -23,6 +23,11 @@ #include "srslte/asn1/rrc.h" #include "srslte/common/bcd_helpers.h" #include "srslte/common/security.h" +#include "srslte/interfaces/ue_gw_interfaces.h" +#include "srslte/interfaces/ue_nas_interfaces.h" +#include "srslte/interfaces/ue_pdcp_interfaces.h" +#include "srslte/interfaces/ue_rlc_interfaces.h" +#include "srslte/interfaces/ue_usim_interfaces.h" #include "srsue/hdr/stack/rrc/phy_controller.h" #include "srsue/hdr/stack/rrc/rrc_meas.h" #include "srsue/hdr/stack/rrc/rrc_procedures.h" @@ -32,9 +37,7 @@ #include #include #include -#include #include -#include bool simulate_rlf = false; @@ -106,18 +109,18 @@ void rrc::init(phy_interface_rrc_lte* phy_, nas_interface_rrc* nas_, usim_interface_rrc* usim_, gw_interface_rrc* gw_, - rrc_nr_interface_rrc* rrc_nr_, - const rrc_args_t& args_) + rrc_nr_interface_rrc* rrc_nr_, + const rrc_args_t& args_) { - phy = phy_; - mac = mac_; - rlc = rlc_; - pdcp = pdcp_; - nas = nas_; - usim = usim_; - gw = gw_; + phy = phy_; + mac = mac_; + rlc = rlc_; + pdcp = pdcp_; + nas = nas_; + usim = usim_; + gw = gw_; rrc_nr = rrc_nr_; - args = args_; + args = args_; auto on_every_cell_selection = [this](uint32_t earfcn, uint32_t pci, bool csel_result) { if (not csel_result) { @@ -2066,8 +2069,7 @@ void rrc::handle_ue_capability_enquiry(const ue_cap_enquiry_s& enquiry) memcpy(info->ue_cap_rat_container_list[rat_idx].ue_cap_rat_container.data(), buf, cap_len); rat_idx++; - } - else if (enquiry.crit_exts.c1().ue_cap_enquiry_r8().ue_cap_request[i] == rat_type_e::eutra_nr && has_nr_dc()) { + } else if (enquiry.crit_exts.c1().ue_cap_enquiry_r8().ue_cap_request[i] == rat_type_e::eutra_nr && has_nr_dc()) { info->ue_cap_rat_container_list[rat_idx] = get_eutra_nr_capabilities(); logger.info("Including EUTRA-NR capabilities in UE Capability Info (%d B)", info->ue_cap_rat_container_list[rat_idx].ue_cap_rat_container.size()); @@ -2077,8 +2079,7 @@ void rrc::handle_ue_capability_enquiry(const ue_cap_enquiry_s& enquiry) logger.info("Including NR capabilities in UE Capability Info (%d B)", info->ue_cap_rat_container_list[rat_idx].ue_cap_rat_container.size()); rat_idx++; - } - else { + } else { logger.error("RAT Type of UE Cap request not supported or not configured"); } } diff --git a/srsue/src/stack/rrc/rrc_meas.cc b/srsue/src/stack/rrc/rrc_meas.cc index df26193df..7b9da4784 100644 --- a/srsue/src/stack/rrc/rrc_meas.cc +++ b/srsue/src/stack/rrc/rrc_meas.cc @@ -21,6 +21,7 @@ #include "srsue/hdr/stack/rrc/rrc_meas.h" #include "srslte/asn1/rrc/dl_dcch_msg.h" +#include "srslte/interfaces/ue_phy_interfaces.h" #include "srslte/rrc/rrc_cfg_utils.h" #include "srsue/hdr/stack/rrc/rrc.h" @@ -343,7 +344,7 @@ void rrc::rrc_meas::var_meas_report_list::generate_report_eutra(meas_results_s* } } else { if (var_meas.periodic_timer.is_valid()) { - var_meas.periodic_timer.clear(); + var_meas.periodic_timer.release(); } // else if the triggerType is set to ‘periodical’: if (var_meas.report_cfg_eutra.trigger_type.type().value == report_cfg_eutra_s::trigger_type_c_::types::periodical) { @@ -355,7 +356,6 @@ void rrc::rrc_meas::var_meas_report_list::generate_report_eutra(meas_results_s* } void rrc::rrc_meas::var_meas_report_list::generate_report_interrat(meas_results_s* report, const uint32_t measId) { - meas_result_cell_list_nr_r15_l& neigh_list = report->meas_result_neigh_cells.set_meas_result_neigh_cell_list_nr_r15(); var_meas_report& var_meas = varMeasReportList.at(measId); @@ -370,7 +370,6 @@ void rrc::rrc_meas::var_meas_report_list::generate_report_interrat(meas_results_ // the following for (auto& cell : var_meas.cell_triggered_list) { - if (neigh_list.size() <= var_meas.report_cfg_inter.max_report_cells) { meas_result_cell_nr_r15_s rc = {}; @@ -425,7 +424,7 @@ void rrc::rrc_meas::var_meas_report_list::generate_report_interrat(meas_results_ } } else { if (var_meas.periodic_timer.is_valid()) { - var_meas.periodic_timer.clear(); + var_meas.periodic_timer.release(); } // else if the triggerType is set to ‘periodical’: if (var_meas.report_cfg_inter.trigger_type.type().value == @@ -588,7 +587,6 @@ void rrc::rrc_meas::var_meas_cfg::report_triggers_eutra_check_new(int32_t } if (new_cell_trigger) { - // include a measurement reporting entry within the VarMeasReportList for this measId (nof_reports reset // inside) include the concerned cell(s) in the cellsTriggeredList defined within the VarMeasReportList meas_report->set_measId(meas_id, meas_obj.carrier_freq, report_cfg, cells_triggered_list); @@ -761,7 +759,6 @@ void rrc::rrc_meas::var_meas_cfg::report_triggers() { // for each measId included in the measIdList within VarMeasConfig for (auto& m : measIdList) { - if (!reportConfigList.count(m.second.report_cfg_id) || !measObjectsList.count(m.second.meas_obj_id)) { logger.error("MEAS: Computing report triggers. MeasId=%d has invalid report or object settings", m.first); continue; @@ -780,14 +777,12 @@ void rrc::rrc_meas::var_meas_cfg::report_triggers() if (meas_obj.meas_obj.type().value == meas_obj_to_add_mod_s::meas_obj_c_::types_opts::meas_obj_eutra && report_cfg.report_cfg.type().value == report_cfg_to_add_mod_s::report_cfg_c_::types::report_cfg_eutra) { report_triggers_eutra(m.first, report_cfg.report_cfg.report_cfg_eutra(), meas_obj.meas_obj.meas_obj_eutra()); - } - else if (meas_obj.meas_obj.type().value == meas_obj_to_add_mod_s::meas_obj_c_::types_opts::meas_obj_nr_r15 && - report_cfg.report_cfg.type().value == - report_cfg_to_add_mod_s::report_cfg_c_::types::report_cfg_inter_rat) { + } else if (meas_obj.meas_obj.type().value == meas_obj_to_add_mod_s::meas_obj_c_::types_opts::meas_obj_nr_r15 && + report_cfg.report_cfg.type().value == + report_cfg_to_add_mod_s::report_cfg_c_::types::report_cfg_inter_rat) { report_triggers_interrat_nr( m.first, report_cfg.report_cfg.report_cfg_inter_rat(), meas_obj.meas_obj.meas_obj_nr_r15()); - } - else { + } else { logger.error("Unsupported combination of measurement object type %s and report config type %s ", meas_obj.meas_obj.type().to_string().c_str(), report_cfg.report_cfg.type().to_string().c_str()); @@ -825,7 +820,6 @@ void rrc::rrc_meas::var_meas_cfg::eval_triggers_eutra(uint32_t meas_i if (report_cfg.trigger_type.type() == report_cfg_eutra_s::trigger_type_c_::types::event) { // A1 & A2 are for serving cell only if (event_id.type().value < eutra_event_s::event_id_c_::types::event_a3) { - float thresh = 0.0; bool enter_condition = false; bool exit_condition = false; @@ -1026,9 +1020,9 @@ void rrc::rrc_meas::var_meas_cfg::eval_triggers() report_cfg.report_cfg.type().value == report_cfg_to_add_mod_s::report_cfg_c_::types::report_cfg_eutra) { eval_triggers_eutra( m.first, report_cfg.report_cfg.report_cfg_eutra(), meas_obj.meas_obj.meas_obj_eutra(), serv_cell, Ofs, Ocs); - } - else if (meas_obj.meas_obj.type().value == meas_obj_to_add_mod_s::meas_obj_c_::types_opts::meas_obj_nr_r15 && - report_cfg.report_cfg.type().value == report_cfg_to_add_mod_s::report_cfg_c_::types::report_cfg_inter_rat) + } else if (meas_obj.meas_obj.type().value == meas_obj_to_add_mod_s::meas_obj_c_::types_opts::meas_obj_nr_r15 && + report_cfg.report_cfg.type().value == + report_cfg_to_add_mod_s::report_cfg_c_::types::report_cfg_inter_rat) eval_triggers_interrat_nr( m.first, report_cfg.report_cfg.report_cfg_inter_rat(), meas_obj.meas_obj.meas_obj_nr_r15()); else { diff --git a/srsue/src/stack/rrc/rrc_nr.cc b/srsue/src/stack/rrc/rrc_nr.cc index 22cf1fecc..ffb2a735c 100644 --- a/srsue/src/stack/rrc/rrc_nr.cc +++ b/srsue/src/stack/rrc/rrc_nr.cc @@ -21,6 +21,8 @@ #include "srsue/hdr/stack/rrc/rrc_nr.h" #include "srslte/common/security.h" +#include "srslte/interfaces/ue_pdcp_interfaces.h" +#include "srslte/interfaces/ue_rlc_interfaces.h" #include "srsue/hdr/stack/upper/usim.h" #define Error(fmt, ...) rrc_ptr->log_h->error("Proc \"%s\" - " fmt, name(), ##__VA_ARGS__) diff --git a/srsue/src/stack/rrc/rrc_procedures.cc b/srsue/src/stack/rrc/rrc_procedures.cc index c6333105e..aecd9080a 100644 --- a/srsue/src/stack/rrc/rrc_procedures.cc +++ b/srsue/src/stack/rrc/rrc_procedures.cc @@ -23,6 +23,9 @@ #include "srslte/common/security.h" #include "srslte/common/standard_streams.h" #include "srslte/common/tti_point.h" +#include "srslte/interfaces/ue_pdcp_interfaces.h" +#include "srslte/interfaces/ue_rlc_interfaces.h" +#include "srslte/interfaces/ue_usim_interfaces.h" #include "srsue/hdr/stack/rrc/rrc_meas.h" #include // for printing uint64_t @@ -736,7 +739,7 @@ proc_outcome_t rrc::plmn_search_proc::step() if (rrc_ptr->meas_cells.serving_cell().has_sib1()) { // Save PLMN and TAC to NAS for (uint32_t i = 0; i < rrc_ptr->meas_cells.serving_cell().nof_plmns(); i++) { - if (nof_plmns < MAX_FOUND_PLMNS) { + if (nof_plmns < nas_interface_rrc::MAX_FOUND_PLMNS) { found_plmns[nof_plmns].plmn_id = rrc_ptr->meas_cells.serving_cell().get_plmn(i); found_plmns[nof_plmns].tac = rrc_ptr->meas_cells.serving_cell().get_tac(); nof_plmns++; @@ -1330,9 +1333,9 @@ proc_outcome_t rrc::connection_reest_proc::init(asn1::rrc::reest_cause_e cause) reest_cellid = rrc_ptr->meas_cells.find_cell(reest_source_freq, reest_source_pci)->get_cell_id(); Info("Starting... cause: \"%s\", UE context: {C-RNTI=0x%x, PCI=%d, CELL ID=%d}", - reest_cause == asn1::rrc::reest_cause_opts::recfg_fail ? "Reconfiguration failure" - : cause == asn1::rrc::reest_cause_opts::ho_fail ? "Handover failure" - : "Other failure", + reest_cause == asn1::rrc::reest_cause_opts::recfg_fail + ? "Reconfiguration failure" + : cause == asn1::rrc::reest_cause_opts::ho_fail ? "Handover failure" : "Other failure", reest_rnti, reest_source_pci, reest_cellid); diff --git a/srsue/src/stack/ue_stack_lte.cc b/srsue/src/stack/ue_stack_lte.cc index c18ce250b..7242a3a15 100644 --- a/srsue/src/stack/ue_stack_lte.cc +++ b/srsue/src/stack/ue_stack_lte.cc @@ -21,7 +21,8 @@ #include "srsue/hdr/stack/ue_stack_lte.h" #include "srslte/common/logmap.h" -#include "srslte/srslte.h" +#include "srslte/interfaces/ue_phy_interfaces.h" + #include #include #include @@ -31,17 +32,18 @@ using namespace srslte; namespace srsue { -ue_stack_lte::ue_stack_lte(srslog::sink& log_sink) : +ue_stack_lte::ue_stack_lte() : running(false), args(), - logger(nullptr), - stack_logger(srslog::fetch_basic_logger("STCK", log_sink, false)), - mac_logger(srslog::fetch_basic_logger("MAC", log_sink)), - rlc_logger(srslog::fetch_basic_logger("RLC", log_sink, false)), - pdcp_logger(srslog::fetch_basic_logger("PDCP", log_sink, false)), - rrc_logger(srslog::fetch_basic_logger("RRC", log_sink, false)), - usim_logger(srslog::fetch_basic_logger("USIM", log_sink, false)), - nas_logger(srslog::fetch_basic_logger("NAS", log_sink, false)), + stack_logger(srslog::fetch_basic_logger("STCK", false)), + mac_logger(srslog::fetch_basic_logger("MAC")), + rlc_logger(srslog::fetch_basic_logger("RLC", false)), + pdcp_logger(srslog::fetch_basic_logger("PDCP", false)), + rrc_logger(srslog::fetch_basic_logger("RRC", false)), + usim_logger(srslog::fetch_basic_logger("USIM", false)), + nas_logger(srslog::fetch_basic_logger("NAS", false)), + mac_pcap(), + mac_nr_pcap(), usim(nullptr), phy(nullptr), rlc("RLC"), @@ -52,10 +54,10 @@ ue_stack_lte::ue_stack_lte(srslog::sink& log_sink) : pdcp(&task_sched, "PDCP"), nas(&task_sched), thread("STACK"), - task_sched(512, 2, 64), - tti_tprof("tti_tprof", "STCK", TTI_STAT_PERIOD), - mac_pcap(srslte_rat_t::lte) + task_sched(512, 64), + tti_tprof("tti_tprof", "STCK", TTI_STAT_PERIOD) { + get_background_workers().set_nof_workers(2); ue_task_queue = task_sched.make_task_queue(); gw_queue_id = task_sched.make_task_queue(); cfg_task_queue = task_sched.make_task_queue(); @@ -73,37 +75,32 @@ std::string ue_stack_lte::get_type() } int ue_stack_lte::init(const stack_args_t& args_, - srslte::logger* logger_, phy_interface_stack_lte* phy_, phy_interface_stack_nr* phy_nr_, gw_interface_stack* gw_) { phy_nr = phy_nr_; - if (init(args_, logger_, phy_, gw_)) { + if (init(args_, phy_, gw_)) { return SRSLTE_ERROR; } return SRSLTE_SUCCESS; } -int ue_stack_lte::init(const stack_args_t& args_, - srslte::logger* logger_, - phy_interface_stack_lte* phy_, - gw_interface_stack* gw_) +int ue_stack_lte::init(const stack_args_t& args_, phy_interface_stack_lte* phy_, gw_interface_stack* gw_) { phy = phy_; gw = gw_; - if (init(args_, logger_)) { + if (init(args_)) { return SRSLTE_ERROR; } return SRSLTE_SUCCESS; } -int ue_stack_lte::init(const stack_args_t& args_, srslte::logger* logger_) +int ue_stack_lte::init(const stack_args_t& args_) { - args = args_; - logger = logger_; + args = args_; // init own log stack_logger.set_level(srslog::str_to_basic_level(args.log.stack_level)); @@ -111,41 +108,87 @@ int ue_stack_lte::init(const stack_args_t& args_, srslte::logger* logger_) byte_buffer_pool::get_instance()->enable_logger(true); // init layer logs - srslte::logmap::register_log(std::unique_ptr{new srslte::log_filter{"MAC", logger, true}}); - mac_log->set_level(args.log.mac_level); - mac_log->set_hex_limit(args.log.mac_hex_limit); mac_logger.set_level(srslog::str_to_basic_level(args.log.mac_level)); mac_logger.set_hex_dump_max_size(args.log.mac_hex_limit); - rlc_log->set_level(args.log.rlc_level); - rlc_log->set_hex_limit(args.log.rlc_hex_limit); rlc_logger.set_level(srslog::str_to_basic_level(args.log.rlc_level)); rlc_logger.set_hex_dump_max_size(args.log.rlc_hex_limit); - pdcp_log->set_level(args.log.pdcp_level); - pdcp_log->set_hex_limit(args.log.pdcp_hex_limit); pdcp_logger.set_level(srslog::str_to_basic_level(args.log.pdcp_level)); pdcp_logger.set_hex_dump_max_size(args.log.pdcp_hex_limit); - rrc_log->set_level(args.log.rrc_level); - rrc_log->set_hex_limit(args.log.rrc_hex_limit); rrc_logger.set_level(srslog::str_to_basic_level(args.log.rrc_level)); rrc_logger.set_hex_dump_max_size(args.log.rrc_hex_limit); - usim_log->set_level(args.log.usim_level); - usim_log->set_hex_limit(args.log.usim_hex_limit); usim_logger.set_level(srslog::str_to_basic_level(args.log.usim_level)); usim_logger.set_hex_dump_max_size(args.log.usim_hex_limit); - nas_log->set_level(args.log.nas_level); - nas_log->set_hex_limit(args.log.nas_hex_limit); nas_logger.set_level(srslog::str_to_basic_level(args.log.nas_level)); nas_logger.set_hex_dump_max_size(args.log.nas_hex_limit); // Set up pcap - if (args.pcap.enable) { - if (mac_pcap.open(args.pcap.filename.c_str()) == SRSLTE_SUCCESS) { - mac.start_pcap(&mac_pcap); + // parse pcap trace list + std::vector pcap_list; + srslte::string_parse_list(args.pkt_trace.enable, ',', pcap_list); + if (pcap_list.empty()) { + stack_logger.error("PCAP enable list empty defaulting to disable all PCAPs"); + args.pkt_trace.mac_pcap.enable = false; + args.pkt_trace.mac_nr_pcap.enable = false; + args.pkt_trace.mac_nr_pcap.enable = false; + } + + for (auto& pcap : pcap_list) { + // Remove white spaces + pcap.erase(std::remove_if(pcap.begin(), pcap.end(), isspace), pcap.end()); + if (pcap == "mac" || pcap == "MAC") { + args.pkt_trace.mac_pcap.enable = true; + } else if (pcap == "mac_nr" || pcap == "MAC_NR") { + args.pkt_trace.mac_nr_pcap.enable = true; + } else if (pcap == "nas" || pcap == "NAS") { + args.pkt_trace.nas_pcap.enable = true; + } else if (pcap == "none" || pcap == "NONE") { + args.pkt_trace.mac_pcap.enable = false; + args.pkt_trace.mac_nr_pcap.enable = false; + args.pkt_trace.mac_nr_pcap.enable = false; + } else { + stack_logger.error("Unknown PCAP option %s", pcap.c_str()); } } - if (args.pcap.nas_enable) { - nas_pcap.open(args.pcap.nas_filename.c_str()); - nas.start_pcap(&nas_pcap); + + // If mac and mac_nr pcap option is enabled and if the filenames are the same, + // mac and mac_nr should write in the same PCAP file. + if (args.pkt_trace.mac_pcap.enable && args.pkt_trace.mac_nr_pcap.enable && + args.pkt_trace.mac_pcap.filename == args.pkt_trace.mac_nr_pcap.filename) { + stack_logger.info("Using same MAC PCAP file %s for LTE and NR", args.pkt_trace.mac_pcap.filename.c_str()); + if (mac_pcap.open(args.pkt_trace.mac_pcap.filename.c_str()) == SRSLTE_SUCCESS) { + mac.start_pcap(&mac_pcap); + mac_nr.start_pcap(&mac_pcap); + stack_logger.info("Open mac pcap file %s", args.pkt_trace.mac_pcap.filename.c_str()); + } else { + stack_logger.error("Can not open pcap file %s", args.pkt_trace.mac_pcap.filename.c_str()); + } + } else { + if (args.pkt_trace.mac_pcap.enable) { + if (mac_pcap.open(args.pkt_trace.mac_pcap.filename.c_str()) == SRSLTE_SUCCESS) { + mac.start_pcap(&mac_pcap); + stack_logger.info("Open mac pcap file %s", args.pkt_trace.mac_pcap.filename.c_str()); + } else { + stack_logger.error("Can not open pcap file %s", args.pkt_trace.mac_pcap.filename.c_str()); + } + } + + if (args.pkt_trace.mac_nr_pcap.enable) { + if (mac_nr_pcap.open(args.pkt_trace.mac_nr_pcap.filename.c_str()) == SRSLTE_SUCCESS) { + mac_nr.start_pcap(&mac_nr_pcap); + stack_logger.info("Open mac nr pcap file %s", args.pkt_trace.mac_nr_pcap.filename.c_str()); + } else { + stack_logger.error("Can not open pcap file %s", args.pkt_trace.mac_nr_pcap.filename.c_str()); + } + } + } + + if (args.pkt_trace.nas_pcap.enable) { + if (nas_pcap.open(args.pkt_trace.nas_pcap.filename.c_str()) == SRSLTE_SUCCESS) { + nas.start_pcap(&nas_pcap); + stack_logger.info("Open nas pcap file %s", args.pkt_trace.nas_pcap.filename.c_str()); + } else { + stack_logger.error("Can not open pcap file %s", args.pkt_trace.nas_pcap.filename.c_str()); + } } // Init USIM first to allow early exit in case reader couldn't be found @@ -165,16 +208,7 @@ int ue_stack_lte::init(const stack_args_t& args_, srslte::logger* logger_) mac_nr_args_t mac_nr_args = {}; mac_nr.init(mac_nr_args, phy_nr, &rlc); - rrc_nr.init(phy_nr, - &mac_nr, - &rlc, - &pdcp, - gw, - &rrc, - usim.get(), - task_sched.get_timer_handler(), - nullptr, - args.rrc_nr); + rrc_nr.init(phy_nr, &mac_nr, &rlc, &pdcp, gw, &rrc, usim.get(), task_sched.get_timer_handler(), nullptr, args.rrc_nr); rrc.init(phy, &mac, &rlc, &pdcp, &nas, usim.get(), gw, &rrc_nr, args.rrc); running = true; @@ -203,12 +237,18 @@ void ue_stack_lte::stop_impl() pdcp.stop(); mac.stop(); - if (args.pcap.enable) { + if (args.pkt_trace.mac_pcap.enable) { mac_pcap.close(); } - if (args.pcap.nas_enable) { + if (args.pkt_trace.mac_nr_pcap.enable) { + mac_nr_pcap.close(); + } + if (args.pkt_trace.nas_pcap.enable) { nas_pcap.close(); } + + task_sched.stop(); + get_background_workers().stop(); } bool ue_stack_lte::switch_on() diff --git a/srsue/src/stack/ue_stack_nr.cc b/srsue/src/stack/ue_stack_nr.cc index bcb1a0e24..e7cad87d8 100644 --- a/srsue/src/stack/ue_stack_nr.cc +++ b/srsue/src/stack/ue_stack_nr.cc @@ -27,8 +27,9 @@ using namespace srslte; namespace srsue { ue_stack_nr::ue_stack_nr(srslte::logger* logger_) : - logger(logger_), thread("STACK"), task_sched(64, 2, 64), rlc_log("RLC"), pdcp_log("PDCP") + logger(logger_), thread("STACK"), task_sched(64, 64), rlc_log("RLC"), pdcp_log("PDCP") { + get_background_workers().set_nof_workers(2); mac.reset(new mac_nr(&task_sched)); pdcp.reset(new srslte::pdcp(&task_sched, "PDCP")); rlc.reset(new srslte::rlc("RLC")); @@ -74,7 +75,6 @@ int ue_stack_nr::init(const stack_args_t& args_) 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()); rlc->init(pdcp.get(), rrc.get(), task_sched.get_timer_handler(), 0 /* RB_ID_SRB0 */); pdcp->init(rlc.get(), rrc.get(), gw); @@ -111,6 +111,8 @@ void ue_stack_nr::stop_impl() rlc->stop(); pdcp->stop(); mac->stop(); + + get_background_workers().stop(); } bool ue_stack_nr::switch_on() diff --git a/srsue/src/stack/upper/gw.cc b/srsue/src/stack/upper/gw.cc index af08d5801..445408936 100644 --- a/srsue/src/stack/upper/gw.cc +++ b/srsue/src/stack/upper/gw.cc @@ -20,14 +20,17 @@ */ #include "srsue/hdr/stack/upper/gw.h" +#include "srslte/interfaces/ue_pdcp_interfaces.h" #include "srslte/upper/ipv6.h" +#include #include #include #include #include #include #include +#include #include #include #include @@ -36,10 +39,9 @@ namespace srsue { gw::gw() : thread("GW"), logger(srslog::fetch_basic_logger("GW", false)), tft_matcher(logger) {} -int gw::init(const gw_args_t& args_, srslte::logger* logger_, stack_interface_gw* stack_) +int gw::init(const gw_args_t& args_, stack_interface_gw* stack_) { stack = stack_; - old_logger = logger_; args = args_; run_enable = true; diff --git a/srsue/src/stack/upper/nas.cc b/srsue/src/stack/upper/nas.cc index c42d4c570..9f28c6492 100644 --- a/srsue/src/stack/upper/nas.cc +++ b/srsue/src/stack/upper/nas.cc @@ -25,14 +25,13 @@ #include #include #include -#include -#include #include #include "srslte/asn1/liblte_mme.h" -#include "srslte/common/bcd_helpers.h" #include "srslte/common/logmap.h" -#include "srslte/common/security.h" +#include "srslte/interfaces/ue_gw_interfaces.h" +#include "srslte/interfaces/ue_rrc_interfaces.h" +#include "srslte/interfaces/ue_usim_interfaces.h" #include "srsue/hdr/stack/upper/nas.h" #include "srsue/hdr/stack/upper/nas_idle_procedures.h" @@ -431,8 +430,7 @@ bool nas::connection_request_completed(bool outcome) return true; } -void nas::plmn_search_completed(const rrc_interface_nas::found_plmn_t found_plmns[rrc_interface_nas::MAX_FOUND_PLMNS], - int nof_plmns) +void nas::plmn_search_completed(const found_plmn_t found_plmns[MAX_FOUND_PLMNS], int nof_plmns) { plmn_searcher.trigger(plmn_search_proc::plmn_search_complete_t(found_plmns, nof_plmns)); } diff --git a/srsue/src/stack/upper/nas_idle_procedures.cc b/srsue/src/stack/upper/nas_idle_procedures.cc index 75fbd5b6e..92a774ccb 100644 --- a/srsue/src/stack/upper/nas_idle_procedures.cc +++ b/srsue/src/stack/upper/nas_idle_procedures.cc @@ -20,6 +20,7 @@ */ #include "srsue/hdr/stack/upper/nas_idle_procedures.h" +#include "srslte/interfaces/ue_rrc_interfaces.h" using namespace srslte; diff --git a/srsue/src/stack/upper/usim_base.cc b/srsue/src/stack/upper/usim_base.cc index 3ca0d9829..e43dfc92a 100644 --- a/srsue/src/stack/upper/usim_base.cc +++ b/srsue/src/stack/upper/usim_base.cc @@ -88,7 +88,7 @@ bool usim_base::get_imei_vec(uint8_t* imei_, uint32_t n) return false; } - uint64 temp = imei; + uint64_t temp = imei; for (int i = 14; i >= 0; i--) { imei_[i] = temp % 10; temp /= 10; diff --git a/srsue/src/ue.cc b/srsue/src/ue.cc index 5f6646c7e..d67b90fb4 100644 --- a/srsue/src/ue.cc +++ b/srsue/src/ue.cc @@ -27,8 +27,8 @@ #include "srslte/radio/radio_null.h" #include "srslte/srslte.h" #include "srsue/hdr/phy/phy.h" -#include "srsue/hdr/stack/ue_stack_lte.h" #include "srsue/hdr/phy/vnf_phy_nr.h" +#include "srsue/hdr/stack/ue_stack_lte.h" #include "srsue/hdr/stack/ue_stack_nr.h" #include #include @@ -38,8 +38,7 @@ using namespace srslte; namespace srsue { -ue::ue(srslog::sink& log_sink) : - old_logger(nullptr), log_sink(log_sink), logger(srslog::fetch_basic_logger("UE", log_sink, false)) +ue::ue() : old_logger(nullptr), logger(srslog::fetch_basic_logger("UE", false)) { // print build info std::cout << std::endl << get_build_string() << std::endl << std::endl; @@ -67,7 +66,7 @@ int ue::init(const all_args_t& args_, srslte::logger* logger_) // Instantiate layers and stack together our UE if (args.stack.type == "lte") { - std::unique_ptr lte_stack(new ue_stack_lte(log_sink)); + std::unique_ptr lte_stack(new ue_stack_lte); if (!lte_stack) { srslte::console("Error creating LTE stack instance.\n"); return SRSLTE_ERROR; @@ -79,7 +78,7 @@ int ue::init(const all_args_t& args_, srslte::logger* logger_) return SRSLTE_ERROR; } - std::unique_ptr lte_phy = std::unique_ptr(new srsue::phy(log_sink)); + std::unique_ptr lte_phy = std::unique_ptr(new srsue::phy); if (!lte_phy) { srslte::console("Error creating LTE PHY instance.\n"); return SRSLTE_ERROR; @@ -114,12 +113,12 @@ int ue::init(const all_args_t& args_, srslte::logger* logger_) ret = SRSLTE_ERROR; } - if (lte_stack->init(args.stack, old_logger, lte_phy.get(), lte_phy.get(), gw_ptr.get())) { + if (lte_stack->init(args.stack, lte_phy.get(), lte_phy.get(), gw_ptr.get())) { srslte::console("Error initializing stack.\n"); ret = SRSLTE_ERROR; } - if (gw_ptr->init(args.gw, old_logger, lte_stack.get())) { + if (gw_ptr->init(args.gw, lte_stack.get())) { srslte::console("Error initializing GW.\n"); ret = SRSLTE_ERROR; } @@ -152,7 +151,7 @@ int ue::init(const all_args_t& args_, srslte::logger* logger_) return SRSLTE_ERROR; } - if (gw_ptr->init(args.gw, old_logger, nr_stack.get())) { + if (gw_ptr->init(args.gw, nr_stack.get())) { srslte::console("Error initializing GW.\n"); return SRSLTE_ERROR; } @@ -338,6 +337,7 @@ bool ue::get_metrics(ue_metrics_t* m) radio->get_metrics(&m->rf); stack->get_metrics(&m->stack); gw_inst->get_metrics(m->gw, m->stack.mac[0].nof_tti); + m->sys = sys_proc.get_metrics(); return true; } diff --git a/srsue/test/mac_nr/proc_ra_nr_test.cc b/srsue/test/mac_nr/proc_ra_nr_test.cc index 4c68af719..5f60ef5a2 100644 --- a/srsue/test/mac_nr/proc_ra_nr_test.cc +++ b/srsue/test/mac_nr/proc_ra_nr_test.cc @@ -32,14 +32,14 @@ public: void send_prach(const uint32_t prach_occasion_, const int preamble_index_, const float preamble_received_target_power_, - const float ta_base_sec_ = 0.0f) + const float ta_base_sec_ = 0.0f) override { prach_occasion = prach_occasion_; preamble_index = preamble_index_; preamble_received_target_power = preamble_received_target_power_; } - int tx_request(const tx_request_t& request) { return 0; } - int set_ul_grant(std::array, uint16_t rnti, srslte_rnti_type_t rnti_type) + int tx_request(const tx_request_t& request) override { return 0; } + int set_ul_grant(std::array, uint16_t rnti, srslte_rnti_type_t rnti_type) override { return 0; } @@ -50,11 +50,12 @@ public: *preamble_index_ = preamble_index; *preamble_received_target_power_ = preamble_received_target_power; } + void sr_send(uint32_t sr_id) override {} private: - uint32_t prach_occasion; - uint32_t preamble_index; - int preamble_received_target_power; + uint32_t prach_occasion = 0; + uint32_t preamble_index = 0; + int preamble_received_target_power = 0; }; class dummy_mac : public mac_interface_proc_ra_nr @@ -72,7 +73,7 @@ public: void msga_flush(){}; private: - uint16_t crnti; + uint16_t crnti = SRSLTE_INVALID_RNTI; }; int main() diff --git a/srsue/test/mac_test.cc b/srsue/test/mac_test.cc index dc9cf06e6..36d857e27 100644 --- a/srsue/test/mac_test.cc +++ b/srsue/test/mac_test.cc @@ -21,10 +21,8 @@ #include "srslte/asn1/rrc/rr_common.h" #include "srslte/asn1/rrc_utils.h" -#include "srslte/common/log_filter.h" #include "srslte/common/mac_pcap.h" #include "srslte/common/test_common.h" -#include "srslte/interfaces/ue_interfaces.h" #include "srslte/test/ue_test_interfaces.h" #include "srsue/hdr/stack/mac/mac.h" #include "srsue/hdr/stack/mac/mux.h" @@ -110,7 +108,6 @@ public: nof_rar_grants = 0; rar_temp_rnti = 0; rar_time_adv = 0; - last_crnti = 0; prach_transmitted = false; prach_info_tx = false; } @@ -156,7 +153,6 @@ public: void set_mch_period_stop(uint32_t stop) override{}; // phy_interface_mac_common - void set_crnti(uint16_t rnti) override { last_crnti = rnti; } void set_timeadv_rar(uint32_t ta_cmd) override { rar_time_adv = ta_cmd; } void set_timeadv(uint32_t ta_cmd) override{}; void set_activation_deactivation_scell(uint32_t cmd, uint32_t tti) override { scell_cmd = cmd; }; @@ -177,7 +173,6 @@ public: // Testing methods int dl_grant(mac* mac_h, bool ack, uint16_t rnti, uint32_t len, const uint8_t* payload) { - bool ack_v[SRSLTE_MAX_CODEWORDS] = {ack, 0}; mac_interface_phy_lte::tb_action_dl_t dl_action = {}; @@ -214,7 +209,6 @@ public: int rar_and_check(mac* mac_h, bool preamble_matches, uint32_t temp_rnti) { - // Generate RAR to MAC uint8_t grant[SRSLTE_RAR_GRANT_LEN] = {1}; @@ -252,7 +246,6 @@ public: bool is_rar = false, bool adaptive_retx = false) { - mac_interface_phy_lte::tb_action_ul_t ul_action = {}; mac_interface_phy_lte::mac_grant_ul_t ul_mac_grant = {}; @@ -301,8 +294,6 @@ public: uint32_t get_rar_rnti() { return (prach_tti % 10) + 1; } - uint16_t get_crnti() { return last_crnti; } - const static uint32_t prach_delay = 5; private: @@ -315,8 +306,6 @@ private: float last_target_power = 0; int last_preamble_idx = -1; - uint16_t last_crnti = 0; - srslog::basic_logger& logger = srslog::fetch_basic_logger("PHY"); bool ul_ndi = false; @@ -932,7 +921,7 @@ int mac_ul_sch_pdu_with_short_bsr_test() rlc.write_sdu(1, 10); // generate TTI - uint32 tti = 0; + uint32_t tti = 0; stack.run_tti(tti++); usleep(100); @@ -989,7 +978,7 @@ int mac_ul_sch_pdu_with_short_bsr_zero_test() rlc.write_sdu(2, 2); // generate TTI - uint32 tti = 0; + uint32_t tti = 0; stack.run_tti(tti++); usleep(100); @@ -1276,7 +1265,7 @@ int mac_ul_sch_regular_bsr_retx_test() rlc.write_sdu(3, 1000); // generate TTI - uint32 tti = 0; + uint32_t tti = 0; stack.run_tti(tti++); usleep(100); @@ -1441,7 +1430,7 @@ int mac_ul_sch_periodic_bsr_test() rlc.write_sdu(3, 100); // generate TTI - uint32 tti = 0; + uint32_t tti = 0; stack.run_tti(tti++); usleep(100); @@ -1714,7 +1703,7 @@ int mac_ul_sch_trunc_bsr_test2() rlc.write_sdu(3, 100); // generate TTI - uint32 tti = 0; + uint32_t tti = 0; stack.run_tti(tti++); usleep(100); @@ -2006,7 +1995,6 @@ int run_mac_ra_test(struct ra_test test, mac* mac, phy_dummy* phy, uint32_t* tti bool new_prach = false; for (uint32_t j = 0; j < test.nof_prachs; j++) { - // In the next TTI, a BSR shall be triggered which triggers SR which triggers PRACH if (test.assume_prach_transmitted != (int)j) { phy->set_prach_tti(tti + phy->prach_delay); @@ -2057,7 +2045,6 @@ int run_mac_ra_test(struct ra_test test, mac* mac, phy_dummy* phy, uint32_t* tti // Request Msg3 (re)-transmission for (uint32_t i = 0; i < test.nof_msg3_retx + 1; i++) { - // Step to contention resolution. Make sure timer does not start until Msg3 is transmitted // and restarts on every retx for (int k = 0; k < test.rach_cfg.ra_supervision_info.mac_contention_resolution_timer.to_number() - 2; k++) { @@ -2094,7 +2081,6 @@ int run_mac_ra_test(struct ra_test test, mac* mac, phy_dummy* phy, uint32_t* tti if (phy->dl_grant(mac, true, test.crnti, 2, tv_msg4_nocontres)) { return -1; } - TESTASSERT(phy->get_crnti() != test.crnti); // UL grant is checked later if (test.send_valid_ul_grant) { @@ -2130,7 +2116,6 @@ int run_mac_ra_test(struct ra_test test, mac* mac, phy_dummy* phy, uint32_t* tti if (test.check_ra_successful) { stack->run_tti(tti); stack->run_tti(tti); - TESTASSERT(phy->get_crnti() == (test.crnti ? test.crnti : test.temp_rnti)); TESTASSERT(mac->get_dl_sched_rnti(tti) == (test.crnti ? test.crnti : test.temp_rnti)); tti++; } @@ -2174,7 +2159,7 @@ int mac_random_access_test() set_mac_cfg_t_rach_cfg_common(&mac_cfg, rach_cfg); mac.set_config(mac_cfg); - uint32 tti = 0; + uint32_t tti = 0; stack.run_tti(tti++); // make sure MAC/PRACH config is applied // generate config for LCIDs in different LCGs than CCCH @@ -2271,7 +2256,6 @@ int mac_random_access_test() // To trigger a new RA we have to either generate more data for high-prio LCID (e.g. SRB1) // or wait until BSR-reTX is triggered rlc.write_sdu(1, 100); - phy.set_crnti(0); srslog::fetch_basic_logger("MAC").info("\n=========== Test %d =============", test_id++); my_test.crnti = my_test.temp_rnti; my_test.temp_rnti++; // Temporal C-RNTI has to change to avoid duplicate @@ -2286,7 +2270,6 @@ int mac_random_access_test() srslog::fetch_basic_logger("MAC").info("\n=========== Test %d =============", test_id++); rrc.ho_finish_successful = false; phy.set_prach_tti(tti + phy.prach_delay); - phy.set_crnti(0); rlc.write_sdu(0, 6); // Add new UL-CCCH with Msg3 (DRB SDU still buffered) stack.run_tti(tti++); my_test.nof_prachs = rach_cfg.ra_supervision_info.preamb_trans_max.to_number(); @@ -2333,7 +2316,6 @@ int mac_random_access_test() rlc.write_sdu(0, 6); // Add new UL-CCCH with Msg3 (DRB SDU still buffered) phy.set_prach_tti(tti + phy.prach_delay); stack.run_tti(tti++); - phy.set_crnti(0); my_test.nof_prachs = rach_cfg.ra_supervision_info.preamb_trans_max.to_number(); my_test.rar_nof_invalid_rapid = rach_cfg.ra_supervision_info.ra_resp_win_size.to_number(); my_test.temp_rnti++; // Temporal C-RNTI has to change to avoid duplicate @@ -2352,7 +2334,6 @@ int mac_random_access_test() rlc.write_sdu(0, 6); // Add new UL-CCCH with Msg3 (DRB SDU still buffered) phy.set_prach_tti(tti + phy.prach_delay); stack.run_tti(tti++); - phy.set_crnti(0); my_test.nof_prachs = 1; my_test.rar_nof_invalid_rapid = 0; my_test.check_ra_successful = true; @@ -2384,13 +2365,6 @@ int main(int argc, char** argv) phy_logger.set_hex_dump_max_size(100000); srslog::init(); - srslte::log_filter rlc_log("RLC"); - rlc_log.set_level(srslte::LOG_LEVEL_DEBUG); - rlc_log.set_hex_limit(100000); - srslte::log_filter mac_log("MAC"); - mac_log.set_level(srslte::LOG_LEVEL_DEBUG); - mac_log.set_hex_limit(100000); - TESTASSERT(mac_unpack_test() == SRSLTE_SUCCESS); TESTASSERT(mac_ul_sch_pdu_test1() == SRSLTE_SUCCESS); TESTASSERT(mac_ul_logical_channel_prioritization_test1() == SRSLTE_SUCCESS); diff --git a/srsue/test/phy/scell_search_test.cc b/srsue/test/phy/scell_search_test.cc index 854e4ba42..1f805e331 100644 --- a/srsue/test/phy/scell_search_test.cc +++ b/srsue/test/phy/scell_search_test.cc @@ -19,17 +19,16 @@ * */ +#include "srslte/interfaces/phy_interface_types.h" #include "srslte/srslog/srslog.h" +#include "srsue/hdr/phy/scell/intra_measure.h" #include #include #include #include #include #include -#include #include -#include -#include #include // Common execution parameters @@ -131,10 +130,6 @@ public: if (srslte_enb_dl_set_cell(&enb_dl, cell)) { ERROR("Error setting eNb DL cell"); } - - if (srslte_enb_dl_add_rnti(&enb_dl, serving_cell_pdsch_rnti)) { - ERROR("Error adding RNTI"); - } } int work(srslte_dl_sf_cfg_t* dl_sf, @@ -422,8 +417,7 @@ int main(int argc, char** argv) srslte_softbuffer_tx_t* softbuffer_tx[SRSLTE_MAX_TB] = {}; // Over-the-air only - std::unique_ptr radio = nullptr; - std::unique_ptr radio_log = nullptr; + std::unique_ptr radio = nullptr; // Set Receiver args common.args = &phy_args; @@ -528,7 +522,7 @@ int main(int argc, char** argv) channel_args.delay_enable = std::isnormal(channel_delay_max_us); channel_args.delay_min_us = channel_delay_us; channel_args.delay_max_us = channel_delay_us; - channel_args.delay_period_s = (uint32)channel_period_s; + channel_args.delay_period_s = (uint32_t)channel_period_s; channel_args.delay_init_time_s = channel_init_time_s; channel_args.awgn_enable = std::isnormal(channel_snr_db) and (pci == *pcis_to_simulate.begin()); channel_args.awgn_signal_power_dBfs = srslte_enb_dl_get_maximum_signal_power_dBfs(cell.nof_prb); diff --git a/srsue/test/phy/ue_phy_test.cc b/srsue/test/phy/ue_phy_test.cc index a44d2e238..8f5f51d8b 100644 --- a/srsue/test/phy/ue_phy_test.cc +++ b/srsue/test/phy/ue_phy_test.cc @@ -373,7 +373,7 @@ private: std::condition_variable cvar; public: - phy_test_bench(const srsue::phy_args_t& phy_args, const srslte_cell_t& cell, srslte::logger& logger_) : + phy_test_bench(const srsue::phy_args_t& phy_args, const srslte_cell_t& cell) : radio(cell.nof_ports, srslte_sampling_freq_hz(cell.nof_prb)), thread("phy_test_bench"), logger(srslog::fetch_basic_logger("test bench", false)) @@ -382,7 +382,7 @@ public: sf_len = SRSLTE_SF_LEN_PRB(cell.nof_prb); // Initialise UE - phy = std::unique_ptr(new srsue::phy(srslog::get_default_sink())); + phy = std::unique_ptr(new srsue::phy); phy->init(phy_args, &stack, &radio); // Initialise DL baseband buffers @@ -422,9 +422,6 @@ public: void configure_dedicated(uint16_t rnti, srslte::phy_cfg_t& phy_cfg) { - // set RNTI - phy->set_crnti(rnti); - // Set PHY configuration phy->set_config(phy_cfg, 0); } @@ -510,15 +507,11 @@ int main(int argc, char** argv) // Set custom test cell and arguments here phy_args.log.phy_level = "info"; - // Setup logging. - srslte::srslog_wrapper log_wrapper(srslog::fetch_log_channel("main_channel")); - // Start the log backend. srslog::init(); // Create test bench - std::unique_ptr phy_test = - std::unique_ptr(new phy_test_bench(phy_args, cell, log_wrapper)); + std::unique_ptr phy_test = std::unique_ptr(new phy_test_bench(phy_args, cell)); phy_test->set_loglevel("info"); // Start test bench diff --git a/srsue/test/ttcn3/hdr/lte_ttcn3_phy.h b/srsue/test/ttcn3/hdr/lte_ttcn3_phy.h index 2e031c33c..3a46d0a1c 100644 --- a/srsue/test/ttcn3/hdr/lte_ttcn3_phy.h +++ b/srsue/test/ttcn3/hdr/lte_ttcn3_phy.h @@ -22,10 +22,11 @@ #ifndef SRSUE_TTCN3_LTE_PHY_H #define SRSUE_TTCN3_LTE_PHY_H +#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/interfaces/ue_phy_interfaces.h" #include "srsue/hdr/phy/ue_lte_phy_base.h" #include "srsue/hdr/ue.h" #include "ttcn3_interfaces.h" -#include #include using namespace srsue; @@ -91,7 +92,6 @@ public: int sr_last_tx_tti() override; // phy_interface_mac_common - void set_crnti(uint16_t rnti) override; void set_timeadv_rar(uint32_t ta_cmd) override; void set_timeadv(uint32_t ta_cmd) override; void set_rar_grant(uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN], uint16_t rnti) override; diff --git a/srsue/test/ttcn3/hdr/ttcn3_drb_interface.h b/srsue/test/ttcn3/hdr/ttcn3_drb_interface.h index 655668aee..77c88edbf 100644 --- a/srsue/test/ttcn3/hdr/ttcn3_drb_interface.h +++ b/srsue/test/ttcn3/hdr/ttcn3_drb_interface.h @@ -75,7 +75,7 @@ private: Document document; if (document.Parse((char*)&rx_buf->at(2)).HasParseError() || document.IsObject() == false) { - logger.error((uint8*)&rx_buf->at(2), json_len, "Error parsing incoming data."); + logger.error((uint8_t*)&rx_buf->at(2), json_len, "Error parsing incoming data."); return SRSLTE_ERROR; } diff --git a/srsue/test/ttcn3/hdr/ttcn3_interfaces.h b/srsue/test/ttcn3/hdr/ttcn3_interfaces.h index 2a0ec16db..9833d91d2 100644 --- a/srsue/test/ttcn3/hdr/ttcn3_interfaces.h +++ b/srsue/test/ttcn3/hdr/ttcn3_interfaces.h @@ -24,6 +24,7 @@ #include "srslte/common/common.h" #include "srslte/interfaces/ue_interfaces.h" +#include "srslte/interfaces/ue_pdcp_interfaces.h" #include "ttcn3_helpers.h" // Interfaces used by system interface to communicate with main component @@ -85,8 +86,8 @@ public: virtual void release_as_security(const ttcn3_helpers::timing_info_t timing, const std::string cell_name) = 0; virtual ttcn3_helpers::pdcp_count_map_t get_pdcp_count(const std::string cell_name) = 0; - virtual uint32_t get_tti() = 0; - virtual void set_forced_lcid(int lcid) = 0; + virtual uint32_t get_tti() = 0; + virtual void set_forced_lcid(int lcid) = 0; }; class ss_srb_interface diff --git a/srsue/test/ttcn3/hdr/ttcn3_srb_interface.h b/srsue/test/ttcn3/hdr/ttcn3_srb_interface.h index 6e1bd6d53..17c00ddee 100644 --- a/srsue/test/ttcn3/hdr/ttcn3_srb_interface.h +++ b/srsue/test/ttcn3/hdr/ttcn3_srb_interface.h @@ -76,7 +76,7 @@ private: Document document; if (document.Parse((char*)&rx_buf->at(2)).HasParseError() || document.IsObject() == false) { - logger.error((uint8*)&rx_buf->at(2), json_len, "Error parsing incoming data."); + logger.error((uint8_t*)&rx_buf->at(2), json_len, "Error parsing incoming data."); return SRSLTE_ERROR; } diff --git a/srsue/test/ttcn3/hdr/ttcn3_sys_interface.h b/srsue/test/ttcn3/hdr/ttcn3_sys_interface.h index 5db433d14..57abdcf9f 100644 --- a/srsue/test/ttcn3/hdr/ttcn3_sys_interface.h +++ b/srsue/test/ttcn3/hdr/ttcn3_sys_interface.h @@ -68,7 +68,7 @@ private: Document document; if (document.Parse(json).HasParseError() || document.IsObject() == false) { - logger.error((uint8*)json, json_len, "Error parsing incoming data."); + logger.error((uint8_t*)json, json_len, "Error parsing incoming data."); return SRSLTE_ERROR; } diff --git a/srsue/test/ttcn3/hdr/ttcn3_syssim.h b/srsue/test/ttcn3/hdr/ttcn3_syssim.h index 8b07f9329..271a2cf01 100644 --- a/srsue/test/ttcn3/hdr/ttcn3_syssim.h +++ b/srsue/test/ttcn3/hdr/ttcn3_syssim.h @@ -47,7 +47,7 @@ class ttcn3_syssim : public syssim_interface_phy, public srslte::pdu_queue::process_callback { public: - ttcn3_syssim(srslte::logger& logger_file_, srslte::logger& logger_stdout_, ttcn3_ue* ue_); + explicit ttcn3_syssim(ttcn3_ue* ue_); ~ttcn3_syssim(); @@ -229,15 +229,6 @@ private: epoll_timer_handler timer_handler; epoll_signal_handler signal_handler; - // Logging stuff (to be removed) - srslte::logger& logger_stdout; - srslte::logger& logger_file; - srslte::logger* old_logger = nullptr; - srslte::log_ref log; - srslte::log_ref ss_mac_log{"SS-MAC"}; - srslte::log_ref ss_rlc_log{"SS-RLC"}; - srslte::log_ref ss_pdcp_log{"SS-PDCP"}; - all_args_t args = {}; // Simulator vars @@ -271,8 +262,7 @@ private: { public: syssim_cell_t(ttcn3_syssim* ss) : - rlc(ss->ss_rlc_log->get_service_name().c_str()), - pdcp(&ss->stack.task_sched, ss->ss_pdcp_log->get_service_name().c_str()) + rlc(ss->ss_rlc_logger.id().c_str()), pdcp(&ss->stack.task_sched, ss->ss_pdcp_logger.id().c_str()) {} cell_config_t config; diff --git a/srsue/test/ttcn3/hdr/ttcn3_ue.h b/srsue/test/ttcn3/hdr/ttcn3_ue.h index fc23c4b90..0c13fc85d 100644 --- a/srsue/test/ttcn3/hdr/ttcn3_ue.h +++ b/srsue/test/ttcn3/hdr/ttcn3_ue.h @@ -33,7 +33,7 @@ public: virtual ~ttcn3_ue(); - int init(all_args_t args, srslte::logger* logger_, syssim_interface_phy* syssim_, const std::string tc_name_); + int init(all_args_t args, syssim_interface_phy* syssim_, const std::string tc_name_); void stop(); @@ -85,7 +85,6 @@ private: std::unique_ptr stack; // Generic logger members - srslte::logger* old_logger = nullptr; srslog::basic_logger& logger; test_loop_mode_state_t test_loop_mode = TEST_LOOP_INACTIVE; diff --git a/srsue/test/ttcn3/src/lte_ttcn3_phy.cc b/srsue/test/ttcn3/src/lte_ttcn3_phy.cc index 6c4ef33b6..71f203e72 100644 --- a/srsue/test/ttcn3/src/lte_ttcn3_phy.cc +++ b/srsue/test/ttcn3/src/lte_ttcn3_phy.cc @@ -224,12 +224,6 @@ int lte_ttcn3_phy::sr_last_tx_tti() // The RAT-agnostic interface for MAC -/* Sets a C-RNTI allowing the PHY to pregenerate signals if necessary */ -void lte_ttcn3_phy::set_crnti(uint16_t rnti) -{ - logger.debug("Set Temp-RNTI=%d, pregen not used", rnti); -} - /* Time advance commands */ void lte_ttcn3_phy::set_timeadv_rar(uint32_t ta_cmd) { diff --git a/srsue/test/ttcn3/src/ttcn3_dut.cc b/srsue/test/ttcn3/src/ttcn3_dut.cc index 0f590a1cd..426a9f954 100644 --- a/srsue/test/ttcn3/src/ttcn3_dut.cc +++ b/srsue/test/ttcn3/src/ttcn3_dut.cc @@ -37,7 +37,8 @@ using namespace rapidjson; namespace bpo = boost::program_options; typedef struct { - pcap_args_t pcap; + pcap_args_t mac_pcap; + pcap_args_t nas_pcap; std::string log_filename; std::string log_level; int32_t log_hex_level; @@ -54,10 +55,10 @@ all_args_t parse_args(ttcn3_dut_args_t* args, int argc, char* argv[]) bpo::options_description common("Configuration options"); // clang-format off common.add_options() - ("pcap.enable", bpo::value(&args->pcap.enable)->default_value(true), "Enable MAC packet captures for wireshark") - ("pcap.filename", bpo::value(&args->pcap.filename)->default_value("/tmp/ttcn3_ue.pcap"), "MAC layer capture filename") - ("pcap.nas_enable", bpo::value(&args->pcap.nas_enable)->default_value(false), "Enable NAS packet captures for wireshark") - ("pcap.nas_filename", bpo::value(&args->pcap.nas_filename)->default_value("/tmp/ttcn3_ue_nas.pcap"), "NAS layer capture filename (useful when NAS encryption is enabled)") + ("pcap.enable", bpo::value(&args->mac_pcap.enable)->default_value(true), "Enable MAC packet captures for wireshark") + ("pcap.filename", bpo::value(&args->mac_pcap.filename)->default_value("/tmp/ttcn3_ue.pcap"), "MAC layer capture filename") + ("pcap.nas_enable", bpo::value(&args->nas_pcap.enable)->default_value(false), "Enable NAS packet captures for wireshark") + ("pcap.nas_filename", bpo::value(&args->nas_pcap.filename)->default_value("/tmp/ttcn3_ue_nas.pcap"), "NAS layer capture filename (useful when NAS encryption is enabled)") ("logfilename", bpo::value(&args->log_filename)->default_value("/tmp/ttcn3_ue.log"), "Filename of log file") ("loglevel", bpo::value(&args->log_level)->default_value("warning"), "Log level (Error,Warning,Info,Debug)") ("loghexlevel", bpo::value(&args->log_hex_level)->default_value(64), "Log hex level (-1 unbounded)"); @@ -81,11 +82,11 @@ all_args_t parse_args(ttcn3_dut_args_t* args, int argc, char* argv[]) all_args_t all_args = {}; - all_args.stack.pcap.enable = args->pcap.enable; - all_args.stack.pcap.nas_enable = args->pcap.nas_enable; + all_args.stack.pkt_trace.mac_pcap.enable = args->mac_pcap.enable; + all_args.stack.pkt_trace.mac_pcap.filename = args->mac_pcap.filename; - all_args.stack.pcap.filename = args->pcap.filename; - all_args.stack.pcap.nas_filename = args->pcap.nas_filename; + all_args.stack.pkt_trace.nas_pcap.enable = args->nas_pcap.enable; + all_args.stack.pkt_trace.nas_pcap.filename = args->nas_pcap.filename; all_args.log.filename = args->log_filename; all_args.log.all_level = args->log_level; @@ -135,20 +136,14 @@ int main(int argc, char** argv) } srslog::set_default_sink(*default_sink); - srslte::srslog_wrapper file_wrapper(srslog::fetch_log_channel("file_channel")); - srslte::srslog_wrapper stdout_wrapper(srslog::fetch_log_channel("stdout_channel", srslog::fetch_stdout_sink(), {})); - // Start the log backend. srslog::init(); - // Instantiate file logger - srslte::logmap::set_default_logger(&file_wrapper); - // Create UE object unique_ptr ue = std::unique_ptr(new ttcn3_ue()); // create and init SYSSIM - ttcn3_syssim syssim(file_wrapper, stdout_wrapper, ue.get()); + ttcn3_syssim syssim(ue.get()); if (syssim.init(ue_args) != SRSLTE_SUCCESS) { fprintf(stderr, "Error: Couldn't initialize system simulator\n"); return SRSLTE_ERROR; diff --git a/srsue/test/ttcn3/src/ttcn3_syssim.cc b/srsue/test/ttcn3/src/ttcn3_syssim.cc index 07e30c45a..e493f55ff 100644 --- a/srsue/test/ttcn3/src/ttcn3_syssim.cc +++ b/srsue/test/ttcn3/src/ttcn3_syssim.cc @@ -38,7 +38,7 @@ #include "ttcn3_ut_interface.h" #include -ttcn3_syssim::ttcn3_syssim(srslte::logger& logger_file_, srslte::logger& logger_stdout_, ttcn3_ue* ue_) : +ttcn3_syssim::ttcn3_syssim(ttcn3_ue* ue_) : logger(srslog::fetch_basic_logger("SS")), ut_logger(srslog::fetch_basic_logger("UT", false)), sys_logger(srslog::fetch_basic_logger("SYS", false)), @@ -55,18 +55,14 @@ ttcn3_syssim::ttcn3_syssim(srslte::logger& logger_file_, srslte::logger& logger_ ip_ctrl(ip_ctrl_logger), srb(srb_logger), drb(drb_logger), - log{"SS "}, mac_msg_ul(20, ss_mac_logger), mac_msg_dl(20, ss_mac_logger), pdus(logger, 128), - logger_stdout(logger_stdout_), - logger_file(logger_file_), - old_logger(&logger_file), ue(ue_), signal_handler(&running), timer_handler(create_tti_timer(), [&](uint64_t res) { new_tti_indication(res); }) { - if (ue->init(all_args_t{}, old_logger, this, "INIT_TEST") != SRSLTE_SUCCESS) { + if (ue->init(all_args_t{}, this, "INIT_TEST") != SRSLTE_SUCCESS) { ue->stop(); fprintf(stderr, "Couldn't initialize UE.\n"); } @@ -80,7 +76,6 @@ int ttcn3_syssim::init(const all_args_t& args_) // Make sure to get SS logging as well if (args.log.filename == "stdout") { - old_logger = &logger_stdout; auto* swp_sink = srslog::find_sink(swappable_sink::name()); if (!swp_sink) { logger.error("Unable to find the swappable sink"); @@ -89,18 +84,8 @@ int ttcn3_syssim::init(const all_args_t& args_) } static_cast(swp_sink)->swap_to_stdout(); } - srslte::logmap::set_default_logger(old_logger); // init and configure logging - srslte::logmap::register_log(std::unique_ptr{new log_filter{"SS ", old_logger, true}}); - srslte::logmap::register_log(std::unique_ptr{new log_filter{"SS-RLC", old_logger}}); - srslte::logmap::register_log(std::unique_ptr{new log_filter{"SS-PDCP", old_logger}}); - - log->set_level(args.log.all_level); - ss_mac_log->set_level(args.log.all_level); - ss_rlc_log->set_level(args.log.all_level); - ss_pdcp_log->set_level(args.log.all_level); - auto logger_lvl = srslog::str_to_basic_level(args.log.all_level); logger.set_level(logger_lvl); ut_logger.set_level(logger_lvl); @@ -113,11 +98,6 @@ int ttcn3_syssim::init(const all_args_t& args_) ss_rlc_logger.set_level(logger_lvl); ss_pdcp_logger.set_level(logger_lvl); - log->set_hex_limit(args.log.all_hex_limit); - ss_mac_log->set_hex_limit(args.log.all_hex_limit); - ss_rlc_log->set_hex_limit(args.log.all_hex_limit); - ss_pdcp_log->set_hex_limit(args.log.all_hex_limit); - logger.set_hex_dump_max_size(args.log.all_hex_limit); ut_logger.set_hex_dump_max_size(args.log.all_hex_limit); sys_logger.set_hex_dump_max_size(args.log.all_hex_limit); @@ -225,7 +205,6 @@ void ttcn3_syssim::new_tti_indication(uint64_t res) { tti = (tti + 1) % 10240; - log->step(tti); logger.set_context(tti); logger.debug("Start TTI"); @@ -438,23 +417,23 @@ void ttcn3_syssim::tc_start(const char* name) // set up logging if (args.log.filename == "stdout") { - old_logger = &logger_stdout; static_cast(swp_sink)->swap_to_stdout(); } else { const std::string& file_tc_name = get_filename_with_tc_name(local_args.log.filename, run_id, tc_name); static_cast(swp_sink)->swap_sink(file_tc_name); - old_logger = &logger_file; } logger.info("Initializing UE ID=%d for TC=%s", run_id, tc_name.c_str()); srslte::console("Initializing UE ID=%d for TC=%s\n", run_id, tc_name.c_str()); // Patch UE config - local_args.stack.pcap.filename = get_filename_with_tc_name(args.stack.pcap.filename, run_id, tc_name); - local_args.stack.pcap.nas_filename = get_filename_with_tc_name(args.stack.pcap.nas_filename, run_id, tc_name); + local_args.stack.pkt_trace.mac_pcap.filename = + get_filename_with_tc_name(args.stack.pkt_trace.mac_pcap.filename, run_id, tc_name); + local_args.stack.pkt_trace.nas_pcap.filename = + get_filename_with_tc_name(args.stack.pkt_trace.nas_pcap.filename, run_id, tc_name); // bring up UE - if (ue->init(local_args, old_logger, this, tc_name)) { + if (ue->init(local_args, this, tc_name)) { ue->stop(); std::string err("Couldn't initialize UE."); logger.error("%s", err.c_str()); diff --git a/srsue/test/ttcn3/src/ttcn3_ue.cc b/srsue/test/ttcn3/src/ttcn3_ue.cc index 63a4edd11..0f797d87e 100644 --- a/srsue/test/ttcn3/src/ttcn3_ue.cc +++ b/srsue/test/ttcn3/src/ttcn3_ue.cc @@ -31,10 +31,8 @@ SRSLTE_API char* srslte_get_build_mode(); ttcn3_ue::ttcn3_ue() : logger(srslog::fetch_basic_logger("UE", false)), tft_matcher(logger) {} -int ttcn3_ue::init(all_args_t args, srslte::logger* logger_, syssim_interface_phy* syssim_, const std::string tc_name_) +int ttcn3_ue::init(all_args_t args, syssim_interface_phy* syssim_, const std::string tc_name_) { - old_logger = logger_; - // Init UE log logger.set_level(srslog::basic_levels::info); logger.set_hex_dump_max_size(128); @@ -66,7 +64,7 @@ int ttcn3_ue::init(all_args_t args, srslte::logger* logger_, syssim_interface_ph // Instantiate layers and stack together our UE if (args.stack.type == "lte") { - stack = std::unique_ptr(new ue_stack_lte(srslog::get_default_sink())); + stack = std::unique_ptr(new ue_stack_lte); if (!stack) { srslte::console("Error creating LTE stack instance.\n"); return SRSLTE_ERROR; @@ -88,7 +86,7 @@ int ttcn3_ue::init(all_args_t args, srslte::logger* logger_, syssim_interface_ph return SRSLTE_ERROR; } - if (stack->init(args.stack, old_logger, phy.get(), this)) { + if (stack->init(args.stack, phy.get(), this)) { srslte::console("Error initializing stack.\n"); return SRSLTE_ERROR; } diff --git a/srsue/test/ttcn3/test/ttcn3_if_handler_test.cc b/srsue/test/ttcn3/test/ttcn3_if_handler_test.cc index c33bd82e6..cae77f938 100644 --- a/srsue/test/ttcn3/test/ttcn3_if_handler_test.cc +++ b/srsue/test/ttcn3/test/ttcn3_if_handler_test.cc @@ -39,6 +39,8 @@ int if_handler_test() int main(int argc, char** argv) { + srslog::init(); + if_handler_test(); return SRSLTE_SUCCESS; diff --git a/srsue/test/upper/gw_test.cc b/srsue/test/upper/gw_test.cc index f6354ae69..6c58b5f73 100644 --- a/srsue/test/upper/gw_test.cc +++ b/srsue/test/upper/gw_test.cc @@ -19,15 +19,14 @@ * */ -#include "srslte/common/common.h" -#include "srslte/common/log.h" #include "srslte/common/logger_srslog_wrapper.h" #include "srslte/common/test_common.h" -#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/interfaces/ue_pdcp_interfaces.h" #include "srslte/srslog/srslog.h" -#include "srslte/srslte.h" #include "srsue/hdr/stack/upper/gw.h" +#include + class test_stack_dummy : public srsue::stack_interface_gw { public: @@ -39,34 +38,13 @@ public: int gw_change_lcid_test() { - - // Setup logging. - srslog::sink* log_sink = srslog::create_stdout_sink(); - if (!log_sink) { - return SRSLTE_ERROR; - } - - srslog::log_channel* chan = srslog::create_log_channel("main_channel", *log_sink); - if (!chan) { - return SRSLTE_ERROR; - } - - srslte::srslog_wrapper log_wrapper(*chan); - - srslte::log_filter log; - log.init("TEST ", &log_wrapper); - log.set_level("debug"); - log.set_hex_limit(10000); - - srslog::init(); - srsue::gw_args_t gw_args; gw_args.tun_dev_name = "tun1"; gw_args.log.gw_level = "debug"; gw_args.log.gw_hex_limit = 100000; test_stack_dummy stack; srsue::gw gw; - gw.init(gw_args, &log_wrapper, &stack); + gw.init(gw_args, &stack); uint32_t eps_bearer_id = 5; uint32_t non_existing_eps_bearer_id = 23; @@ -79,7 +57,8 @@ int gw_change_lcid_test() eps_bearer_id, old_lcid, LIBLTE_MME_PDN_TYPE_IPV4, htonl(inet_addr("192.168.56.32")), nullptr, err_str); if (rtn != SRSLTE_SUCCESS) { - log.error("Failed to setup GW interface. Not possible to test function. Try to execute with sudo rights."); + srslog::fetch_basic_logger("TEST", false) + .error("Failed to setup GW interface. Not possible to test function. Try to execute with sudo rights."); gw.stop(); return SRSLTE_SUCCESS; } @@ -92,6 +71,9 @@ int gw_change_lcid_test() int main(int argc, char** argv) { + srslog::init(); + TESTASSERT(gw_change_lcid_test() == SRSLTE_SUCCESS); + return SRSLTE_SUCCESS; } diff --git a/srsue/test/upper/nas_test.cc b/srsue/test/upper/nas_test.cc index 146a19d64..c93e545f5 100644 --- a/srsue/test/upper/nas_test.cc +++ b/srsue/test/upper/nas_test.cc @@ -20,26 +20,18 @@ */ #include "srslte/common/bcd_helpers.h" -#include "srslte/common/log_filter.h" #include "srslte/common/logger_srslog_wrapper.h" #include "srslte/common/logmap.h" #include "srslte/common/test_common.h" -#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/interfaces/ue_pdcp_interfaces.h" #include "srslte/srslog/srslog.h" #include "srslte/test/ue_test_interfaces.h" -#include "srslte/upper/pdcp.h" -#include "srslte/upper/pdcp_entity_lte.h" -#include "srslte/upper/rlc.h" -#include "srsue/hdr/stack/mac/mac.h" -#include "srsue/hdr/stack/rrc/rrc.h" #include "srsue/hdr/stack/upper/gw.h" #include "srsue/hdr/stack/upper/nas.h" #include "srsue/hdr/stack/upper/usim.h" #include "srsue/hdr/stack/upper/usim_base.h" -#include using namespace srsue; -using namespace asn1::rrc; static_assert(alignof(LIBLTE_BYTE_MSG_STRUCT) == alignof(byte_buffer_t), "liblte buffer and byte buffer members misaligned"); @@ -76,8 +68,6 @@ uint8_t deactivate_eps_bearer_pdu[] = {0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, uint16 mcc = 61441; uint16 mnc = 65281; -static srslte::logger* g_logger = nullptr; - using namespace srslte; namespace srslte { @@ -141,10 +131,10 @@ public: bool has_nr_dc() { return false; } private: - nas* nas_ptr; - uint32_t last_sdu_len; - found_plmn_t plmns[rrc_interface_nas::MAX_FOUND_PLMNS]; - bool is_connected_flag = false; + nas* nas_ptr; + uint32_t last_sdu_len; + nas_interface_rrc::found_plmn_t plmns[nas_interface_rrc::MAX_FOUND_PLMNS]; + bool is_connected_flag = false; }; class test_stack_dummy : public srsue::stack_test_dummy, public stack_interface_gw, public thread @@ -218,14 +208,7 @@ class gw_dummy : public gw_interface_nas, public gw_interface_pdcp int security_command_test() { - int ret = SRSLTE_ERROR; - srslte::log_filter rrc_log("RRC"); - srslte::log_filter mac_log("MAC"); - srslte::log_filter usim_log("USIM"); - - rrc_log.set_level(srslte::LOG_LEVEL_DEBUG); - rrc_log.set_hex_limit(100000); - + int ret = SRSLTE_ERROR; stack_test_dummy stack; rrc_dummy rrc_dummy; @@ -278,18 +261,7 @@ int security_command_test() int mme_attach_request_test() { - int ret = SRSLTE_ERROR; - srslte::log_filter rrc_log("RRC"); - srslte::log_filter mac_log("MAC"); - srslte::log_filter usim_log("USIM"); - srslte::log_filter gw_log("GW"); - - rrc_log.set_level(srslte::LOG_LEVEL_DEBUG); - usim_log.set_level(srslte::LOG_LEVEL_DEBUG); - gw_log.set_level(srslte::LOG_LEVEL_DEBUG); - rrc_log.set_hex_limit(100000); - usim_log.set_hex_limit(100000); - gw_log.set_hex_limit(100000); + int ret = SRSLTE_ERROR; rrc_dummy rrc_dummy; pdcp_dummy pdcp_dummy; @@ -321,7 +293,7 @@ int mme_attach_request_test() gw_args.log.gw_level = "debug"; gw_args.log.gw_hex_limit = 100000; - gw.init(gw_args, g_logger, &stack); + gw.init(gw_args, &stack); stack.init(&nas); // trigger test stack.switch_on(); @@ -355,13 +327,7 @@ int mme_attach_request_test() int esm_info_request_test() { - int ret = SRSLTE_ERROR; - srslte::log_filter rrc_log("RRC"); - srslte::log_filter mac_log("MAC"); - srslte::log_filter usim_log("USIM"); - - rrc_log.set_level(srslte::LOG_LEVEL_DEBUG); - rrc_log.set_hex_limit(100000); + int ret = SRSLTE_ERROR; srsue::stack_test_dummy stack{}; @@ -405,13 +371,6 @@ int esm_info_request_test() int dedicated_eps_bearer_test() { - srslte::log_filter rrc_log("RRC"); - srslte::log_filter mac_log("MAC"); - srslte::log_filter usim_log("USIM"); - - rrc_log.set_level(srslte::LOG_LEVEL_DEBUG); - rrc_log.set_hex_limit(100000); - srsue::stack_test_dummy stack; rrc_dummy rrc_dummy; @@ -484,11 +443,6 @@ int dedicated_eps_bearer_test() int main(int argc, char** argv) { // Setup logging. - srslog::sink& log_sink = srslog::fetch_stdout_sink(); - srslog::log_channel* chan = srslog::create_log_channel("mme_attach_request_test", log_sink); - srslte::srslog_wrapper log_wrapper(*chan); - g_logger = &log_wrapper; - auto& rrc_logger = srslog::fetch_basic_logger("RRC", false); rrc_logger.set_level(srslog::basic_levels::debug); rrc_logger.set_hex_dump_max_size(100000); @@ -505,9 +459,6 @@ int main(int argc, char** argv) // Start the log backend. srslog::init(); - srslte::logmap::set_default_log_level(LOG_LEVEL_DEBUG); - srslte::logmap::set_default_hex_limit(100000); - if (security_command_test()) { printf("Security command test failed.\n"); return -1; diff --git a/srsue/test/upper/pcsc_usim_test.cc b/srsue/test/upper/pcsc_usim_test.cc index 9969b3835..34eea9800 100644 --- a/srsue/test/upper/pcsc_usim_test.cc +++ b/srsue/test/upper/pcsc_usim_test.cc @@ -20,7 +20,6 @@ */ #include "srsue/hdr/stack/upper/pcsc_usim.h" -#include #include using namespace srsue; @@ -36,11 +35,11 @@ int main(int argc, char** argv) logger.set_hex_dump_max_size(100000); srslog::init(); - uint8_t res[16]; - int res_len; - uint8_t k_asme[32]; - uint16 mcc = 0; - uint16 mnc = 0; + uint8_t res[16]; + int res_len; + uint8_t k_asme[32]; + uint16_t mcc = 0; + uint16_t mnc = 0; usim_args_t args; args.pin = "6129"; diff --git a/srsue/test/upper/rrc_meas_test.cc b/srsue/test/upper/rrc_meas_test.cc index 6689c8d5d..baf72a605 100644 --- a/srsue/test/upper/rrc_meas_test.cc +++ b/srsue/test/upper/rrc_meas_test.cc @@ -257,11 +257,11 @@ class rrc_test : public rrc stack_test_dummy* stack = nullptr; public: - rrc_test(srslte::log_ref log_, stack_test_dummy* stack_) : + rrc_test(const std::string& log_name, stack_test_dummy* stack_) : rrc(stack_, &stack_->task_sched), stack(stack_), mactest(this, &stack_->task_sched) { nastest = std::unique_ptr(new nas_test(&stack->task_sched)); - pdcptest = std::unique_ptr(new pdcp_test(log_->get_service_name().c_str(), &stack->task_sched)); + pdcptest = std::unique_ptr(new pdcp_test(log_name.c_str(), &stack->task_sched)); rrcnrtest = std::unique_ptr(new rrc_nr_test()); } void init() @@ -382,12 +382,6 @@ private: // Test Cell select int cell_select_test() { - srslte::log_ref log1("RRC_MEAS"), rrc_log("RRC"); - log1->set_level(srslte::LOG_LEVEL_DEBUG); - log1->set_hex_limit(-1); - rrc_log->set_level(srslte::LOG_LEVEL_DEBUG); - rrc_log->set_hex_limit(-1); - printf("==========================================================\n"); printf("====== Cell Select Testing ===============\n"); printf("==========================================================\n"); @@ -396,7 +390,7 @@ int cell_select_test() // CHECK: The starting serving cell pci=2 is the weakest, and cell selection procedure chooses pci=1 // CHECK: phy cell selection is successful, and rrc remains in pci=1 stack_test_dummy stack; - rrc_test rrctest(log1, &stack); + rrc_test rrctest(srslog::fetch_basic_logger("RRC_MEAS").id(), &stack); rrctest.init(); rrctest.connect(); @@ -427,7 +421,7 @@ int cell_select_test() // for pci=1. // CHECK: Cell selection fails in the phy, and rrc moves to pci=2 stack_test_dummy stack; - rrc_test rrctest(log1, &stack); + rrc_test rrctest(srslog::fetch_basic_logger("RRC_MEAS").id(), &stack); rrctest.init(); rrctest.connect(); @@ -487,9 +481,6 @@ int cell_select_test() // Tests the measObject configuration and the successful activation of PHY cells to search for int meas_obj_test() { - srslte::log_ref log1("RRC_MEAS"); - log1->set_level(srslte::LOG_LEVEL_DEBUG); - log1->set_hex_limit(-1); auto& rrc_meas_logger = srslog::fetch_basic_logger("RRC_MEAS"); printf("==========================================================\n"); @@ -497,7 +488,7 @@ int meas_obj_test() printf("==========================================================\n"); stack_test_dummy stack; - rrc_test rrctest(log1, &stack); + rrc_test rrctest(rrc_meas_logger.id(), &stack); rrctest.init(); rrctest.connect(); @@ -912,11 +903,6 @@ int a1event_report_test(uint32_t a1_rsrp_th, report_cfg_eutra_s::report_amount_e_ report_amount, report_interv_e report_interv) { - srslte::log_ref log1("RRC_MEAS"), rrc_log("RRC"); - log1->set_level(srslte::LOG_LEVEL_DEBUG); - log1->set_hex_limit(-1); - rrc_log->set_level(srslte::LOG_LEVEL_DEBUG); - rrc_log->set_hex_limit(-1); auto& rrc_meas_logger = srslog::fetch_basic_logger("RRC_MEAS"); printf("==========================================================\n"); @@ -924,7 +910,7 @@ int a1event_report_test(uint32_t a1_rsrp_th, printf("==========================================================\n"); stack_test_dummy stack; - rrc_test rrctest(log1, &stack); + rrc_test rrctest(rrc_meas_logger.id(), &stack); rrctest.init(); rrctest.connect(); @@ -1048,11 +1034,6 @@ int a1event_report_test(uint32_t a1_rsrp_th, // Test A3-event reporting and management of report amount and interval int a3event_report_test(uint32_t a3_offset, uint32_t hyst, bool report_on_leave) { - srslte::log_ref log1("RRC_MEAS"), rrc_log("RRC"); - log1->set_level(srslte::LOG_LEVEL_DEBUG); - log1->set_hex_limit(-1); - rrc_log->set_level(srslte::LOG_LEVEL_DEBUG); - rrc_log->set_hex_limit(-1); auto& rrc_meas_logger = srslog::fetch_basic_logger("RRC_MEAS"); printf("==========================================================\n"); @@ -1060,7 +1041,7 @@ int a3event_report_test(uint32_t a3_offset, uint32_t hyst, bool report_on_leave) printf("==========================================================\n"); stack_test_dummy stack; - rrc_test rrctest(log1, &stack); + rrc_test rrctest(rrc_meas_logger.id(), &stack); rrctest.init(); rrctest.connect(); @@ -1166,18 +1147,12 @@ int a3event_report_test(uint32_t a3_offset, uint32_t hyst, bool report_on_leave) // Minimal testcase for testing inter rat reporting with nr int meas_obj_inter_rat_nr_test() { - srslte::log_ref log1("RRC_MEAS"), rrc_log("RRC"); - log1->set_level(srslte::LOG_LEVEL_DEBUG); - log1->set_hex_limit(-1); - rrc_log->set_level(srslte::LOG_LEVEL_DEBUG); - rrc_log->set_hex_limit(-1); - printf("==========================================================\n"); printf("====== NR Inter Rat Configuration Testing ==========\n"); printf("==========================================================\n"); stack_test_dummy stack; - rrc_test rrctest(log1, &stack); + rrc_test rrctest(srslog::fetch_basic_logger("RRC_MEAS").id(), &stack); rrctest.init(); rrctest.connect(); diff --git a/srsue/test/upper/rrc_reconfig_test.cc b/srsue/test/upper/rrc_reconfig_test.cc index 7dc0e4b0d..022121967 100644 --- a/srsue/test/upper/rrc_reconfig_test.cc +++ b/srsue/test/upper/rrc_reconfig_test.cc @@ -39,10 +39,6 @@ using namespace asn1::rrc; int nas_test() { - srslte::log_filter log1("NAS"); - log1.set_level(srslte::LOG_LEVEL_DEBUG); - log1.set_hex_limit(-1); - uint8_t nas_message[128] = {0x27, 0x4f, 0xab, 0xef, 0x59, 0x01, 0x07, 0x42, 0x01, 0x49, 0x06, 0x40, 0x00, 0xf1, 0x10, 0x31, 0x32, 0x00, 0x22, 0x52, 0x01, 0xc1, 0x05, 0x07, 0xff, 0xff, 0xff, 0xff, 0x0c, 0x0b, 0x76, 0x7a, 0x77, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x05, 0x01, 0x0e, 0x0e, @@ -99,10 +95,6 @@ int nas_test() int meas_obj_test() { - srslte::log_filter log1("RRC"); - log1.set_level(srslte::LOG_LEVEL_DEBUG); - log1.set_hex_limit(-1); - asn1::rrc::dl_dcch_msg_s dl_dcch_msg; uint8_t rrc_msg[256] = { diff --git a/srsue/test/upper/ue_rrc_nr_test.cc b/srsue/test/upper/ue_rrc_nr_test.cc index 2a1421b1f..1b83ad39e 100644 --- a/srsue/test/upper/ue_rrc_nr_test.cc +++ b/srsue/test/upper/ue_rrc_nr_test.cc @@ -26,11 +26,10 @@ using namespace srsue; int rrc_nr_cap_request_test() { - srslte::log_ref rrc_log("RRC"); rrc_log->set_level(srslte::LOG_LEVEL_DEBUG); rrc_log->set_hex_limit(-1); - srslte::task_scheduler task_sched{512, 0, 100}; + srslte::task_scheduler task_sched{512, 100}; srslte::task_sched_handle task_sched_handle(&task_sched); rrc_nr rrc_nr(task_sched_handle); srslte::byte_buffer_t caps; diff --git a/srsue/test/upper/usim_test.cc b/srsue/test/upper/usim_test.cc index 15aeec006..9a06d9665 100644 --- a/srsue/test/upper/usim_test.cc +++ b/srsue/test/upper/usim_test.cc @@ -57,8 +57,8 @@ static uint8_t rand_enb[] = static uint8_t autn_enb[] = {0xd7, 0x44, 0x51, 0x9b, 0x25, 0xaa, 0x80, 0x00, 0x84, 0xba, 0x37, 0xb0, 0xf6, 0x73, 0x4d, 0xd1}; -static constexpr uint16 mcc = 208; -static constexpr uint16 mnc = 93; +static constexpr uint16_t mcc = 208; +static constexpr uint16_t mnc = 93; int main(int argc, char** argv) { diff --git a/srsue/ue.conf.example b/srsue/ue.conf.example index 47176060d..69ae83a71 100644 --- a/srsue/ue.conf.example +++ b/srsue/ue.conf.example @@ -55,25 +55,26 @@ tx_gain = 80 ##################################################################### # Packet capture configuration # -# Packet capture is supported at both MAC and NAS layers. -# MAC-layer packets are captured to file in the compact format -# decoded by the Wireshark mac-lte-framed dissector. -# To use this dissector, edit the preferences for DLT_USER to -# add an entry with DLT=147, Payload Protocol=mac-lte-framed. +# Packet capture is supported at the MAC, MAC_NR, and NAS layer. +# MAC-layer packets are captured to file a the compact format decoded +# by the Wireshark. For decoding, use the UDP dissector and the UDP +# heuristic dissection. Edit the preferences (Edit > Preferences > +# Protocols > DLT_USER) for DLT_USER to add an entry for DLT=149 with +# Protocol=udp. Further, enable the heuristic dissection in UDP under: +# Analyze > Enabled Protocols > MAC-LTE > mac_lte_udp and MAC-NR > mac_nr_udp # For more information see: https://wiki.wireshark.org/MAC-LTE -# NAS-layer packets are dissected with DLT=148, and -# Payload Protocol = nas-eps. +# NAS-layer packets are dissected with DLT=148, and Protocol = nas-eps. # -# enable: Enable MAC layer packet captures (true/false) -# filename: File path to use for MAC packet captures -# nas_enable: Enable NAS layer packet captures (true/false) -# nas_filename: File path to use for NAS packet captures +# enable: Enable packet captures of layers (mac/mac_nr/nas/none) multiple option list +# mac_filename: File path to use for MAC packet capture +# mac_nr_filename: File path to use for MAC NR packet capture +# nas_filename: File path to use for NAS packet capture ##################################################################### [pcap] -enable = false -filename = /tmp/ue.pcap -nas_enable = false -nas_filename = /tmp/nas.pcap +enable = none +mac_filename = /tmp/ue_mac.pcap +mac_nr_filename = /tmp/ue_mac_nr.pcap +nas_filename = /tmp/ue_nas.pcap ##################################################################### # Log configuration