diff --git a/lib/include/srsran/rlc/rlc_am_nr.h b/lib/include/srsran/rlc/rlc_am_nr.h index bc644020f..9801a4109 100644 --- a/lib/include/srsran/rlc/rlc_am_nr.h +++ b/lib/include/srsran/rlc/rlc_am_nr.h @@ -125,10 +125,39 @@ private: public: // Getters/Setters + void set_tx_state(const rlc_am_nr_tx_state_t& st_) { st = st_; } // This should only be used for testing. rlc_am_nr_tx_state_t get_tx_state() { return st; } // This should only be used for testing. uint32_t get_tx_window_size() { return tx_window.size(); } // This should only be used for testing. }; +/**************************************************************************** + * RX State Variables + * Ref: 3GPP TS 38.322 v16.2.0 Section 7.1 + ***************************************************************************/ +struct rlc_am_nr_rx_state_t { + /* + * RX_Next: This state variable holds the value of the SN following the last in-sequence completely received RLC + * SDU, and it serves as the lower edge of the receiving window. It is initially set to 0, and is updated whenever + * the AM RLC entity receives an RLC SDU with SN = RX_Next. + */ + uint32_t rx_next = 0; + /* + * RX_Next_Status_Trigger: This state variable holds the value of the SN following the SN of the RLC SDU which + * triggered t-Reassembly. + */ + uint32_t rx_next_status_trigger = 0; + /* + * RX_Next_Highest: This state variable holds the highest possible value of the SN which can be indicated by + *"ACK_SN" when a STATUS PDU needs to be constructed. It is initially set to 0. + */ + 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. + */ + uint32_t rx_next_highest = 0; +}; + // Receiver sub-class class rlc_am_nr_rx : public rlc_am::rlc_am_base_rx { @@ -170,7 +199,7 @@ private: byte_buffer_pool* pool = nullptr; uint32_t mod_nr = 4096; - inline int32_t rx_mod_base_nr(uint32_t sn) { return ((int32_t)sn - (int32_t)rx_next) % mod_nr; } + inline int32_t rx_mod_base_nr(uint32_t sn) { return ((int32_t)sn - (int32_t)st.rx_next) % mod_nr; } // RX Window rlc_ringbuffer_t rx_window; @@ -178,32 +207,6 @@ private: // Mutexes std::mutex mutex; - /**************************************************************************** - * State Variables - * Ref: 3GPP TS 38.322 v16.2.0 Section 7.1 - ***************************************************************************/ - /* - * RX_Next: This state variable holds the value of the SN following the last in-sequence completely received RLC - * SDU, and it serves as the lower edge of the receiving window. It is initially set to 0, and is updated whenever - * the AM RLC entity receives an RLC SDU with SN = RX_Next. - */ - uint32_t rx_next = 0; - /* - * RX_Next_Status_Trigger: This state variable holds the value of the SN following the SN of the RLC SDU which - * triggered t-Reassembly. - */ - uint32_t rx_next_status_trigger = 0; - /* - * RX_Next_Highest: This state variable holds the highest possible value of the SN which can be indicated by - *"ACK_SN" when a STATUS PDU needs to be constructed. It is initially set to 0. - */ - 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. - */ - uint32_t rx_next_highest = 0; - /**************************************************************************** * Rx timers * Ref: 3GPP TS 38.322 v16.2.0 Section 7.3 @@ -216,6 +219,18 @@ private: * Ref: 3GPP TS 38.322 v16.2.0 Section 7.4 ***************************************************************************/ rlc_am_nr_config_t cfg = {}; + + /**************************************************************************** + * Tx state variables + * Ref: 3GPP TS 38.322 v16.2.0 Section 7.1 + ***************************************************************************/ + struct rlc_am_nr_rx_state_t st = {}; + +public: + // Getters/Setters + void set_rx_state(const rlc_am_nr_rx_state_t& st_) { st = st_; } // This should only be used for testing. + rlc_am_nr_rx_state_t get_rx_state() { return st; } // This should only be used for testing. + uint32_t get_rx_window_size() { return rx_window.size(); } // This should only be used for testing. }; } // namespace srsran diff --git a/lib/src/rlc/rlc_am_nr.cc b/lib/src/rlc/rlc_am_nr.cc index ba24ea220..63a7e4220 100644 --- a/lib/src/rlc/rlc_am_nr.cc +++ b/lib/src/rlc/rlc_am_nr.cc @@ -454,8 +454,8 @@ void rlc_am_nr_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_bytes) logger->info("%s SN=%d outside rx window [%d:%d] - discarding", parent->rb_name, header.sn, - rx_next, - rx_next + RLC_AM_NR_WINDOW_SIZE); + st.rx_next, + st.rx_next + RLC_AM_NR_WINDOW_SIZE); return; } @@ -510,8 +510,8 @@ void rlc_am_nr_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_bytes) // 5.2.3.2.3 Actions when an AMD PDU is placed in the reception buffer // Update Rx_Next_Highest - if (rx_mod_base_nr(header.sn) >= rx_mod_base_nr(rx_next_highest)) { - rx_next_highest = (header.sn + 1) % MOD; + if (rx_mod_base_nr(header.sn) >= rx_mod_base_nr(st.rx_next_highest)) { + st.rx_next_highest = (header.sn + 1) % MOD; } // Update RX_Highest_Status @@ -520,10 +520,10 @@ void rlc_am_nr_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_bytes) * - update RX_Highest_Status to the SN of the first RLC SDU with SN > current RX_Highest_Status for which not * all bytes have been received. */ - if (rx_mod_base_nr(header.sn) == rx_mod_base_nr(rx_highest_status)) { + if (rx_mod_base_nr(header.sn) == rx_mod_base_nr(st.rx_highest_status)) { uint32_t sn_upd = 0; - uint32_t window_top = rx_next + RLC_AM_WINDOW_SIZE; - for (sn_upd = rx_highest_status; sn_upd < window_top; ++sn_upd) { + uint32_t window_top = st.rx_next + RLC_AM_WINDOW_SIZE; + for (sn_upd = st.rx_highest_status; sn_upd < window_top; ++sn_upd) { if (rx_window.has_sn(sn_upd)) { if (not rx_window[sn_upd].fully_received) { break; // first SDU not fully received @@ -534,7 +534,7 @@ void rlc_am_nr_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_bytes) } // Update to the SN of the first SDU with missing bytes. // If it not exists, update to the end of the rx_window. - rx_highest_status = sn_upd; + st.rx_highest_status = sn_upd; } /* @@ -542,10 +542,10 @@ void rlc_am_nr_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_bytes) * - update RX_Next to the SN of the first RLC SDU with SN > current RX_Next for which not all bytes * have been received. */ - if (rx_mod_base_nr(header.sn) == rx_mod_base_nr(rx_next)) { + if (rx_mod_base_nr(header.sn) == rx_mod_base_nr(st.rx_next)) { uint32_t sn_upd = 0; - uint32_t window_top = rx_next + RLC_AM_WINDOW_SIZE; - for (sn_upd = rx_next; sn_upd < window_top; ++sn_upd) { + uint32_t window_top = st.rx_next + RLC_AM_WINDOW_SIZE; + for (sn_upd = st.rx_next; sn_upd < window_top; ++sn_upd) { if (rx_window.has_sn(sn_upd)) { if (not rx_window[sn_upd].fully_received) { break; // first SDU not fully received @@ -559,7 +559,7 @@ void rlc_am_nr_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_bytes) } // Update to the SN of the first SDU with missing bytes. // If it not exists, update to the end of the rx_window. - rx_next = sn_upd; + st.rx_next = sn_upd; } if (reassembly_timer.is_running()) { @@ -581,24 +581,24 @@ void rlc_am_nr_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_bytes) * - set RX_Next_Status_Trigger to RX_Next_Highest. */ bool restart_reassembly_timer = false; - if (rx_next_highest > rx_next + 1) { + if (st.rx_next_highest > st.rx_next + 1) { restart_reassembly_timer = true; } - if (rx_next_highest == rx_next + 1 && - rx_window[rx_next + 1].fully_received == false) { // TODO: does the last by need to be received? + if (st.rx_next_highest == st.rx_next + 1 && + rx_window[st.rx_next + 1].fully_received == false) { // TODO: does the last by need to be received? restart_reassembly_timer = true; } if (restart_reassembly_timer) { reassembly_timer.run(); - rx_next_status_trigger = rx_next_highest; + st.rx_next_status_trigger = st.rx_next_highest; } } } bool rlc_am_nr_rx::inside_rx_window(uint32_t sn) { - return (rx_mod_base_nr(sn) >= rx_mod_base_nr(rx_next)) && - (rx_mod_base_nr(sn) < rx_mod_base_nr(rx_next + RLC_AM_NR_WINDOW_SIZE)); + return (rx_mod_base_nr(sn) >= rx_mod_base_nr(st.rx_next)) && + (rx_mod_base_nr(sn) < rx_mod_base_nr(st.rx_next + RLC_AM_NR_WINDOW_SIZE)); } /* @@ -612,12 +612,12 @@ 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 the lower end of the window + status->ack_sn = st.rx_next; // Start with the lower end of the window byte_buffer_t tmp_buf; 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) { + while (rx_mod_base_nr(i) <= rx_mod_base_nr(st.rx_highest_status)) { + if (rx_window.has_sn(i) || i == st.rx_highest_status) { // only update ACK_SN if this SN has been received, or if we reached the maximum possible SN status->ack_sn = i; } else { @@ -674,22 +674,23 @@ void rlc_am_nr_rx::timer_expired(uint32_t timeout_id) * - 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++) { + for (uint32_t tmp_sn = st.rx_next_status_trigger; tmp_sn < st.rx_next_status_trigger + RLC_AM_WINDOW_SIZE; + tmp_sn++) { if (not rx_window.has_sn(tmp_sn) || not rx_window[tmp_sn].fully_received) { - rx_highest_status = tmp_sn; + st.rx_highest_status = tmp_sn; break; } } bool restart_reassembly_timer = false; - if (rx_next_highest > rx_highest_status + 1) { + if (st.rx_next_highest > st.rx_highest_status + 1) { restart_reassembly_timer = true; } - if (rx_next_highest == rx_highest_status + 1 && not rx_window[rx_next_highest].fully_received) { + if (st.rx_next_highest == st.rx_highest_status + 1 && not rx_window[st.rx_next_highest].fully_received) { restart_reassembly_timer = true; } if (restart_reassembly_timer) { reassembly_timer.run(); - rx_next_status_trigger = rx_next_highest; + st.rx_next_status_trigger = st.rx_next_highest; } /* 5.3.4 Status reporting: @@ -730,9 +731,9 @@ uint32_t rlc_am_nr_rx::get_rx_buffered_bytes() void rlc_am_nr_rx::debug_state() { logger->debug("RX entity state: Rx_Next %d, Rx_Next_Status_Trigger %d, Rx_Highest_Status %d, Rx_Next_Highest", - rx_next, - rx_next_status_trigger, - rx_highest_status, - rx_next_highest); + st.rx_next, + st.rx_next_status_trigger, + st.rx_highest_status, + st.rx_next_highest); } } // namespace srsran