rlc: separate types of rlc_amd_retx_t for LTE and NR

master
Robert Falkenberg 3 years ago
parent 4886dc8340
commit bb7339910f

@ -300,7 +300,7 @@ private:
uint32_t count = 0; uint32_t count = 0;
}; };
struct rlc_amd_retx_t { struct rlc_amd_retx_lte_t {
uint32_t sn; uint32_t sn;
bool is_segment; bool is_segment;
uint32_t so_start; // offset to first byte of this segment uint32_t so_start; // offset to first byte of this segment
@ -308,21 +308,29 @@ struct rlc_amd_retx_t {
uint32_t current_so; uint32_t current_so;
}; };
template <std::size_t WINDOW_SIZE> struct rlc_amd_retx_nr_t {
uint32_t sn;
bool is_segment;
uint32_t so_start; // offset to first byte of this segment
uint32_t so_end; // offset to first byte beyond the end of this segment
uint32_t current_so;
};
template <class T, std::size_t WINDOW_SIZE>
class pdu_retx_queue class pdu_retx_queue
{ {
public: public:
rlc_amd_retx_t& push() T& push()
{ {
assert(not full()); assert(not full());
rlc_amd_retx_t& p = buffer[wpos]; T& p = buffer[wpos];
wpos = (wpos + 1) % WINDOW_SIZE; wpos = (wpos + 1) % WINDOW_SIZE;
return p; return p;
} }
void pop() { rpos = (rpos + 1) % WINDOW_SIZE; } void pop() { rpos = (rpos + 1) % WINDOW_SIZE; }
rlc_amd_retx_t& front() T& front()
{ {
assert(not empty()); assert(not empty());
return buffer[rpos]; return buffer[rpos];
@ -349,9 +357,9 @@ public:
bool full() const { return size() == WINDOW_SIZE - 1; } bool full() const { return size() == WINDOW_SIZE - 1; }
private: private:
std::array<rlc_amd_retx_t, WINDOW_SIZE> buffer; std::array<T, WINDOW_SIZE> buffer;
size_t wpos = 0; size_t wpos = 0;
size_t rpos = 0; size_t rpos = 0;
}; };
} // namespace srsran } // namespace srsran

@ -79,11 +79,11 @@ private:
int build_status_pdu(uint8_t* payload, uint32_t nof_bytes); int build_status_pdu(uint8_t* payload, uint32_t nof_bytes);
int build_retx_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_segment(uint8_t* payload, uint32_t nof_bytes, rlc_amd_retx_lte_t retx);
int build_data_pdu(uint8_t* payload, uint32_t nof_bytes); int build_data_pdu(uint8_t* payload, uint32_t nof_bytes);
void update_notification_ack_info(uint32_t rlc_sn); void update_notification_ack_info(uint32_t rlc_sn);
int required_buffer_size(const rlc_amd_retx_t& retx); int required_buffer_size(const rlc_amd_retx_lte_t& retx);
void retransmit_pdu(uint32_t sn); void retransmit_pdu(uint32_t sn);
// Helpers // Helpers
@ -137,7 +137,7 @@ private:
// Tx windows // Tx windows
rlc_ringbuffer_t<rlc_amd_tx_pdu<rlc_amd_pdu_header_t>, RLC_AM_WINDOW_SIZE> tx_window; rlc_ringbuffer_t<rlc_amd_tx_pdu<rlc_amd_pdu_header_t>, RLC_AM_WINDOW_SIZE> tx_window;
pdu_retx_queue<RLC_AM_WINDOW_SIZE> retx_queue; pdu_retx_queue<rlc_amd_retx_lte_t, RLC_AM_WINDOW_SIZE> retx_queue;
pdcp_sn_vector_t notify_info_vec; pdcp_sn_vector_t notify_info_vec;
// Mutexes // Mutexes

@ -53,7 +53,7 @@ int rlc_am_write_status_pdu(rlc_status_pdu_t* status, uint8_t* payload);
uint32_t rlc_am_packed_length(rlc_amd_pdu_header_t* header); uint32_t rlc_am_packed_length(rlc_amd_pdu_header_t* header);
uint32_t rlc_am_packed_length(rlc_status_pdu_t* status); uint32_t rlc_am_packed_length(rlc_status_pdu_t* status);
uint32_t rlc_am_packed_length(rlc_amd_retx_t retx); uint32_t rlc_am_packed_length(rlc_amd_retx_lte_t retx);
bool rlc_am_is_pdu_segment(uint8_t* payload); bool rlc_am_is_pdu_segment(uint8_t* payload);
bool rlc_am_is_valid_status_pdu(const rlc_status_pdu_t& status, uint32_t rx_win_min = 0); bool rlc_am_is_valid_status_pdu(const rlc_status_pdu_t& status, uint32_t rx_win_min = 0);
bool rlc_am_start_aligned(const uint8_t fi); bool rlc_am_start_aligned(const uint8_t fi);

@ -107,10 +107,10 @@ public:
uint32_t build_new_sdu_segment(rlc_amd_tx_pdu_nr& tx_pdu, uint8_t* payload, uint32_t nof_bytes); uint32_t build_new_sdu_segment(rlc_amd_tx_pdu_nr& tx_pdu, uint8_t* payload, uint32_t nof_bytes);
uint32_t build_continuation_sdu_segment(rlc_amd_tx_pdu_nr& tx_pdu, uint8_t* payload, uint32_t nof_bytes); uint32_t build_continuation_sdu_segment(rlc_amd_tx_pdu_nr& tx_pdu, uint8_t* payload, uint32_t nof_bytes);
uint32_t build_retx_pdu(uint8_t* payload, uint32_t nof_bytes); uint32_t build_retx_pdu(uint8_t* payload, uint32_t nof_bytes);
uint32_t build_retx_pdu_without_segmentation(rlc_amd_retx_t& retx, uint8_t* payload, uint32_t nof_bytes); uint32_t build_retx_pdu_without_segmentation(rlc_amd_retx_nr_t& retx, uint8_t* payload, uint32_t nof_bytes);
uint32_t build_retx_pdu_with_segmentation(rlc_amd_retx_t& retx, uint8_t* payload, uint32_t nof_bytes); uint32_t build_retx_pdu_with_segmentation(rlc_amd_retx_nr_t& retx, uint8_t* payload, uint32_t nof_bytes);
bool is_retx_segmentation_required(const rlc_amd_retx_t& retx, uint32_t nof_bytes); bool is_retx_segmentation_required(const rlc_amd_retx_nr_t& retx, uint32_t nof_bytes);
uint32_t get_retx_expected_hdr_len(const rlc_amd_retx_t& retx); uint32_t get_retx_expected_hdr_len(const rlc_amd_retx_nr_t& retx);
// Buffer State // Buffer State
bool has_data() final; bool has_data() final;
@ -150,7 +150,7 @@ private:
rlc_ringbuffer_t<rlc_amd_tx_pdu_nr, RLC_AM_WINDOW_SIZE> tx_window; rlc_ringbuffer_t<rlc_amd_tx_pdu_nr, RLC_AM_WINDOW_SIZE> tx_window;
// Queues and buffers // Queues and buffers
pdu_retx_queue<RLC_AM_WINDOW_SIZE> retx_queue; pdu_retx_queue<rlc_amd_retx_nr_t, RLC_AM_WINDOW_SIZE> retx_queue;
uint32_t sdu_under_segmentation_sn = INVALID_RLC_SN; // SN of the SDU currently being segmented. uint32_t sdu_under_segmentation_sn = INVALID_RLC_SN; // SN of the SDU currently being segmented.
pdcp_sn_vector_t notify_info_vec; pdcp_sn_vector_t notify_info_vec;

@ -223,7 +223,7 @@ void rlc_am_lte_tx::get_buffer_state_nolock(uint32_t& n_bytes_newtx, uint32_t& n
// Bytes needed for retx // Bytes needed for retx
if (not retx_queue.empty()) { if (not retx_queue.empty()) {
rlc_amd_retx_t& retx = retx_queue.front(); rlc_amd_retx_lte_t& retx = retx_queue.front();
RlcDebug("Buffer state - retx - SN=%d, Segment: %s, %d:%d", RlcDebug("Buffer state - retx - SN=%d, Segment: %s, %d:%d",
retx.sn, retx.sn,
retx.is_segment ? "true" : "false", retx.is_segment ? "true" : "false",
@ -353,11 +353,11 @@ void rlc_am_lte_tx::retransmit_pdu(uint32_t sn)
RlcInfo("Schedule SN=%d for retx", pdu.rlc_sn); RlcInfo("Schedule SN=%d for retx", pdu.rlc_sn);
rlc_amd_retx_t& retx = retx_queue.push(); rlc_amd_retx_lte_t& retx = retx_queue.push();
retx.is_segment = false; retx.is_segment = false;
retx.so_start = 0; retx.so_start = 0;
retx.so_end = pdu.buf->N_bytes; retx.so_end = pdu.buf->N_bytes;
retx.sn = pdu.rlc_sn; retx.sn = pdu.rlc_sn;
} }
/**************************************************************************** /****************************************************************************
@ -443,7 +443,7 @@ int rlc_am_lte_tx::build_retx_pdu(uint8_t* payload, uint32_t nof_bytes)
return -1; return -1;
} }
rlc_amd_retx_t retx = retx_queue.front(); rlc_amd_retx_lte_t retx = retx_queue.front();
// Sanity check - drop any retx SNs not present in tx_window // Sanity check - drop any retx SNs not present in tx_window
while (not tx_window.has_sn(retx.sn)) { while (not tx_window.has_sn(retx.sn)) {
@ -516,7 +516,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; 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_tx::build_segment(uint8_t* payload, uint32_t nof_bytes, rlc_amd_retx_lte_t retx)
{ {
if (tx_window[retx.sn].buf == NULL) { if (tx_window[retx.sn].buf == NULL) {
RlcError("In build_segment: retx.sn=%d has null buffer", retx.sn); RlcError("In build_segment: retx.sn=%d has null buffer", retx.sn);
@ -956,7 +956,7 @@ void rlc_am_lte_tx::handle_control_pdu(uint8_t* payload, uint32_t nof_bytes)
pdu.retx_count++; pdu.retx_count++;
check_sn_reached_max_retx(i); check_sn_reached_max_retx(i);
rlc_amd_retx_t& retx = retx_queue.push(); rlc_amd_retx_lte_t& retx = retx_queue.push();
srsran_expect(tx_window[i].rlc_sn == i, "Incorrect RLC SN=%d!=%d being accessed", tx_window[i].rlc_sn, i); srsran_expect(tx_window[i].rlc_sn == i, "Incorrect RLC SN=%d!=%d being accessed", tx_window[i].rlc_sn, i);
retx.sn = i; retx.sn = i;
retx.is_segment = false; retx.is_segment = false;
@ -1080,7 +1080,7 @@ void rlc_am_lte_tx::debug_state()
RlcDebug("vt_a = %d, vt_ms = %d, vt_s = %d, poll_sn = %d", vt_a, vt_ms, vt_s, poll_sn); RlcDebug("vt_a = %d, vt_ms = %d, vt_s = %d, poll_sn = %d", 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_tx::required_buffer_size(const rlc_amd_retx_lte_t& retx)
{ {
if (!retx.is_segment) { if (!retx.is_segment) {
if (tx_window.has_sn(retx.sn)) { if (tx_window.has_sn(retx.sn)) {

@ -404,7 +404,7 @@ uint32_t rlc_am_nr_tx::build_retx_pdu(uint8_t* payload, uint32_t nof_bytes)
return 0; return 0;
} }
rlc_amd_retx_t& retx = retx_queue.front(); rlc_amd_retx_nr_t& retx = retx_queue.front();
// Sanity check - drop any retx SNs not present in tx_window // Sanity check - drop any retx SNs not present in tx_window
while (not tx_window.has_sn(retx.sn)) { while (not tx_window.has_sn(retx.sn)) {
@ -447,7 +447,8 @@ uint32_t rlc_am_nr_tx::build_retx_pdu(uint8_t* payload, uint32_t nof_bytes)
* \remark this function will not update the SI. This means that if the retx is of the last * \remark this function will not update the SI. This means that if the retx is of the last
* SDU segment, the SI should already be of the `last_segment` type. * SDU segment, the SI should already be of the `last_segment` type.
*/ */
uint32_t rlc_am_nr_tx::build_retx_pdu_without_segmentation(rlc_amd_retx_t& retx, uint8_t* payload, uint32_t nof_bytes) uint32_t
rlc_am_nr_tx::build_retx_pdu_without_segmentation(rlc_amd_retx_nr_t& retx, uint8_t* payload, uint32_t nof_bytes)
{ {
srsran_assert(tx_window.has_sn(retx.sn), "Called %s without checking retx SN", __FUNCTION__); srsran_assert(tx_window.has_sn(retx.sn), "Called %s without checking retx SN", __FUNCTION__);
srsran_assert(not is_retx_segmentation_required(retx, nof_bytes), srsran_assert(not is_retx_segmentation_required(retx, nof_bytes),
@ -536,7 +537,7 @@ uint32_t rlc_am_nr_tx::build_retx_pdu_without_segmentation(rlc_amd_retx_t& retx,
* \returns the number of bytes written to the payload buffer. * \returns the number of bytes written to the payload buffer.
* \remark: This functions assumes that the SDU has already been copied to tx_pdu.sdu_buf. * \remark: This functions assumes that the SDU has already been copied to tx_pdu.sdu_buf.
*/ */
uint32_t rlc_am_nr_tx::build_retx_pdu_with_segmentation(rlc_amd_retx_t& retx, uint8_t* payload, uint32_t nof_bytes) uint32_t rlc_am_nr_tx::build_retx_pdu_with_segmentation(rlc_amd_retx_nr_t& retx, uint8_t* payload, uint32_t nof_bytes)
{ {
// Get tx_pdu info from tx_window // Get tx_pdu info from tx_window
srsran_assert(tx_window.has_sn(retx.sn), "Called %s without checking retx SN", __FUNCTION__); srsran_assert(tx_window.has_sn(retx.sn), "Called %s without checking retx SN", __FUNCTION__);
@ -633,7 +634,7 @@ uint32_t rlc_am_nr_tx::build_retx_pdu_with_segmentation(rlc_amd_retx_t& retx, ui
return hdr_len + retx_pdu_payload_size; return hdr_len + retx_pdu_payload_size;
} }
bool rlc_am_nr_tx::is_retx_segmentation_required(const rlc_amd_retx_t& retx, uint32_t nof_bytes) bool rlc_am_nr_tx::is_retx_segmentation_required(const rlc_amd_retx_nr_t& retx, uint32_t nof_bytes)
{ {
bool segmentation_required = false; bool segmentation_required = false;
if (retx.is_segment) { if (retx.is_segment) {
@ -651,7 +652,7 @@ bool rlc_am_nr_tx::is_retx_segmentation_required(const rlc_amd_retx_t& retx, uin
return segmentation_required; return segmentation_required;
} }
uint32_t rlc_am_nr_tx::get_retx_expected_hdr_len(const rlc_amd_retx_t& retx) uint32_t rlc_am_nr_tx::get_retx_expected_hdr_len(const rlc_amd_retx_nr_t& retx)
{ {
uint32_t expected_hdr_len = min_hdr_size; uint32_t expected_hdr_len = min_hdr_size;
if (retx.is_segment && retx.current_so != 0) { if (retx.is_segment && retx.current_so != 0) {
@ -748,12 +749,12 @@ void rlc_am_nr_tx::handle_control_pdu(uint8_t* payload, uint32_t nof_bytes)
segm++) { segm++) {
if (segm->so >= nack.so_start && segm->so <= nack.so_end) { if (segm->so >= nack.so_start && segm->so <= nack.so_end) {
// TODO: Check if this segment is not already queued for retransmission // TODO: Check if this segment is not already queued for retransmission
rlc_amd_retx_t& retx = retx_queue.push(); rlc_amd_retx_nr_t& retx = retx_queue.push();
retx.sn = nack_sn; retx.sn = nack_sn;
retx.is_segment = true; retx.is_segment = true;
retx.so_start = segm->so; retx.so_start = segm->so;
retx.current_so = segm->so; retx.current_so = segm->so;
retx.so_end = segm->so + segm->payload_len; retx.so_end = segm->so + segm->payload_len;
retx_sn_set.insert(nack_sn); retx_sn_set.insert(nack_sn);
RlcInfo( RlcInfo(
"Scheduled RETX of SDU segment SN=%d, so_start=%d, so_end=%d", retx.sn, retx.so_start, retx.so_end); "Scheduled RETX of SDU segment SN=%d, so_start=%d, so_end=%d", retx.sn, retx.so_start, retx.so_end);
@ -763,12 +764,12 @@ void rlc_am_nr_tx::handle_control_pdu(uint8_t* payload, uint32_t nof_bytes)
// NACK'ing full SDU. // NACK'ing full SDU.
// add to retx queue if it's not already there // add to retx queue if it's not already there
if (not retx_queue.has_sn(nack_sn)) { if (not retx_queue.has_sn(nack_sn)) {
rlc_amd_retx_t& retx = retx_queue.push(); rlc_amd_retx_nr_t& retx = retx_queue.push();
retx.sn = nack_sn; retx.sn = nack_sn;
retx.is_segment = false; retx.is_segment = false;
retx.so_start = 0; retx.so_start = 0;
retx.current_so = 0; retx.current_so = 0;
retx.so_end = pdu.sdu_buf->N_bytes; retx.so_end = pdu.sdu_buf->N_bytes;
retx_sn_set.insert(nack_sn); retx_sn_set.insert(nack_sn);
RlcInfo("Scheduled RETX of SDU SN=%d", retx.sn); RlcInfo("Scheduled RETX of SDU SN=%d", retx.sn);
} }
@ -847,7 +848,7 @@ void rlc_am_nr_tx::get_buffer_state(uint32_t& n_bytes_new, uint32_t& n_bytes_pri
// Bytes needed for retx // Bytes needed for retx
if (not retx_queue.empty()) { if (not retx_queue.empty()) {
rlc_amd_retx_t& retx = retx_queue.front(); rlc_amd_retx_nr_t& retx = retx_queue.front();
RlcDebug("buffer state - retx - SN=%d, Segment: %s, %d:%d", RlcDebug("buffer state - retx - SN=%d, Segment: %s, %d:%d",
retx.sn, retx.sn,
retx.is_segment ? "true" : "false", retx.is_segment ? "true" : "false",

@ -147,10 +147,10 @@ int retx_segmentation_required_checker_test()
// Test full SDU retx // Test full SDU retx
{ {
uint32_t nof_bytes = 8; uint32_t nof_bytes = 8;
rlc_amd_retx_t retx = {}; rlc_amd_retx_nr_t retx = {};
retx.sn = 0; retx.sn = 0;
retx.is_segment = false; retx.is_segment = false;
tx->is_retx_segmentation_required(retx, nof_bytes); tx->is_retx_segmentation_required(retx, nof_bytes);
TESTASSERT_EQ(false, tx->is_retx_segmentation_required(retx, nof_bytes)); TESTASSERT_EQ(false, tx->is_retx_segmentation_required(retx, nof_bytes));
@ -158,8 +158,8 @@ int retx_segmentation_required_checker_test()
// Test SDU retx segmentation required // Test SDU retx segmentation required
{ {
uint32_t nof_bytes = 4; uint32_t nof_bytes = 4;
rlc_amd_retx_t retx; rlc_amd_retx_nr_t retx;
retx.sn = 0; retx.sn = 0;
retx.is_segment = false; retx.is_segment = false;
@ -169,12 +169,12 @@ int retx_segmentation_required_checker_test()
// Test full SDU segment retx // Test full SDU segment retx
{ {
uint32_t nof_bytes = 40; uint32_t nof_bytes = 40;
rlc_amd_retx_t retx = {}; rlc_amd_retx_nr_t retx = {};
retx.sn = 0; retx.sn = 0;
retx.is_segment = true; retx.is_segment = true;
retx.so_start = 4; retx.so_start = 4;
retx.so_end = 6; retx.so_end = 6;
tx->is_retx_segmentation_required(retx, nof_bytes); tx->is_retx_segmentation_required(retx, nof_bytes);
TESTASSERT_EQ(false, tx->is_retx_segmentation_required(retx, nof_bytes)); TESTASSERT_EQ(false, tx->is_retx_segmentation_required(retx, nof_bytes));
@ -182,12 +182,12 @@ int retx_segmentation_required_checker_test()
// Test SDU segment retx segmentation required // Test SDU segment retx segmentation required
{ {
uint32_t nof_bytes = 4; uint32_t nof_bytes = 4;
rlc_amd_retx_t retx = {}; rlc_amd_retx_nr_t retx = {};
retx.sn = 0; retx.sn = 0;
retx.is_segment = true; retx.is_segment = true;
retx.so_start = 4; retx.so_start = 4;
retx.so_end = 6; retx.so_end = 6;
tx->is_retx_segmentation_required(retx, nof_bytes); tx->is_retx_segmentation_required(retx, nof_bytes);
TESTASSERT_EQ(true, tx->is_retx_segmentation_required(retx, nof_bytes)); TESTASSERT_EQ(true, tx->is_retx_segmentation_required(retx, nof_bytes));

Loading…
Cancel
Save