Adding t_reassembly to RLC AM NR

This commit is contained in:
Pedro Alvarez 2021-10-21 13:39:54 +01:00
parent f09020e57f
commit 3f000f0472
5 changed files with 68 additions and 22 deletions

View File

@ -98,7 +98,7 @@ struct rlc_am_nr_config_t {
// Timers Ref: 3GPP TS 38.322 Section 7.3 // Timers Ref: 3GPP TS 38.322 Section 7.3
int32_t t_poll_retx; // Poll retx timeout (ms) 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) 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 // Configurable Parameters. Ref: 3GPP TS 38.322 Section 7.4

View File

@ -55,7 +55,7 @@ public:
void empty_queue() final; void empty_queue() final;
bool has_data() final; bool has_data() final;
uint32_t get_buffer_state() 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(); bool do_status();
uint32_t build_status_pdu(byte_buffer_t* payload, uint32_t nof_bytes); uint32_t build_status_pdu(byte_buffer_t* payload, uint32_t nof_bytes);
@ -103,9 +103,6 @@ public:
void stop(); void stop();
void reestablish(); void reestablish();
uint32_t get_sdu_rx_latency_ms();
uint32_t get_rx_buffered_bytes();
// Status PDU // Status PDU
bool get_do_status(); bool get_do_status();
uint32_t get_status_pdu(rlc_am_nr_status_pdu_t* status, uint32_t len); 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); 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); bool inside_rx_window(uint32_t sn);
// Metrics
uint32_t get_sdu_rx_latency_ms() final;
uint32_t get_rx_buffered_bytes() final;
// Timers // Timers
void timer_expired(uint32_t timeout_id); void timer_expired(uint32_t timeout_id);
@ -132,18 +133,6 @@ private:
// Mutexes // Mutexes
std::mutex mutex; 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 * State Variables
* Ref: 3GPP TS 38.322 v10.0.0 Section 7.1 * Ref: 3GPP TS 38.322 v10.0.0 Section 7.1
@ -166,9 +155,22 @@ private:
uint32_t rx_highest_status = 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 * 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; 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 } // namespace srsran

View File

@ -50,6 +50,12 @@ struct rlc_amd_rx_pdu_nr {
explicit rlc_amd_rx_pdu_nr(uint32_t rlc_sn_) : rlc_sn(rlc_sn_) {} 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<rlc_amd_rx_pdu_nr> segments;
};
///< AM NR Status PDU header (perhaps merge with LTE version) ///< AM NR Status PDU header (perhaps merge with LTE version)
typedef struct { typedef struct {
rlc_am_nr_control_pdu_type_t cpt; rlc_am_nr_control_pdu_type_t cpt;

View File

@ -241,12 +241,17 @@ bool rlc_am_nr_rx::configure(const rlc_config_t& cfg_)
{ {
cfg = cfg_.am_nr; cfg = cfg_.am_nr;
// configure timers // Configure status prohibit timer
if (cfg.t_status_prohibit > 0) { if (cfg.t_status_prohibit > 0) {
status_prohibit_timer.set(static_cast<uint32_t>(cfg.t_status_prohibit), status_prohibit_timer.set(static_cast<uint32_t>(cfg.t_status_prohibit),
[this](uint32_t timerid) { timer_expired(timerid); }); [this](uint32_t timerid) { timer_expired(timerid); });
} }
// Configure t_reassembly timer
if (cfg.t_reassembly > 0) {
reassembly_timer.set(static_cast<uint32_t>(cfg.t_reassembly), [this](uint32_t timerid) { timer_expired(timerid); });
}
return true; 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->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; byte_buffer_t tmp_buf;
uint32_t len; uint32_t len;
// We don't use segment NACKs - just NACK the full PDU
uint32_t i = status->ack_sn; uint32_t i = status->ack_sn;
while (RX_MOD_BASE_NR(i) <= RX_MOD_BASE_NR(rx_highest_status)) { while (RX_MOD_BASE_NR(i) <= RX_MOD_BASE_NR(rx_highest_status)) {
if (rx_window.has_sn(i) || i == 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) void rlc_am_nr_rx::timer_expired(uint32_t timeout_id)
{ {
std::unique_lock<std::mutex> lock(mutex); std::unique_lock<std::mutex> lock(mutex);
// Status Prohibit
if (status_prohibit_timer.is_valid() && status_prohibit_timer.id() == timeout_id) { 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()); 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;
} }
} }

View File

@ -88,7 +88,7 @@ int basic_test()
int len = rlc2.read_pdu(status_buf.msg, 3); int len = rlc2.read_pdu(status_buf.msg, 3);
status_buf.N_bytes = len; status_buf.N_bytes = len;
// TESTASSERT(0 == rlc2.get_buffer_state()); TESTASSERT(0 == rlc2.get_buffer_state());
// Assert status is correct // Assert status is correct
rlc_am_nr_status_pdu_t status_check = {}; rlc_am_nr_status_pdu_t status_check = {};