mirror of https://github.com/PentHertz/srsLTE.git
Changed generation of status report to use rx_counts instead of
undeliverd_sdus_queue. Added a queue to store information about rx_counts received. Added unit test for when the SNs wrap-around in status report genaration
This commit is contained in:
parent
6159cb3817
commit
3f79cd6281
|
@ -21,6 +21,8 @@
|
|||
#include "srslte/interfaces/ue_rrc_interfaces.h"
|
||||
#include "srslte/upper/pdcp_entity_base.h"
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace srsue {
|
||||
|
||||
class gw_interface_pdcp;
|
||||
|
@ -165,9 +167,30 @@ private:
|
|||
// Discard callback (discardTimer)
|
||||
class discard_callback;
|
||||
|
||||
// TX Queue
|
||||
// Tx info queue
|
||||
uint32_t maximum_allocated_sns_window = 2048;
|
||||
std::unique_ptr<undelivered_sdus_queue> undelivered_sdus;
|
||||
|
||||
// Rx info queue
|
||||
uint32_t fmc = 0;
|
||||
std::set<uint32_t> rx_counts_info; // Keeps the RX_COUNT for generation of the stauts report
|
||||
void update_rx_counts_queue(uint32_t rx_count);
|
||||
|
||||
/*
|
||||
* Helper function to see if an SN is larger
|
||||
*/
|
||||
bool is_sn_larger(uint32_t sn1, uint32_t sn2)
|
||||
{
|
||||
int32_t diff = sn2 - sn1;
|
||||
uint32_t nof_sns = 1u << cfg.sn_len;
|
||||
if (diff > (int32_t)(nof_sns / 2)) {
|
||||
return false;
|
||||
}
|
||||
if (diff <= 0 && diff > -((int32_t)(nof_sns / 2))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// Discard callback (discardTimer)
|
||||
|
|
|
@ -404,10 +404,27 @@ void pdcp_entity_lte::handle_am_drb_pdu(srslte::unique_byte_buffer_t pdu)
|
|||
// Update info on last PDU submitted to upper layers
|
||||
st.last_submitted_pdcp_rx_sn = sn;
|
||||
|
||||
// Store Rx SN/COUNT
|
||||
update_rx_counts_queue(count);
|
||||
|
||||
// Pass to upper layers
|
||||
gw->write_pdu(lcid, std::move(pdu));
|
||||
}
|
||||
|
||||
void pdcp_entity_lte::update_rx_counts_queue(uint32_t rx_count)
|
||||
{
|
||||
// The received COUNT is the first missing COUNT
|
||||
if (rx_count == fmc) {
|
||||
fmc++;
|
||||
// Update the queue for the Status report bitmap, if NEXT_PDCP_RX_SN changed
|
||||
while (not rx_counts_info.empty() && *rx_counts_info.begin() == fmc) {
|
||||
rx_counts_info.erase(fmc);
|
||||
fmc++;
|
||||
}
|
||||
} else {
|
||||
rx_counts_info.insert(rx_count);
|
||||
}
|
||||
}
|
||||
/****************************************************************************
|
||||
* Control handler functions (Status Report)
|
||||
* Ref: 3GPP TS 36.323 v10.1.0 Section 5.1.3
|
||||
|
@ -434,15 +451,10 @@ void pdcp_entity_lte::send_status_report()
|
|||
}
|
||||
|
||||
// Get First Missing Segment (FMS)
|
||||
uint32_t fms = 0;
|
||||
if (undelivered_sdus->empty()) {
|
||||
fms = st.next_pdcp_tx_sn;
|
||||
} else {
|
||||
fms = undelivered_sdus->get_fms();
|
||||
}
|
||||
uint32_t fms = SN(fmc);
|
||||
|
||||
// Get Last Missing Segment
|
||||
uint32_t lms = undelivered_sdus->get_lms();
|
||||
uint32_t nof_sns_in_bitmap = rx_counts_info.size();
|
||||
|
||||
// Allocate Status Report PDU
|
||||
unique_byte_buffer_t pdu = make_byte_buffer();
|
||||
|
@ -451,7 +463,7 @@ void pdcp_entity_lte::send_status_report()
|
|||
return;
|
||||
}
|
||||
|
||||
logger.debug("Status report: FMS=%d, LMS=%d", fms, lms);
|
||||
logger.debug("Status report: FMS=%d, Nof SNs in bitmap=%d", fms, nof_sns_in_bitmap);
|
||||
// Set control bit and type of PDU
|
||||
pdu->msg[0] = ((uint8_t)PDCP_DC_FIELD_CONTROL_PDU << 7) | ((uint8_t)PDCP_PDU_TYPE_STATUS_REPORT << 4);
|
||||
|
||||
|
@ -474,8 +486,9 @@ void pdcp_entity_lte::send_status_report()
|
|||
}
|
||||
|
||||
// Add bitmap of missing PDUs, if necessary
|
||||
if (not undelivered_sdus->empty()) {
|
||||
if (not rx_counts_info.empty()) {
|
||||
// First check size of bitmap
|
||||
uint32_t lms = *rx_counts_info.rbegin();
|
||||
int32_t diff = lms - (fms - 1);
|
||||
uint32_t nof_sns = 1u << cfg.sn_len;
|
||||
if (diff > (int32_t)(nof_sns / 2)) {
|
||||
|
@ -494,14 +507,13 @@ void pdcp_entity_lte::send_status_report()
|
|||
lms,
|
||||
fms - 1,
|
||||
bitmap_sz);
|
||||
for (uint32_t offset = 0; offset < sn_diff; ++offset) {
|
||||
uint32_t sn = (fms + 1 + offset) % (1u << cfg.sn_len);
|
||||
if (undelivered_sdus->has_sdu(sn)) {
|
||||
for (uint32_t rx_count : rx_counts_info) {
|
||||
logger.debug("Setting bitmap for RX_COUNT=%d", rx_count);
|
||||
uint32_t offset = rx_count - (fmc + 1);
|
||||
uint32_t bit_offset = offset % 8;
|
||||
uint32_t byte_offset = offset / 8;
|
||||
pdu->msg[pdu->N_bytes + byte_offset] |= 1 << (7 - bit_offset);
|
||||
}
|
||||
}
|
||||
pdu->N_bytes += bitmap_sz;
|
||||
}
|
||||
pdu->md.pdcp_sn = -1;
|
||||
|
@ -575,6 +587,7 @@ void pdcp_entity_lte::handle_status_report_pdu(unique_byte_buffer_t pdu)
|
|||
undelivered_sdus->clear_sdu(sn);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* TX PDUs Queue Helper
|
||||
***************************************************************************/
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
*/
|
||||
int test_tx_status_report(const srslte::pdcp_lte_state_t& init_state, srslog::basic_logger& logger)
|
||||
{
|
||||
srslte::pdcp_config_t cfg = {1,
|
||||
srslte::pdcp_config_t cfg_tx = {1,
|
||||
srslte::PDCP_RB_IS_DRB,
|
||||
srslte::SECURITY_DIRECTION_UPLINK,
|
||||
srslte::SECURITY_DIRECTION_DOWNLINK,
|
||||
|
@ -26,31 +26,52 @@ int test_tx_status_report(const srslte::pdcp_lte_state_t& init_state, srslog::ba
|
|||
srslte::pdcp_discard_timer_t::ms500,
|
||||
true};
|
||||
|
||||
pdcp_lte_test_helper pdcp_hlp(cfg, sec_cfg, logger);
|
||||
srslte::pdcp_entity_lte* pdcp = &pdcp_hlp.pdcp;
|
||||
rlc_dummy* rlc = &pdcp_hlp.rlc;
|
||||
srsue::stack_test_dummy* stack = &pdcp_hlp.stack;
|
||||
srslte::pdcp_config_t cfg_rx = {1,
|
||||
srslte::PDCP_RB_IS_DRB,
|
||||
srslte::SECURITY_DIRECTION_DOWNLINK,
|
||||
srslte::SECURITY_DIRECTION_UPLINK,
|
||||
srslte::PDCP_SN_LEN_12,
|
||||
srslte::pdcp_t_reordering_t::ms500,
|
||||
srslte::pdcp_discard_timer_t::ms500,
|
||||
true};
|
||||
|
||||
pdcp_hlp.set_pdcp_initial_state(init_state);
|
||||
// Setup TX
|
||||
pdcp_lte_test_helper pdcp_hlp_tx(cfg_tx, sec_cfg, logger);
|
||||
srslte::pdcp_entity_lte* pdcp_tx = &pdcp_hlp_tx.pdcp;
|
||||
rlc_dummy* rlc_tx = &pdcp_hlp_tx.rlc;
|
||||
srsue::stack_test_dummy* stack_tx = &pdcp_hlp_tx.stack;
|
||||
pdcp_hlp_tx.set_pdcp_initial_state(init_state);
|
||||
|
||||
// Setup RX
|
||||
pdcp_lte_test_helper pdcp_hlp_rx(cfg_tx, sec_cfg, logger);
|
||||
srslte::pdcp_entity_lte* pdcp_rx = &pdcp_hlp_tx.pdcp;
|
||||
rlc_dummy* rlc_rx = &pdcp_hlp_tx.rlc;
|
||||
srsue::stack_test_dummy* stack_rx = &pdcp_hlp_tx.stack;
|
||||
pdcp_hlp_rx.set_pdcp_initial_state(init_state);
|
||||
|
||||
// Tmp variable to hold the PDCP PDU
|
||||
srslte::unique_byte_buffer_t out_pdu = srslte::make_byte_buffer();
|
||||
|
||||
// Write 256 SDUs and notify imediatly -> FMS 0001 0000 0001
|
||||
for (uint32_t i = 0; i < 257; i++) {
|
||||
srslte::unique_byte_buffer_t sdu = srslte::make_byte_buffer();
|
||||
srslte::unique_byte_buffer_t pdu = srslte::make_byte_buffer();
|
||||
sdu->append_bytes(sdu1, sizeof(sdu1));
|
||||
pdcp->write_sdu(std::move(sdu));
|
||||
pdcp->notify_delivery({i});
|
||||
pdcp_tx->write_sdu(std::move(sdu));
|
||||
pdcp_tx->notify_delivery({i});
|
||||
rlc_tx->get_last_sdu(pdu);
|
||||
pdcp_rx->write_pdu(std::move(pdu));
|
||||
}
|
||||
|
||||
// Check undelivered SDUs queue size
|
||||
TESTASSERT(pdcp->nof_discard_timers() == 0); // 0 timers should be running
|
||||
TESTASSERT(pdcp_tx->nof_discard_timers() == 0); // 0 timers should be running on TX
|
||||
|
||||
// Generate the status report
|
||||
pdcp->send_status_report();
|
||||
rlc->get_last_sdu(out_pdu);
|
||||
pdcp_rx->send_status_report();
|
||||
rlc_rx->get_last_sdu(out_pdu);
|
||||
logger.debug(out_pdu->msg, out_pdu->N_bytes, "Status PDU:");
|
||||
|
||||
// Check status PDU
|
||||
// Check status PDU. We received up to
|
||||
/*
|
||||
* | D/C | TYPE | FMS | -> | 0 | 0 | 0001 |
|
||||
* | FMS | -> | 00000001 |
|
||||
|
@ -62,33 +83,36 @@ int test_tx_status_report(const srslte::pdcp_lte_state_t& init_state, srslog::ba
|
|||
// Write another 16 SDUs but don't notify SN=257, SN=258, SN=271 and SN=272
|
||||
for (uint32_t i = 257; i < 273; i++) {
|
||||
srslte::unique_byte_buffer_t sdu = srslte::make_byte_buffer();
|
||||
srslte::unique_byte_buffer_t pdu = srslte::make_byte_buffer();
|
||||
sdu->append_bytes(sdu1, sizeof(sdu1));
|
||||
pdcp->write_sdu(std::move(sdu));
|
||||
pdcp_tx->write_sdu(std::move(sdu));
|
||||
if (i != 257 && i != 258 && i != 271 && i != 272) {
|
||||
pdcp->notify_delivery({i});
|
||||
pdcp_tx->notify_delivery({i});
|
||||
rlc_tx->get_last_sdu(pdu);
|
||||
pdcp_rx->write_pdu(std::move(pdu));
|
||||
}
|
||||
}
|
||||
|
||||
// Check undelivered SDUs queue size
|
||||
TESTASSERT(pdcp->nof_discard_timers() == 4);
|
||||
TESTASSERT(pdcp_tx->nof_discard_timers() == 4);
|
||||
|
||||
// Generate the status report
|
||||
pdcp->send_status_report();
|
||||
rlc->get_last_sdu(out_pdu);
|
||||
pdcp_tx->send_status_report();
|
||||
rlc_tx->get_last_sdu(out_pdu);
|
||||
logger.debug(out_pdu->msg, out_pdu->N_bytes, "Status PDU:");
|
||||
|
||||
// Check status PDU
|
||||
/*
|
||||
* | D/C | TYPE | FMS | -> | 0 | 0 | 0001 |
|
||||
* | FMS | -> | 00000001 |
|
||||
* | bitmap | -> | 11000000 |
|
||||
* | bitmap | -> | 01111111 |
|
||||
* | bitmap (cont.) | -> | 00000011 |
|
||||
*/
|
||||
TESTASSERT(out_pdu->N_bytes == 4);
|
||||
TESTASSERT(out_pdu->msg[0] == 0b00000001);
|
||||
TESTASSERT(out_pdu->msg[0] == 0b00000001); // FMS = 257
|
||||
TESTASSERT(out_pdu->msg[1] == 0b00000001);
|
||||
TESTASSERT(out_pdu->msg[2] == 0b10000000);
|
||||
TESTASSERT(out_pdu->msg[3] == 0b00000110);
|
||||
TESTASSERT(out_pdu->msg[2] == 0b01111111); // FMS + 1 is missing
|
||||
TESTASSERT(out_pdu->msg[3] == 0b11111000); //
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -97,7 +121,7 @@ int test_tx_status_report(const srslte::pdcp_lte_state_t& init_state, srslog::ba
|
|||
*/
|
||||
int test_tx_wraparound_status_report(const srslte::pdcp_lte_state_t& init_state, srslog::basic_logger& logger)
|
||||
{
|
||||
srslte::pdcp_config_t cfg = {1,
|
||||
srslte::pdcp_config_t cfg_tx = {1,
|
||||
srslte::PDCP_RB_IS_DRB,
|
||||
srslte::SECURITY_DIRECTION_UPLINK,
|
||||
srslte::SECURITY_DIRECTION_DOWNLINK,
|
||||
|
@ -106,28 +130,48 @@ int test_tx_wraparound_status_report(const srslte::pdcp_lte_state_t& init_state,
|
|||
srslte::pdcp_discard_timer_t::ms500,
|
||||
true};
|
||||
|
||||
pdcp_lte_test_helper pdcp_hlp(cfg, sec_cfg, logger);
|
||||
srslte::pdcp_entity_lte* pdcp = &pdcp_hlp.pdcp;
|
||||
rlc_dummy* rlc = &pdcp_hlp.rlc;
|
||||
srsue::stack_test_dummy* stack = &pdcp_hlp.stack;
|
||||
srslte::pdcp_config_t cfg_rx = {1,
|
||||
srslte::PDCP_RB_IS_DRB,
|
||||
srslte::SECURITY_DIRECTION_DOWNLINK,
|
||||
srslte::SECURITY_DIRECTION_UPLINK,
|
||||
srslte::PDCP_SN_LEN_12,
|
||||
srslte::pdcp_t_reordering_t::ms500,
|
||||
srslte::pdcp_discard_timer_t::ms500,
|
||||
true};
|
||||
|
||||
// Setup TX
|
||||
pdcp_lte_test_helper pdcp_hlp_tx(cfg_tx, sec_cfg, logger);
|
||||
srslte::pdcp_entity_lte* pdcp_tx = &pdcp_hlp_tx.pdcp;
|
||||
rlc_dummy* rlc_tx = &pdcp_hlp_tx.rlc;
|
||||
srsue::stack_test_dummy* stack_tx = &pdcp_hlp_tx.stack;
|
||||
pdcp_hlp_tx.set_pdcp_initial_state(init_state);
|
||||
|
||||
// Setup RX
|
||||
pdcp_lte_test_helper pdcp_hlp_rx(cfg_tx, sec_cfg, logger);
|
||||
srslte::pdcp_entity_lte* pdcp_rx = &pdcp_hlp_tx.pdcp;
|
||||
rlc_dummy* rlc_rx = &pdcp_hlp_tx.rlc;
|
||||
srsue::stack_test_dummy* stack_rx = &pdcp_hlp_tx.stack;
|
||||
pdcp_hlp_rx.set_pdcp_initial_state(init_state);
|
||||
|
||||
pdcp_hlp.set_pdcp_initial_state(init_state);
|
||||
srslte::unique_byte_buffer_t out_pdu = srslte::make_byte_buffer();
|
||||
|
||||
// Write 256 SDUs and notify imediatly -> FMS 1111 1111 0000
|
||||
for (uint32_t i = 0; i < 4080; i++) {
|
||||
srslte::unique_byte_buffer_t sdu = srslte::make_byte_buffer();
|
||||
srslte::unique_byte_buffer_t pdu = srslte::make_byte_buffer();
|
||||
sdu->append_bytes(sdu1, sizeof(sdu1));
|
||||
pdcp->write_sdu(std::move(sdu));
|
||||
pdcp->notify_delivery({i});
|
||||
pdcp_tx->write_sdu(std::move(sdu));
|
||||
pdcp_tx->notify_delivery({i});
|
||||
rlc_tx->get_last_sdu(pdu);
|
||||
pdcp_rx->write_pdu(std::move(pdu));
|
||||
}
|
||||
|
||||
// Check undelivered SDUs queue size
|
||||
TESTASSERT(pdcp->nof_discard_timers() == 0); // 0 timers should be running
|
||||
TESTASSERT(pdcp_tx->nof_discard_timers() == 0); // 0 timers should be running
|
||||
|
||||
// Generate the status report
|
||||
pdcp->send_status_report();
|
||||
rlc->get_last_sdu(out_pdu);
|
||||
pdcp_rx->send_status_report();
|
||||
rlc_rx->get_last_sdu(out_pdu);
|
||||
logger.debug(out_pdu->msg, out_pdu->N_bytes, "Status PDU:");
|
||||
|
||||
// Check status PDU
|
||||
|
@ -142,19 +186,22 @@ int test_tx_wraparound_status_report(const srslte::pdcp_lte_state_t& init_state,
|
|||
// Write another 32 SDUs but don't notify SN=4080, SN=4081, SN=14 and SN=15
|
||||
for (uint32_t i = 4080; i < 4112; i++) {
|
||||
srslte::unique_byte_buffer_t sdu = srslte::make_byte_buffer();
|
||||
srslte::unique_byte_buffer_t pdu = srslte::make_byte_buffer();
|
||||
sdu->append_bytes(sdu1, sizeof(sdu1));
|
||||
pdcp->write_sdu(std::move(sdu));
|
||||
pdcp_tx->write_sdu(std::move(sdu));
|
||||
if (i != 4080 && i != 4081 && i != 4110 && i != 4111) {
|
||||
pdcp->notify_delivery({i % 4096});
|
||||
pdcp_tx->notify_delivery({i % 4096});
|
||||
rlc_tx->get_last_sdu(pdu);
|
||||
pdcp_rx->write_pdu(std::move(pdu));
|
||||
}
|
||||
}
|
||||
|
||||
// Check undelivered SDUs queue size
|
||||
TESTASSERT(pdcp->nof_discard_timers() == 4);
|
||||
TESTASSERT(pdcp_tx->nof_discard_timers() == 4);
|
||||
|
||||
// Generate the status report
|
||||
pdcp->send_status_report();
|
||||
rlc->get_last_sdu(out_pdu);
|
||||
pdcp_rx->send_status_report();
|
||||
rlc_rx->get_last_sdu(out_pdu);
|
||||
logger.debug(out_pdu->msg, out_pdu->N_bytes, "Status PDU:");
|
||||
|
||||
// Check status PDU
|
||||
|
@ -167,10 +214,10 @@ int test_tx_wraparound_status_report(const srslte::pdcp_lte_state_t& init_state,
|
|||
TESTASSERT(out_pdu->N_bytes == 6);
|
||||
TESTASSERT(out_pdu->msg[0] == 0b00001111);
|
||||
TESTASSERT(out_pdu->msg[1] == 0b11110000);
|
||||
TESTASSERT(out_pdu->msg[2] == 0b10000000);
|
||||
TESTASSERT(out_pdu->msg[3] == 0b00000000);
|
||||
TESTASSERT(out_pdu->msg[4] == 0b00000000);
|
||||
TESTASSERT(out_pdu->msg[5] == 0b00000110);
|
||||
TESTASSERT(out_pdu->msg[2] == 0b01111111);
|
||||
TESTASSERT(out_pdu->msg[3] == 0b11111111);
|
||||
TESTASSERT(out_pdu->msg[4] == 0b11111111);
|
||||
TESTASSERT(out_pdu->msg[5] == 0b11111000);
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
|
@ -233,20 +280,6 @@ int test_rx_status_report(const srslte::pdcp_lte_state_t& init_state, srslog::ba
|
|||
pdcp->write_pdu(std::move(status_pdu));
|
||||
|
||||
TESTASSERT(pdcp->nof_discard_timers() == 1);
|
||||
|
||||
// Check if the SDUs were correctly discarded with the status report
|
||||
pdcp->send_status_report();
|
||||
rlc->get_last_sdu(out_pdu);
|
||||
logger.debug(out_pdu->msg, out_pdu->N_bytes, "Status PDU:");
|
||||
|
||||
// Check status PDU, only 271 is missing => FMS = 271
|
||||
/*
|
||||
* | D/C | TYPE | FMS | -> | 0 | 0 | 0001 |
|
||||
* | FMS | -> | 00001111 |
|
||||
*/
|
||||
TESTASSERT(out_pdu->N_bytes == 3);
|
||||
TESTASSERT(out_pdu->msg[0] == 0b00000001);
|
||||
TESTASSERT(out_pdu->msg[1] == 0b00001111);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -259,7 +292,8 @@ int run_all_tests()
|
|||
logger.set_hex_dump_max_size(128);
|
||||
|
||||
// This is the normal initial state. All state variables are set to zero
|
||||
srslte::pdcp_lte_state_t normal_init_state = {};
|
||||
srslte::pdcp_lte_state_t normal_init_state = {
|
||||
.next_pdcp_tx_sn = 0, .tx_hfn = 0, .rx_hfn = 0, .next_pdcp_rx_sn = 0, .last_submitted_pdcp_rx_sn = 4095};
|
||||
|
||||
TESTASSERT(test_tx_status_report(normal_init_state, logger) == 0);
|
||||
TESTASSERT(test_tx_wraparound_status_report(normal_init_state, logger) == 0);
|
||||
|
|
Loading…
Reference in New Issue