mirror of https://github.com/PentHertz/srsLTE.git
lib,rlc_am_nr: added pollBYTE support and a unit test for it
This commit is contained in:
parent
eaa8fff6a0
commit
1d1e6dd832
|
@ -122,7 +122,7 @@ public:
|
|||
uint32_t build_status_pdu(byte_buffer_t* payload, uint32_t nof_bytes);
|
||||
|
||||
// Polling
|
||||
uint8_t get_pdu_poll(bool is_retx);
|
||||
uint8_t get_pdu_poll(bool is_retx, uint32_t sdu_bytes);
|
||||
|
||||
void stop() final;
|
||||
|
||||
|
|
|
@ -195,7 +195,7 @@ uint32_t rlc_am_nr_tx::build_new_pdu(uint8_t* payload, uint32_t nof_bytes)
|
|||
// Prepare header
|
||||
rlc_am_nr_pdu_header_t hdr = {};
|
||||
hdr.dc = RLC_DC_FIELD_DATA_PDU;
|
||||
hdr.p = get_pdu_poll(false);
|
||||
hdr.p = get_pdu_poll(false, tx_sdu->N_bytes);
|
||||
hdr.si = rlc_nr_si_field_t::full_sdu;
|
||||
hdr.sn_size = cfg.tx_sn_field_length;
|
||||
hdr.sn = st.tx_next;
|
||||
|
@ -249,10 +249,12 @@ uint32_t rlc_am_nr_tx::build_new_sdu_segment(rlc_amd_tx_pdu_nr& tx_pdu, uint8_t*
|
|||
return 0;
|
||||
}
|
||||
|
||||
uint32_t segment_payload_len = nof_bytes - min_hdr_size;
|
||||
|
||||
// Prepare header
|
||||
rlc_am_nr_pdu_header_t hdr = {};
|
||||
hdr.dc = RLC_DC_FIELD_DATA_PDU;
|
||||
hdr.p = get_pdu_poll(false);
|
||||
hdr.p = get_pdu_poll(false, segment_payload_len);
|
||||
hdr.si = rlc_nr_si_field_t::first_segment;
|
||||
hdr.sn_size = cfg.tx_sn_field_length;
|
||||
hdr.sn = st.tx_next;
|
||||
|
@ -268,7 +270,6 @@ uint32_t rlc_am_nr_tx::build_new_sdu_segment(rlc_amd_tx_pdu_nr& tx_pdu, uint8_t*
|
|||
}
|
||||
|
||||
// Copy PDU to payload
|
||||
uint32_t segment_payload_len = nof_bytes - hdr_len;
|
||||
srsran_assert((hdr_len + segment_payload_len) <= nof_bytes, "Error calculating hdr_len and segment_payload_len");
|
||||
memcpy(&payload[hdr_len], tx_pdu.sdu_buf->msg, segment_payload_len);
|
||||
|
||||
|
@ -354,7 +355,7 @@ uint32_t rlc_am_nr_tx::build_continuation_sdu_segment(rlc_amd_tx_pdu_nr& tx_pdu,
|
|||
// Prepare header
|
||||
rlc_am_nr_pdu_header_t hdr = {};
|
||||
hdr.dc = RLC_DC_FIELD_DATA_PDU;
|
||||
hdr.p = get_pdu_poll(false);
|
||||
hdr.p = get_pdu_poll(false, segment_payload_len);
|
||||
hdr.si = si;
|
||||
hdr.sn_size = cfg.tx_sn_field_length;
|
||||
hdr.sn = st.tx_next;
|
||||
|
@ -505,7 +506,7 @@ rlc_am_nr_tx::build_retx_pdu_without_segmentation(rlc_amd_retx_nr_t& retx, uint8
|
|||
current_so = retx.current_so;
|
||||
}
|
||||
rlc_am_nr_pdu_header_t new_header = tx_pdu.header;
|
||||
new_header.p = get_pdu_poll(true);
|
||||
new_header.p = get_pdu_poll(true, 0);
|
||||
new_header.si = si;
|
||||
new_header.so = current_so;
|
||||
uint32_t hdr_len = rlc_am_nr_write_data_pdu_header(new_header, payload);
|
||||
|
@ -598,7 +599,7 @@ uint32_t rlc_am_nr_tx::build_retx_pdu_with_segmentation(rlc_amd_retx_nr_t& retx,
|
|||
|
||||
// Write header
|
||||
rlc_am_nr_pdu_header_t hdr = tx_pdu.header;
|
||||
hdr.p = get_pdu_poll(true);
|
||||
hdr.p = get_pdu_poll(true, 0);
|
||||
hdr.so = retx.current_so;
|
||||
hdr.si = si;
|
||||
uint32_t hdr_len = rlc_am_nr_write_data_pdu_header(hdr, payload);
|
||||
|
@ -905,16 +906,25 @@ void rlc_am_nr_tx::get_buffer_state(uint32_t& n_bytes_new, uint32_t& n_bytes_pri
|
|||
* Check whether the polling bit needs to be set, as specified in
|
||||
* TS 38.322, section 5.3.3.2
|
||||
*/
|
||||
uint8_t rlc_am_nr_tx::get_pdu_poll(bool is_retx)
|
||||
uint8_t rlc_am_nr_tx::get_pdu_poll(bool is_retx, uint32_t sdu_bytes)
|
||||
{
|
||||
/* For each AMD PDU or AMD PDU segment that has not been previoulsy tranmitted:
|
||||
* - increment PDU_WITHOUT_POLL by one;
|
||||
* - increment BYTE_WITHOUT_POLL by every new byte of Data field element that it maps to the Data field of the AMD
|
||||
* PDU;
|
||||
* - if PDU_WITHOUT_POLL >= pollPDU; or
|
||||
* - if BYTE_WITHOUT_POLL >= pollByte:
|
||||
* - include a poll in the AMD PDU as described below.
|
||||
*/
|
||||
uint8_t poll = 0;
|
||||
if (!is_retx) {
|
||||
st.pdu_without_poll++;
|
||||
st.byte_without_poll += sdu_bytes;
|
||||
if (cfg.poll_pdu > 0) {
|
||||
if (st.pdu_without_poll >= (uint32_t)cfg.poll_pdu) {
|
||||
poll = 1;
|
||||
st.pdu_without_poll = 0;
|
||||
} else {
|
||||
st.pdu_without_poll++;
|
||||
if (st.pdu_without_poll >= (uint32_t)cfg.poll_pdu || st.byte_without_poll >= (uint32_t)cfg.poll_byte) {
|
||||
poll = 1;
|
||||
st.pdu_without_poll = 0;
|
||||
st.byte_without_poll = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -483,7 +483,7 @@ int basic_segmentation_test(rlc_am_nr_sn_size_t sn_size)
|
|||
// Push 1 SDU into RLC1
|
||||
unique_byte_buffer_t sdu;
|
||||
constexpr uint32_t payload_size = 3; // Give the SDU the size of 3 bytes
|
||||
sdu = srsran::make_byte_buffer();
|
||||
sdu = srsran::make_byte_buffer();
|
||||
TESTASSERT(nullptr != sdu);
|
||||
sdu->msg[0] = 0; // Write the index into the buffer
|
||||
sdu->N_bytes = payload_size; // Give the SDU the size of 3 bytes
|
||||
|
@ -532,7 +532,7 @@ int basic_segmentation_test(rlc_am_nr_sn_size_t sn_size)
|
|||
TESTASSERT_EQ(n_pdus, metrics2.num_rx_pdus); // 3 PDUs
|
||||
TESTASSERT_EQ(0, metrics2.num_tx_pdu_bytes);
|
||||
TESTASSERT_EQ(total_rx_pdu_bytes, metrics2.num_rx_pdu_bytes); // 1 PDU (No SO) + 2 PDUs (with SO)
|
||||
TESTASSERT_EQ(0, metrics2.num_lost_sdus); // No lost SDUs
|
||||
TESTASSERT_EQ(0, metrics2.num_lost_sdus); // No lost SDUs
|
||||
|
||||
// Check state
|
||||
rlc_am_nr_tx_state_t state1_tx = tx1->get_tx_state();
|
||||
|
@ -714,13 +714,13 @@ int segment_retx_test(rlc_am_nr_sn_size_t sn_size)
|
|||
TESTASSERT_EQ(15, metrics2.num_rx_sdu_bytes); // 5 SDUs, 3 bytes each
|
||||
TESTASSERT_EQ(0, metrics2.num_lost_sdus);
|
||||
// SDU metrics
|
||||
TESTASSERT_EQ(2, metrics2.num_tx_pdus); // Two status PDUs
|
||||
TESTASSERT_EQ(7, metrics2.num_rx_pdus); // 7 PDUs (8 tx'ed, but one was lost)
|
||||
TESTASSERT_EQ(2, metrics2.num_tx_pdus); // Two status PDUs
|
||||
TESTASSERT_EQ(7, metrics2.num_rx_pdus); // 7 PDUs (8 tx'ed, but one was lost)
|
||||
TESTASSERT_EQ(total_tx_pdu_bytes2, metrics2.num_tx_pdu_bytes);
|
||||
TESTASSERT_EQ(total_rx_pdu_bytes2,
|
||||
metrics2.num_rx_pdu_bytes); // 2 Bytes * (NBUFFS-1) (header size) + (NBUFFS-1) * 3 (data)
|
||||
// 3 (1 retx no SO) + 2 * 5 (2 retx with SO) = 33
|
||||
TESTASSERT_EQ(0, metrics2.num_lost_sdus); // No lost SDUs
|
||||
metrics2.num_rx_pdu_bytes); // 2 Bytes * (NBUFFS-1) (header size) + (NBUFFS-1) * 3 (data)
|
||||
// 3 (1 retx no SO) + 2 * 5 (2 retx with SO) = 33
|
||||
TESTASSERT_EQ(0, metrics2.num_lost_sdus); // No lost SDUs
|
||||
|
||||
// Check state
|
||||
rlc_am_nr_rx_state_t state2_rx = rx2->get_rx_state();
|
||||
|
@ -1114,9 +1114,9 @@ int discard_test(rlc_am_nr_sn_size_t sn_size)
|
|||
rlc_am_tester tester;
|
||||
timer_handler timers(8);
|
||||
|
||||
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);
|
||||
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("discard test (%d bit SN)", to_number(sn_size));
|
||||
|
||||
srslog::fetch_basic_logger("RLC_AM_1").set_hex_dump_max_size(100);
|
||||
|
@ -1211,6 +1211,111 @@ int discard_test(rlc_am_nr_sn_size_t sn_size)
|
|||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
// This test checks the correct functioning of RLC TX polling bit setting
|
||||
int poll_test_poll_pdu()
|
||||
{
|
||||
rlc_am_tester tester;
|
||||
timer_handler timers(8);
|
||||
|
||||
auto& test_logger = srslog::fetch_basic_logger("TESTER ");
|
||||
test_delimit_logger delimiter("poll test pollPDU");
|
||||
|
||||
srslog::fetch_basic_logger("RLC_AM_1").set_hex_dump_max_size(100);
|
||||
|
||||
rlc_config_t rlc_cnfg = {};
|
||||
rlc_cnfg.rat = srsran_rat_t::nr;
|
||||
rlc_cnfg.rlc_mode = rlc_mode_t::am;
|
||||
rlc_cnfg.am_nr.poll_pdu = 4;
|
||||
rlc_cnfg.am_nr.poll_byte = 3000;
|
||||
rlc_cnfg.am_nr.t_status_prohibit = 8;
|
||||
rlc_cnfg.am_nr.max_retx_thresh = 8;
|
||||
rlc_cnfg.am_nr.t_reassembly = 35;
|
||||
|
||||
// Test p bit set on new TX with PollPDU
|
||||
{
|
||||
rlc_am rlc1(srsran_rat_t::nr, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
|
||||
if (not rlc1.configure(rlc_cnfg)) {
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
// pollPDU == 4
|
||||
uint32_t num_tx_sdus = 6;
|
||||
for (uint32_t i = 0; i < num_tx_sdus; ++i) {
|
||||
// Write SDU
|
||||
unique_byte_buffer_t sdu = srsran::make_byte_buffer();
|
||||
TESTASSERT(sdu != nullptr);
|
||||
sdu->N_bytes = 1;
|
||||
sdu->md.pdcp_sn = i;
|
||||
rlc1.write_sdu(std::move(sdu));
|
||||
}
|
||||
uint32_t num_tx_pdus = 6;
|
||||
for (uint32_t i = 0; i < num_tx_pdus; ++i) {
|
||||
unique_byte_buffer_t pdu = srsran::make_byte_buffer();
|
||||
TESTASSERT(pdu != nullptr);
|
||||
pdu->N_bytes = rlc1.read_pdu(pdu->msg, 3);
|
||||
rlc_am_nr_pdu_header_t hdr;
|
||||
rlc_am_nr_read_data_pdu_header(pdu.get(), rlc_am_nr_sn_size_t::size18bits, &hdr);
|
||||
if (i != 3 && i != 5) { // P bit set for PollPDU and for empty TX queue
|
||||
TESTASSERT_EQ(0, hdr.p);
|
||||
} else {
|
||||
TESTASSERT_EQ(1, hdr.p);
|
||||
}
|
||||
}
|
||||
}
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
// Test p bit set on new TX with PollBYTE
|
||||
int poll_test_poll_byte()
|
||||
{
|
||||
rlc_am_tester tester;
|
||||
timer_handler timers(8);
|
||||
|
||||
auto& test_logger = srslog::fetch_basic_logger("TESTER ");
|
||||
test_delimit_logger delimiter("poll test pollBYTE");
|
||||
|
||||
srslog::fetch_basic_logger("RLC_AM_1").set_hex_dump_max_size(100);
|
||||
|
||||
rlc_config_t rlc_cnfg = {};
|
||||
rlc_cnfg.rat = srsran_rat_t::nr;
|
||||
rlc_cnfg.rlc_mode = rlc_mode_t::am;
|
||||
rlc_cnfg.am_nr.poll_pdu = 4;
|
||||
rlc_cnfg.am_nr.poll_byte = 3000;
|
||||
rlc_cnfg.am_nr.t_status_prohibit = 8;
|
||||
rlc_cnfg.am_nr.max_retx_thresh = 8;
|
||||
rlc_cnfg.am_nr.t_reassembly = 35;
|
||||
|
||||
rlc_am rlc1(srsran_rat_t::nr, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
|
||||
if (not rlc1.configure(rlc_cnfg)) {
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
// pollByte == 3000
|
||||
uint32_t num_tx_sdus = 4;
|
||||
for (uint32_t i = 0; i < num_tx_sdus; ++i) {
|
||||
// Write SDU
|
||||
unique_byte_buffer_t sdu = srsran::make_byte_buffer();
|
||||
TESTASSERT(sdu != nullptr);
|
||||
sdu->N_bytes = i == 0 ? 2999 : 1;
|
||||
sdu->md.pdcp_sn = i;
|
||||
rlc1.write_sdu(std::move(sdu));
|
||||
}
|
||||
uint32_t num_tx_pdus = num_tx_sdus;
|
||||
for (uint32_t i = 0; i < num_tx_pdus; ++i) {
|
||||
unique_byte_buffer_t pdu = srsran::make_byte_buffer();
|
||||
TESTASSERT(pdu != nullptr);
|
||||
uint32_t nof_bytes = i == 0 ? 3001 : 3;
|
||||
pdu->N_bytes = rlc1.read_pdu(pdu->msg, nof_bytes);
|
||||
TESTASSERT_EQ(nof_bytes, pdu->N_bytes);
|
||||
rlc_am_nr_pdu_header_t hdr;
|
||||
rlc_am_nr_read_data_pdu_header(pdu.get(), rlc_am_nr_sn_size_t::size18bits, &hdr);
|
||||
if (i != 1 && i != 3) {
|
||||
TESTASSERT_EQ(0, hdr.p);
|
||||
} else {
|
||||
TESTASSERT_EQ(1, hdr.p);
|
||||
}
|
||||
}
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
// Setup the log message spy to intercept error and warning log entries from RLC
|
||||
|
@ -1250,5 +1355,12 @@ int main()
|
|||
TESTASSERT(max_retx_lost_sdu_test(sns) == SRSRAN_SUCCESS); // Fixme
|
||||
TESTASSERT(max_retx_lost_segments_test(sns) == SRSRAN_SUCCESS); // Fixme
|
||||
TESTASSERT(discard_test(sns) == SRSRAN_SUCCESS); // Fixme
|
||||
TESTASSERT(poll_test_poll_pdu() == SRSRAN_SUCCESS);
|
||||
TESTASSERT(poll_test_poll_byte() == SRSRAN_SUCCESS);
|
||||
// Test p bit *not* set on RETX with PollPDU
|
||||
// Test p bit *not* set on RETX with PollBYTE
|
||||
// Test p bit set on empty TX queue and empty retx queue
|
||||
// Test p bit *not* set on empty TX queue and empty retx queue
|
||||
// Test p bit set on window stall
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue