mirror of https://github.com/PentHertz/srsLTE.git
Add RLC resume procedure
This commit is contained in:
parent
3f613d7183
commit
ade720e032
|
@ -83,6 +83,7 @@ public:
|
||||||
void add_bearer_mrb(uint32_t lcid);
|
void add_bearer_mrb(uint32_t lcid);
|
||||||
void del_bearer(uint32_t lcid);
|
void del_bearer(uint32_t lcid);
|
||||||
void del_bearer_mrb(uint32_t lcid);
|
void del_bearer_mrb(uint32_t lcid);
|
||||||
|
void resume_bearer(uint32_t lcid);
|
||||||
void change_lcid(uint32_t old_lcid, uint32_t new_lcid);
|
void change_lcid(uint32_t old_lcid, uint32_t new_lcid);
|
||||||
bool has_bearer(uint32_t lcid);
|
bool has_bearer(uint32_t lcid);
|
||||||
|
|
||||||
|
|
|
@ -71,6 +71,7 @@ public:
|
||||||
srsue::pdcp_interface_rlc *pdcp_,
|
srsue::pdcp_interface_rlc *pdcp_,
|
||||||
srsue::rrc_interface_rlc *rrc_,
|
srsue::rrc_interface_rlc *rrc_,
|
||||||
mac_interface_timers *mac_timers_);
|
mac_interface_timers *mac_timers_);
|
||||||
|
bool resume();
|
||||||
bool configure(srslte_rlc_config_t cfg_);
|
bool configure(srslte_rlc_config_t cfg_);
|
||||||
void reestablish();
|
void reestablish();
|
||||||
void stop();
|
void stop();
|
||||||
|
@ -292,7 +293,8 @@ private:
|
||||||
srsue::pdcp_interface_rlc *pdcp;
|
srsue::pdcp_interface_rlc *pdcp;
|
||||||
mac_interface_timers *mac_timers;
|
mac_interface_timers *mac_timers;
|
||||||
uint32_t lcid;
|
uint32_t lcid;
|
||||||
srslte_rlc_am_config_t cfg;
|
srslte_rlc_config_t cfg;
|
||||||
|
bool has_configuration;
|
||||||
std::string rb_name;
|
std::string rb_name;
|
||||||
|
|
||||||
static const int poll_periodicity = 8; // After how many data PDUs a status PDU shall be requested
|
static const int poll_periodicity = 8; // After how many data PDUs a status PDU shall be requested
|
||||||
|
|
|
@ -149,6 +149,7 @@ public:
|
||||||
srsue::rrc_interface_rlc *rrc_,
|
srsue::rrc_interface_rlc *rrc_,
|
||||||
srslte::mac_interface_timers *mac_timers_) = 0;
|
srslte::mac_interface_timers *mac_timers_) = 0;
|
||||||
virtual bool configure(srslte_rlc_config_t cnfg) = 0;
|
virtual bool configure(srslte_rlc_config_t cnfg) = 0;
|
||||||
|
virtual bool resume() = 0;
|
||||||
virtual void stop() = 0;
|
virtual void stop() = 0;
|
||||||
virtual void reestablish() = 0;
|
virtual void reestablish() = 0;
|
||||||
virtual void empty_queue() = 0;
|
virtual void empty_queue() = 0;
|
||||||
|
|
|
@ -42,6 +42,7 @@ public:
|
||||||
srsue::rrc_interface_rlc *rrc_,
|
srsue::rrc_interface_rlc *rrc_,
|
||||||
mac_interface_timers *mac_timers);
|
mac_interface_timers *mac_timers);
|
||||||
bool configure(srslte_rlc_config_t cnfg);
|
bool configure(srslte_rlc_config_t cnfg);
|
||||||
|
bool resume();
|
||||||
void stop();
|
void stop();
|
||||||
void reestablish();
|
void reestablish();
|
||||||
void empty_queue();
|
void empty_queue();
|
||||||
|
|
|
@ -51,6 +51,7 @@ public:
|
||||||
srsue::rrc_interface_rlc *rrc_,
|
srsue::rrc_interface_rlc *rrc_,
|
||||||
mac_interface_timers *mac_timers_);
|
mac_interface_timers *mac_timers_);
|
||||||
bool configure(srslte_rlc_config_t cnfg);
|
bool configure(srslte_rlc_config_t cnfg);
|
||||||
|
bool resume();
|
||||||
void reestablish();
|
void reestablish();
|
||||||
void stop();
|
void stop();
|
||||||
void empty_queue();
|
void empty_queue();
|
||||||
|
@ -209,7 +210,8 @@ private:
|
||||||
srsue::rrc_interface_rlc *rrc;
|
srsue::rrc_interface_rlc *rrc;
|
||||||
srslte::log *log;
|
srslte::log *log;
|
||||||
uint32_t lcid;
|
uint32_t lcid;
|
||||||
srslte_rlc_um_config_t cfg;
|
srslte_rlc_config_t cfg;
|
||||||
|
bool has_configuration;
|
||||||
std::string rb_name;
|
std::string rb_name;
|
||||||
byte_buffer_pool *pool;
|
byte_buffer_pool *pool;
|
||||||
|
|
||||||
|
|
|
@ -563,6 +563,26 @@ exit:
|
||||||
pthread_rwlock_unlock(&rwlock);
|
pthread_rwlock_unlock(&rwlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void rlc::resume_bearer(uint32_t lcid)
|
||||||
|
{
|
||||||
|
pthread_rwlock_wrlock(&rwlock);
|
||||||
|
|
||||||
|
if (not valid_lcid(lcid)) {
|
||||||
|
|
||||||
|
// Need to call init again because timers have been destroyed
|
||||||
|
rlc_array.at(lcid)->init(rlc_log, lcid, pdcp, rrc, mac_timers);
|
||||||
|
|
||||||
|
if (rlc_array.at(lcid)->resume()) {
|
||||||
|
rlc_log->info("Resumed radio bearer %s\n", rrc->get_rb_name(lcid).c_str());
|
||||||
|
} else {
|
||||||
|
rlc_log->error("Error resuming RLC entity\n.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rlc_log->error("Resuming bearer: bearer %s not configured.\n", rrc->get_rb_name(lcid).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_rwlock_unlock(&rwlock);
|
||||||
|
}
|
||||||
|
|
||||||
bool rlc::has_bearer(uint32_t lcid)
|
bool rlc::has_bearer(uint32_t lcid)
|
||||||
{
|
{
|
||||||
|
|
|
@ -32,7 +32,17 @@
|
||||||
|
|
||||||
namespace srslte {
|
namespace srslte {
|
||||||
|
|
||||||
rlc_am::rlc_am() : tx(this), rx(this), log(NULL), rrc(NULL), pdcp(NULL), mac_timers(NULL), lcid(0), rb_name(""), cfg()
|
rlc_am::rlc_am() :
|
||||||
|
tx(this),
|
||||||
|
rx(this),
|
||||||
|
log(NULL),
|
||||||
|
rrc(NULL),
|
||||||
|
pdcp(NULL),
|
||||||
|
mac_timers(NULL),
|
||||||
|
lcid(0),
|
||||||
|
rb_name(""),
|
||||||
|
cfg(),
|
||||||
|
has_configuration(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,28 +66,47 @@ void rlc_am::init(srslte::log *log_,
|
||||||
tx.init();
|
tx.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool rlc_am::resume()
|
||||||
|
{
|
||||||
|
if (not has_configuration) {
|
||||||
|
log->error("Error resuming bearer: no previous configuration found\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (not rx.configure(cfg.am)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (not tx.configure(cfg)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool rlc_am::configure(srslte_rlc_config_t cfg_)
|
bool rlc_am::configure(srslte_rlc_config_t cfg_)
|
||||||
{
|
{
|
||||||
// determine bearer name and configure Rx/Tx objects
|
// determine bearer name and configure Rx/Tx objects
|
||||||
rb_name = rrc->get_rb_name(lcid);
|
rb_name = rrc->get_rb_name(lcid);
|
||||||
|
|
||||||
if (not rx.configure(cfg_.am)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (not tx.configure(cfg_)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// store config
|
// store config
|
||||||
cfg = cfg_.am;
|
cfg = cfg_;
|
||||||
|
has_configuration = true;
|
||||||
|
|
||||||
log->warning("%s configured: t_poll_retx=%d, poll_pdu=%d, poll_byte=%d, max_retx_thresh=%d, "
|
if (resume()) {
|
||||||
"t_reordering=%d, t_status_prohibit=%d\n",
|
log->info("%s configured: t_poll_retx=%d, poll_pdu=%d, poll_byte=%d, max_retx_thresh=%d, "
|
||||||
rb_name.c_str(), cfg.t_poll_retx, cfg.poll_pdu, cfg.poll_byte, cfg.max_retx_thresh,
|
"t_reordering=%d, t_status_prohibit=%d\n",
|
||||||
cfg.t_reordering, cfg.t_status_prohibit);
|
rb_name.c_str(),
|
||||||
|
cfg.am.t_poll_retx,
|
||||||
return true;
|
cfg.am.poll_pdu,
|
||||||
|
cfg.am.poll_byte,
|
||||||
|
cfg.am.max_retx_thresh,
|
||||||
|
cfg.am.t_reordering,
|
||||||
|
cfg.am.t_status_prohibit);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void rlc_am::empty_queue()
|
void rlc_am::empty_queue()
|
||||||
|
@ -88,12 +117,14 @@ void rlc_am::empty_queue()
|
||||||
|
|
||||||
void rlc_am::reestablish()
|
void rlc_am::reestablish()
|
||||||
{
|
{
|
||||||
|
log->debug("Reestablished bearer %s\n", rb_name.c_str());
|
||||||
tx.reestablish(); // calls stop and enables tx again
|
tx.reestablish(); // calls stop and enables tx again
|
||||||
rx.reestablish(); // calls only stop
|
rx.reestablish(); // calls only stop
|
||||||
}
|
}
|
||||||
|
|
||||||
void rlc_am::stop()
|
void rlc_am::stop()
|
||||||
{
|
{
|
||||||
|
log->debug("Stopped bearer %s\n", rb_name.c_str());
|
||||||
tx.stop();
|
tx.stop();
|
||||||
rx.stop();
|
rx.stop();
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,6 +60,11 @@ bool rlc_tm::configure(srslte_rlc_config_t cnfg)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool rlc_tm::resume()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void rlc_tm::empty_queue()
|
void rlc_tm::empty_queue()
|
||||||
{
|
{
|
||||||
// Drop all messages in TX queue
|
// Drop all messages in TX queue
|
||||||
|
|
|
@ -54,28 +54,44 @@ void rlc_um::init(srslte::log *log_,
|
||||||
log = log_;
|
log = log_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool rlc_um::resume()
|
||||||
|
{
|
||||||
|
if (not has_configuration) {
|
||||||
|
log->error("Error resuming bearer: no previous configuration found\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (not rx.configure(cfg, rb_name)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (not tx.configure(cfg, rb_name)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool rlc_um::configure(srslte_rlc_config_t cnfg_)
|
bool rlc_um::configure(srslte_rlc_config_t cnfg_)
|
||||||
{
|
{
|
||||||
// determine bearer name and configure Rx/Tx objects
|
// determine bearer name and configure Rx/Tx objects
|
||||||
rb_name = get_rb_name(rrc, lcid, cnfg_.um.is_mrb);
|
rb_name = get_rb_name(rrc, lcid, cnfg_.um.is_mrb);
|
||||||
|
|
||||||
if (not rx.configure(cnfg_, rb_name)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (not tx.configure(cnfg_, rb_name)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// store config
|
// store config
|
||||||
cfg = cnfg_.um;
|
cfg = cnfg_;
|
||||||
|
has_configuration = true;
|
||||||
|
|
||||||
log->warning("%s configured in %s: t_reordering=%d ms, rx_sn_field_length=%u bits, tx_sn_field_length=%u bits\n",
|
if (resume()) {
|
||||||
rb_name.c_str(), rlc_mode_text[cnfg_.rlc_mode], cfg.t_reordering,
|
log->info("%s configured in %s: t_reordering=%d ms, rx_sn_field_length=%u bits, tx_sn_field_length=%u bits\n",
|
||||||
rlc_umd_sn_size_num[cfg.rx_sn_field_length], rlc_umd_sn_size_num[cfg.rx_sn_field_length]);
|
rb_name.c_str(),
|
||||||
|
rlc_mode_text[cnfg_.rlc_mode],
|
||||||
return true;
|
cfg.um.t_reordering,
|
||||||
|
rlc_umd_sn_size_num[cfg.um.rx_sn_field_length],
|
||||||
|
rlc_umd_sn_size_num[cfg.um.rx_sn_field_length]);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -109,7 +125,7 @@ void rlc_um::empty_queue() {
|
||||||
|
|
||||||
bool rlc_um::is_mrb()
|
bool rlc_um::is_mrb()
|
||||||
{
|
{
|
||||||
return cfg.is_mrb;
|
return cfg.um.is_mrb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -129,6 +129,30 @@ private:
|
||||||
bool running;
|
bool running;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void basic_test_tx(rlc_am* rlc, byte_buffer_t pdu_bufs[NBUFS])
|
||||||
|
{
|
||||||
|
|
||||||
|
// Push 5 SDUs into RLC1
|
||||||
|
byte_buffer_pool* pool = byte_buffer_pool::get_instance();
|
||||||
|
unique_byte_buffer_t sdu_bufs[NBUFS];
|
||||||
|
for (int i = 0; i < NBUFS; i++) {
|
||||||
|
sdu_bufs[i] = srslte::allocate_unique_buffer(*pool, true);
|
||||||
|
sdu_bufs[i]->msg[0] = i; // Write the index into the buffer
|
||||||
|
sdu_bufs[i]->N_bytes = 1; // Give each buffer a size of 1 byte
|
||||||
|
rlc->write_sdu(std::move(sdu_bufs[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(14 == rlc->get_buffer_state());
|
||||||
|
|
||||||
|
// Read 5 PDUs from RLC1 (1 byte each)
|
||||||
|
for (int i = 0; i < NBUFS; i++) {
|
||||||
|
uint32_t len = rlc->read_pdu(pdu_bufs[i].msg, 4); // 3 bytes for header + payload
|
||||||
|
pdu_bufs[i].N_bytes = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(0 == rlc->get_buffer_state());
|
||||||
|
}
|
||||||
|
|
||||||
bool basic_test()
|
bool basic_test()
|
||||||
{
|
{
|
||||||
srslte::log_filter log1("RLC_AM_1");
|
srslte::log_filter log1("RLC_AM_1");
|
||||||
|
@ -139,6 +163,7 @@ bool basic_test()
|
||||||
log2.set_hex_limit(-1);
|
log2.set_hex_limit(-1);
|
||||||
rlc_am_tester tester;
|
rlc_am_tester tester;
|
||||||
mac_dummy_timers timers;
|
mac_dummy_timers timers;
|
||||||
|
byte_buffer_t pdu_bufs[NBUFS];
|
||||||
|
|
||||||
rlc_am rlc1;
|
rlc_am rlc1;
|
||||||
rlc_am rlc2;
|
rlc_am rlc2;
|
||||||
|
@ -168,28 +193,7 @@ bool basic_test()
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Push 5 SDUs into RLC1
|
basic_test_tx(&rlc1, pdu_bufs);
|
||||||
byte_buffer_pool* pool = byte_buffer_pool::get_instance();
|
|
||||||
unique_byte_buffer_t sdu_bufs[NBUFS];
|
|
||||||
for(int i=0;i<NBUFS;i++)
|
|
||||||
{
|
|
||||||
sdu_bufs[i] = srslte::allocate_unique_buffer(*pool, true);
|
|
||||||
sdu_bufs[i]->msg[0] = i; // Write the index into the buffer
|
|
||||||
sdu_bufs[i]->N_bytes = 1; // Give each buffer a size of 1 byte
|
|
||||||
rlc1.write_sdu(std::move(sdu_bufs[i]));
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(14 == rlc1.get_buffer_state());
|
|
||||||
|
|
||||||
// Read 5 PDUs from RLC1 (1 byte each)
|
|
||||||
byte_buffer_t pdu_bufs[NBUFS];
|
|
||||||
for(int i=0;i<NBUFS;i++)
|
|
||||||
{
|
|
||||||
len = rlc1.read_pdu(pdu_bufs[i].msg, 4); // 3 bytes for header + payload
|
|
||||||
pdu_bufs[i].N_bytes = len;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(0 == rlc1.get_buffer_state());
|
|
||||||
|
|
||||||
// Write 5 PDUs into RLC2
|
// Write 5 PDUs into RLC2
|
||||||
for(int i=0;i<NBUFS;i++)
|
for(int i=0;i<NBUFS;i++)
|
||||||
|
@ -1677,6 +1681,67 @@ bool reset_test()
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool resume_test()
|
||||||
|
{
|
||||||
|
srslte::log_filter log1("RLC_AM_1");
|
||||||
|
srslte::log_filter log2("RLC_AM_2");
|
||||||
|
log1.set_level(srslte::LOG_LEVEL_DEBUG);
|
||||||
|
log2.set_level(srslte::LOG_LEVEL_DEBUG);
|
||||||
|
log1.set_hex_limit(-1);
|
||||||
|
log2.set_hex_limit(-1);
|
||||||
|
rlc_am_tester tester;
|
||||||
|
mac_dummy_timers timers;
|
||||||
|
|
||||||
|
rlc_am rlc1;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
log1.set_level(srslte::LOG_LEVEL_DEBUG);
|
||||||
|
|
||||||
|
rlc1.init(&log1, 1, &tester, &tester, &timers);
|
||||||
|
|
||||||
|
rlc_cfg_c cnfg;
|
||||||
|
cnfg.set(rlc_cfg_c::types::am);
|
||||||
|
cnfg.am().dl_am_rlc.t_reordering = t_reordering_e::ms5;
|
||||||
|
cnfg.am().dl_am_rlc.t_status_prohibit = t_status_prohibit_e::ms5;
|
||||||
|
cnfg.am().ul_am_rlc.max_retx_thres = ul_am_rlc_s::max_retx_thres_e_::t4;
|
||||||
|
cnfg.am().ul_am_rlc.poll_byte = poll_byte_e::kb25;
|
||||||
|
cnfg.am().ul_am_rlc.poll_pdu = poll_pdu_e::p4;
|
||||||
|
cnfg.am().ul_am_rlc.t_poll_retx = t_poll_retx_e::ms5;
|
||||||
|
|
||||||
|
if (not rlc1.configure(&cnfg)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push 1 SDU of size 10 into RLC1
|
||||||
|
byte_buffer_pool* pool = byte_buffer_pool::get_instance();
|
||||||
|
unique_byte_buffer_t sdu_buf = srslte::allocate_unique_buffer(*pool, true);
|
||||||
|
sdu_buf->msg[0] = 1; // Write the index into the buffer
|
||||||
|
sdu_buf->N_bytes = 100;
|
||||||
|
rlc1.write_sdu(std::move(sdu_buf));
|
||||||
|
|
||||||
|
// read 1 PDU from RLC1 and force segmentation
|
||||||
|
byte_buffer_t pdu_bufs;
|
||||||
|
len = rlc1.read_pdu(pdu_bufs.msg, 4);
|
||||||
|
pdu_bufs.N_bytes = len;
|
||||||
|
|
||||||
|
// reestablish RLC1
|
||||||
|
rlc1.reestablish();
|
||||||
|
|
||||||
|
// resume RLC1
|
||||||
|
rlc1.resume();
|
||||||
|
|
||||||
|
// Buffer should be zero
|
||||||
|
if (0 != rlc1.get_buffer_state()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do basic test
|
||||||
|
byte_buffer_t pdu_bufs_tx[NBUFS];
|
||||||
|
basic_test_tx(&rlc1, pdu_bufs_tx);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool stop_test()
|
bool stop_test()
|
||||||
{
|
{
|
||||||
srslte::log_filter log1("RLC_AM_1");
|
srslte::log_filter log1("RLC_AM_1");
|
||||||
|
@ -1808,4 +1873,10 @@ int main(int argc, char **argv)
|
||||||
exit(-1);
|
exit(-1);
|
||||||
};
|
};
|
||||||
byte_buffer_pool::get_instance()->cleanup();
|
byte_buffer_pool::get_instance()->cleanup();
|
||||||
|
|
||||||
|
if (resume_test()) {
|
||||||
|
printf("resume_test failed\n");
|
||||||
|
exit(-1);
|
||||||
|
};
|
||||||
|
byte_buffer_pool::get_instance()->cleanup();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue