rrc,ue: refactor wait conditions before transition to RRC idle

before entering RRC idle, after receiving a RRC connection release for example,
we need to wait until the RLC for SRB1 or SRB2 have been flushed, i.e.
the RLC has acknowledged the reception of the message.

Previously we have only waited for SRB1 but the message can also be received on SRB2
and in this case both bearers need to be checked.

The method is now streamlined to check both SRBs and is also used when
checking the msg transmission of an detach request.
This commit is contained in:
Andre Puschmann 2020-06-29 15:49:29 +02:00
parent 67877d15d5
commit e981d5ee70
5 changed files with 34 additions and 13 deletions

View File

@ -351,6 +351,8 @@ public:
const phy_interface_rrc_lte::phy_cell_t& found_cell);
void cell_select_completed(bool cs_ret);
bool srbs_flushed(); //< Check if data on SRBs still needs to be sent
protected:
// Moved to protected to be accessible by unit tests
void set_serving_cell(phy_interface_rrc_lte::phy_cell_t phy_cell, bool discard_serving);

View File

@ -259,7 +259,7 @@ public:
static const char* name() { return "Go Idle"; }
private:
static const uint32_t rlc_flush_timeout = 2000;
static const uint32_t rlc_flush_timeout_ms = 60; // TS 36.331 Sec 5.3.8.3
rrc* rrc_ptr;
srslte::timer_handler::unique_timer rlc_flush_timer;

View File

@ -1270,6 +1270,27 @@ void rrc::cell_select_completed(bool cs_ret)
phy_cell_selector.trigger(cell_select_event_t{cs_ret});
}
/**
* Check whether data on SRB1 or SRB2 still needs to be sent.
* If the bearer is suspended it will not be considered.
*
* @return True if no further data needs to be sent on SRBs, False otherwise
*/
bool rrc::srbs_flushed()
{
// Check SRB1
if (rlc->has_data(RB_ID_SRB1) && not rlc->is_suspended(RB_ID_SRB1)) {
return false;
}
// Check SRB2
if (rlc->has_data(RB_ID_SRB2) && not rlc->is_suspended(RB_ID_SRB2)) {
return false;
}
return true;
}
/*******************************************************************************
*
* Interface from RRC measurements class

View File

@ -1041,7 +1041,7 @@ proc_outcome_t rrc::process_pcch_proc::react(paging_complete e)
rrc::go_idle_proc::go_idle_proc(srsue::rrc* rrc_) : rrc_ptr(rrc_)
{
rlc_flush_timer = rrc_ptr->stack->get_unique_timer();
rlc_flush_timer.set(rlc_flush_timeout, [this](uint32_t tid) { rrc_ptr->idle_setter.trigger(true); });
rlc_flush_timer.set(rlc_flush_timeout_ms, [this](uint32_t tid) { rrc_ptr->idle_setter.trigger(true); });
}
proc_outcome_t rrc::go_idle_proc::init()
@ -1066,14 +1066,13 @@ proc_outcome_t rrc::go_idle_proc::step()
return proc_outcome_t::success;
}
// If the RLC SRB1 is not suspended
// wait for max. 2s for RLC on SRB1 to be flushed
if (rrc_ptr->rlc->is_suspended(RB_ID_SRB1) || not rrc_ptr->rlc->has_data(RB_ID_SRB1)) {
// wait for RLC of SRB1 and SRB2 to be flushed
if (rrc_ptr->srbs_flushed()) {
rrc_ptr->leave_connected();
Info("Left connected state\n");
return proc_outcome_t::success;
} else {
Debug("Postponing transition to RRC IDLE (%d ms < %d ms)\n", rlc_flush_timer.time_elapsed(), rlc_flush_timeout);
Debug("Postponing transition to RRC IDLE (%d ms < %d ms)\n", rlc_flush_timer.time_elapsed(), rlc_flush_timeout_ms);
}
return proc_outcome_t::yield;
}

View File

@ -25,6 +25,7 @@
#include <algorithm>
#include <chrono>
#include <numeric>
#include <thread>
using namespace srslte;
@ -180,15 +181,13 @@ bool ue_stack_lte::switch_off()
nas.detach_request(true);
// wait for max. 5s for it to be sent (according to TS 24.301 Sec 25.5.2.2)
const uint32_t RB_ID_SRB1 = 1;
int cnt = 0, timeout = 5000;
while (rlc.has_data(RB_ID_SRB1) && ++cnt <= timeout) {
usleep(1000);
int cnt = 0, timeout_ms = 5000;
while (not rrc.srbs_flushed() && ++cnt <= timeout_ms) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
bool detach_sent = true;
if (rlc.has_data(RB_ID_SRB1)) {
logmap::get("NAS ")->warning("Detach couldn't be sent after %ds.\n", timeout);
if (not rrc.srbs_flushed()) {
logmap::get("NAS ")->warning("Detach couldn't be sent after %dms.\n", timeout_ms);
detach_sent = false;
}