diff --git a/lib/include/srsran/interfaces/rlc_interface_types.h b/lib/include/srsran/interfaces/rlc_interface_types.h index eb9cd11cf..9e9bb7c92 100644 --- a/lib/include/srsran/interfaces/rlc_interface_types.h +++ b/lib/include/srsran/interfaces/rlc_interface_types.h @@ -98,7 +98,7 @@ struct rlc_am_nr_config_t { // Timers Ref: 3GPP TS 38.322 Section 7.3 int32_t t_poll_retx; // Poll retx timeout (ms) - int32_t t_reassambly; // Timer used by rx to detect PDU loss (ms) + int32_t t_reassembly; // Timer used by rx to detect PDU loss (ms) int32_t t_status_prohibit; // Timer used by rx to prohibit tx of status PDU (ms) // Configurable Parameters. Ref: 3GPP TS 38.322 Section 7.4 diff --git a/lib/include/srsran/rlc/rlc_am_nr.h b/lib/include/srsran/rlc/rlc_am_nr.h index 35bb108c0..10def47d1 100644 --- a/lib/include/srsran/rlc/rlc_am_nr.h +++ b/lib/include/srsran/rlc/rlc_am_nr.h @@ -55,7 +55,7 @@ public: void empty_queue() final; bool has_data() final; uint32_t get_buffer_state() final; - void get_buffer_state(uint32_t& tx_queue, uint32_t& prio_tx_queue); + void get_buffer_state(uint32_t& tx_queue, uint32_t& prio_tx_queue) final; bool do_status(); uint32_t build_status_pdu(byte_buffer_t* payload, uint32_t nof_bytes); @@ -103,9 +103,6 @@ public: void stop(); void reestablish(); - uint32_t get_sdu_rx_latency_ms(); - uint32_t get_rx_buffered_bytes(); - // Status PDU bool get_do_status(); uint32_t get_status_pdu(rlc_am_nr_status_pdu_t* status, uint32_t len); @@ -115,6 +112,10 @@ public: void handle_data_pdu_full(uint8_t* payload, uint32_t nof_bytes, rlc_am_nr_pdu_header_t& header); bool inside_rx_window(uint32_t sn); + // Metrics + uint32_t get_sdu_rx_latency_ms() final; + uint32_t get_rx_buffered_bytes() final; + // Timers void timer_expired(uint32_t timeout_id); @@ -132,18 +133,6 @@ private: // Mutexes std::mutex mutex; - /**************************************************************************** - * Rx timers - * Ref: 3GPP TS 38.322 v10.0.0 Section 7.3 - ***************************************************************************/ - srsran::timer_handler::unique_timer status_prohibit_timer; - - /**************************************************************************** - * Configurable parameters - * Ref: 3GPP TS 38.322 v10.0.0 Section 7.4 - ***************************************************************************/ - rlc_am_nr_config_t cfg = {}; - /**************************************************************************** * State Variables * Ref: 3GPP TS 38.322 v10.0.0 Section 7.1 @@ -166,9 +155,22 @@ private: uint32_t rx_highest_status = 0; /* * RX_Next_Highest: This state variable holds the value of the SN following the SN of the RLC SDU with the - * highest SN among received *RLC SDUs. It is initially set to 0. + * highest SN among received RLC SDUs. It is initially set to 0. */ uint32_t rx_next_highest = 0; + + /**************************************************************************** + * Rx timers + * Ref: 3GPP TS 38.322 v10.0.0 Section 7.3 + ***************************************************************************/ + srsran::timer_handler::unique_timer status_prohibit_timer; + srsran::timer_handler::unique_timer reassembly_timer; + + /**************************************************************************** + * Configurable parameters + * Ref: 3GPP TS 38.322 v10.0.0 Section 7.4 + ***************************************************************************/ + rlc_am_nr_config_t cfg = {}; }; } // namespace srsran diff --git a/lib/include/srsran/rlc/rlc_am_nr_packing.h b/lib/include/srsran/rlc/rlc_am_nr_packing.h index b15ba15c5..6e13ac08e 100644 --- a/lib/include/srsran/rlc/rlc_am_nr_packing.h +++ b/lib/include/srsran/rlc/rlc_am_nr_packing.h @@ -50,6 +50,12 @@ struct rlc_amd_rx_pdu_nr { explicit rlc_amd_rx_pdu_nr(uint32_t rlc_sn_) : rlc_sn(rlc_sn_) {} }; +struct rlc_amd_rx_sdu_t { + uint32_t rlc_sn = 0; + bool fully_received = false; + std::list segments; +}; + ///< AM NR Status PDU header (perhaps merge with LTE version) typedef struct { rlc_am_nr_control_pdu_type_t cpt; diff --git a/lib/src/rlc/rlc_am_nr.cc b/lib/src/rlc/rlc_am_nr.cc index 43a1860a3..ae978c473 100644 --- a/lib/src/rlc/rlc_am_nr.cc +++ b/lib/src/rlc/rlc_am_nr.cc @@ -241,12 +241,17 @@ bool rlc_am_nr_rx::configure(const rlc_config_t& cfg_) { cfg = cfg_.am_nr; - // configure timers + // Configure status prohibit timer if (cfg.t_status_prohibit > 0) { status_prohibit_timer.set(static_cast(cfg.t_status_prohibit), [this](uint32_t timerid) { timer_expired(timerid); }); } + // Configure t_reassembly timer + if (cfg.t_reassembly > 0) { + reassembly_timer.set(static_cast(cfg.t_reassembly), [this](uint32_t timerid) { timer_expired(timerid); }); + } + return true; } @@ -405,11 +410,10 @@ uint32_t rlc_am_nr_rx::get_status_pdu(rlc_am_nr_status_pdu_t* status, uint32_t m } status->N_nack = 0; - status->ack_sn = rx_next; // start with lower edge of the rx window + status->ack_sn = rx_highest_status; // ACK RX_Highest_Status byte_buffer_t tmp_buf; uint32_t len; - // We don't use segment NACKs - just NACK the full PDU uint32_t i = status->ack_sn; while (RX_MOD_BASE_NR(i) <= RX_MOD_BASE_NR(rx_highest_status)) { if (rx_window.has_sn(i) || i == rx_highest_status) { @@ -445,8 +449,42 @@ bool rlc_am_nr_rx::get_do_status() void rlc_am_nr_rx::timer_expired(uint32_t timeout_id) { std::unique_lock lock(mutex); + + // Status Prohibit if (status_prohibit_timer.is_valid() && status_prohibit_timer.id() == timeout_id) { logger->debug("%s Status prohibit timer expired after %dms", parent->rb_name, status_prohibit_timer.duration()); + return; + } + + // Reassembly + if (reassembly_timer.is_valid() && reassembly_timer.id() == timeout_id) { + logger->debug("%s Reassembly timer expired after %dms", parent->rb_name, reassembly_timer.duration()); + /* + * 5.2.3.2.4 Actions when t-Reassembly expires: + * - update RX_Highest_Status to the SN of the first RLC SDU with SN >= RX_Next_Status_Trigger for which not + * all bytes have been received; + * - if RX_Next_Highest> RX_Highest_Status +1: or + * - if RX_Next_Highest = RX_Highest_Status + 1 and there is at least one missing byte segment of the SDU + * associated with SN = RX_Highest_Status before the last byte of all received segments of this SDU: + * - start t-Reassembly; + * - set RX_Next_Status_Trigger to RX_Next_Highest. + */ + for (uint32_t tmp_sn = rx_next_status_trigger; tmp_sn < rx_next_status_trigger + RLC_AM_WINDOW_SIZE; tmp_sn++) { + if (not rx_window.has_sn(tmp_sn) /*|| rx_window[tmp_sn].fully_received*/) { + rx_highest_status = tmp_sn; + break; + } + } + bool restart_reassembly_timer = false; + if (rx_next_highest > rx_highest_status + 1) { + restart_reassembly_timer = true; + } + if (rx_next_highest == rx_highest_status + 1) { + restart_reassembly_timer = true; + } + if (restart_reassembly_timer) { + } + return; } } diff --git a/lib/test/rlc/rlc_am_nr_test.cc b/lib/test/rlc/rlc_am_nr_test.cc index 4f55645cf..101956798 100644 --- a/lib/test/rlc/rlc_am_nr_test.cc +++ b/lib/test/rlc/rlc_am_nr_test.cc @@ -88,7 +88,7 @@ int basic_test() int len = rlc2.read_pdu(status_buf.msg, 3); status_buf.N_bytes = len; - // TESTASSERT(0 == rlc2.get_buffer_state()); + TESTASSERT(0 == rlc2.get_buffer_state()); // Assert status is correct rlc_am_nr_status_pdu_t status_check = {};