Added NR specific config struct for RLC AM. Added status prohibit timer.

This commit is contained in:
Pedro Alvarez 2021-10-14 11:45:37 +01:00
parent 5e8ab48c25
commit 9e4631ee24
4 changed files with 69 additions and 50 deletions

View File

@ -219,6 +219,14 @@ public:
rlc_cnfg.am.t_poll_retx = 5;
return rlc_cnfg;
}
static rlc_config_t default_rlc_am_nr_config()
{
rlc_config_t rlc_cnfg = {};
rlc_cnfg.rat = srsran_rat_t::nr;
rlc_cnfg.rlc_mode = rlc_mode_t::am;
rlc_cnfg.am_nr.t_status_prohibit = 8;
return rlc_cnfg;
}
static rlc_config_t default_rlc_um_nr_config(uint32_t sn_size = 6)
{
rlc_config_t cnfg = {};

View File

@ -115,6 +115,9 @@ public:
void handle_data_pdu_full(uint8_t* payload, uint32_t nof_bytes, rlc_am_nr_pdu_header_t& header);
bool inside_rx_window(uint32_t sn);
// Timers
void timer_expired(uint32_t timeout_id);
// Helpers
void debug_state();
@ -129,11 +132,17 @@ private:
// Mutexes
std::mutex mutex;
/****************************************************************************
* Rx timers
* Ref: 3GPP TS 38.322 v10.0.0 Section 7.3
***************************************************************************/
srsran::timer_handler::unique_timer status_prohibit_timer;
/****************************************************************************
* Configurable parameters
* Ref: 3GPP TS 38.322 v10.0.0 Section 7.4
***************************************************************************/
rlc_am_config_t cfg = {};
rlc_am_nr_config_t cfg = {};
/****************************************************************************
* State Variables

View File

@ -33,11 +33,7 @@ namespace srsran {
/***************************************************************************
* Tx subclass implementation
***************************************************************************/
rlc_am_nr_tx::rlc_am_nr_tx(rlc_am* parent_) : parent(parent_), rlc_am_base_tx(&parent_->logger)
{
parent->logger.debug("Initializing RLC AM NR TX: Tx_Next: %d",
st.tx_next); // Temporarly silence unused variable warning
}
rlc_am_nr_tx::rlc_am_nr_tx(rlc_am* parent_) : parent(parent_), rlc_am_base_tx(&parent_->logger) {}
bool rlc_am_nr_tx::configure(const rlc_config_t& cfg_)
{
@ -63,7 +59,8 @@ bool rlc_am_nr_tx::configure(const rlc_config_t& cfg_)
bool rlc_am_nr_tx::has_data()
{
return true;
return do_status() || // if we have a status PDU to transmit
tx_sdu_queue.get_n_sdus() != 1; // or if there is a SDU queued up for transmission
}
uint32_t rlc_am_nr_tx::read_pdu(uint8_t* payload, uint32_t nof_bytes)
@ -194,7 +191,7 @@ void rlc_am_nr_tx::get_buffer_state(uint32_t& tx_queue, uint32_t& prio_tx_queue)
// Bytes needed for status report
if (do_status() /* && not TODO status_prohibit_timer*/) {
n_bytes += parent->rx->get_status_pdu_length();
n_bytes += rx->get_status_pdu_length();
logger->debug("%s Buffer state - total status report: %d bytes", rb_name, n_bytes);
}
@ -237,14 +234,21 @@ void rlc_am_nr_tx::stop() {}
* Rx subclass implementation
***************************************************************************/
rlc_am_nr_rx::rlc_am_nr_rx(rlc_am* parent_) :
parent(parent_), pool(byte_buffer_pool::get_instance()), rlc_am_base_rx(parent_, &parent_->logger)
{
parent->logger.debug("Initializing RLC AM NR RX"); // Temporarly silence unused variable warning
}
parent(parent_),
pool(byte_buffer_pool::get_instance()),
status_prohibit_timer(parent->timers->get_unique_timer()),
rlc_am_base_rx(parent_, &parent_->logger)
{}
bool rlc_am_nr_rx::configure(const rlc_config_t& cfg_)
{
cfg = cfg_.am;
cfg = cfg_.am_nr;
// configure timers
if (cfg.t_status_prohibit > 0) {
status_prohibit_timer.set(static_cast<uint32_t>(cfg.t_status_prohibit),
[this](uint32_t timerid) { timer_expired(timerid); });
}
return true;
}
@ -260,26 +264,12 @@ void rlc_am_nr_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_bytes)
{
// Get AMD PDU Header
rlc_am_nr_pdu_header_t header = {};
rlc_am_nr_read_data_pdu_header(payload, nof_bytes, rlc_am_nr_sn_size_t::size12bits, &header);
// TODO
// if (header.rf != 0) {
// handle_data_pdu_segment(payload, payload_len, header); TODO
//} else {
handle_data_pdu_full(payload, nof_bytes, header);
//}
}
void rlc_am_nr_rx::handle_data_pdu_full(uint8_t* payload, uint32_t nof_bytes, rlc_am_nr_pdu_header_t& header)
{
std::map<uint32_t, rlc_amd_rx_pdu_nr>::iterator it;
uint32_t hdr_len = rlc_am_nr_read_data_pdu_header(payload, nof_bytes, rlc_am_nr_sn_size_t::size12bits, &header);
logger->info(payload, nof_bytes, "%s Rx data PDU SN=%d (%d B)", parent->rb_name, header.sn, nof_bytes);
log_rlc_am_nr_pdu_header_to_string(logger->debug, header);
// sanity check for segments not exceeding PDU length
// TODO
// Check wether SDU is within Rx Window
if (!inside_rx_window(header.sn)) {
logger->info("%s SN=%d outside rx window [%d:%d] - discarding",
parent->rb_name,
@ -314,8 +304,8 @@ void rlc_am_nr_rx::handle_data_pdu_full(uint8_t* payload, uint32_t nof_bytes, rl
rx_pdu.buf->get_tailroom());
return;
}
memcpy(rx_pdu.buf->msg, payload, nof_bytes);
rx_pdu.buf->N_bytes = nof_bytes;
memcpy(rx_pdu.buf->msg, payload + hdr_len, nof_bytes - hdr_len); // Don't copy header
rx_pdu.buf->N_bytes = nof_bytes - hdr_len;
rx_pdu.header = header;
// Check poll bit
@ -324,21 +314,6 @@ void rlc_am_nr_rx::handle_data_pdu_full(uint8_t* payload, uint32_t nof_bytes, rl
do_status = true;
}
// Update Rx_Next_Highest
if (RX_MOD_BASE_NR(header.sn) >= RX_MOD_BASE_NR(rx_next_highest)) {
rx_next_highest = (header.sn + 1) % MOD;
}
// Update RX_Highest_Status
if (RX_MOD_BASE_NR(header.sn) == RX_MOD_BASE_NR(rx_highest_status)) {
rx_highest_status = (header.sn + 1) % MOD;
}
// Update RX_Next (FIXME should only be updated if all segments are received)
if (RX_MOD_BASE_NR(header.sn) == RX_MOD_BASE_NR(rx_next)) {
rx_next = header.sn + 1 % MOD;
}
// Update reordering variables and timers (36.322 v10.0.0 Section 5.1.3.2.3)
// TODO
@ -355,6 +330,21 @@ void rlc_am_nr_rx::handle_data_pdu_full(uint8_t* payload, uint32_t nof_bytes, rl
break;
}
}
// Update Rx_Next_Highest
if (RX_MOD_BASE_NR(header.sn) >= RX_MOD_BASE_NR(rx_next_highest)) {
rx_next_highest = (header.sn + 1) % MOD;
}
// Update RX_Highest_Status
if (RX_MOD_BASE_NR(header.sn) == RX_MOD_BASE_NR(rx_highest_status)) {
rx_highest_status = (header.sn + 1) % MOD;
}
// Update RX_Next (FIXME should only be updated if all segments are received)
if (RX_MOD_BASE_NR(header.sn) == RX_MOD_BASE_NR(rx_next)) {
rx_next = header.sn + 1 % MOD;
}
}
bool rlc_am_nr_rx::inside_rx_window(uint32_t sn)
@ -394,7 +384,9 @@ uint32_t rlc_am_nr_rx::get_status_pdu(rlc_am_nr_status_pdu_t* status, uint32_t m
// TODO
i = (i + 1) % MOD;
}
//
if (max_len != UINT32_MAX) {
status_prohibit_timer.run(); // UINT32_MAX is used just to querry the status PDU length
}
return tmp_buf.N_bytes;
}
@ -406,7 +398,17 @@ uint32_t rlc_am_nr_rx::get_status_pdu_length()
bool rlc_am_nr_rx::get_do_status()
{
return do_status.load(std::memory_order_relaxed);
return do_status.load(std::memory_order_relaxed) && not status_prohibit_timer.is_running();
}
void rlc_am_nr_rx::timer_expired(uint32_t timeout_id)
{
std::unique_lock<std::mutex> lock(mutex);
if (status_prohibit_timer.is_valid() && status_prohibit_timer.id() == timeout_id) {
logger->debug("%s Status prohibit timer expired after %dms", parent->rb_name, status_prohibit_timer.duration());
}
lock.unlock();
}
/*

View File

@ -63,11 +63,11 @@ int basic_test()
// before configuring entity
TESTASSERT(0 == rlc1.get_buffer_state());
if (not rlc1.configure(rlc_config_t::default_rlc_am_config())) {
if (not rlc1.configure(rlc_config_t::default_rlc_am_nr_config())) {
return -1;
}
if (not rlc2.configure(rlc_config_t::default_rlc_am_config())) {
if (not rlc2.configure(rlc_config_t::default_rlc_am_nr_config())) {
return -1;
}