mirror of https://github.com/PentHertz/srsLTE.git
lib,rlc_am_nr: starting to add test for segmentation. Starting to add functions for creating new segments and segment continuation.
This commit is contained in:
parent
f544cc7f7e
commit
76c33c78a9
|
@ -90,10 +90,22 @@ public:
|
|||
|
||||
// Data PDU helpers
|
||||
using rlc_amd_tx_pdu_nr = rlc_amd_tx_pdu<rlc_am_nr_pdu_header_t>;
|
||||
/*
|
||||
struct rlc_amd_tx_pdu_nr {
|
||||
const uint32_t rlc_sn = INVALID_RLC_SN;
|
||||
const uint32_t pdcp_sn = INVALID_RLC_SN;
|
||||
struct tx_pdu_segment {
|
||||
rlc_am_nr_pdu_header_t header = {};
|
||||
uint32_t retx_count = 0;
|
||||
uint32_t so = 0;
|
||||
uint32_t len = 0;
|
||||
};
|
||||
};*/
|
||||
int build_new_sdu_segment(const unique_byte_buffer_t& tx_sdu,
|
||||
rlc_amd_tx_pdu_nr& tx_pdu,
|
||||
uint8_t* payload,
|
||||
uint32_t nof_bytes);
|
||||
int build_continuation_sdu_segment(rlc_amd_tx_pdu_nr& tx_pdu, uint8_t* payload, uint32_t nof_bytes);
|
||||
int build_retx_pdu(unique_byte_buffer_t& tx_pdu, uint32_t nof_bytes);
|
||||
|
||||
// Buffer State
|
||||
|
@ -131,7 +143,10 @@ private:
|
|||
***************************************************************************/
|
||||
struct rlc_am_nr_tx_state_t st = {};
|
||||
rlc_ringbuffer_t<rlc_amd_tx_pdu_nr, RLC_AM_WINDOW_SIZE> tx_window;
|
||||
pdu_retx_queue<RLC_AM_WINDOW_SIZE> retx_queue;
|
||||
|
||||
// Queues and buffers
|
||||
pdu_retx_queue<RLC_AM_WINDOW_SIZE> retx_queue;
|
||||
rlc_amd_tx_sdu_nr_t current_sdu; // Currently SDU beind segmented
|
||||
|
||||
public:
|
||||
// Getters/Setters
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
|
||||
namespace srsran {
|
||||
|
||||
const uint32_t INVALID_RLC_SN = 0xFFFFFFFF;
|
||||
|
||||
///< AM NR PDU header
|
||||
struct rlc_am_nr_pdu_header_t {
|
||||
rlc_am_nr_pdu_header_t() = default;
|
||||
|
@ -60,6 +62,14 @@ struct rlc_amd_rx_sdu_nr_t {
|
|||
explicit rlc_amd_rx_sdu_nr_t(uint32_t rlc_sn_) : rlc_sn(rlc_sn_) {}
|
||||
};
|
||||
|
||||
struct rlc_amd_tx_sdu_nr_t {
|
||||
uint32_t rlc_sn = INVALID_RLC_SN;
|
||||
unique_byte_buffer_t buf;
|
||||
|
||||
rlc_amd_tx_sdu_nr_t() = default;
|
||||
explicit rlc_amd_tx_sdu_nr_t(uint32_t rlc_sn_) : rlc_sn(rlc_sn_) {}
|
||||
};
|
||||
|
||||
///< AM NR Status PDU header (perhaps merge with LTE version)
|
||||
typedef struct {
|
||||
rlc_am_nr_control_pdu_type_t cpt;
|
||||
|
|
|
@ -87,9 +87,6 @@ uint32_t rlc_am_nr_tx::read_pdu(uint8_t* payload, uint32_t nof_bytes)
|
|||
return tx_pdu->N_bytes;
|
||||
}
|
||||
|
||||
// Section 5.2.2.3 in TS 36.311, if tx_window is full and retx_queue empty, retransmit PDU
|
||||
// TODO
|
||||
|
||||
// RETX if required
|
||||
if (not retx_queue.empty()) {
|
||||
logger->info("Retx required. Retx queue size: %d", retx_queue.size());
|
||||
|
@ -105,6 +102,17 @@ uint32_t rlc_am_nr_tx::read_pdu(uint8_t* payload, uint32_t nof_bytes)
|
|||
}
|
||||
}
|
||||
|
||||
// Send remaining segment, if it exists
|
||||
if (current_sdu.rlc_sn != INVALID_RLC_SN) {
|
||||
if (not tx_window.has_sn(current_sdu.rlc_sn)) {
|
||||
current_sdu.rlc_sn = INVALID_RLC_SN;
|
||||
logger->error("SDU currently being segmented does not exist in tx_window. Aborting segmenttion SN=%d",
|
||||
current_sdu.rlc_sn);
|
||||
return 0;
|
||||
}
|
||||
return build_continuation_sdu_segment(tx_window[current_sdu.rlc_sn], payload, nof_bytes);
|
||||
}
|
||||
|
||||
// Check wether there is something to TX
|
||||
if (tx_sdu_queue.is_empty()) {
|
||||
logger->info("No data available to be sent");
|
||||
|
@ -138,10 +146,7 @@ uint32_t rlc_am_nr_tx::read_pdu(uint8_t* payload, uint32_t nof_bytes)
|
|||
uint16_t hdr_size = 2;
|
||||
if (tx_sdu->N_bytes + hdr_size > nof_bytes) {
|
||||
logger->info("Trying to build PDU segment from SDU.");
|
||||
if (build_new_sdu_segment(tx_sdu, tx_pdu, payload, nof_bytes) != SRSRAN_SUCCESS) {
|
||||
return 0;
|
||||
}
|
||||
return tx_pdu.buf->N_bytes;
|
||||
return build_new_sdu_segment(tx_sdu, tx_pdu, payload, nof_bytes);
|
||||
}
|
||||
|
||||
memcpy(tx_pdu.buf->msg, tx_sdu->msg, tx_sdu->N_bytes);
|
||||
|
@ -177,16 +182,23 @@ int rlc_am_nr_tx::build_new_sdu_segment(const unique_byte_buffer_t& tx_sdu,
|
|||
uint8_t* payload,
|
||||
uint32_t nof_bytes)
|
||||
{
|
||||
logger->info("Creating new SDU segment. Tx SDU (%d B),,nof_bytes=%d B ", tx_sdu->N_bytes, nof_bytes);
|
||||
|
||||
// Sanity check: can this SDU be sent this in a single PDU?
|
||||
if (tx_sdu->N_bytes + 2 >= nof_bytes) {
|
||||
logger->error("Calling build_new_sdu_segment(), but there are enough bytes to tx in a single PDU.");
|
||||
return SRSRAN_ERROR;
|
||||
if ((tx_sdu->N_bytes + 2) < nof_bytes) {
|
||||
logger->error("Calling build_new_sdu_segment(), but there are enough bytes to tx in a single PDU. Tx SDU (%d B), "
|
||||
"nof_bytes=%d B ",
|
||||
tx_sdu->N_bytes,
|
||||
nof_bytes);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Sanity check: can this SDU be sent considering header overhead?
|
||||
if (1 + 2 >= nof_bytes) { // Only two bytes, as SO is 0
|
||||
logger->error("Cannot build new sdu_segment, but there are not enough bytes to tx header plus data.");
|
||||
return SRSRAN_ERROR;
|
||||
if (3 < nof_bytes) { // Only two bytes of header, as SO is 0
|
||||
logger->error(
|
||||
"Cannot build new sdu_segment, there are not enough bytes allocated to tx header plus data. nof_bytes=%d",
|
||||
nof_bytes);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Prepare header
|
||||
|
@ -201,12 +213,29 @@ int rlc_am_nr_tx::build_new_sdu_segment(const unique_byte_buffer_t& tx_sdu,
|
|||
log_rlc_am_nr_pdu_header_to_string(logger->info, hdr);
|
||||
|
||||
// Write header
|
||||
uint32_t len = rlc_am_nr_write_data_pdu_header(hdr, payload);
|
||||
if (len > nof_bytes) {
|
||||
uint32_t hdr_len = rlc_am_nr_write_data_pdu_header(hdr, payload);
|
||||
if (hdr_len > nof_bytes) {
|
||||
logger->error("Error writing AMD PDU header");
|
||||
}
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
uint32_t segment_payload_len = nof_bytes - hdr_len;
|
||||
memcpy(&payload[hdr_len], tx_pdu.buf->msg, segment_payload_len);
|
||||
return hdr_len + segment_payload_len;
|
||||
}
|
||||
|
||||
int rlc_am_nr_tx::build_continuation_sdu_segment(rlc_amd_tx_pdu_nr& tx_pdu, uint8_t* payload, uint32_t nof_bytes)
|
||||
{
|
||||
logger->info("Continuing SDU segment. SN=%d, Tx SDU (%d B), nof_bytes=%d B ",
|
||||
current_sdu.rlc_sn,
|
||||
current_sdu.buf->N_bytes,
|
||||
nof_bytes);
|
||||
|
||||
// Can the rest of the SDU be sent on a single segment PDU?
|
||||
|
||||
// Sanity check: can this SDU be sent considering header overhead?
|
||||
|
||||
// Prepare header
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rlc_am_nr_tx::build_retx_pdu(unique_byte_buffer_t& tx_pdu, uint32_t nof_bytes)
|
||||
|
|
|
@ -220,12 +220,10 @@ int lost_pdu_test()
|
|||
timer_handler timers(8);
|
||||
byte_buffer_t pdu_bufs[NBUFS];
|
||||
|
||||
auto& test_logger = srslog::fetch_basic_logger("TESTER ");
|
||||
test_logger.info("=======================");
|
||||
test_logger.info("==== Lost PDU Test ====");
|
||||
test_logger.info("=======================");
|
||||
rlc_am rlc1(srsran_rat_t::nr, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
|
||||
rlc_am rlc2(srsran_rat_t::nr, srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers);
|
||||
auto& test_logger = srslog::fetch_basic_logger("TESTER ");
|
||||
rlc_am rlc1(srsran_rat_t::nr, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
|
||||
rlc_am rlc2(srsran_rat_t::nr, srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers);
|
||||
test_delimit_logger delimiter("lost PDU");
|
||||
|
||||
// before configuring entity
|
||||
TESTASSERT(0 == rlc1.get_buffer_state());
|
||||
|
@ -340,15 +338,13 @@ int lost_pdu_test()
|
|||
}
|
||||
|
||||
/*
|
||||
* Test the loss of a single PDU.
|
||||
* NACK should be visible in the status report.
|
||||
* Retx after NACK should be present too.
|
||||
* Test the basic segmentation of a single SDU.
|
||||
* A single SDU of 3 bytes is segmented into 3 PDUs
|
||||
*/
|
||||
int basic_segmentation_test()
|
||||
{
|
||||
rlc_am_tester tester;
|
||||
timer_handler timers(8);
|
||||
byte_buffer_t pdu_bufs[NBUFS];
|
||||
auto& test_logger = srslog::fetch_basic_logger("TESTER ");
|
||||
test_delimit_logger delimiter("basic segmentation");
|
||||
rlc_am rlc1(srsran_rat_t::nr, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
|
||||
|
@ -365,14 +361,29 @@ int basic_segmentation_test()
|
|||
return -1;
|
||||
}
|
||||
|
||||
basic_test_tx(&rlc1, pdu_bufs);
|
||||
// Push 1 SDU into RLC1
|
||||
unique_byte_buffer_t sdu;
|
||||
sdu = srsran::make_byte_buffer();
|
||||
TESTASSERT(nullptr != sdu);
|
||||
sdu->msg[0] = 0; // Write the index into the buffer
|
||||
sdu->N_bytes = 3; // Give the SDU the size of 3 bytes
|
||||
sdu->md.pdcp_sn = 0; // PDCP SN for notifications
|
||||
rlc1.write_sdu(std::move(sdu));
|
||||
|
||||
// Write 5 PDUs into RLC2
|
||||
for (int i = 0; i < NBUFS; i++) {
|
||||
if (i != 3) {
|
||||
rlc2.write_pdu(pdu_bufs[i].msg, pdu_bufs[i].N_bytes); // Don't write RLC_SN=3.
|
||||
// Read 3 PDUs
|
||||
unique_byte_buffer_t pdu_bufs[3];
|
||||
for (int i = 0; i < 3; i++) {
|
||||
pdu_bufs[i] = srsran::make_byte_buffer();
|
||||
TESTASSERT(nullptr != pdu_bufs[i]);
|
||||
if (i == 0) {
|
||||
pdu_bufs[i]->N_bytes = rlc1.read_pdu(pdu_bufs[i]->msg, 3);
|
||||
TESTASSERT_EQ(3, pdu_bufs[i]->N_bytes);
|
||||
} else {
|
||||
pdu_bufs[i]->N_bytes = rlc1.read_pdu(pdu_bufs[i]->msg, 5);
|
||||
TESTASSERT_EQ(5, pdu_bufs[i]->N_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -404,6 +415,7 @@ int main(int argc, char** argv)
|
|||
TESTASSERT(window_checker_test() == SRSRAN_SUCCESS);
|
||||
TESTASSERT(basic_test() == SRSRAN_SUCCESS);
|
||||
TESTASSERT(lost_pdu_test() == SRSRAN_SUCCESS);
|
||||
TESTASSERT(basic_segmentation_test() == SRSRAN_SUCCESS);
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue