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;
};
struct rlc_amd_retx_t {
struct rlc_amd_retx_lte_t {
uint32_t sn;
bool is_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;
};
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
{
public:
rlc_amd_retx_t& push()
T& push()
{
assert(not full());
rlc_amd_retx_t& p = buffer[wpos];
T& p = buffer[wpos];
wpos = (wpos + 1) % WINDOW_SIZE;
return p;
}
void pop() { rpos = (rpos + 1) % WINDOW_SIZE; }
rlc_amd_retx_t& front()
T& front()
{
assert(not empty());
return buffer[rpos];
@ -349,9 +357,9 @@ public:
bool full() const { return size() == WINDOW_SIZE - 1; }
private:
std::array<rlc_amd_retx_t, WINDOW_SIZE> buffer;
size_t wpos = 0;
size_t rpos = 0;
std::array<T, WINDOW_SIZE> buffer;
size_t wpos = 0;
size_t rpos = 0;
};
} // namespace srsran

@ -79,11 +79,11 @@ private:
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_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);
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);
// Helpers
@ -137,7 +137,7 @@ private:
// Tx windows
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;
// 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_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_valid_status_pdu(const rlc_status_pdu_t& status, uint32_t rx_win_min = 0);
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_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_without_segmentation(rlc_amd_retx_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);
bool is_retx_segmentation_required(const rlc_amd_retx_t& retx, uint32_t nof_bytes);
uint32_t get_retx_expected_hdr_len(const rlc_amd_retx_t& retx);
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_nr_t& retx, uint8_t* payload, 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_nr_t& retx);
// Buffer State
bool has_data() final;
@ -150,7 +150,7 @@ private:
rlc_ringbuffer_t<rlc_amd_tx_pdu_nr, RLC_AM_WINDOW_SIZE> tx_window;
// 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.
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
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",
retx.sn,
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);
rlc_amd_retx_t& retx = retx_queue.push();
retx.is_segment = false;
retx.so_start = 0;
retx.so_end = pdu.buf->N_bytes;
retx.sn = pdu.rlc_sn;
rlc_amd_retx_lte_t& retx = retx_queue.push();
retx.is_segment = false;
retx.so_start = 0;
retx.so_end = pdu.buf->N_bytes;
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;
}
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
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;
}
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) {
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++;
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);
retx.sn = i;
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);
}
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 (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;
}
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
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
* 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(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.
* \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
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;
}
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;
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;
}
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;
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++) {
if (segm->so >= nack.so_start && segm->so <= nack.so_end) {
// TODO: Check if this segment is not already queued for retransmission
rlc_amd_retx_t& retx = retx_queue.push();
retx.sn = nack_sn;
retx.is_segment = true;
retx.so_start = segm->so;
retx.current_so = segm->so;
retx.so_end = segm->so + segm->payload_len;
rlc_amd_retx_nr_t& retx = retx_queue.push();
retx.sn = nack_sn;
retx.is_segment = true;
retx.so_start = segm->so;
retx.current_so = segm->so;
retx.so_end = segm->so + segm->payload_len;
retx_sn_set.insert(nack_sn);
RlcInfo(
"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.
// add to retx queue if it's not already there
if (not retx_queue.has_sn(nack_sn)) {
rlc_amd_retx_t& retx = retx_queue.push();
retx.sn = nack_sn;
retx.is_segment = false;
retx.so_start = 0;
retx.current_so = 0;
retx.so_end = pdu.sdu_buf->N_bytes;
rlc_amd_retx_nr_t& retx = retx_queue.push();
retx.sn = nack_sn;
retx.is_segment = false;
retx.so_start = 0;
retx.current_so = 0;
retx.so_end = pdu.sdu_buf->N_bytes;
retx_sn_set.insert(nack_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
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",
retx.sn,
retx.is_segment ? "true" : "false",

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

Loading…
Cancel
Save