From 022c51493bf1edf1db6a97832e2e93c2dbd7c9e7 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Fri, 23 Jul 2021 13:13:10 +0100 Subject: [PATCH] Refactored RLC AM NR/LTE Rx and Tx entities to use a rlc_am_base_rx/tx class. This was done to make it easier to share entity specific code between LTE and NR. This removes the previously used templates. --- lib/include/srsran/rlc/rlc_am_base.h | 224 ++++++++---------- lib/include/srsran/rlc/rlc_am_lte.h | 336 ++++++++++++++------------- lib/include/srsran/rlc/rlc_am_nr.h | 146 +++++++----- lib/src/rlc/rlc_am_base.cc | 187 +++++++++++++++ lib/src/rlc/rlc_am_lte.cc | 163 ++++++------- lib/src/rlc/rlc_am_nr.cc | 56 +++-- 6 files changed, 645 insertions(+), 467 deletions(-) diff --git a/lib/include/srsran/rlc/rlc_am_base.h b/lib/include/srsran/rlc/rlc_am_base.h index bf9f21a74..fcde9a069 100644 --- a/lib/include/srsran/rlc/rlc_am_base.h +++ b/lib/include/srsran/rlc/rlc_am_base.h @@ -36,70 +36,35 @@ namespace srsran { bool rlc_am_is_control_pdu(uint8_t* payload); bool rlc_am_is_control_pdu(byte_buffer_t* pdu); -/******************************* - * rlc_am_base class - ******************************/ -template +/******************************************************* + * RLC AM entity + * This entity is common between LTE and NR + * and only the TX/RX entities change between them + *******************************************************/ class rlc_am_base : public rlc_common { +protected: + class rlc_am_base_tx; + class rlc_am_base_rx; + public: rlc_am_base(srslog::basic_logger& logger, uint32_t lcid_, srsue::pdcp_interface_rlc* pdcp_, srsue::rrc_interface_rlc* rrc_, - srsran::timer_handler* timers_) : - logger(logger), rrc(rrc_), pdcp(pdcp_), timers(timers_), lcid(lcid_), tx(this), rx(this) + srsran::timer_handler* timers_, + rlc_am_base_tx* tx_, + rlc_am_base_rx* rx_) : + logger(logger), rrc(rrc_), pdcp(pdcp_), timers(timers_), lcid(lcid_), tx_base(tx_), rx_base(rx_) {} - bool configure(const rlc_config_t& cfg_) final - { - // determine bearer name and configure Rx/Tx objects - rb_name = rrc->get_rb_name(lcid); - - // store config - cfg = cfg_; - - if (not rx.configure(cfg)) { - logger.error("Error configuring bearer (RX)"); - return false; - } - - if (not tx.configure(cfg)) { - logger.error("Error configuring bearer (TX)"); - return false; - } - - logger.info("%s configured: t_poll_retx=%d, poll_pdu=%d, poll_byte=%d, max_retx_thresh=%d, " - "t_reordering=%d, t_status_prohibit=%d", - rb_name.c_str(), - cfg.am.t_poll_retx, - cfg.am.poll_pdu, - cfg.am.poll_byte, - cfg.am.max_retx_thresh, - cfg.am.t_reordering, - cfg.am.t_status_prohibit); - return true; - } - - void reestablish() final - { - logger.debug("Reestablished bearer %s", rb_name.c_str()); - tx.reestablish(); // calls stop and enables tx again - rx.reestablish(); // calls only stop - } + bool configure(const rlc_config_t& cfg_) final; - void stop() final - { - logger.debug("Stopped bearer %s", rb_name.c_str()); - tx.stop(); - rx.stop(); - } + void reestablish() final; - void empty_queue() final - { - // Drop all messages in TX SDU queue - tx.empty_queue(); - } + void stop() final; + + void empty_queue() final { tx_base->empty_queue(); } rlc_mode_t get_mode() final { return rlc_mode_t::am; } @@ -108,101 +73,104 @@ public: /**************************************************************************** * PDCP interface ***************************************************************************/ - void write_sdu(unique_byte_buffer_t sdu) final - { - if (tx.write_sdu(std::move(sdu)) == SRSRAN_SUCCESS) { - std::lock_guard lock(metrics_mutex); - metrics.num_tx_sdus++; - } - } + void write_sdu(unique_byte_buffer_t sdu) final; - void discard_sdu(uint32_t discard_sn) final - { - tx.discard_sdu(discard_sn); - - std::lock_guard lock(metrics_mutex); - metrics.num_lost_sdus++; - } + void discard_sdu(uint32_t discard_sn) final; - bool sdu_queue_is_full() final { return tx.sdu_queue_is_full(); } + bool sdu_queue_is_full() final; /**************************************************************************** * MAC interface ***************************************************************************/ - bool has_data() final { return tx.has_data(); } - uint32_t get_buffer_state() final { return tx.get_buffer_state(); } - void get_buffer_state(uint32_t& tx_queue, uint32_t& prio_tx_queue) final - { - tx.get_buffer_state(tx_queue, prio_tx_queue); - } + bool has_data() final; + uint32_t get_buffer_state() final; + void get_buffer_state(uint32_t& n_bytes_newtx, uint32_t& n_bytes_prio) final; - uint32_t read_pdu(uint8_t* payload, uint32_t nof_bytes) final - { - uint32_t read_bytes = tx.read_pdu(payload, nof_bytes); + uint32_t read_pdu(uint8_t* payload, uint32_t nof_bytes) final; - std::lock_guard lock(metrics_mutex); - metrics.num_tx_pdus++; - metrics.num_tx_pdu_bytes += read_bytes; - - return read_bytes; - } - - void write_pdu(uint8_t* payload, uint32_t nof_bytes) final - { - rx.write_pdu(payload, nof_bytes); - - std::lock_guard lock(metrics_mutex); - metrics.num_rx_pdus++; - metrics.num_rx_pdu_bytes += nof_bytes; - } + void write_pdu(uint8_t* payload, uint32_t nof_bytes) final; /**************************************************************************** * Metrics ***************************************************************************/ - rlc_bearer_metrics_t get_metrics() - { - // update values that aren't calculated on the fly - uint32_t latency = rx.get_sdu_rx_latency_ms(); - uint32_t buffered_bytes = rx.get_rx_buffered_bytes(); - - std::lock_guard lock(metrics_mutex); - metrics.rx_latency_ms = latency; - metrics.rx_buffered_bytes = buffered_bytes; - - return metrics; - } + rlc_bearer_metrics_t get_metrics() final; + void reset_metrics() final; - void reset_metrics() - { - std::lock_guard lock(metrics_mutex); - metrics = {}; - } - - // BSR callback - void set_bsr_callback(bsr_callback_t callback) final { tx.set_bsr_callback(callback); } + /**************************************************************************** + * BSR Callback + ***************************************************************************/ + void set_bsr_callback(bsr_callback_t callback) final; -private: +protected: // Common variables needed/provided by parent class - srsue::rrc_interface_rlc* rrc = nullptr; - srslog::basic_logger& logger; - srsue::pdcp_interface_rlc* pdcp = nullptr; - srsran::timer_handler* timers = nullptr; - uint32_t lcid = 0; - rlc_config_t cfg = {}; - std::string rb_name; + srslog::basic_logger& logger; + srsran::timer_handler* timers = nullptr; + uint32_t lcid = 0; + rlc_config_t cfg = {}; + std::string rb_name; static const int poll_periodicity = 8; // After how many data PDUs a status PDU shall be requested - // Rx and Tx objects - friend class rlc_am_lte_tx; - friend class rlc_am_lte_rx; - friend class rlc_am_nr_tx; - friend class rlc_am_nr_rx; - T_rlc_tx tx; - T_rlc_rx rx; - std::mutex metrics_mutex; rlc_bearer_metrics_t metrics = {}; + + srsue::rrc_interface_rlc* rrc = nullptr; + srsue::pdcp_interface_rlc* pdcp = nullptr; + + /******************************************************* + * RLC AM TX entity + * This class is used for common code between the + * LTE and NR TX entitites + *******************************************************/ + class rlc_am_base_tx + { + public: + virtual bool configure(const rlc_config_t& cfg_) = 0; + virtual void reestablish() = 0; + virtual void stop() = 0; + virtual void empty_queue() = 0; + virtual void discard_sdu(uint32_t pdcp_sn) = 0; + virtual bool sdu_queue_is_full() = 0; + virtual bool has_data() = 0; + virtual uint32_t get_buffer_state() = 0; + virtual void get_buffer_state(uint32_t& tx_queue, uint32_t& prio_tx_queue) = 0; + virtual uint32_t read_pdu(uint8_t* payload, uint32_t nof_bytes) = 0; + + void set_bsr_callback(bsr_callback_t callback); + + int write_sdu(unique_byte_buffer_t sdu); + + byte_buffer_pool* pool = nullptr; + bool tx_enabled = false; + std::string rb_name; + + bsr_callback_t bsr_callback; + + // Tx SDU buffers + byte_buffer_queue tx_sdu_queue; + + // Mutexes + std::mutex mutex; + }; + + /******************************************************* + * RLC AM RX entity + * This class is used for common code between the + * LTE and NR RX entitites + *******************************************************/ + class rlc_am_base_rx + { + public: + virtual bool configure(const rlc_config_t& cfg_) = 0; + virtual void reestablish() = 0; + virtual void stop() = 0; + virtual void write_pdu(uint8_t* payload, uint32_t nof_bytes) = 0; + virtual uint32_t get_sdu_rx_latency_ms() = 0; + virtual uint32_t get_rx_buffered_bytes() = 0; + }; + + rlc_am_base_tx* tx_base = nullptr; + rlc_am_base_rx* rx_base = nullptr; }; } // namespace srsran diff --git a/lib/include/srsran/rlc/rlc_am_lte.h b/lib/include/srsran/rlc/rlc_am_lte.h index c1d62ac5a..0c5c79e34 100644 --- a/lib/include/srsran/rlc/rlc_am_lte.h +++ b/lib/include/srsran/rlc/rlc_am_lte.h @@ -80,198 +80,208 @@ private: size_t rpos = 0; }; -// Transmitter sub-class -class rlc_am_lte_tx; -class rlc_am_lte_rx; -using rlc_am_lte = rlc_am_base; -class rlc_am_lte_tx : public timer_callback +/****************************** + * + * RLC AM LTE entity + * + *****************************/ +class rlc_am_lte : public rlc_am_base { public: - explicit rlc_am_lte_tx(rlc_am_lte* parent_); - ~rlc_am_lte_tx() = default; - - bool configure(const rlc_config_t& cfg_); - - void empty_queue(); - void reestablish(); - void stop(); - - int write_sdu(unique_byte_buffer_t sdu); - uint32_t read_pdu(uint8_t* payload, uint32_t nof_bytes); - void discard_sdu(uint32_t discard_sn); - bool sdu_queue_is_full(); - - bool has_data(); - uint32_t get_buffer_state(); - void get_buffer_state(uint32_t& tx_queue, uint32_t& prio_tx_queue); - - // Timeout callback interface - void timer_expired(uint32_t timeout_id) final; - - // Interface for Rx subclass - void handle_control_pdu(uint8_t* payload, uint32_t nof_bytes); - - void set_bsr_callback(bsr_callback_t callback); - -private: - void stop_nolock(); - - int build_status_pdu(uint8_t* payload, uint32_t nof_bytes); - 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(uint32_t rlc_sn); + rlc_am_lte(srslog::basic_logger& logger, + uint32_t lcid_, + srsue::pdcp_interface_rlc* pdcp_, + srsue::rrc_interface_rlc* rrc_, + srsran::timer_handler* timers_); + + /****************************** + * RLC AM LTE TX entity + *****************************/ + class rlc_am_lte_tx : public rlc_am_base_tx, timer_callback + { + public: + explicit rlc_am_lte_tx(rlc_am_lte* parent_); + ~rlc_am_lte_tx() = default; - void empty_queue_nolock(); - void debug_state(); + bool configure(const rlc_config_t& cfg_); + void empty_queue(); + void reestablish(); + void stop(); - int required_buffer_size(const rlc_amd_retx_t& retx); - void retransmit_pdu(uint32_t sn); + uint32_t read_pdu(uint8_t* payload, uint32_t nof_bytes); + void discard_sdu(uint32_t discard_sn); + bool sdu_queue_is_full(); - // Helpers - void get_buffer_state_nolock(uint32_t& new_tx, uint32_t& prio_tx); - bool poll_required(); - bool do_status(); - void check_sn_reached_max_retx(uint32_t sn); + bool has_data(); + uint32_t get_buffer_state(); + void get_buffer_state(uint32_t& n_bytes_newtx, uint32_t& n_bytes_prio); - rlc_am_lte* parent = nullptr; - byte_buffer_pool* pool = nullptr; - srslog::basic_logger& logger; - rlc_am_pdu_segment_pool segment_pool; + void empty_queue_nolock(); + void debug_state(); - /**************************************************************************** - * Configurable parameters - * Ref: 3GPP TS 36.322 v10.0.0 Section 7 - ***************************************************************************/ + // Timeout callback interface + void timer_expired(uint32_t timeout_id) final; - rlc_am_config_t cfg = {}; + // Interface for Rx subclass + void handle_control_pdu(uint8_t* payload, uint32_t nof_bytes); - // TX SDU buffers - byte_buffer_queue tx_sdu_queue; - unique_byte_buffer_t tx_sdu; + private: + void stop_nolock(); - bool tx_enabled = false; + int build_status_pdu(uint8_t* payload, uint32_t nof_bytes); + 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(uint32_t rlc_sn); - /**************************************************************************** - * State variables and counters - * Ref: 3GPP TS 36.322 v10.0.0 Section 7 - ***************************************************************************/ + int required_buffer_size(const rlc_amd_retx_t& retx); + void retransmit_pdu(uint32_t sn); - // Tx state variables - uint32_t vt_a = 0; // ACK state. SN of next PDU in sequence to be ACKed. Low edge of tx window. - uint32_t vt_ms = RLC_AM_WINDOW_SIZE; // Max send state. High edge of tx window. vt_a + window_size. - uint32_t vt_s = 0; // Send state. SN to be assigned for next PDU. - uint32_t poll_sn = 0; // Poll send state. SN of most recent PDU txed with poll bit set. + // Helpers + bool poll_required(); + bool do_status(); + void check_sn_reached_max_retx(uint32_t sn); + void get_buffer_state_nolock(uint32_t& new_tx, uint32_t& prio_tx); - // Tx counters - uint32_t pdu_without_poll = 0; - uint32_t byte_without_poll = 0; + rlc_am_lte* parent = nullptr; + byte_buffer_pool* pool = nullptr; + srslog::basic_logger& logger; + rlc_am_pdu_segment_pool segment_pool; - rlc_status_pdu_t tx_status; + /**************************************************************************** + * Configurable parameters + * Ref: 3GPP TS 36.322 v10.0.0 Section 7 + ***************************************************************************/ - /**************************************************************************** - * Timers - * Ref: 3GPP TS 36.322 v10.0.0 Section 7 - ***************************************************************************/ + rlc_am_config_t cfg = {}; - srsran::timer_handler::unique_timer poll_retx_timer; - srsran::timer_handler::unique_timer status_prohibit_timer; + // TX SDU buffers + unique_byte_buffer_t tx_sdu; - // SDU info for PDCP notifications - buffered_pdcp_pdu_list undelivered_sdu_info_queue; + /**************************************************************************** + * State variables and counters + * Ref: 3GPP TS 36.322 v10.0.0 Section 7 + ***************************************************************************/ - // Callback function for buffer status report - bsr_callback_t bsr_callback; + // Tx state variables + uint32_t vt_a = 0; // ACK state. SN of next PDU in sequence to be ACKed. Low edge of tx window. + uint32_t vt_ms = RLC_AM_WINDOW_SIZE; // Max send state. High edge of tx window. vt_a + window_size. + uint32_t vt_s = 0; // Send state. SN to be assigned for next PDU. + uint32_t poll_sn = 0; // Poll send state. SN of most recent PDU txed with poll bit set. - // Tx windows - rlc_ringbuffer_t tx_window; - pdu_retx_queue retx_queue; - pdcp_sn_vector_t notify_info_vec; + // Tx counters + uint32_t pdu_without_poll = 0; + uint32_t byte_without_poll = 0; - // Mutexes - std::mutex mutex; + rlc_status_pdu_t tx_status; - // default to RLC SDU queue length - const uint32_t MAX_SDUS_PER_RLC_PDU = RLC_TX_QUEUE_LEN; -}; + /**************************************************************************** + * Timers + * Ref: 3GPP TS 36.322 v10.0.0 Section 7 + ***************************************************************************/ -// Receiver sub-class -class rlc_am_lte_rx : public timer_callback -{ -public: - rlc_am_lte_rx(rlc_am_lte* parent_); - ~rlc_am_lte_rx(); + srsran::timer_handler::unique_timer poll_retx_timer; + srsran::timer_handler::unique_timer status_prohibit_timer; - bool configure(rlc_config_t cfg_); - void reestablish(); - void stop(); + // SDU info for PDCP notifications + buffered_pdcp_pdu_list undelivered_sdu_info_queue; - void write_pdu(uint8_t* payload, uint32_t nof_bytes); + // Tx windows + rlc_ringbuffer_t tx_window; + pdu_retx_queue retx_queue; + pdcp_sn_vector_t notify_info_vec; - uint32_t get_rx_buffered_bytes(); // returns sum of PDUs in rx_window - uint32_t get_sdu_rx_latency_ms(); + // Mutexes + std::mutex mutex; - // Timeout callback interface - void timer_expired(uint32_t timeout_id); + // default to RLC SDU queue length + const uint32_t MAX_SDUS_PER_RLC_PDU = RLC_TX_QUEUE_LEN; + }; - // Functions needed by Tx subclass to query rx state - int get_status_pdu_length(); - int get_status_pdu(rlc_status_pdu_t* status, const uint32_t nof_bytes); - bool get_do_status(); + /****************************** + * RLC AM LTE RX entity + *****************************/ + class rlc_am_lte_rx : public rlc_am_base_rx, public timer_callback + { + public: + rlc_am_lte_rx(rlc_am_lte* parent_); + ~rlc_am_lte_rx(); + + bool configure(const rlc_config_t& cfg_) final; + void reestablish() final; + void stop() final; + + void write_pdu(uint8_t* payload, uint32_t nof_bytes) final; + + uint32_t get_rx_buffered_bytes() final; // returns sum of PDUs in rx_window + uint32_t get_sdu_rx_latency_ms() final; + + // Timeout callback interface + void timer_expired(uint32_t timeout_id) final; + + // Functions needed by Tx subclass to query rx state + int get_status_pdu_length(); + int get_status_pdu(rlc_status_pdu_t* status, uint32_t nof_bytes); + bool get_do_status(); + + private: + void handle_data_pdu(uint8_t* payload, uint32_t nof_bytes, rlc_amd_pdu_header_t& header); + void handle_data_pdu_segment(uint8_t* payload, uint32_t nof_bytes, rlc_amd_pdu_header_t& header); + void reassemble_rx_sdus(); + bool inside_rx_window(const int16_t sn); + void debug_state(); + void print_rx_segments(); + bool add_segment_and_check(rlc_amd_rx_pdu_segments_t* pdu, rlc_amd_rx_pdu* segment); + void reset_status(); + + rlc_am_lte* parent = nullptr; + byte_buffer_pool* pool = nullptr; + srslog::basic_logger& logger; + + /**************************************************************************** + * Configurable parameters + * Ref: 3GPP TS 36.322 v10.0.0 Section 7 + ***************************************************************************/ + rlc_am_config_t cfg = {}; + + // RX SDU buffers + unique_byte_buffer_t rx_sdu; + + /**************************************************************************** + * State variables and counters + * Ref: 3GPP TS 36.322 v10.0.0 Section 7 + ***************************************************************************/ + + // Rx state variables + uint32_t vr_r = 0; // Receive state. SN following last in-sequence received PDU. Low edge of rx window + uint32_t vr_mr = RLC_AM_WINDOW_SIZE; // Max acceptable receive state. High edge of rx window. vr_r + window size. + uint32_t vr_x = 0; // t_reordering state. SN following PDU which triggered t_reordering. + uint32_t vr_ms = 0; // Max status tx state. Highest possible value of SN for ACK_SN in status PDU. + uint32_t vr_h = 0; // Highest rx state. SN following PDU with highest SN among rxed PDUs. + + // Mutex to protect members + std::mutex mutex; + + // Rx windows + rlc_ringbuffer_t rx_window; + std::map rx_segments; + + bool poll_received = false; + std::atomic do_status = {false}; // light-weight access from Tx entity + + /**************************************************************************** + * Timers + * Ref: 3GPP TS 36.322 v10.0.0 Section 7 + ***************************************************************************/ + + srsran::timer_handler::unique_timer reordering_timer; + + srsran::rolling_average sdu_rx_latency_ms; + }; private: - void handle_data_pdu(uint8_t* payload, uint32_t nof_bytes, rlc_amd_pdu_header_t& header); - void handle_data_pdu_segment(uint8_t* payload, uint32_t nof_bytes, rlc_amd_pdu_header_t& header); - void reassemble_rx_sdus(); - bool inside_rx_window(const int16_t sn); - void debug_state(); - void print_rx_segments(); - bool add_segment_and_check(rlc_amd_rx_pdu_segments_t* pdu, rlc_amd_rx_pdu* segment); - void reset_status(); - - rlc_am_lte* parent = nullptr; - byte_buffer_pool* pool = nullptr; - srslog::basic_logger& logger; - - /**************************************************************************** - * Configurable parameters - * Ref: 3GPP TS 36.322 v10.0.0 Section 7 - ***************************************************************************/ - rlc_am_config_t cfg = {}; - - // RX SDU buffers - unique_byte_buffer_t rx_sdu; - - /**************************************************************************** - * State variables and counters - * Ref: 3GPP TS 36.322 v10.0.0 Section 7 - ***************************************************************************/ - - // Rx state variables - uint32_t vr_r = 0; // Receive state. SN following last in-sequence received PDU. Low edge of rx window - uint32_t vr_mr = RLC_AM_WINDOW_SIZE; // Max acceptable receive state. High edge of rx window. vr_r + window size. - uint32_t vr_x = 0; // t_reordering state. SN following PDU which triggered t_reordering. - uint32_t vr_ms = 0; // Max status tx state. Highest possible value of SN for ACK_SN in status PDU. - uint32_t vr_h = 0; // Highest rx state. SN following PDU with highest SN among rxed PDUs. - - // Mutex to protect members - std::mutex mutex; - - // Rx windows - rlc_ringbuffer_t rx_window; - std::map rx_segments; - - bool poll_received = false; - std::atomic do_status = {false}; // light-weight access from Tx entity - - /**************************************************************************** - * Timers - * Ref: 3GPP TS 36.322 v10.0.0 Section 7 - ***************************************************************************/ - - srsran::timer_handler::unique_timer reordering_timer; - - srsran::rolling_average sdu_rx_latency_ms; + rlc_am_lte_tx* tx = nullptr; + rlc_am_lte_rx* rx = nullptr; }; } // namespace srsran diff --git a/lib/include/srsran/rlc/rlc_am_nr.h b/lib/include/srsran/rlc/rlc_am_nr.h index f52795ac0..0b7a20c94 100644 --- a/lib/include/srsran/rlc/rlc_am_nr.h +++ b/lib/include/srsran/rlc/rlc_am_nr.h @@ -25,72 +25,96 @@ namespace srsran { -// Transmitter sub-class -class rlc_am_nr_tx; -class rlc_am_nr_rx; -using rlc_am_nr = rlc_am_base; - -// Transmitter sub-class -class rlc_am_nr_tx -{ -public: - explicit rlc_am_nr_tx(rlc_am_nr* parent_); - ~rlc_am_nr_tx() = default; - - bool configure(const rlc_config_t& cfg_); - void stop(); - - int write_sdu(unique_byte_buffer_t sdu); - uint32_t read_pdu(uint8_t* payload, uint32_t nof_bytes); - void discard_sdu(uint32_t discard_sn); - bool sdu_queue_is_full(); - void reestablish(); - - void empty_queue(); - bool has_data(); - uint32_t get_buffer_state(); - void get_buffer_state(uint32_t& tx_queue, uint32_t& prio_tx_queue); - void set_bsr_callback(const bsr_callback_t& callback); - -private: - rlc_am_nr* parent = nullptr; - byte_buffer_pool* pool = nullptr; - srslog::basic_logger& logger; - - /**************************************************************************** - * Configurable parameters - * Ref: 3GPP TS 38.322 v10.0.0 Section 7.4 - ***************************************************************************/ - rlc_am_config_t cfg = {}; -}; - -// Receiver sub-class -class rlc_am_nr_rx +/****************************** + * + * RLC AM NR entity + * + *****************************/ +class rlc_am_nr : public rlc_am_base { public: - explicit rlc_am_nr_rx(rlc_am_nr* parent_); - ~rlc_am_nr_rx() = default; - - bool configure(const rlc_config_t& cfg_); - void stop(); - void reestablish(); - - void write_pdu(uint8_t* payload, uint32_t nof_bytes); - uint32_t get_sdu_rx_latency_ms(); - uint32_t get_rx_buffered_bytes(); + rlc_am_nr(srslog::basic_logger& logger, + uint32_t lcid_, + srsue::pdcp_interface_rlc* pdcp_, + srsue::rrc_interface_rlc* rrc_, + srsran::timer_handler* timers_); + + // Transmitter sub-class + class rlc_am_nr_tx : public rlc_am_base_tx + { + public: + explicit rlc_am_nr_tx(rlc_am_nr* parent_); + ~rlc_am_nr_tx() = default; + + bool configure(const rlc_config_t& cfg_); + void stop(); + + int write_sdu(unique_byte_buffer_t sdu); + uint32_t read_pdu(uint8_t* payload, uint32_t nof_bytes); + void discard_sdu(uint32_t discard_sn); + bool sdu_queue_is_full(); + void reestablish(); + + void empty_queue(); + bool has_data(); + uint32_t get_buffer_state(); + void get_buffer_state(uint32_t& tx_queue, uint32_t& prio_tx_queue); + + private: + rlc_am_nr* parent = nullptr; + byte_buffer_pool* pool = nullptr; + srslog::basic_logger& logger; + + /**************************************************************************** + * Configurable parameters + * Ref: 3GPP TS 38.322 v10.0.0 Section 7.4 + ***************************************************************************/ + rlc_am_config_t cfg = {}; + + /**************************************************************************** + * Tx state variables + * Ref: 3GPP TS 38.322 v10.0.0 Section 7.1 + ***************************************************************************/ + struct rlc_nr_tx_state_t { + uint32_t tx_next_ack; + uint32_t tx_next; + uint32_t poll_sn; + uint32_t pdu_without_poll; + uint32_t byte_without_poll; + } st = {}; + }; + + // Receiver sub-class + class rlc_am_nr_rx : public rlc_am_base_rx + { + public: + explicit rlc_am_nr_rx(rlc_am_nr* parent_); + ~rlc_am_nr_rx() = default; + + bool configure(const rlc_config_t& cfg_); + void stop(); + void reestablish(); + + void write_pdu(uint8_t* payload, uint32_t nof_bytes); + uint32_t get_sdu_rx_latency_ms(); + uint32_t get_rx_buffered_bytes(); + + private: + rlc_am_nr* parent = nullptr; + byte_buffer_pool* pool = nullptr; + srslog::basic_logger& logger; + + /**************************************************************************** + * Configurable parameters + * Ref: 3GPP TS 38.322 v10.0.0 Section 7.4 + ***************************************************************************/ + rlc_am_config_t cfg = {}; + }; private: - rlc_am_nr* parent = nullptr; - byte_buffer_pool* pool = nullptr; - srslog::basic_logger& logger; - - /**************************************************************************** - * Configurable parameters - * Ref: 3GPP TS 38.322 v10.0.0 Section 7.4 - ***************************************************************************/ - rlc_am_config_t cfg = {}; + rlc_am_nr_tx* tx = nullptr; + rlc_am_nr_rx* rx = nullptr; }; } // namespace srsran - #endif // SRSRAN_RLC_AM_NR_H diff --git a/lib/src/rlc/rlc_am_base.cc b/lib/src/rlc/rlc_am_base.cc index 9de01ac07..dc629a4c9 100644 --- a/lib/src/rlc/rlc_am_base.cc +++ b/lib/src/rlc/rlc_am_base.cc @@ -25,4 +25,191 @@ bool rlc_am_is_control_pdu(byte_buffer_t* pdu) return rlc_am_is_control_pdu(pdu->msg); } +/******************************************************* + * RLC AM entity + * This entity is common between LTE and NR + * and only the TX/RX entities change between them + *******************************************************/ +bool rlc_am_base::configure(const rlc_config_t& cfg_) +{ + // determine bearer name and configure Rx/Tx objects + rb_name = rrc->get_rb_name(lcid); + + // store config + cfg = cfg_; + + if (not rx_base->configure(cfg)) { + logger.error("Error configuring bearer (RX)"); + return false; + } + + if (not tx_base->configure(cfg)) { + logger.error("Error configuring bearer (TX)"); + return false; + } + + logger.info("%s configured: t_poll_retx=%d, poll_pdu=%d, poll_byte=%d, max_retx_thresh=%d, " + "t_reordering=%d, t_status_prohibit=%d", + rb_name.c_str(), + cfg.am.t_poll_retx, + cfg.am.poll_pdu, + cfg.am.poll_byte, + cfg.am.max_retx_thresh, + cfg.am.t_reordering, + cfg.am.t_status_prohibit); + return true; +} + +void rlc_am_base::stop() +{ + logger.debug("Stopped bearer %s", rb_name.c_str()); + tx_base->stop(); + rx_base->stop(); +} + +void rlc_am_base::reestablish() +{ + logger.debug("Reestablished bearer %s", rb_name.c_str()); + tx_base->reestablish(); // calls stop and enables tx again + rx_base->reestablish(); // calls only stop +} + +/**************************************************************************** + * PDCP interface + ***************************************************************************/ +void rlc_am_base::write_sdu(unique_byte_buffer_t sdu) +{ + if (tx_base->write_sdu(std::move(sdu)) == SRSRAN_SUCCESS) { + std::lock_guard lock(metrics_mutex); + metrics.num_tx_sdus++; + } +} + +void rlc_am_base::discard_sdu(uint32_t discard_sn) +{ + tx_base->discard_sdu(discard_sn); + + std::lock_guard lock(metrics_mutex); + metrics.num_lost_sdus++; +} + +bool rlc_am_base::sdu_queue_is_full() +{ + return tx_base->sdu_queue_is_full(); +} + +/**************************************************************************** + * MAC interface + ***************************************************************************/ +bool rlc_am_base::has_data() +{ + return tx_base->has_data(); +} + +uint32_t rlc_am_base::get_buffer_state() +{ + return tx_base->get_buffer_state(); +} + +void rlc_am_base::get_buffer_state(uint32_t& n_bytes_newtx, uint32_t& n_bytes_prio) +{ + tx_base->get_buffer_state(n_bytes_newtx, n_bytes_prio); + return; +} + +uint32_t rlc_am_base::read_pdu(uint8_t* payload, uint32_t nof_bytes) +{ + uint32_t read_bytes = tx_base->read_pdu(payload, nof_bytes); + + std::lock_guard lock(metrics_mutex); + metrics.num_tx_pdus++; + metrics.num_tx_pdu_bytes += read_bytes; + return read_bytes; +} + +void rlc_am_base::write_pdu(uint8_t* payload, uint32_t nof_bytes) +{ + rx_base->write_pdu(payload, nof_bytes); + + std::lock_guard lock(metrics_mutex); + metrics.num_rx_pdus++; + metrics.num_rx_pdu_bytes += nof_bytes; +} + +/**************************************************************************** + * Metrics + ***************************************************************************/ +rlc_bearer_metrics_t rlc_am_base::get_metrics() +{ + // update values that aren't calculated on the fly + uint32_t latency = rx_base->get_sdu_rx_latency_ms(); + uint32_t buffered_bytes = rx_base->get_rx_buffered_bytes(); + + std::lock_guard lock(metrics_mutex); + metrics.rx_latency_ms = latency; + metrics.rx_buffered_bytes = buffered_bytes; + return metrics; +} + +void rlc_am_base::reset_metrics() +{ + std::lock_guard lock(metrics_mutex); + metrics = {}; +} + +/**************************************************************************** + * BSR callback + ***************************************************************************/ +void rlc_am_base::set_bsr_callback(bsr_callback_t callback) +{ + tx_base->set_bsr_callback(callback); +} + +/******************************************************* + * RLC AM TX entity + * This class is used for common code between the + * LTE and NR TX entitites + *******************************************************/ +int rlc_am_base::rlc_am_base_tx::write_sdu(unique_byte_buffer_t sdu) +{ + std::lock_guard lock(mutex); + + if (!tx_enabled) { + return SRSRAN_ERROR; + } + + if (sdu.get() == nullptr) { + srslog::fetch_basic_logger("RLC").warning("NULL SDU pointer in write_sdu()"); + return SRSRAN_ERROR; + } + + // Get SDU info + uint32_t sdu_pdcp_sn = sdu->md.pdcp_sn; + + // Store SDU + uint8_t* msg_ptr = sdu->msg; + uint32_t nof_bytes = sdu->N_bytes; + srsran::error_type ret = tx_sdu_queue.try_write(std::move(sdu)); + if (ret) { + srslog::fetch_basic_logger("RLC").info( + msg_ptr, nof_bytes, "%s Tx SDU (%d B, tx_sdu_queue_len=%d)", rb_name, nof_bytes, tx_sdu_queue.size()); + } else { + // in case of fail, the try_write returns back the sdu + srslog::fetch_basic_logger("RLC").warning(ret.error()->msg, + ret.error()->N_bytes, + "[Dropped SDU] %s Tx SDU (%d B, tx_sdu_queue_len=%d)", + rb_name, + ret.error()->N_bytes, + tx_sdu_queue.size()); + return SRSRAN_ERROR; + } + + return SRSRAN_SUCCESS; +} + +void rlc_am_base::rlc_am_base_tx::set_bsr_callback(bsr_callback_t callback) +{ + bsr_callback = callback; +} + } // namespace srsran diff --git a/lib/src/rlc/rlc_am_lte.cc b/lib/src/rlc/rlc_am_lte.cc index 73398a936..5a479e1cf 100644 --- a/lib/src/rlc/rlc_am_lte.cc +++ b/lib/src/rlc/rlc_am_lte.cc @@ -89,11 +89,25 @@ rlc_amd_tx_pdu::~rlc_amd_tx_pdu() } } +/**************************************************************************** + * RLC AM LTE entity + ***************************************************************************/ +rlc_am_lte::rlc_am_lte(srslog::basic_logger& logger, + uint32_t lcid_, + srsue::pdcp_interface_rlc* pdcp_, + srsue::rrc_interface_rlc* rrc_, + srsran::timer_handler* timers_) : + rlc_am_base(logger, lcid_, pdcp_, rrc_, timers_, nullptr, nullptr) +{ + tx = new rlc_am_lte::rlc_am_lte_tx(this); + rx = new rlc_am_lte::rlc_am_lte_rx(this); + tx_base = tx; + rx_base = rx; +} /**************************************************************************** * Tx subclass implementation ***************************************************************************/ - -rlc_am_lte_tx::rlc_am_lte_tx(rlc_am_lte* parent_) : +rlc_am_lte::rlc_am_lte_tx::rlc_am_lte_tx(rlc_am_lte* parent_) : parent(parent_), logger(parent_->logger), pool(byte_buffer_pool::get_instance()), @@ -101,12 +115,7 @@ rlc_am_lte_tx::rlc_am_lte_tx(rlc_am_lte* parent_) : status_prohibit_timer(parent_->timers->get_unique_timer()) {} -void rlc_am_lte_tx::set_bsr_callback(bsr_callback_t callback) -{ - bsr_callback = callback; -} - -bool rlc_am_lte_tx::configure(const rlc_config_t& cfg_) +bool rlc_am_lte::rlc_am_lte_tx::configure(const rlc_config_t& cfg_) { std::lock_guard lock(mutex); if (cfg_.tx_queue_length > MAX_SDUS_PER_RLC_PDU) { @@ -144,13 +153,13 @@ bool rlc_am_lte_tx::configure(const rlc_config_t& cfg_) return true; } -void rlc_am_lte_tx::stop() +void rlc_am_lte::rlc_am_lte_tx::stop() { std::lock_guard lock(mutex); stop_nolock(); } -void rlc_am_lte_tx::stop_nolock() +void rlc_am_lte::rlc_am_lte_tx::stop_nolock() { empty_queue_nolock(); @@ -182,13 +191,13 @@ void rlc_am_lte_tx::stop_nolock() undelivered_sdu_info_queue.clear(); } -void rlc_am_lte_tx::empty_queue() +void rlc_am_lte::rlc_am_lte_tx::empty_queue() { std::lock_guard lock(mutex); empty_queue_nolock(); } -void rlc_am_lte_tx::empty_queue_nolock() +void rlc_am_lte::rlc_am_lte_tx::empty_queue_nolock() { // deallocate all SDUs in transmit queue while (tx_sdu_queue.size() > 0) { @@ -202,20 +211,20 @@ void rlc_am_lte_tx::empty_queue_nolock() tx_sdu.reset(); } -void rlc_am_lte_tx::reestablish() +void rlc_am_lte::rlc_am_lte_tx::reestablish() { std::lock_guard lock(mutex); stop_nolock(); tx_enabled = true; } -bool rlc_am_lte_tx::do_status() +bool rlc_am_lte::rlc_am_lte_tx::do_status() { - return parent->rx.get_do_status(); + return parent->rx->get_do_status(); } // Function is supposed to return as fast as possible -bool rlc_am_lte_tx::has_data() +bool rlc_am_lte::rlc_am_lte_tx::has_data() { return (((do_status() && not status_prohibit_timer.is_running())) || // if we have a status PDU to transmit (not retx_queue.empty()) || // if we have a retransmission @@ -232,7 +241,7 @@ bool rlc_am_lte_tx::has_data() * * @param sn The SN of the PDU to check */ -void rlc_am_lte_tx::check_sn_reached_max_retx(uint32_t sn) +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 SN=%d", RB_NAME, tx_window[sn].retx_count, sn); @@ -248,20 +257,20 @@ void rlc_am_lte_tx::check_sn_reached_max_retx(uint32_t sn) } } -uint32_t rlc_am_lte_tx::get_buffer_state() +uint32_t rlc_am_lte::rlc_am_lte_tx::get_buffer_state() { uint32_t new_tx_queue = 0, prio_tx_queue = 0; get_buffer_state(new_tx_queue, prio_tx_queue); return new_tx_queue + prio_tx_queue; } -void rlc_am_lte_tx::get_buffer_state(uint32_t& n_bytes_newtx, uint32_t& n_bytes_prio) +void rlc_am_lte::rlc_am_lte_tx::get_buffer_state(uint32_t& n_bytes_newtx, uint32_t& n_bytes_prio) { std::lock_guard lock(mutex); get_buffer_state_nolock(n_bytes_newtx, n_bytes_prio); } -void rlc_am_lte_tx::get_buffer_state_nolock(uint32_t& n_bytes_newtx, uint32_t& n_bytes_prio) +void rlc_am_lte::rlc_am_lte_tx::get_buffer_state_nolock(uint32_t& n_bytes_newtx, uint32_t& n_bytes_prio) { n_bytes_newtx = 0; n_bytes_prio = 0; @@ -276,7 +285,7 @@ void rlc_am_lte_tx::get_buffer_state_nolock(uint32_t& n_bytes_newtx, uint32_t& n // Bytes needed for status report if (do_status() && not status_prohibit_timer.is_running()) { - n_bytes_prio += parent->rx.get_status_pdu_length(); + n_bytes_prio += parent->rx->get_status_pdu_length(); logger.debug("%s Buffer state - total status report: %d bytes", RB_NAME, n_bytes_prio); } @@ -323,47 +332,12 @@ void rlc_am_lte_tx::get_buffer_state_nolock(uint32_t& n_bytes_newtx, uint32_t& n } if (bsr_callback) { + logger.debug("%s Calling BSR callback - %d new_tx, %d prio bytes", RB_NAME, n_bytes_newtx, n_bytes_prio); bsr_callback(parent->lcid, n_bytes_newtx, n_bytes_prio); } } -int rlc_am_lte_tx::write_sdu(unique_byte_buffer_t sdu) -{ - std::lock_guard lock(mutex); - - if (!tx_enabled) { - return SRSRAN_ERROR; - } - - if (sdu.get() == nullptr) { - logger.warning("NULL SDU pointer in write_sdu()"); - return SRSRAN_ERROR; - } - - // Get SDU info - uint32_t sdu_pdcp_sn = sdu->md.pdcp_sn; - - // Store SDU - uint8_t* msg_ptr = sdu->msg; - uint32_t nof_bytes = sdu->N_bytes; - srsran::error_type ret = tx_sdu_queue.try_write(std::move(sdu)); - if (ret) { - logger.info(msg_ptr, nof_bytes, "%s Tx SDU (%d B, tx_sdu_queue_len=%d)", RB_NAME, nof_bytes, tx_sdu_queue.size()); - } else { - // in case of fail, the try_write returns back the sdu - logger.warning(ret.error()->msg, - ret.error()->N_bytes, - "[Dropped SDU] %s Tx SDU (%d B, tx_sdu_queue_len=%d)", - RB_NAME, - ret.error()->N_bytes, - tx_sdu_queue.size()); - return SRSRAN_ERROR; - } - - return SRSRAN_SUCCESS; -} - -void rlc_am_lte_tx::discard_sdu(uint32_t discard_sn) +void rlc_am_lte::rlc_am_lte_tx::discard_sdu(uint32_t discard_sn) { if (!tx_enabled) { return; @@ -381,12 +355,12 @@ void rlc_am_lte_tx::discard_sdu(uint32_t discard_sn) logger.info("%s PDU with PDCP_SN=%d", discarded ? "Discarding" : "Couldn't discard", discard_sn); } -bool rlc_am_lte_tx::sdu_queue_is_full() +bool rlc_am_lte::rlc_am_lte_tx::sdu_queue_is_full() { return tx_sdu_queue.is_full(); } -uint32_t rlc_am_lte_tx::read_pdu(uint8_t* payload, uint32_t nof_bytes) +uint32_t rlc_am_lte::rlc_am_lte_tx::read_pdu(uint8_t* payload, uint32_t nof_bytes) { std::lock_guard lock(mutex); @@ -424,7 +398,7 @@ uint32_t rlc_am_lte_tx::read_pdu(uint8_t* payload, uint32_t nof_bytes) return build_data_pdu(payload, nof_bytes); } -void rlc_am_lte_tx::timer_expired(uint32_t timeout_id) +void rlc_am_lte::rlc_am_lte_tx::timer_expired(uint32_t timeout_id) { std::unique_lock lock(mutex); if (poll_retx_timer.is_valid() && poll_retx_timer.id() == timeout_id) { @@ -445,7 +419,7 @@ void rlc_am_lte_tx::timer_expired(uint32_t timeout_id) } } -void rlc_am_lte_tx::retransmit_pdu(uint32_t sn) +void rlc_am_lte::rlc_am_lte_tx::retransmit_pdu(uint32_t sn) { if (tx_window.empty()) { logger.warning("%s No PDU to retransmit", RB_NAME); @@ -484,7 +458,7 @@ void rlc_am_lte_tx::retransmit_pdu(uint32_t sn) * * @return True if a status PDU needs to be requested, false otherwise. */ -bool rlc_am_lte_tx::poll_required() +bool rlc_am_lte::rlc_am_lte_tx::poll_required() { if (cfg.poll_pdu > 0 && pdu_without_poll > static_cast(cfg.poll_pdu)) { return true; @@ -519,9 +493,10 @@ bool rlc_am_lte_tx::poll_required() return false; } -int rlc_am_lte_tx::build_status_pdu(uint8_t* payload, uint32_t nof_bytes) +int rlc_am_lte::rlc_am_lte_tx::build_status_pdu(uint8_t* payload, uint32_t nof_bytes) { - int pdu_len = parent->rx.get_status_pdu(&tx_status, nof_bytes); + logger->debug("%s Generating status PDU. Nof bytes %d", RB_NAME, nof_bytes); + int pdu_len = parent->rx->get_status_pdu(&tx_status, nof_bytes); if (pdu_len == SRSRAN_ERROR) { logger.debug("%s Deferred Status PDU. Cause: Failed to acquire Rx lock", RB_NAME); pdu_len = 0; @@ -541,7 +516,7 @@ int rlc_am_lte_tx::build_status_pdu(uint8_t* payload, uint32_t nof_bytes) return pdu_len; } -int rlc_am_lte_tx::build_retx_pdu(uint8_t* payload, uint32_t nof_bytes) +int rlc_am_lte::rlc_am_lte_tx::build_retx_pdu(uint8_t* payload, uint32_t nof_bytes) { // Check there is at least 1 element before calling front() if (retx_queue.empty()) { @@ -622,7 +597,7 @@ int rlc_am_lte_tx::build_retx_pdu(uint8_t* payload, uint32_t nof_bytes) return (ptr - payload) + tx_window[retx.sn].buf->N_bytes; } -int rlc_am_lte_tx::build_segment(uint8_t* payload, uint32_t nof_bytes, rlc_amd_retx_t retx) +int rlc_am_lte::rlc_am_lte_tx::build_segment(uint8_t* payload, uint32_t nof_bytes, rlc_amd_retx_t retx) { if (tx_window[retx.sn].buf == NULL) { logger.error("In build_segment: retx.sn=%d has null buffer", retx.sn); @@ -797,7 +772,7 @@ int rlc_am_lte_tx::build_segment(uint8_t* payload, uint32_t nof_bytes, rlc_amd_r return pdu_len; } -int rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_bytes) +int rlc_am_lte::rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_bytes) { if (tx_sdu == NULL && tx_sdu_queue.is_empty()) { logger.info("No data available to be sent"); @@ -1013,7 +988,7 @@ int rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_bytes) return total_len; } -void rlc_am_lte_tx::handle_control_pdu(uint8_t* payload, uint32_t nof_bytes) +void rlc_am_lte::rlc_am_lte_tx::handle_control_pdu(uint8_t* payload, uint32_t nof_bytes) { if (not tx_enabled) { return; @@ -1161,7 +1136,7 @@ void rlc_am_lte_tx::handle_control_pdu(uint8_t* payload, uint32_t nof_bytes) * @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_tx::update_notification_ack_info(uint32_t rlc_sn) +void rlc_am_lte::rlc_am_lte_tx::update_notification_ack_info(uint32_t rlc_sn) { logger.debug("Updating ACK info: RLC SN=%d, number of notified SDU=%ld, number of undelivered SDUs=%ld", rlc_sn, @@ -1198,12 +1173,12 @@ void rlc_am_lte_tx::update_notification_ack_info(uint32_t rlc_sn) } } -void rlc_am_lte_tx::debug_state() +void rlc_am_lte::rlc_am_lte_tx::debug_state() { logger.debug("%s vt_a = %d, vt_ms = %d, vt_s = %d, poll_sn = %d", RB_NAME, vt_a, vt_ms, vt_s, poll_sn); } -int rlc_am_lte_tx::required_buffer_size(const rlc_amd_retx_t& retx) +int rlc_am_lte::rlc_am_lte_tx::required_buffer_size(const rlc_amd_retx_t& retx) { if (!retx.is_segment) { if (tx_window.has_sn(retx.sn)) { @@ -1280,16 +1255,16 @@ int rlc_am_lte_tx::required_buffer_size(const rlc_amd_retx_t& retx) * Rx subclass implementation ***************************************************************************/ -rlc_am_lte_rx::rlc_am_lte_rx(rlc_am_lte* parent_) : +rlc_am_lte::rlc_am_lte_rx::rlc_am_lte_rx(rlc_am_lte* parent_) : parent(parent_), pool(byte_buffer_pool::get_instance()), logger(parent_->logger), reordering_timer(parent_->timers->get_unique_timer()) {} -rlc_am_lte_rx::~rlc_am_lte_rx() {} +rlc_am_lte::rlc_am_lte_rx::~rlc_am_lte_rx() {} -bool rlc_am_lte_rx::configure(rlc_config_t cfg_) +bool rlc_am_lte::rlc_am_lte_rx::configure(const rlc_config_t& cfg_) { // TODO: add config checks cfg = cfg_.am; @@ -1308,12 +1283,12 @@ bool rlc_am_lte_rx::configure(rlc_config_t cfg_) return true; } -void rlc_am_lte_rx::reestablish() +void rlc_am_lte::rlc_am_lte_rx::reestablish() { stop(); } -void rlc_am_lte_rx::stop() +void rlc_am_lte::rlc_am_lte_rx::stop() { std::lock_guard lock(mutex); @@ -1345,7 +1320,7 @@ void rlc_am_lte_rx::stop() * @param nof_bytes Payload length * @param header Reference to PDU header (unpacked by caller) */ -void rlc_am_lte_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_bytes, rlc_amd_pdu_header_t& header) +void rlc_am_lte::rlc_am_lte_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_bytes, rlc_amd_pdu_header_t& header) { std::map::iterator it; @@ -1462,7 +1437,9 @@ void rlc_am_lte_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_bytes, rlc_am debug_state(); } -void rlc_am_lte_rx::handle_data_pdu_segment(uint8_t* payload, uint32_t nof_bytes, rlc_amd_pdu_header_t& header) +void rlc_am_lte::rlc_am_lte_rx::handle_data_pdu_segment(uint8_t* payload, + uint32_t nof_bytes, + rlc_amd_pdu_header_t& header) { std::map::iterator it; @@ -1550,7 +1527,7 @@ void rlc_am_lte_rx::handle_data_pdu_segment(uint8_t* payload, uint32_t nof_bytes debug_state(); } -void rlc_am_lte_rx::reassemble_rx_sdus() +void rlc_am_lte::rlc_am_lte_rx::reassemble_rx_sdus() { uint32_t len = 0; if (rx_sdu == NULL) { @@ -1701,25 +1678,25 @@ void rlc_am_lte_rx::reassemble_rx_sdus() } } -void rlc_am_lte_rx::reset_status() +void rlc_am_lte::rlc_am_lte_rx::reset_status() { do_status = false; poll_received = false; } -bool rlc_am_lte_rx::get_do_status() +bool rlc_am_lte::rlc_am_lte_rx::get_do_status() { return do_status.load(std::memory_order_relaxed); } -void rlc_am_lte_rx::write_pdu(uint8_t* payload, const uint32_t nof_bytes) +void rlc_am_lte::rlc_am_lte_rx::write_pdu(uint8_t* payload, const uint32_t nof_bytes) { if (nof_bytes < 1) { return; } if (rlc_am_is_control_pdu(payload)) { - parent->tx.handle_control_pdu(payload, nof_bytes); + parent->tx->handle_control_pdu(payload, nof_bytes); } else { std::lock_guard lock(mutex); rlc_amd_pdu_header_t header = {}; @@ -1737,13 +1714,13 @@ void rlc_am_lte_rx::write_pdu(uint8_t* payload, const uint32_t nof_bytes) } } -uint32_t rlc_am_lte_rx::get_rx_buffered_bytes() +uint32_t rlc_am_lte::rlc_am_lte_rx::get_rx_buffered_bytes() { std::lock_guard lock(mutex); return rx_window.get_buffered_bytes(); } -uint32_t rlc_am_lte_rx::get_sdu_rx_latency_ms() +uint32_t rlc_am_lte::rlc_am_lte_rx::get_sdu_rx_latency_ms() { std::lock_guard lock(mutex); return sdu_rx_latency_ms.value(); @@ -1754,7 +1731,7 @@ uint32_t rlc_am_lte_rx::get_sdu_rx_latency_ms() * * @param timeout_id */ -void rlc_am_lte_rx::timer_expired(uint32_t timeout_id) +void rlc_am_lte::rlc_am_lte_rx::timer_expired(uint32_t timeout_id) { std::lock_guard lock(mutex); if (reordering_timer.is_valid() and reordering_timer.id() == timeout_id) { @@ -1781,7 +1758,7 @@ void rlc_am_lte_rx::timer_expired(uint32_t timeout_id) // Called from Tx object to pack status PDU that doesn't exceed a given size // If lock-acquisition fails, return -1. Otherwise it returns the length of the generated PDU. -int rlc_am_lte_rx::get_status_pdu(rlc_status_pdu_t* status, const uint32_t max_pdu_size) +int rlc_am_lte::rlc_am_lte_rx::get_status_pdu(rlc_status_pdu_t* status, const uint32_t max_pdu_size) { std::unique_lock lock(mutex, std::try_to_lock); if (not lock.owns_lock()) { @@ -1834,7 +1811,7 @@ int rlc_am_lte_rx::get_status_pdu(rlc_status_pdu_t* status, const uint32_t max_p } // Called from Tx object to obtain length of the full status PDU -int rlc_am_lte_rx::get_status_pdu_length() +int rlc_am_lte::rlc_am_lte_rx::get_status_pdu_length() { std::unique_lock lock(mutex, std::try_to_lock); if (not lock.owns_lock()) { @@ -1852,7 +1829,7 @@ int rlc_am_lte_rx::get_status_pdu_length() return rlc_am_packed_length(&status); } -void rlc_am_lte_rx::print_rx_segments() +void rlc_am_lte::rlc_am_lte_rx::print_rx_segments() { std::map::iterator it; std::stringstream ss; @@ -1868,7 +1845,7 @@ void rlc_am_lte_rx::print_rx_segments() } // NOTE: Preference would be to capture by value, and then move; but header is stack allocated -bool rlc_am_lte_rx::add_segment_and_check(rlc_amd_rx_pdu_segments_t* pdu, rlc_amd_rx_pdu* segment) +bool rlc_am_lte::rlc_am_lte_rx::add_segment_and_check(rlc_amd_rx_pdu_segments_t* pdu, rlc_amd_rx_pdu* segment) { // Find segment insertion point in the list of segments auto it1 = pdu->segments.begin(); @@ -2048,7 +2025,7 @@ bool rlc_am_lte_rx::add_segment_and_check(rlc_amd_rx_pdu_segments_t* pdu, rlc_am return true; } -bool rlc_am_lte_rx::inside_rx_window(const int16_t sn) +bool rlc_am_lte::rlc_am_lte_rx::inside_rx_window(const int16_t sn) { if (RX_MOD_BASE(sn) >= RX_MOD_BASE(static_cast(vr_r)) && RX_MOD_BASE(sn) < RX_MOD_BASE(vr_mr)) { return true; @@ -2057,7 +2034,7 @@ bool rlc_am_lte_rx::inside_rx_window(const int16_t sn) } } -void rlc_am_lte_rx::debug_state() +void rlc_am_lte::rlc_am_lte_rx::debug_state() { logger.debug("%s vr_r = %d, vr_mr = %d, vr_x = %d, vr_ms = %d, vr_h = %d", RB_NAME, vr_r, vr_mr, vr_x, vr_ms, vr_h); } diff --git a/lib/src/rlc/rlc_am_nr.cc b/lib/src/rlc/rlc_am_nr.cc index a6845bfde..d927681da 100644 --- a/lib/src/rlc/rlc_am_nr.cc +++ b/lib/src/rlc/rlc_am_nr.cc @@ -19,15 +19,29 @@ namespace srsran { +/**************************************************************************** + * RLC AM NR entity + ***************************************************************************/ +rlc_am_nr::rlc_am_nr(srslog::basic_logger& logger, + uint32_t lcid_, + srsue::pdcp_interface_rlc* pdcp_, + srsue::rrc_interface_rlc* rrc_, + srsran::timer_handler* timers_) : + rlc_am_base(logger, lcid_, pdcp_, rrc_, timers_, new rlc_am_nr::rlc_am_nr_tx(this), new rlc_am_nr::rlc_am_nr_rx(this)) +{ + tx = dynamic_cast(tx_base); + rx = dynamic_cast(rx_base); +} + /******************************* * RLC AM NR * Tx subclass implementation ***************************************************************************/ -rlc_am_nr_tx::rlc_am_nr_tx(rlc_am_nr* parent_) : +rlc_am_nr::rlc_am_nr_tx::rlc_am_nr_tx(rlc_am_nr* parent_) : parent(parent_), logger(parent_->logger), pool(byte_buffer_pool::get_instance()) {} -bool rlc_am_nr_tx::configure(const rlc_config_t& cfg_) +bool rlc_am_nr::rlc_am_nr_tx::configure(const rlc_config_t& cfg_) { /* if (cfg_.tx_queue_length > MAX_SDUS_PER_RLC_PDU) { @@ -42,75 +56,73 @@ bool rlc_am_nr_tx::configure(const rlc_config_t& cfg_) return true; } -bool rlc_am_nr_tx::has_data() +bool rlc_am_nr::rlc_am_nr_tx::has_data() { return true; } -uint32_t rlc_am_nr_tx::read_pdu(uint8_t* payload, uint32_t nof_bytes) +uint32_t rlc_am_nr::rlc_am_nr_tx::read_pdu(uint8_t* payload, uint32_t nof_bytes) { return 0; } -void rlc_am_nr_tx::reestablish() +void rlc_am_nr::rlc_am_nr_tx::reestablish() { stop(); } -uint32_t rlc_am_nr_tx::get_buffer_state() +uint32_t rlc_am_nr::rlc_am_nr_tx::get_buffer_state() { return 0; } -void rlc_am_nr_tx::get_buffer_state(uint32_t& tx_queue, uint32_t& prio_tx_queue) {} +void rlc_am_nr::rlc_am_nr_tx::get_buffer_state(uint32_t& tx_queue, uint32_t& prio_tx_queue) {} -int rlc_am_nr_tx::write_sdu(unique_byte_buffer_t sdu) +int rlc_am_nr::rlc_am_nr_tx::write_sdu(unique_byte_buffer_t sdu) { return 0; } -void rlc_am_nr_tx::discard_sdu(uint32_t discard_sn) {} +void rlc_am_nr::rlc_am_nr_tx::discard_sdu(uint32_t discard_sn) {} -bool rlc_am_nr_tx::sdu_queue_is_full() +bool rlc_am_nr::rlc_am_nr_tx::sdu_queue_is_full() { return false; } -void rlc_am_nr_tx::empty_queue() {} - -void rlc_am_nr_tx::set_bsr_callback(const bsr_callback_t& callback) {} +void rlc_am_nr::rlc_am_nr_tx::empty_queue() {} -void rlc_am_nr_tx::stop() {} +void rlc_am_nr::rlc_am_nr_tx::stop() {} /**************************************************************************** * Rx subclass implementation ***************************************************************************/ -rlc_am_nr_rx::rlc_am_nr_rx(rlc_am_nr* parent_) : - parent(parent_), pool(byte_buffer_pool::get_instance()), logger(parent_->logger) +rlc_am_nr::rlc_am_nr_rx::rlc_am_nr_rx(rlc_am_nr* parent_) : + parent(parent_), logger(parent_->logger), pool(byte_buffer_pool::get_instance()) {} -bool rlc_am_nr_rx::configure(const rlc_config_t& cfg_) +bool rlc_am_nr::rlc_am_nr_rx::configure(const rlc_config_t& cfg_) { cfg = cfg_.am; return true; } -void rlc_am_nr_rx::stop() {} +void rlc_am_nr::rlc_am_nr_rx::stop() {} -void rlc_am_nr_rx::write_pdu(uint8_t* payload, uint32_t nof_bytes) {} +void rlc_am_nr::rlc_am_nr_rx::write_pdu(uint8_t* payload, uint32_t nof_bytes) {} -void rlc_am_nr_rx::reestablish() +void rlc_am_nr::rlc_am_nr_rx::reestablish() { stop(); } -uint32_t rlc_am_nr_rx::get_sdu_rx_latency_ms() +uint32_t rlc_am_nr::rlc_am_nr_rx::get_sdu_rx_latency_ms() { return 0; } -uint32_t rlc_am_nr_rx::get_rx_buffered_bytes() +uint32_t rlc_am_nr::rlc_am_nr_rx::get_rx_buffered_bytes() { return 0; }