From d19eb28a16a3c6d41f289ea7f8b4f0a3a62f33df Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Wed, 5 Sep 2018 12:21:19 +0200 Subject: [PATCH 01/10] fix various variable initializations that gcc-4.8 complained about --- lib/src/phy/enb/enb_dl.c | 6 ++++-- lib/src/phy/fec/test/turbocoder_test.c | 3 ++- lib/src/phy/utils/test/vector_test.c | 8 ++++++-- lib/src/radio/test/benchmark_radio.cc | 4 +++- lib/test/phy/phy_dl_test.c | 14 ++++++++++---- srsue/src/upper/nas.cc | 3 ++- srsue/src/upper/rrc.cc | 6 +++--- 7 files changed, 30 insertions(+), 14 deletions(-) diff --git a/lib/src/phy/enb/enb_dl.c b/lib/src/phy/enb/enb_dl.c index 0040b65a9..b5e2cd283 100644 --- a/lib/src/phy/enb/enb_dl.c +++ b/lib/src/phy/enb/enb_dl.c @@ -417,7 +417,8 @@ int srslte_enb_dl_put_pdcch_dl(srslte_enb_dl_t *q, srslte_ra_dl_dci_t *grant, srslte_dci_format_t format, srslte_dci_location_t location, uint16_t rnti, uint32_t sf_idx) { - srslte_dci_msg_t dci_msg = {}; + srslte_dci_msg_t dci_msg; + bzero(&dci_msg, sizeof(dci_msg)); bool rnti_is_user = true; if (rnti == SRSLTE_SIRNTI || rnti == SRSLTE_PRNTI || (rnti >= SRSLTE_RARNTI_START && rnti <= SRSLTE_RARNTI_END)) { @@ -439,7 +440,8 @@ int srslte_enb_dl_put_pdcch_ul(srslte_enb_dl_t *q, srslte_ra_ul_dci_t *grant, srslte_dci_location_t location, uint16_t rnti, uint32_t sf_idx) { - srslte_dci_msg_t dci_msg = {}; + srslte_dci_msg_t dci_msg; + bzero(&dci_msg, sizeof(dci_msg)); srslte_dci_msg_pack_pusch(grant, &dci_msg, q->cell.nof_prb); if (srslte_pdcch_encode(&q->pdcch, &dci_msg, location, rnti, q->sf_symbols, sf_idx, q->cfi)) { diff --git a/lib/src/phy/fec/test/turbocoder_test.c b/lib/src/phy/fec/test/turbocoder_test.c index 172d2d898..37b82902e 100644 --- a/lib/src/phy/fec/test/turbocoder_test.c +++ b/lib/src/phy/fec/test/turbocoder_test.c @@ -97,7 +97,8 @@ int main(int argc, char **argv) { } /* Create CRC for Transport Block, it is not currently used but it is required */ - srslte_crc_t crc_tb = {}; + srslte_crc_t crc_tb; + bzero(&crc_tb, sizeof(crc_tb)); if (srslte_crc_init(&crc_tb, SRSLTE_LTE_CRC24A, 24)) { printf("error initialising CRC\n"); exit(-1); diff --git a/lib/src/phy/utils/test/vector_test.c b/lib/src/phy/utils/test/vector_test.c index 35156acaa..44f8af1ca 100644 --- a/lib/src/phy/utils/test/vector_test.c +++ b/lib/src/phy/utils/test/vector_test.c @@ -60,6 +60,8 @@ bool verbose = false; #define TEST(X, CODE) static bool test_##X (char *func_name, double *timing, uint32_t block_size) {\ struct timeval start, end;\ + bzero(&start, sizeof(start));\ + bzero(&end, sizeof(end));\ float mse = 0.0f;\ bool passed;\ strncpy(func_name, #X, 32);\ @@ -781,7 +783,8 @@ TEST(srslte_vec_apply_cfo, ) TEST(srslte_cfo_correct, - srslte_cfo_t srslte_cfo = {0}; + srslte_cfo_t srslte_cfo; + bzero(&srslte_cfo, sizeof(srslte_cfo)); MALLOC(cf_t, x); MALLOC(cf_t, z); @@ -807,7 +810,8 @@ TEST(srslte_cfo_correct, ) TEST(srslte_cfo_correct_change, - srslte_cfo_t srslte_cfo = {0}; + srslte_cfo_t srslte_cfo; + bzero(&srslte_cfo, sizeof(srslte_cfo)); MALLOC(cf_t, x); MALLOC(cf_t, z); diff --git a/lib/src/radio/test/benchmark_radio.cc b/lib/src/radio/test/benchmark_radio.cc index d15adaa6b..844624086 100644 --- a/lib/src/radio/test/benchmark_radio.cc +++ b/lib/src/radio/test/benchmark_radio.cc @@ -129,7 +129,9 @@ int main(int argc, char **argv) { int ret = SRSLTE_ERROR; srslte::radio_multi *radio_h = NULL; - srslte_timestamp_t ts_rx = {}, ts_tx = {}; + srslte_timestamp_t ts_rx, ts_tx; + bzero(&ts_rx, sizeof(ts_rx)); + bzero(&ts_tx, sizeof(ts_tx)); signal(SIGINT, sig_int_handler); diff --git a/lib/test/phy/phy_dl_test.c b/lib/test/phy/phy_dl_test.c index 50ea25a1e..6ed22c5d9 100644 --- a/lib/test/phy/phy_dl_test.c +++ b/lib/test/phy/phy_dl_test.c @@ -190,8 +190,8 @@ uint32_t prbset_to_bitmask() { int main(int argc, char **argv) { struct timeval t[3] = {}; size_t tx_nof_bits = 0, rx_nof_bits = 0; - srslte_enb_dl_t enb_dl = {}; - srslte_ue_dl_t ue_dl = {}; + srslte_enb_dl_t enb_dl; + srslte_ue_dl_t ue_dl; srslte_softbuffer_tx_t *softbuffer_tx[SRSLTE_MAX_TB] = {}; srslte_softbuffer_rx_t *softbuffer_rx[SRSLTE_MAX_TB] = {}; uint8_t *data_tx[SRSLTE_MAX_TB] = {}; @@ -206,6 +206,9 @@ int main(int argc, char **argv) { cf_t *signal_buffer[SRSLTE_MAX_PORTS] = {NULL}; + bzero(&enb_dl, sizeof(enb_dl)); + bzero(&ue_dl, sizeof(ue_dl)); + /* * Allocate Memory */ @@ -304,9 +307,12 @@ int main(int argc, char **argv) { /* * Run eNodeB */ - srslte_ra_dl_dci_t dci = {}; + srslte_ra_dl_dci_t dci; srslte_dci_format_t dci_format = SRSLTE_DCI_FORMAT1A; - srslte_ra_dl_grant_t grant = {}; + srslte_ra_dl_grant_t grant; + + bzero(&dci, sizeof(dci)); + bzero(&grant, sizeof(grant)); prbset_num = (int) ceilf((float) cell.nof_prb / srslte_ra_type0_P(cell.nof_prb)); last_prbset_num = prbset_num; diff --git a/srsue/src/upper/nas.cc b/srsue/src/upper/nas.cc index 0109be17f..ee2228ec4 100644 --- a/srsue/src/upper/nas.cc +++ b/srsue/src/upper/nas.cc @@ -1176,7 +1176,8 @@ void nas::send_detach_request(bool switch_off) return; } - LIBLTE_MME_DETACH_REQUEST_MSG_STRUCT detach_request = {}; + LIBLTE_MME_DETACH_REQUEST_MSG_STRUCT detach_request; + bzero(&detach_request, sizeof(detach_request)); if (switch_off) { detach_request.detach_type.switch_off = 1; detach_request.detach_type.type_of_detach = LIBLTE_MME_SO_FLAG_SWITCH_OFF; diff --git a/srsue/src/upper/rrc.cc b/srsue/src/upper/rrc.cc index edf89ba34..080de4b27 100644 --- a/srsue/src/upper/rrc.cc +++ b/srsue/src/upper/rrc.cc @@ -729,10 +729,10 @@ uint32_t rrc::sib_start_tti(uint32_t tti, uint32_t period, uint32_t offset, uint */ bool rrc::si_acquire(uint32_t sib_index) { - uint32_t tti; + uint32_t tti = 0; uint32_t si_win_start=0, si_win_len=0; - uint16_t period; - uint32_t sched_index; + uint16_t period = 0; + uint32_t sched_index = 0; uint32_t x, sf, offset; uint32_t last_win_start = 0; From 855a55d4d85982487eff77666240a29de802fe95 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Wed, 5 Sep 2018 13:39:13 +0200 Subject: [PATCH 02/10] fix issue with assigning imsi in pcsc --- srsue/src/upper/pcsc_usim.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/srsue/src/upper/pcsc_usim.cc b/srsue/src/upper/pcsc_usim.cc index 0d423c73c..0375a9fe7 100644 --- a/srsue/src/upper/pcsc_usim.cc +++ b/srsue/src/upper/pcsc_usim.cc @@ -64,7 +64,7 @@ int pcsc_usim::init(usim_args_t *args, srslte::log *log_) log->error("Error reading IMSI from SIM.\n"); return ret; } - imsi_str = tmp; + imsi_str.assign(tmp, tmp_len); // Check extracted IMSI and convert if(15 == imsi_str.length()) { From 6a791f1416ff2a35d21932a77ceb6327292d2265 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Thu, 6 Sep 2018 15:22:37 +0200 Subject: [PATCH 03/10] Change TX mutex to semaphores (mutex implementation was violating lock ownership requirement) --- srsenb/hdr/phy/phch_common.h | 32 +++++----------- srsenb/hdr/phy/phch_worker.h | 5 ++- srsenb/hdr/phy/txrx.h | 12 +++--- srsenb/src/phy/phch_common.cc | 71 +++++++++++++++++++++++++---------- srsenb/src/phy/phch_worker.cc | 6 +-- srsenb/src/phy/phy.cc | 4 +- srsenb/src/phy/txrx.cc | 14 +++---- srsue/hdr/phy/phch_common.h | 15 ++++---- srsue/hdr/phy/phch_recv.h | 7 ++-- srsue/hdr/phy/phch_worker.h | 2 +- srsue/src/phy/phch_common.cc | 67 +++++++++++++++++++-------------- srsue/src/phy/phch_recv.cc | 10 ++--- srsue/src/phy/phch_worker.cc | 6 +-- srsue/src/phy/phy.cc | 2 +- 14 files changed, 140 insertions(+), 113 deletions(-) diff --git a/srsenb/hdr/phy/phch_common.h b/srsenb/hdr/phy/phch_common.h index 7d83239bf..47e1add77 100644 --- a/srsenb/hdr/phy/phch_common.h +++ b/srsenb/hdr/phy/phch_common.h @@ -28,6 +28,7 @@ #define SRSENB_PHCH_COMMON_H #include +#include #include "srslte/interfaces/enb_interfaces.h" #include "srslte/interfaces/enb_metrics_interface.h" #include "srslte/common/gen_mch_tables.h" @@ -36,6 +37,7 @@ #include "srslte/common/thread_pool.h" #include "srslte/radio/radio.h" #include + namespace srsenb { typedef struct { @@ -73,29 +75,16 @@ class phch_common { public: - - phch_common(uint32_t max_mutex_) : tx_mutex(max_mutex_) { - nof_mutex = 0; - max_mutex = max_mutex_; - params.max_prach_offset_us = 20; - radio = NULL; - mac = NULL; - is_first_tx = false; - is_first_of_burst = false; - pdsch_p_b = 0; - nof_workers = 0; - bzero(&pusch_cfg, sizeof(pusch_cfg)); - bzero(&hopping_cfg, sizeof(hopping_cfg)); - bzero(&pucch_cfg, sizeof(pucch_cfg)); - bzero(&ul_grants, sizeof(ul_grants)); - } - + + phch_common(uint32_t nof_workers); + ~phch_common(); + + void set_nof_workers(uint32_t nof_workers); + bool init(srslte_cell_t *cell, srslte::radio *radio_handler, mac_interface_phy *mac); void reset(); void stop(); - void set_nof_mutex(uint32_t nof_mutex); - void worker_end(uint32_t tx_mutex_cnt, cf_t *buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t tx_time); // Common objects @@ -148,13 +137,12 @@ public: private: - std::vector tx_mutex; + std::vector tx_sem; bool is_first_tx; bool is_first_of_burst; uint32_t nof_workers; - uint32_t nof_mutex; - uint32_t max_mutex; + uint32_t max_workers; pthread_mutex_t user_mutex; diff --git a/srsenb/hdr/phy/phch_worker.h b/srsenb/hdr/phy/phch_worker.h index 776ba0a1b..24e27a181 100644 --- a/srsenb/hdr/phy/phch_worker.h +++ b/srsenb/hdr/phy/phch_worker.h @@ -46,7 +46,7 @@ public: void reset(); cf_t *get_buffer_rx(uint32_t antenna_idx); - void set_time(uint32_t tti, uint32_t tx_mutex_cnt, srslte_timestamp_t tx_time); + void set_time(uint32_t tti, uint32_t tx_worker_cnt, srslte_timestamp_t tx_time); int add_rnti(uint16_t rnti); void rem_rnti(uint16_t rnti); @@ -93,8 +93,9 @@ private: cf_t *signal_buffer_rx[SRSLTE_MAX_PORTS]; cf_t *signal_buffer_tx[SRSLTE_MAX_PORTS]; uint32_t tti_rx, tti_tx_dl, tti_tx_ul; - uint32_t sf_rx, sf_tx, tx_mutex_cnt; + uint32_t sf_rx, sf_tx; uint32_t t_rx, t_tx_dl, t_tx_ul; + uint32_t tx_worker_cnt; srslte_enb_dl_t enb_dl; srslte_enb_ul_t enb_ul; srslte_softbuffer_tx_t temp_mbsfn_softbuffer; diff --git a/srsenb/hdr/phy/txrx.h b/srsenb/hdr/phy/txrx.h index 69a119900..8833f2b6a 100644 --- a/srsenb/hdr/phy/txrx.h +++ b/srsenb/hdr/phy/txrx.h @@ -50,8 +50,6 @@ public: uint32_t prio); void stop(); - const static int MUTEX_X_WORKER = 4; - private: void run_thread(); @@ -61,12 +59,12 @@ private: srslte::thread_pool *workers_pool; prach_worker *prach; phch_common *worker_com; - - uint32_t tx_mutex_cnt; - uint32_t nof_tx_mutex; - + // Main system TTI counter - uint32_t tti; + uint32_t tti; + + uint32_t tx_worker_cnt; + uint32_t nof_workers; bool running; }; diff --git a/srsenb/src/phy/phch_common.cc b/srsenb/src/phy/phch_common.cc index 536b0a358..29c0254a3 100644 --- a/srsenb/src/phy/phch_common.cc +++ b/srsenb/src/phy/phch_common.cc @@ -41,9 +41,35 @@ using namespace std; namespace srsenb { -void phch_common::set_nof_mutex(uint32_t nof_mutex_) { - nof_mutex = nof_mutex_; - assert(nof_mutex <= max_mutex); +phch_common::phch_common(uint32_t max_workers) : tx_sem(max_workers) +{ + this->nof_workers = nof_workers; + params.max_prach_offset_us = 20; + radio = NULL; + mac = NULL; + is_first_tx = false; + is_first_of_burst = false; + pdsch_p_b = 0; + this->max_workers = max_workers; + bzero(&pusch_cfg, sizeof(pusch_cfg)); + bzero(&hopping_cfg, sizeof(hopping_cfg)); + bzero(&pucch_cfg, sizeof(pucch_cfg)); + bzero(&ul_grants, sizeof(ul_grants)); + + for (uint32_t i=0;inof_workers = nof_workers; } void phch_common::reset() { @@ -61,35 +87,42 @@ bool phch_common::init(srslte_cell_t *cell_, srslte::radio* radio_h_, mac_interf is_first_of_burst = true; is_first_tx = true; - for (uint32_t i=0;iset_tti(tx_mutex_cnt); + // Wait for the green light to transmit in the current TTI + sem_wait(&tx_sem[tti%nof_workers]); + + radio->set_tti(tti); radio->tx((void **) buffer, nof_samples, tx_time); - - // Trigger next transmission - pthread_mutex_unlock(&tx_mutex[(tx_mutex_cnt+1)%nof_mutex]); + + // Allow next TTI to transmit + sem_post(&tx_sem[(tti+1)%nof_workers]); // Trigger MAC clock mac->tti_clock(); diff --git a/srsenb/src/phy/phch_worker.cc b/srsenb/src/phy/phch_worker.cc index b1b6cb67e..ef5a5cbad 100644 --- a/srsenb/src/phy/phch_worker.cc +++ b/srsenb/src/phy/phch_worker.cc @@ -206,7 +206,7 @@ cf_t* phch_worker::get_buffer_rx(uint32_t antenna_idx) return signal_buffer_rx[antenna_idx]; } -void phch_worker::set_time(uint32_t tti_, uint32_t tx_mutex_cnt_, srslte_timestamp_t tx_time_) +void phch_worker::set_time(uint32_t tti_, uint32_t tx_worker_cnt_, srslte_timestamp_t tx_time_) { tti_rx = tti_; tti_tx_dl = TTI_TX(tti_rx); @@ -219,7 +219,7 @@ void phch_worker::set_time(uint32_t tti_, uint32_t tx_mutex_cnt_, srslte_timesta t_rx = TTIMOD(tti_rx); t_tx_ul = TTIMOD(tti_tx_ul); - tx_mutex_cnt = tx_mutex_cnt_; + tx_worker_cnt = tx_worker_cnt_; memcpy(&tx_time, &tx_time_, sizeof(srslte_timestamp_t)); } @@ -483,7 +483,7 @@ void phch_worker::work_imp() pthread_mutex_unlock(&mutex); Debug("Sending to radio\n"); - phy->worker_end(tx_mutex_cnt, signal_buffer_tx, SRSLTE_SF_LEN_PRB(phy->cell.nof_prb), tx_time); + phy->worker_end(tx_worker_cnt, signal_buffer_tx, SRSLTE_SF_LEN_PRB(phy->cell.nof_prb), tx_time); is_worker_running = false; diff --git a/srsenb/src/phy/phy.cc b/srsenb/src/phy/phy.cc index ee7c1e890..3b8c2839d 100644 --- a/srsenb/src/phy/phy.cc +++ b/srsenb/src/phy/phy.cc @@ -48,7 +48,7 @@ namespace srsenb { phy::phy() : workers_pool(MAX_WORKERS), workers(MAX_WORKERS), - workers_common(txrx::MUTEX_X_WORKER*MAX_WORKERS), + workers_common(MAX_WORKERS), nof_workers(0) { radio_handler = NULL; @@ -141,10 +141,10 @@ bool phy::init(phy_args_t *args, void phy::stop() { tx_rx.stop(); - workers_common.stop(); for (uint32_t i=0;iget_nof_workers(); - worker_com->set_nof_mutex(nof_tx_mutex); + nof_workers = workers_pool->get_nof_workers(); + worker_com->set_nof_workers(nof_workers); start(prio_); return true; @@ -126,12 +126,12 @@ void txrx::run_thread() srslte_timestamp_add(&tx_time, 0, HARQ_DELAY_MS*1e-3); Debug("Settting TTI=%d, tx_mutex=%d, tx_time=%ld:%f to worker %d\n", - tti, tx_mutex_cnt, + tti, tx_worker_cnt, tx_time.full_secs, tx_time.frac_secs, worker->get_id()); - worker->set_time(tti, tx_mutex_cnt, tx_time); - tx_mutex_cnt = (tx_mutex_cnt+1)%nof_tx_mutex; + worker->set_time(tti, tx_worker_cnt, tx_time); + tx_worker_cnt = (tx_worker_cnt+1)%nof_workers; // Trigger phy worker execution workers_pool->start_worker(worker); diff --git a/srsue/hdr/phy/phch_common.h b/srsue/hdr/phy/phch_common.h index 90379c854..5db0dd2cb 100644 --- a/srsue/hdr/phy/phch_common.h +++ b/srsue/hdr/phy/phch_common.h @@ -33,6 +33,7 @@ #include #include #include +#include #include "srslte/srslte.h" #include "srslte/interfaces/ue_interfaces.h" #include "srslte/radio/radio.h" @@ -116,7 +117,8 @@ typedef struct { uint8_t last_ri; uint8_t last_pmi; - phch_common(uint32_t max_mutex = 3); + phch_common(uint32_t max_workers); + ~phch_common(); void init(phy_interface_rrc::phy_cfg_t *config, phy_args_t *args, srslte::log *_log, @@ -144,8 +146,7 @@ typedef struct { void worker_end(uint32_t tti, bool tx_enable, cf_t *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time); - void set_nof_mutex(uint32_t nof_mutex); - + void set_nof_workers(uint32_t nof_workers); bool sr_enabled; int sr_last_tx_tti; @@ -179,7 +180,9 @@ typedef struct { - std::vector tx_mutex; + std::vector tx_sem; + uint32_t nof_workers; + uint32_t max_workers; bool is_first_of_burst; srslte::radio *radio_h; @@ -208,10 +211,6 @@ typedef struct { bool is_first_tx; - uint32_t nof_workers; - uint32_t nof_mutex; - uint32_t max_mutex; - srslte_cell_t cell; dl_metrics_t dl_metrics; diff --git a/srsue/hdr/phy/phch_recv.h b/srsue/hdr/phy/phch_recv.h index f58bc64a1..6e9e62a94 100644 --- a/srsue/hdr/phy/phch_recv.h +++ b/srsue/hdr/phy/phch_recv.h @@ -83,7 +83,6 @@ public: void force_freq(float dl_freq, float ul_freq); // Other functions - const static int MUTEX_X_WORKER = 4; double set_rx_gain(double gain); int radio_recv_fnc(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time); int scell_recv_fnc(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time); @@ -438,9 +437,9 @@ private: float time_adv_sec, next_time_adv_sec; uint32_t tti; bool do_agc; - - uint32_t nof_tx_mutex; - uint32_t tx_mutex_cnt; + + uint32_t tx_worker_cnt; + uint32_t nof_workers; float ul_dl_factor; int current_earfcn; diff --git a/srsue/hdr/phy/phch_worker.h b/srsue/hdr/phy/phch_worker.h index 244657975..085c9d1ce 100644 --- a/srsue/hdr/phy/phch_worker.h +++ b/srsue/hdr/phy/phch_worker.h @@ -52,7 +52,7 @@ public: /* Functions used by main PHY thread */ cf_t* get_buffer(uint32_t antenna_idx); - void set_tti(uint32_t tti, uint32_t tx_tti); + void set_tti(uint32_t tti, uint32_t tx_worker_cnt); void set_tx_time(srslte_timestamp_t tx_time, uint32_t next_offset); void set_prach(cf_t *prach_ptr, float prach_power); void set_cfo(float cfo); diff --git a/srsue/src/phy/phch_common.cc b/srsue/src/phy/phch_common.cc index d09338c4c..0cc3c6e93 100644 --- a/srsue/src/phy/phch_common.cc +++ b/srsue/src/phy/phch_common.cc @@ -39,15 +39,14 @@ namespace srsue { cf_t zeros[50000]; -phch_common::phch_common(uint32_t max_mutex_) : tx_mutex(max_mutex_) +phch_common::phch_common(uint32_t max_workers) : tx_sem(max_workers) { config = NULL; args = NULL; log_h = NULL; radio_h = NULL; - mac = NULL; - max_mutex = max_mutex_; - nof_mutex = 0; + mac = NULL; + this->max_workers = max_workers; rx_gain_offset = 0; last_ri = 0; last_pmi = 0; @@ -65,17 +64,28 @@ phch_common::phch_common(uint32_t max_mutex_) : tx_mutex(max_mutex_) bzero(zeros, 50000*sizeof(cf_t)); - // FIXME: This is an ugly fix to avoid the TX filters to empty - /* - for (int i=0;i<50000;i++) { - zeros[i] = 0.01*cexpf(((float) i/50000)*0.1*_Complex_I); - }*/ + for (uint32_t i=0;inof_workers = nof_workers; +} void phch_common::init(phy_interface_rrc::phy_cfg_t *_config, phy_args_t *_args, srslte::log *_log, srslte::radio *_radio, rrc_interface_phy *_rrc, mac_interface_phy *_mac) { @@ -87,15 +97,6 @@ void phch_common::init(phy_interface_rrc::phy_cfg_t *_config, phy_args_t *_args, args = _args; is_first_tx = true; sr_last_tx_tti = -1; - - for (uint32_t i=0;iset_tti(tti); + // Wait for the green light to transmit in the current TTI + sem_wait(&tx_sem[tti%nof_workers]); + + radio_h->set_tti(tti); if (tx_enable) { radio_h->tx_single(buffer, nof_samples, tx_time); is_first_of_burst = false; @@ -263,8 +271,9 @@ void phch_common::worker_end(uint32_t tti, bool tx_enable, } } } - // Trigger next transmission - pthread_mutex_unlock(&tx_mutex[(tti+1)%nof_mutex]); + + // Allow next TTI to transmit + sem_post(&tx_sem[(tti+1)%nof_workers]); } diff --git a/srsue/src/phy/phch_recv.cc b/srsue/src/phy/phch_recv.cc index c7b63cd4f..0fbd9e221 100644 --- a/srsue/src/phy/phch_recv.cc +++ b/srsue/src/phy/phch_recv.cc @@ -81,8 +81,8 @@ void phch_recv::init(srslte::radio_multi *_radio_handler, mac_interface_phy *_ma return; } - nof_tx_mutex = MUTEX_X_WORKER * workers_pool->get_nof_workers(); - worker_com->set_nof_mutex(nof_tx_mutex); + nof_workers = workers_pool->get_nof_workers(); + worker_com->set_nof_workers(nof_workers); // Initialize cell searcher search_p.init(sf_buffer, log_h, nof_rx_antennas, this); @@ -128,7 +128,7 @@ void phch_recv::reset() radio_overflow_return = false; in_sync_cnt = 0; out_of_sync_cnt = 0; - tx_mutex_cnt = 0; + tx_worker_cnt = 0; time_adv_sec = 0; next_offset = 0; srate_mode = SRATE_NONE; @@ -454,13 +454,13 @@ void phch_recv::run_thread() worker->set_prach(prach_ptr?&prach_ptr[prach_sf_cnt*SRSLTE_SF_LEN_PRB(cell.nof_prb)]:NULL, prach_power); worker->set_cfo(get_tx_cfo()); - worker->set_tti(tti, tx_mutex_cnt); + worker->set_tti(tti, tx_worker_cnt); worker->set_tx_time(tx_time, next_offset); next_offset = 0; if (next_time_adv_sec != time_adv_sec) { time_adv_sec = next_time_adv_sec; } - tx_mutex_cnt = (tx_mutex_cnt+1) % nof_tx_mutex; + tx_worker_cnt = (tx_worker_cnt+1) % nof_workers; // Advance/reset prach subframe pointer if (prach_ptr) { diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index 3f688b5b1..178a803ae 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -193,10 +193,10 @@ cf_t* phch_worker::get_buffer(uint32_t antenna_idx) return signal_buffer[antenna_idx]; } -void phch_worker::set_tti(uint32_t tti_, uint32_t tx_tti_) +void phch_worker::set_tti(uint32_t tti_, uint32_t tx_worker_cnt) { - tti = tti_; - tx_tti = tx_tti_; + tti = tti_; + tx_tti = tx_worker_cnt; log_h->step(tti); if (log_phy_lib_h) { log_phy_lib_h->step(tti); diff --git a/srsue/src/phy/phy.cc b/srsue/src/phy/phy.cc index 47354156d..50bec5f09 100644 --- a/srsue/src/phy/phy.cc +++ b/srsue/src/phy/phy.cc @@ -52,7 +52,7 @@ namespace srsue { phy::phy() : workers_pool(MAX_WORKERS), workers(MAX_WORKERS), - workers_common(phch_recv::MUTEX_X_WORKER*MAX_WORKERS),nof_coworkers(0) + workers_common(MAX_WORKERS),nof_coworkers(0) { } From f14ee09ed3a36b53f46aff0c899cc92931710b12 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Fri, 10 Aug 2018 15:50:08 +0200 Subject: [PATCH 04/10] adapt AM test to new MAC timer --- lib/test/upper/rlc_am_test.cc | 155 +++++++++++++++++++++------------- 1 file changed, 98 insertions(+), 57 deletions(-) diff --git a/lib/test/upper/rlc_am_test.cc b/lib/test/upper/rlc_am_test.cc index 00793e7d3..d9281518e 100644 --- a/lib/test/upper/rlc_am_test.cc +++ b/lib/test/upper/rlc_am_test.cc @@ -42,15 +42,21 @@ class mac_dummy_timers :public srslte::mac_interface_timers { public: - srslte::timers::timer* timer_get(uint32_t timer_id) - { - return &t; + mac_dummy_timers() : timers(8) {} + srslte::timers::timer* timer_get(uint32_t timer_id) { + return timers.get(timer_id); + } + void timer_release_id(uint32_t timer_id) { + timers.release_id(timer_id); + } + uint32_t timer_get_unique_id() { + return timers.get_unique_id(); + } + void step_all() { + timers.step_all(); } - uint32_t timer_get_unique_id(){return 0;} - void timer_release_id(uint32_t id){} - private: - srslte::timers::timer t; + srslte::timers timers; }; class rlc_am_tester @@ -166,8 +172,8 @@ void basic_test() cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5; - rlc1.configure(&cnfg); - rlc2.configure(&cnfg); + assert(rlc1.configure(&cnfg) == true); + assert(rlc2.configure(&cnfg) == true); // Push 5 SDUs into RLC1 byte_buffer_t sdu_bufs[NBUFS]; @@ -250,8 +256,8 @@ void concat_test() cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5; - rlc1.configure(&cnfg); - rlc2.configure(&cnfg); + assert(rlc1.configure(&cnfg) == true); + assert(rlc2.configure(&cnfg) == true); // Push 5 SDUs into RLC1 byte_buffer_t sdu_bufs[NBUFS]; @@ -319,8 +325,8 @@ void segment_test() cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5; - rlc1.configure(&cnfg); - rlc2.configure(&cnfg); + assert(rlc1.configure(&cnfg) == true); + assert(rlc2.configure(&cnfg) == true); // Push 5 SDUs into RLC1 byte_buffer_t sdu_bufs[NBUFS]; @@ -405,8 +411,8 @@ void retx_test() cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5; - rlc1.configure(&cnfg); - rlc2.configure(&cnfg); + assert(rlc1.configure(&cnfg) == true); + assert(rlc2.configure(&cnfg) == true); // Push 5 SDUs into RLC1 byte_buffer_t sdu_bufs[NBUFS]; @@ -436,8 +442,11 @@ void retx_test() rlc2.write_pdu(pdu_bufs[i].msg, pdu_bufs[i].N_bytes); } - // Sleep to let reordering timeout expire - usleep(10000); + // Step timers until reordering timeout expires + int cnt = 5; + while (cnt--) { + timers.step_all(); + } assert(4 == rlc2.get_buffer_state()); @@ -502,8 +511,8 @@ void resegment_test_1() cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5; - rlc1.configure(&cnfg); - rlc2.configure(&cnfg); + assert(rlc1.configure(&cnfg) == true); + assert(rlc2.configure(&cnfg) == true); // Push 5 SDUs into RLC1 byte_buffer_t sdu_bufs[NBUFS]; @@ -534,8 +543,11 @@ void resegment_test_1() rlc2.write_pdu(pdu_bufs[i].msg, pdu_bufs[i].N_bytes); } - // Sleep to let reordering timeout expire - usleep(10000); + // Step timers until reordering timeout expires + int cnt = 5; + while (cnt--) { + timers.step_all(); + } assert(4 == rlc2.get_buffer_state()); @@ -612,8 +624,8 @@ void resegment_test_2() cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5; - rlc1.configure(&cnfg); - rlc2.configure(&cnfg); + assert(rlc1.configure(&cnfg) == true); + assert(rlc2.configure(&cnfg) == true); // Push 5 SDUs into RLC1 byte_buffer_t sdu_bufs[NBUFS]; @@ -644,8 +656,11 @@ void resegment_test_2() rlc2.write_pdu(pdu_bufs[i].msg, pdu_bufs[i].N_bytes); } - // Sleep to let reordering timeout expire - usleep(10000); + // Step timers until reordering timeout expires + int cnt = 5; + while (cnt--) { + timers.step_all(); + } assert(4 == rlc2.get_buffer_state()); @@ -719,8 +734,8 @@ void resegment_test_3() cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5; - rlc1.configure(&cnfg); - rlc2.configure(&cnfg); + assert(rlc1.configure(&cnfg) == true); + assert(rlc2.configure(&cnfg) == true); // Push 5 SDUs into RLC1 byte_buffer_t sdu_bufs[NBUFS]; @@ -751,8 +766,11 @@ void resegment_test_3() rlc2.write_pdu(pdu_bufs[i].msg, pdu_bufs[i].N_bytes); } - // Sleep to let reordering timeout expire - usleep(10000); + // Step timers until reordering timeout expires + int cnt = 5; + while (cnt--) { + timers.step_all(); + } assert(4 == rlc2.get_buffer_state()); @@ -822,8 +840,8 @@ void resegment_test_4() cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5; - rlc1.configure(&cnfg); - rlc2.configure(&cnfg); + assert(rlc1.configure(&cnfg) == true); + assert(rlc2.configure(&cnfg) == true); // Push 5 SDUs into RLC1 byte_buffer_t sdu_bufs[NBUFS]; @@ -854,8 +872,11 @@ void resegment_test_4() rlc2.write_pdu(pdu_bufs[i].msg, pdu_bufs[i].N_bytes); } - // Sleep to let reordering timeout expire - usleep(10000); + // Step timers until reordering timeout expires + int cnt = 5; + while (cnt--) { + timers.step_all(); + } assert(4 == rlc2.get_buffer_state()); @@ -925,8 +946,8 @@ void resegment_test_5() cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5; - rlc1.configure(&cnfg); - rlc2.configure(&cnfg); + assert(rlc1.configure(&cnfg) == true); + assert(rlc2.configure(&cnfg) == true); // Push 5 SDUs into RLC1 byte_buffer_t sdu_bufs[NBUFS]; @@ -957,8 +978,11 @@ void resegment_test_5() rlc2.write_pdu(pdu_bufs[i].msg, pdu_bufs[i].N_bytes); } - // Sleep to let reordering timeout expire - usleep(10000); + // Step timers until reordering timeout expires + int cnt = 5; + while (cnt--) { + timers.step_all(); + } assert(4 == rlc2.get_buffer_state()); @@ -1027,8 +1051,8 @@ void resegment_test_6() cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5; - rlc1.configure(&cnfg); - rlc2.configure(&cnfg); + assert(rlc1.configure(&cnfg) == true); + assert(rlc2.configure(&cnfg) == true); // Push SDUs into RLC1 byte_buffer_t sdu_bufs[9]; @@ -1069,8 +1093,11 @@ void resegment_test_6() rlc2.write_pdu(pdu_bufs[i].msg, pdu_bufs[i].N_bytes); } - // Sleep to let reordering timeout expire - usleep(10000); + // Step timers until reordering timeout expires + int cnt = 5; + while (cnt--) { + timers.step_all(); + } assert(4 == rlc2.get_buffer_state()); @@ -1165,8 +1192,8 @@ void resegment_test_7() cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5; - rlc1.configure(&cnfg); - rlc2.configure(&cnfg); + assert(rlc1.configure(&cnfg) == true); + assert(rlc2.configure(&cnfg) == true); // Push 2 SDUs into RLC1 byte_buffer_t sdu_bufs[N_SDU_BUFS]; @@ -1201,8 +1228,11 @@ void resegment_test_7() } } - // Sleep to let reordering timeout expire - usleep(10000); + // Step timers until reordering timeout expires + int cnt = 5; + while (cnt--) { + timers.step_all(); + } assert(12 == rlc1.get_buffer_state()); @@ -1222,7 +1252,7 @@ void resegment_test_7() } } - usleep(10000); + // Read status PDU from RLC2 assert(rlc2.get_buffer_state()); @@ -1237,7 +1267,6 @@ void resegment_test_7() assert(15 == rlc1.get_buffer_state()); - // second round of retx, forcing resegmentation byte_buffer_t retx2[4]; for (uint32_t i = 0; i < 4; i++) { @@ -1253,6 +1282,13 @@ void resegment_test_7() // check buffer states assert(0 == rlc1.get_buffer_state()); + + // Step timers until poll_retx timeout expires + cnt = 5; + while (cnt--) { + timers.step_all(); + } + assert(0 == rlc2.get_buffer_state()); // Check number of SDUs and their content @@ -1318,8 +1354,8 @@ void resegment_test_8() cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5; - rlc1.configure(&cnfg); - rlc2.configure(&cnfg); + assert(rlc1.configure(&cnfg) == true); + assert(rlc2.configure(&cnfg) == true); // Push 2 SDUs into RLC1 byte_buffer_t sdu_bufs[N_SDU_BUFS]; @@ -1354,8 +1390,11 @@ void resegment_test_8() } } - // Sleep to let reordering timeout expire - usleep(10000); + // Step timers until reordering timeout expires + int cnt = 5; + while (cnt--) { + timers.step_all(); + } assert(12 == rlc1.get_buffer_state()); @@ -1375,7 +1414,11 @@ void resegment_test_8() } } - usleep(20000); + // Step timers until reordering timeout expires + cnt = 7; + while (cnt--) { + timers.step_all(); + } // Read status PDU from RLC2 assert(rlc2.get_buffer_state()); @@ -1408,8 +1451,7 @@ void resegment_test_8() // Check number of SDUs and their content assert(tester.n_sdus == N_SDU_BUFS); - for(int i=0; iN_bytes == sdu_size); for(uint32_t j=0;jmsg[j] == i); @@ -1449,7 +1491,7 @@ void reset_test() cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5; - rlc1.configure(&cnfg); + assert(rlc1.configure(&cnfg) == true); // Push 1 SDU of size 10 into RLC1 byte_buffer_t sdu_buf; @@ -1499,7 +1541,7 @@ void stop_test() cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5; - rlc1.configure(&cnfg); + assert(rlc1.configure(&cnfg) == true); // start thread reading ul_writer writer(&rlc1); @@ -1542,7 +1584,6 @@ int main(int argc, char **argv) { resegment_test_6(); byte_buffer_pool::get_instance()->cleanup(); - resegment_test_7(); byte_buffer_pool::get_instance()->cleanup(); From 24cde06e32a8a210cb677296ce5fc598adc2e327 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Fri, 10 Aug 2018 15:50:39 +0200 Subject: [PATCH 05/10] fix UM config printout during init --- lib/src/upper/rlc_um.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/src/upper/rlc_um.cc b/lib/src/upper/rlc_um.cc index 0c6c8dfec..6b2b8d041 100644 --- a/lib/src/upper/rlc_um.cc +++ b/lib/src/upper/rlc_um.cc @@ -75,13 +75,13 @@ bool rlc_um::configure(srslte_rlc_config_t cnfg_) return false; } - log->warning("%s configured in %s mode: t_reordering=%d ms, rx_sn_field_length=%u bits, tx_sn_field_length=%u bits\n", - rb_name.c_str(), rlc_mode_text[cnfg_.rlc_mode], - cfg.t_reordering, rlc_umd_sn_size_num[cfg.rx_sn_field_length], rlc_umd_sn_size_num[cfg.rx_sn_field_length]); - // store config cfg = cnfg_.um; + log->warning("%s configured in %s mode: ft_reordering=%d ms, rx_sn_field_length=%u bits, tx_sn_field_length=%u bits\n", + rb_name.c_str(), rlc_mode_text[cnfg_.rlc_mode], + cfg.t_reordering, rlc_umd_sn_size_num[cfg.rx_sn_field_length], rlc_umd_sn_size_num[cfg.rx_sn_field_length]); + return true; } From 6c896c496219a1a52e9ec3b43bea1a51447d0294 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Mon, 13 Aug 2018 12:44:28 +0200 Subject: [PATCH 06/10] fix RLC AM test in release --- lib/test/upper/rlc_am_test.cc | 336 +++++++++++++++++++++++++--------- 1 file changed, 248 insertions(+), 88 deletions(-) diff --git a/lib/test/upper/rlc_am_test.cc b/lib/test/upper/rlc_am_test.cc index d9281518e..bd5e7e2c0 100644 --- a/lib/test/upper/rlc_am_test.cc +++ b/lib/test/upper/rlc_am_test.cc @@ -141,7 +141,7 @@ private: bool running; }; -void basic_test() +bool basic_test() { srslte::log_filter log1("RLC_AM_1"); srslte::log_filter log2("RLC_AM_2"); @@ -172,8 +172,13 @@ void basic_test() cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5; - assert(rlc1.configure(&cnfg) == true); - assert(rlc2.configure(&cnfg) == true); + if (not rlc1.configure(&cnfg)) { + return -1; + } + + if (not rlc2.configure(&cnfg)) { + return -1; + } // Push 5 SDUs into RLC1 byte_buffer_t sdu_bufs[NBUFS]; @@ -221,11 +226,17 @@ void basic_test() } // Check statistics - assert(rlc1.get_num_tx_bytes() == rlc2.get_num_rx_bytes()); - assert(rlc2.get_num_tx_bytes() == rlc1.get_num_rx_bytes()); + if (rlc1.get_num_tx_bytes() != rlc2.get_num_rx_bytes()) { + return -1; + } + if (rlc2.get_num_tx_bytes() != rlc1.get_num_rx_bytes()) { + return -1; + } + + return 0; } -void concat_test() +bool concat_test() { srslte::log_filter log1("RLC_AM_1"); srslte::log_filter log2("RLC_AM_2"); @@ -256,8 +267,13 @@ void concat_test() cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5; - assert(rlc1.configure(&cnfg) == true); - assert(rlc2.configure(&cnfg) == true); + if (not rlc1.configure(&cnfg)) { + return -1; + } + + if (not rlc2.configure(&cnfg)) { + return -1; + } // Push 5 SDUs into RLC1 byte_buffer_t sdu_bufs[NBUFS]; @@ -290,11 +306,17 @@ void concat_test() } // check statistics - assert(rlc1.get_num_tx_bytes() == rlc2.get_num_rx_bytes()); - assert(rlc2.get_num_tx_bytes() == rlc1.get_num_rx_bytes()); + if (rlc1.get_num_tx_bytes() != rlc2.get_num_rx_bytes()) { + return -1; + } + if (rlc2.get_num_tx_bytes() != rlc1.get_num_rx_bytes()) { + return -1; + } + + return 0; } -void segment_test() +bool segment_test() { srslte::log_filter log1("RLC_AM_1"); srslte::log_filter log2("RLC_AM_2"); @@ -325,8 +347,13 @@ void segment_test() cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5; - assert(rlc1.configure(&cnfg) == true); - assert(rlc2.configure(&cnfg) == true); + if (not rlc1.configure(&cnfg)) { + return -1; + } + + if (not rlc2.configure(&cnfg)) { + return -1; + } // Push 5 SDUs into RLC1 byte_buffer_t sdu_bufs[NBUFS]; @@ -376,11 +403,17 @@ void segment_test() assert(tester.sdus[i]->msg[j] == j); } - assert(rlc1.get_num_tx_bytes() == rlc2.get_num_rx_bytes()); - assert(rlc2.get_num_tx_bytes() == rlc1.get_num_rx_bytes()); + if (rlc1.get_num_tx_bytes() != rlc2.get_num_rx_bytes()) { + return -1; + } + if (rlc2.get_num_tx_bytes() != rlc1.get_num_rx_bytes()) { + return -1; + } + + return 0; } -void retx_test() +bool retx_test() { srslte::log_filter log1("RLC_AM_1"); srslte::log_filter log2("RLC_AM_2"); @@ -411,8 +444,13 @@ void retx_test() cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5; - assert(rlc1.configure(&cnfg) == true); - assert(rlc2.configure(&cnfg) == true); + if (not rlc1.configure(&cnfg)) { + return -1; + } + + if (not rlc2.configure(&cnfg)) { + return -1; + } // Push 5 SDUs into RLC1 byte_buffer_t sdu_bufs[NBUFS]; @@ -471,12 +509,14 @@ void retx_test() assert(tester.n_sdus == 5); for(int i=0; iN_bytes == 1); - assert(*(tester.sdus[i]->msg) == i); + if (tester.sdus[i]->N_bytes != 1) return -1; + if (*(tester.sdus[i]->msg) != i) return -1; } + + return 0; } -void resegment_test_1() +bool resegment_test_1() { // SDUs: | 10 | 10 | 10 | 10 | 10 | // PDUs: | 10 | 10 | 10 | 10 | 10 | @@ -511,8 +551,13 @@ void resegment_test_1() cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5; - assert(rlc1.configure(&cnfg) == true); - assert(rlc2.configure(&cnfg) == true); + if (not rlc1.configure(&cnfg)) { + return -1; + } + + if (not rlc2.configure(&cnfg)) { + return -1; + } // Push 5 SDUs into RLC1 byte_buffer_t sdu_bufs[NBUFS]; @@ -582,13 +627,15 @@ void resegment_test_1() assert(tester.n_sdus == 5); for(int i=0; iN_bytes == 10); + if (tester.sdus[i]->N_bytes != 10) return -1; for(int j=0;j<10;j++) - assert(tester.sdus[i]->msg[j] == j); + if (tester.sdus[i]->msg[j] != j) return -1; } + + return 0; } -void resegment_test_2() +bool resegment_test_2() { // SDUs: | 10 | 10 | 10 | 10 | 10 | @@ -624,8 +671,13 @@ void resegment_test_2() cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5; - assert(rlc1.configure(&cnfg) == true); - assert(rlc2.configure(&cnfg) == true); + if (not rlc1.configure(&cnfg)) { + return -1; + } + + if (not rlc2.configure(&cnfg)) { + return -1; + } // Push 5 SDUs into RLC1 byte_buffer_t sdu_bufs[NBUFS]; @@ -692,13 +744,15 @@ void resegment_test_2() assert(tester.n_sdus == 5); for(int i=0; iN_bytes == 10); + if (tester.sdus[i]->N_bytes != 10) return -1; for(int j=0;j<10;j++) - assert(tester.sdus[i]->msg[j] == j); + if (tester.sdus[i]->msg[j] != j) return -1; } + + return 0; } -void resegment_test_3() +bool resegment_test_3() { // SDUs: | 10 | 10 | 10 | 10 | 10 | @@ -734,8 +788,13 @@ void resegment_test_3() cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5; - assert(rlc1.configure(&cnfg) == true); - assert(rlc2.configure(&cnfg) == true); + if (not rlc1.configure(&cnfg)) { + return -1; + } + + if (not rlc2.configure(&cnfg)) { + return -1; + } // Push 5 SDUs into RLC1 byte_buffer_t sdu_bufs[NBUFS]; @@ -798,13 +857,15 @@ void resegment_test_3() assert(tester.n_sdus == 5); for(int i=0; iN_bytes == 10); + if (tester.sdus[i]->N_bytes != 10) return -1; for(int j=0;j<10;j++) - assert(tester.sdus[i]->msg[j] == j); + if (tester.sdus[i]->msg[j] != j) return -1; } + + return 0; } -void resegment_test_4() +bool resegment_test_4() { // SDUs: | 10 | 10 | 10 | 10 | 10 | @@ -840,8 +901,13 @@ void resegment_test_4() cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5; - assert(rlc1.configure(&cnfg) == true); - assert(rlc2.configure(&cnfg) == true); + if (not rlc1.configure(&cnfg)) { + return -1; + } + + if (not rlc2.configure(&cnfg)) { + return -1; + } // Push 5 SDUs into RLC1 byte_buffer_t sdu_bufs[NBUFS]; @@ -904,13 +970,15 @@ void resegment_test_4() assert(tester.n_sdus == 5); for(int i=0; iN_bytes == 10); + if (tester.sdus[i]->N_bytes != 10) return -1; for(int j=0;j<10;j++) - assert(tester.sdus[i]->msg[j] == j); + if (tester.sdus[i]->msg[j] != j) return -1; } + + return 0; } -void resegment_test_5() +bool resegment_test_5() { // SDUs: | 10 | 10 | 10 | 10 | 10 | @@ -929,8 +997,6 @@ void resegment_test_5() rlc_am rlc1; rlc_am rlc2; - int len; - log1.set_level(srslte::LOG_LEVEL_DEBUG); log2.set_level(srslte::LOG_LEVEL_DEBUG); @@ -946,8 +1012,13 @@ void resegment_test_5() cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5; - assert(rlc1.configure(&cnfg) == true); - assert(rlc2.configure(&cnfg) == true); + if (not rlc1.configure(&cnfg)) { + return -1; + } + + if (not rlc2.configure(&cnfg)) { + return -1; + } // Push 5 SDUs into RLC1 byte_buffer_t sdu_bufs[NBUFS]; @@ -1010,13 +1081,15 @@ void resegment_test_5() assert(tester.n_sdus == 5); for(int i=0; iN_bytes == 10); + if (tester.sdus[i]->N_bytes != 10) return -1; for(int j=0;j<10;j++) - assert(tester.sdus[i]->msg[j] == j); + if (tester.sdus[i]->msg[j] != j) return -1; } + + return 0; } -void resegment_test_6() +bool resegment_test_6() { // SDUs: |10|10|10| 54 | 54 | 54 | 54 | 54 | 54 | // PDUs: |10|10|10| 270 | 54 | @@ -1051,8 +1124,13 @@ void resegment_test_6() cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5; - assert(rlc1.configure(&cnfg) == true); - assert(rlc2.configure(&cnfg) == true); + if (not rlc1.configure(&cnfg)) { + return -1; + } + + if (not rlc2.configure(&cnfg)) { + return -1; + } // Push SDUs into RLC1 byte_buffer_t sdu_bufs[9]; @@ -1138,14 +1216,17 @@ void resegment_test_6() } for(int i=3;i<9;i++) { - assert(tester.sdus[i]->N_bytes == 54); - for(int j=0;j<54;j++) - assert(tester.sdus[i]->msg[j] == j); + if(tester.sdus[i]->N_bytes != 54) return -1; + for(int j=0;j<54;j++) { + if (tester.sdus[i]->msg[j] != j) return -1; + } } + + return 0; } // Retransmission of PDU segments of the same size -void resegment_test_7() +bool resegment_test_7() { // SDUs: | 30 | 30 | // PDUs: | 13 | 13 | 11 | 13 | 10 | @@ -1192,8 +1273,13 @@ void resegment_test_7() cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5; - assert(rlc1.configure(&cnfg) == true); - assert(rlc2.configure(&cnfg) == true); + if (not rlc1.configure(&cnfg)) { + return -1; + } + + if (not rlc2.configure(&cnfg)) { + return -1; + } // Push 2 SDUs into RLC1 byte_buffer_t sdu_bufs[N_SDU_BUFS]; @@ -1252,8 +1338,6 @@ void resegment_test_7() } } - - // Read status PDU from RLC2 assert(rlc2.get_buffer_state()); byte_buffer_t status_buf; @@ -1295,20 +1379,22 @@ void resegment_test_7() assert(tester.n_sdus == N_SDU_BUFS); for(int i=0; iN_bytes == sdu_size); + if (tester.sdus[i]->N_bytes != sdu_size) return -1; for(uint32_t j=0;jmsg[j] == i); + if (tester.sdus[i]->msg[j] != i) return -1; } } #if HAVE_PCAP pcap.close(); #endif + + return 0; } // Retransmission of PDU segments with different size -void resegment_test_8() +bool resegment_test_8() { // SDUs: | 30 | 30 | // PDUs: | 15 | 15 | 15 | 15 | 15 | @@ -1354,8 +1440,13 @@ void resegment_test_8() cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5; - assert(rlc1.configure(&cnfg) == true); - assert(rlc2.configure(&cnfg) == true); + if (not rlc1.configure(&cnfg)) { + exit(-1); + } + + if (not rlc2.configure(&cnfg)) { + exit(-1); + } // Push 2 SDUs into RLC1 byte_buffer_t sdu_bufs[N_SDU_BUFS]; @@ -1445,26 +1536,41 @@ void resegment_test_8() #endif } + // get BSR from RLC2 + status_buf.N_bytes = rlc2.read_pdu(status_buf.msg, 10); // 10 bytes is enough to hold the status + + // Write status PDU to RLC1 + rlc1.write_pdu(status_buf.msg, status_buf.N_bytes); +#if HAVE_PCAP + pcap.write_ul_am_ccch(status_buf.msg, status_buf.N_bytes); +#endif + // check buffer states - assert(0 == rlc1.get_buffer_state()); - assert(0 == rlc2.get_buffer_state()); + if (rlc1.get_buffer_state() != 0) { + return -1; + }; + if (rlc2.get_buffer_state() != 0) { + return -1; + }; // Check number of SDUs and their content assert(tester.n_sdus == N_SDU_BUFS); for(int i=0; iN_bytes == sdu_size); + if (tester.sdus[i]->N_bytes != sdu_size) return -1; for(uint32_t j=0;jmsg[j] == i); + if (tester.sdus[i]->msg[j] != i) return -1; } } #if HAVE_PCAP pcap.close(); #endif + + return 0; } -void reset_test() +bool reset_test() { srslte::log_filter log1("RLC_AM_1"); srslte::log_filter log2("RLC_AM_2"); @@ -1491,7 +1597,9 @@ void reset_test() cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5; - assert(rlc1.configure(&cnfg) == true); + if (not rlc1.configure(&cnfg)) { + return -1; + } // Push 1 SDU of size 10 into RLC1 byte_buffer_t sdu_buf; @@ -1515,10 +1623,14 @@ void reset_test() len = rlc1.read_pdu(pdu_bufs.msg, 100); pdu_bufs.N_bytes = len; - assert(0 == rlc1.get_buffer_state()); + if (0 != rlc1.get_buffer_state()) { + return -1; + } + + return 0; } -void stop_test() +bool stop_test() { srslte::log_filter log1("RLC_AM_1"); log1.set_level(srslte::LOG_LEVEL_DEBUG); @@ -1541,7 +1653,9 @@ void stop_test() cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4; cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5; - assert(rlc1.configure(&cnfg) == true); + if (not rlc1.configure(&cnfg)) { + return -1; + } // start thread reading ul_writer writer(&rlc1); @@ -1552,47 +1666,93 @@ void stop_test() // stop RLC1 rlc1.stop(); + + return 0; } -int main(int argc, char **argv) { - basic_test(); +int main(int argc, char **argv) +{ + if (basic_test()) { + printf("basic_test failed\n"); + exit(-1); + }; byte_buffer_pool::get_instance()->cleanup(); - concat_test(); + if (concat_test()) { + printf("concat_test failed\n"); + exit(-1); + }; byte_buffer_pool::get_instance()->cleanup(); - segment_test(); + if (segment_test()) { + printf("segment_test failed\n"); + exit(-1); + }; byte_buffer_pool::get_instance()->cleanup(); - retx_test(); + if (retx_test()) { + printf("retx_test failed\n"); + exit(-1); + }; byte_buffer_pool::get_instance()->cleanup(); - resegment_test_1(); + if (resegment_test_1()) { + printf("resegment_test_1 failed\n"); + exit(-1); + }; byte_buffer_pool::get_instance()->cleanup(); - resegment_test_2(); + if (resegment_test_2()) { + printf("resegment_test_2 failed\n"); + exit(-1); + }; byte_buffer_pool::get_instance()->cleanup(); - resegment_test_3(); + if (resegment_test_3()) { + printf("resegment_test_3 failed\n"); + exit(-1); + }; byte_buffer_pool::get_instance()->cleanup(); - resegment_test_4(); + if (resegment_test_4()) { + printf("resegment_test_4 failed\n"); + exit(-1); + }; byte_buffer_pool::get_instance()->cleanup(); - resegment_test_5(); + if (resegment_test_5()) { + printf("resegment_test_5 failed\n"); + exit(-1); + }; byte_buffer_pool::get_instance()->cleanup(); - resegment_test_6(); - byte_buffer_pool::get_instance()->cleanup(); - resegment_test_7(); + if (resegment_test_6()) { + printf("resegment_test_6 failed\n"); + exit(-1); + }; byte_buffer_pool::get_instance()->cleanup(); - resegment_test_8(); + if (resegment_test_7()) { + printf("resegment_test_7 failed\n"); + exit(-1); + }; byte_buffer_pool::get_instance()->cleanup(); - reset_test(); + if (resegment_test_8()) { + printf("resegment_test_8 failed\n"); + exit(-1); + }; byte_buffer_pool::get_instance()->cleanup(); - stop_test(); + if (reset_test()) { + printf("reset_test failed\n"); + exit(-1); + }; + byte_buffer_pool::get_instance()->cleanup(); + + if (stop_test()) { + printf("stop_test failed\n"); + exit(-1); + }; byte_buffer_pool::get_instance()->cleanup(); } From c0899ddda99b57f87a0e18eb3e82bffb30efe810 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Thu, 26 Jul 2018 09:41:19 +0200 Subject: [PATCH 07/10] refactor RLC AM, add tx/rx subclasses --- lib/include/srslte/upper/rlc_am.h | 283 ++++--- lib/src/upper/rlc_am.cc | 1296 +++++++++++++++++------------ lib/src/upper/rlc_um.cc | 3 +- 3 files changed, 950 insertions(+), 632 deletions(-) diff --git a/lib/include/srslte/upper/rlc_am.h b/lib/include/srslte/upper/rlc_am.h index ab2c6cd63..f771ef607 100644 --- a/lib/include/srslte/upper/rlc_am.h +++ b/lib/include/srslte/upper/rlc_am.h @@ -100,109 +100,204 @@ public: private: - byte_buffer_pool *pool; - srslte::log *log; - uint32_t lcid; - srsue::pdcp_interface_rlc *pdcp; - srsue::rrc_interface_rlc *rrc; + // Transmitter sub-class + class rlc_am_tx : public timer_callback + { + public: + rlc_am_tx(rlc_am *parent_, uint32_t queue_len); + ~rlc_am_tx(); - // TX SDU buffers - rlc_tx_queue tx_sdu_queue; - byte_buffer_t *tx_sdu; - - // PDU being resegmented - rlc_amd_tx_pdu_t tx_pdu_segments; - - // Tx and Rx windows - std::map tx_window; - std::deque retx_queue; - std::map rx_window; - std::map rx_segments; - - // RX SDU buffers - byte_buffer_t *rx_sdu; - - // Mutexes - pthread_mutex_t mutex; - - bool tx_enabled; - bool poll_received; - bool do_status; - rlc_status_pdu_t status; - - // Metrics - uint32_t num_tx_bytes; - uint32_t num_rx_bytes; - - /**************************************************************************** - * Configurable parameters - * Ref: 3GPP TS 36.322 v10.0.0 Section 7 - ***************************************************************************/ - - srslte_rlc_am_config_t cfg; - - /**************************************************************************** - * State variables and counters - * Ref: 3GPP TS 36.322 v10.0.0 Section 7 - ***************************************************************************/ - - // Tx state variables - uint32_t vt_a; // ACK state. SN of next PDU in sequence to be ACKed. Low edge of tx window. - uint32_t vt_ms; // Max send state. High edge of tx window. vt_a + window_size. - uint32_t vt_s; // Send state. SN to be assigned for next PDU. - uint32_t poll_sn; // Poll send state. SN of most recent PDU txed with poll bit set. - - // Tx counters - uint32_t pdu_without_poll; - uint32_t byte_without_poll; - - // Rx state variables - uint32_t vr_r; // Receive state. SN following last in-sequence received PDU. Low edge of rx window - uint32_t vr_mr; // Max acceptable receive state. High edge of rx window. vr_r + window size. - uint32_t vr_x; // t_reordering state. SN following PDU which triggered t_reordering. - uint32_t vr_ms; // Max status tx state. Highest possible value of SN for ACK_SN in status PDU. - uint32_t vr_h; // Highest rx state. SN following PDU with highest SN among rxed PDUs. - - /**************************************************************************** - * Timers - * Ref: 3GPP TS 36.322 v10.0.0 Section 7 - ***************************************************************************/ - timeout poll_retx_timeout; - timeout reordering_timeout; - timeout status_prohibit_timeout; - - static const int reordering_timeout_id = 1; + void init(); + bool configure(srslte_rlc_am_config_t cfg_); - static const int poll_periodicity = 8; // After how many data PDUs a status PDU shall be requested + void empty_queue(); + void reestablish(); + void stop(); + + void write_sdu(byte_buffer_t *sdu, bool blocking); + int read_pdu(uint8_t *payload, uint32_t nof_bytes); + + uint32_t get_buffer_state(); + uint32_t get_total_buffer_state(); + uint32_t get_num_tx_bytes(); + void reset_metrics(); + + // Timeout callback interface + void timer_expired(uint32_t timeout_id); + + // Interface for Rx subclass + void handle_control_pdu(uint8_t *payload, uint32_t nof_bytes); + + private: + + int build_status_pdu(uint8_t *payload, uint32_t nof_bytes); + int build_retx_pdu(uint8_t *payload, uint32_t nof_bytes); + int build_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_retx_t retx); + int build_data_pdu(uint8_t *payload, uint32_t nof_bytes); + + void debug_state(); + + bool retx_queue_has_sn(uint32_t sn); + int required_buffer_size(rlc_amd_retx_t retx); + + // Timer checks + bool status_prohibited; + + // Helpers + bool poll_required(); + bool do_status(); + + rlc_am *parent; + byte_buffer_pool *pool; + srslte::log *log; + + /**************************************************************************** + * Configurable parameters + * Ref: 3GPP TS 36.322 v10.0.0 Section 7 + ***************************************************************************/ + + srslte_rlc_am_config_t cfg; + + // TX SDU buffers + rlc_tx_queue tx_sdu_queue; + byte_buffer_t *tx_sdu;; + + bool tx_enabled; + + /**************************************************************************** + * State variables and counters + * Ref: 3GPP TS 36.322 v10.0.0 Section 7 + ***************************************************************************/ - // Timer checks - bool status_prohibited(); - bool poll_retx(); - void check_reordering_timeout(); + // Tx state variables + uint32_t vt_a; // ACK state. SN of next PDU in sequence to be ACKed. Low edge of tx window. + uint32_t vt_ms; // Max send state. High edge of tx window. vt_a + window_size. + uint32_t vt_s; // Send state. SN to be assigned for next PDU. + uint32_t poll_sn; // Poll send state. SN of most recent PDU txed with poll bit set. - // Helpers - bool poll_required(); + // Tx counters + uint32_t pdu_without_poll; + uint32_t byte_without_poll; - int prepare_status(); - int build_status_pdu(uint8_t *payload, uint32_t nof_bytes); - int build_retx_pdu(uint8_t *payload, uint32_t nof_bytes); - int build_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_retx_t retx); - int build_data_pdu(uint8_t *payload, uint32_t nof_bytes); + rlc_status_pdu_t tx_status; - void handle_data_pdu(uint8_t *payload, uint32_t nof_bytes, rlc_amd_pdu_header_t &header); - void handle_data_pdu_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_pdu_header_t &header); - void handle_control_pdu(uint8_t *payload, uint32_t nof_bytes); + /**************************************************************************** + * Timers + * Ref: 3GPP TS 36.322 v10.0.0 Section 7 + ***************************************************************************/ - void reassemble_rx_sdus(); + srslte::timers::timer *poll_retx_timer; + uint32_t poll_retx_timer_id; - bool inside_tx_window(uint16_t sn); - bool inside_rx_window(uint16_t sn); - void debug_state(); - void print_rx_segments(); + srslte::timers::timer *status_prohibit_timer; + uint32_t status_prohibit_timer_id; - bool add_segment_and_check(rlc_amd_rx_pdu_segments_t *pdu, rlc_amd_rx_pdu_t *segment); - int required_buffer_size(rlc_amd_retx_t retx); - bool retx_queue_has_sn(uint32_t sn); + // Tx windows + std::map tx_window; + std::deque retx_queue; + + // Mutexes + pthread_mutex_t mutex; + + // Metrics + uint32_t num_tx_bytes; + }; + + // Receiver sub-class + class rlc_am_rx : public timer_callback + { + public: + rlc_am_rx(rlc_am* parent_); + ~rlc_am_rx(); + + void init(); + bool configure(srslte_rlc_am_config_t cfg_); + void reestablish(); + void stop(); + + void write_pdu(uint8_t *payload, uint32_t nof_bytes); + + uint32_t get_num_rx_bytes(); + void reset_metrics(); + + // Timeout callback interface + void timer_expired(uint32_t timeout_id); + + // Functions needed by Tx subclass to query rx state + int get_status(rlc_status_pdu_t* status); + bool get_do_status(); + void reset_status(); // called when status PDU has been sent + + private: + void handle_data_pdu(uint8_t *payload, uint32_t nof_bytes, rlc_amd_pdu_header_t &header); + void handle_data_pdu_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_pdu_header_t &header); + void reassemble_rx_sdus(); + bool inside_rx_window(uint16_t sn); + void debug_state(); + void print_rx_segments(); + bool add_segment_and_check(rlc_amd_rx_pdu_segments_t *pdu, rlc_amd_rx_pdu_t *segment); + + rlc_am *parent; + byte_buffer_pool *pool; + srslte::log *log; + + /**************************************************************************** + * Configurable parameters + * Ref: 3GPP TS 36.322 v10.0.0 Section 7 + ***************************************************************************/ + srslte_rlc_am_config_t cfg; + + // RX SDU buffers + byte_buffer_t *rx_sdu; + + /**************************************************************************** + * State variables and counters + * Ref: 3GPP TS 36.322 v10.0.0 Section 7 + ***************************************************************************/ + + // Rx state variables + uint32_t vr_r; // Receive state. SN following last in-sequence received PDU. Low edge of rx window + uint32_t vr_mr; // Max acceptable receive state. High edge of rx window. vr_r + window size. + uint32_t vr_x; // t_reordering state. SN following PDU which triggered t_reordering. + uint32_t vr_ms; // Max status tx state. Highest possible value of SN for ACK_SN in status PDU. + uint32_t vr_h; // Highest rx state. SN following PDU with highest SN among rxed PDUs. + + // Mutexes + pthread_mutex_t mutex; + + // Rx windows + std::map rx_window; + std::map rx_segments; + + // Metrics + uint32_t num_rx_bytes; + + bool poll_received; + bool do_status; + + /**************************************************************************** + * Timers + * Ref: 3GPP TS 36.322 v10.0.0 Section 7 + ***************************************************************************/ + + srslte::timers::timer *reordering_timer; + uint32_t reordering_timer_id; + }; + + // Rx and Tx objects + rlc_am_tx tx; + rlc_am_rx rx; + + // Common variables needed/provided by parent class + srsue::rrc_interface_rlc *rrc; + srslte::log *log; + srsue::pdcp_interface_rlc *pdcp; + mac_interface_timers *mac_timers; + uint32_t lcid; + srslte_rlc_am_config_t cfg; + std::string rb_name; + + static const int poll_periodicity = 8; // After how many data PDUs a status PDU shall be requested }; /**************************************************************************** diff --git a/lib/src/upper/rlc_am.cc b/lib/src/upper/rlc_am.cc index 4b15e9bc5..9932b9c32 100644 --- a/lib/src/upper/rlc_am.cc +++ b/lib/src/upper/rlc_am.cc @@ -33,146 +33,221 @@ #define MOD 1024 #define RX_MOD_BASE(x) ((x-vr_r)%1024) #define TX_MOD_BASE(x) ((x-vt_a)%1024) +#define LCID (parent->lcid) +#define RB_NAME (parent->rb_name.c_str()) namespace srslte { -rlc_am::rlc_am(uint32_t queue_len) : tx_sdu_queue(queue_len) +rlc_am::rlc_am(uint32_t queue_len) + :tx(this, queue_len) + ,rx(this) + ,log(NULL) + ,rrc(NULL) + ,pdcp(NULL) + ,mac_timers(NULL) + ,lcid(0) + ,rb_name("") + ,cfg() { - log = NULL; - pdcp = NULL; - rrc = NULL; - lcid = 0; - bzero(&cfg, sizeof(srslte_rlc_am_config_t)); - - tx_sdu = NULL; - rx_sdu = NULL; - pool = byte_buffer_pool::get_instance(); - - pthread_mutex_init(&mutex, NULL); - - vt_a = 0; - vt_ms = RLC_AM_WINDOW_SIZE; - vt_s = 0; - poll_sn = 0; - - vr_r = 0; - vr_mr = RLC_AM_WINDOW_SIZE; - vr_x = 0; - vr_ms = 0; - vr_h = 0; - - num_tx_bytes = 0; - num_rx_bytes = 0; - - pdu_without_poll = 0; - byte_without_poll = 0; - - poll_received = false; - do_status = false; } -// Warning: must call stop() to properly deallocate all buffers rlc_am::~rlc_am() { - pthread_mutex_destroy(&mutex); - pool = NULL; } void rlc_am::init(srslte::log *log_, uint32_t lcid_, srsue::pdcp_interface_rlc *pdcp_, srsue::rrc_interface_rlc *rrc_, - srslte::mac_interface_timers *mac_timers) + srslte::mac_interface_timers *mac_timers_) { - log = log_; + log = log_; lcid = lcid_; pdcp = pdcp_; - rrc = rrc_; - tx_enabled = true; + rrc = rrc_; + mac_timers = mac_timers_; + + rx.init(); + tx.init(); } bool rlc_am::configure(srslte_rlc_config_t cfg_) { + // determine bearer name and configure Rx/Tx objects + rb_name = rrc->get_rb_name(lcid); + + if (not rx.configure(cfg_.am)) { + return false; + } + + if (not tx.configure(cfg_.am)) { + return false; + } + + // store config cfg = cfg_.am; + log->warning("%s configured: t_poll_retx=%d, poll_pdu=%d, poll_byte=%d, max_retx_thresh=%d, " - "t_reordering=%d, t_status_prohibit=%d\n", - rrc->get_rb_name(lcid).c_str(), cfg.t_poll_retx, cfg.poll_pdu, cfg.poll_byte, cfg.max_retx_thresh, - cfg.t_reordering, cfg.t_status_prohibit); + "t_reordering=%d, t_status_prohibit=%d\n", + rb_name.c_str(), cfg.t_poll_retx, cfg.poll_pdu, cfg.poll_byte, cfg.max_retx_thresh, + cfg.t_reordering, cfg.t_status_prohibit); return true; } - -void rlc_am::empty_queue() { +void rlc_am::empty_queue() +{ // Drop all messages in TX SDU queue - pthread_mutex_lock(&mutex); - byte_buffer_t *buf; - while(tx_sdu_queue.try_read(&buf)) { - pool->deallocate(buf); + tx.empty_queue(); +} + +void rlc_am::reestablish() +{ + tx.reestablish(); // calls stop and enables tx again + rx.reestablish(); // calls only stop +} + +void rlc_am::stop() +{ + tx.stop(); + rx.stop(); +} + +rlc_mode_t rlc_am::get_mode() +{ + return RLC_MODE_AM; +} + +uint32_t rlc_am::get_bearer() +{ + return lcid; +} + +uint32_t rlc_am::get_num_rx_bytes() +{ + return rx.get_num_rx_bytes(); +} + +uint32_t rlc_am::get_num_tx_bytes() +{ + return tx.get_num_tx_bytes(); +} + +void rlc_am::reset_metrics() +{ + tx.reset_metrics(); + rx.reset_metrics(); +} + +/**************************************************************************** + * PDCP interface + ***************************************************************************/ + +void rlc_am::write_sdu(byte_buffer_t *sdu, bool blocking) +{ + tx.write_sdu(sdu, blocking); +} + +/**************************************************************************** + * MAC interface + ***************************************************************************/ + +uint32_t rlc_am::get_buffer_state() +{ + return tx.get_buffer_state(); +} + +uint32_t rlc_am::get_total_buffer_state() +{ + return tx.get_total_buffer_state(); +} + +int rlc_am::read_pdu(uint8_t *payload, uint32_t nof_bytes) +{ + return tx.read_pdu(payload, nof_bytes); +} + +void rlc_am::write_pdu(uint8_t *payload, uint32_t nof_bytes) +{ + rx.write_pdu(payload, nof_bytes); +} + +/**************************************************************************** + * Tx subclass implementation + ***************************************************************************/ + +rlc_am::rlc_am_tx::rlc_am_tx(rlc_am* parent_, uint32_t queue_len_) + :parent(parent_) + ,poll_retx_timer(NULL) + ,poll_retx_timer_id(0) + ,status_prohibit_timer(NULL) + ,status_prohibit_timer_id(0) + ,vt_a(0) + ,vt_ms(RLC_AM_WINDOW_SIZE) + ,vt_s(0) + ,status_prohibited(false) + ,poll_sn(0) + ,num_tx_bytes(0) + ,pdu_without_poll(0) + ,byte_without_poll(0) + ,tx_sdu(NULL) + ,tx_sdu_queue(queue_len_) + ,log(NULL) + ,cfg() + ,pool(byte_buffer_pool::get_instance()) + ,tx_enabled(false) +{ + pthread_mutex_init(&mutex, NULL); +} + +rlc_am::rlc_am_tx::~rlc_am_tx() +{ + pthread_mutex_destroy(&mutex); +} + +void rlc_am::rlc_am_tx::init() +{ + log = parent->log; + + if (parent->mac_timers) { + poll_retx_timer_id = parent->mac_timers->timer_get_unique_id(); + poll_retx_timer = parent->mac_timers->timer_get(poll_retx_timer_id); + + status_prohibit_timer_id = parent->mac_timers->timer_get_unique_id(); + status_prohibit_timer = parent->mac_timers->timer_get(status_prohibit_timer_id); } - tx_sdu_queue.reset(); - pthread_mutex_unlock(&mutex); } -void rlc_am::reestablish() { - stop(); +bool rlc_am::rlc_am_tx::configure(srslte_rlc_am_config_t cfg_) +{ + // TODO: add config checks + cfg = cfg_; + + // check timers + if (not poll_retx_timer or not status_prohibit_timer) { + return false; + } + tx_enabled = true; + + return true; } -void rlc_am::stop() +void rlc_am::rlc_am_tx::stop() { - // Empty tx_sdu_queue before locking the mutex - tx_enabled = false; - usleep(100); + empty_queue(); pthread_mutex_lock(&mutex); - reordering_timeout.reset(); - if(tx_sdu) { - pool->deallocate(tx_sdu); - tx_sdu = NULL; - } - if(rx_sdu) { - pool->deallocate(rx_sdu); - rx_sdu = NULL; - } vt_a = 0; vt_ms = RLC_AM_WINDOW_SIZE; vt_s = 0; poll_sn = 0; - vr_r = 0; - vr_mr = RLC_AM_WINDOW_SIZE; - vr_x = 0; - vr_ms = 0; - vr_h = 0; - pdu_without_poll = 0; byte_without_poll = 0; - poll_received = false; - do_status = false; - - // Drop all messages in RX segments - std::map::iterator rxsegsit; - std::list::iterator segit; - for(rxsegsit = rx_segments.begin(); rxsegsit != rx_segments.end(); rxsegsit++) { - std::list l = rxsegsit->second.segments; - for(segit = l.begin(); segit != l.end(); segit++) { - pool->deallocate(segit->buf); - } - l.clear(); - } - rx_segments.clear(); - - // Drop all messages in RX window - std::map::iterator rxit; - for(rxit = rx_window.begin(); rxit != rx_window.end(); rxit++) { - pool->deallocate(rxit->second.buf); - } - rx_window.clear(); - // Drop all messages in TX window std::map::iterator txit; for(txit = tx_window.begin(); txit != tx_window.end(); txit++) { @@ -185,136 +260,103 @@ void rlc_am::stop() pthread_mutex_unlock(&mutex); } -rlc_mode_t rlc_am::get_mode() +void rlc_am::rlc_am_tx::empty_queue() { - return RLC_MODE_AM; + pthread_mutex_lock(&mutex); + + // deallocate all SDUs in transmit queue + while(tx_sdu_queue.size() > 0) { + byte_buffer_t *buf; + tx_sdu_queue.read(&buf); + pool->deallocate(buf); + } + + // deallocate SDU that is currently processed + if(tx_sdu) { + pool->deallocate(tx_sdu); + tx_sdu = NULL; + } + + pthread_mutex_unlock(&mutex); } -uint32_t rlc_am::get_bearer() +void rlc_am::rlc_am_tx::reestablish() { - return lcid; + stop(); + tx_enabled = true; } -/**************************************************************************** - * PDCP interface - ***************************************************************************/ - -void rlc_am::write_sdu(byte_buffer_t *sdu, bool blocking) +bool rlc_am::rlc_am_tx::do_status() { - if (!tx_enabled) { - byte_buffer_pool::get_instance()->deallocate(sdu); - return; - } - if (sdu) { - if (blocking) { - // block on write to queue - tx_sdu_queue.write(sdu); - log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU (%d B, tx_sdu_queue_len=%d)", rrc->get_rb_name(lcid).c_str(), sdu->N_bytes, tx_sdu_queue.size()); - } else { - // non-blocking write - if (tx_sdu_queue.try_write(sdu)) { - log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU (%d B, tx_sdu_queue_len=%d)", rrc->get_rb_name(lcid).c_str(), sdu->N_bytes, tx_sdu_queue.size()); - } else { - log->info_hex(sdu->msg, sdu->N_bytes, "[Dropped SDU] %s Tx SDU (%d B, tx_sdu_queue_len=%d)", rrc->get_rb_name(lcid).c_str(), sdu->N_bytes, tx_sdu_queue.size()); - pool->deallocate(sdu); - } - } - } else { - log->warning("NULL SDU pointer in write_sdu()\n"); - } + return parent->rx.get_do_status(); } -/**************************************************************************** - * MAC interface - ***************************************************************************/ - -uint32_t rlc_am::get_total_buffer_state() +uint32_t rlc_am::rlc_am_tx::get_buffer_state() { pthread_mutex_lock(&mutex); uint32_t n_bytes = 0; uint32_t n_sdus = 0; // Bytes needed for status report - check_reordering_timeout(); - if(do_status && !status_prohibited()) { - n_bytes += prepare_status(); - log->debug("%s Buffer state - total status report: %d bytes\n", rrc->get_rb_name(lcid).c_str(), n_bytes); + if (do_status() && not status_prohibited) { + n_bytes = parent->rx.get_status(&tx_status); + log->debug("%s Buffer state - status report: %d bytes\n", RB_NAME, n_bytes); + goto unlock_and_return; } // Bytes needed for retx - if(retx_queue.size() > 0) { + if (retx_queue.size() > 0) { rlc_amd_retx_t retx = retx_queue.front(); log->debug("Buffer state - retx - SN: %d, Segment: %s, %d:%d\n", retx.sn, retx.is_segment ? "true" : "false", retx.so_start, retx.so_end); if(tx_window.end() != tx_window.find(retx.sn)) { int req_bytes = required_buffer_size(retx); if (req_bytes < 0) { - log->error("In get_total_buffer_state(): Removing retx.sn=%d from queue\n", retx.sn); + log->error("In get_buffer_state(): Removing retx.sn=%d from queue\n", retx.sn); retx_queue.pop_front(); - } else { - n_bytes += req_bytes; - log->debug("Buffer state - retx: %d bytes\n", n_bytes); + goto unlock_and_return; } + n_bytes = (uint32_t) req_bytes; + log->debug("Buffer state - retx: %d bytes\n", n_bytes); + goto unlock_and_return; } } // Bytes needed for tx SDUs - if(tx_window.size() < 1024) { + if (tx_window.size() < 1024) { n_sdus = tx_sdu_queue.size(); - n_bytes += tx_sdu_queue.size_bytes(); - if(tx_sdu) - { + n_bytes = tx_sdu_queue.size_bytes(); + if (tx_sdu) { n_sdus++; n_bytes += tx_sdu->N_bytes; } } // Room needed for header extensions? (integer rounding) - if(n_sdus > 1) + if (n_sdus > 1) { n_bytes += ((n_sdus-1)*1.5)+0.5; + } // Room needed for fixed header? - if(n_bytes > 0) { + if (n_bytes > 0) { n_bytes += 3; log->debug("Buffer state - tx SDUs: %d bytes\n", n_bytes); } +unlock_and_return: pthread_mutex_unlock(&mutex); return n_bytes; } -uint32_t rlc_am::get_buffer_state() +uint32_t rlc_am::rlc_am_tx::get_total_buffer_state() { pthread_mutex_lock(&mutex); uint32_t n_bytes = 0; uint32_t n_sdus = 0; // Bytes needed for status report - check_reordering_timeout(); - if(do_status && !status_prohibited()) { - n_bytes = prepare_status(); - log->debug("%s Buffer state - status report: %d bytes\n", rrc->get_rb_name(lcid).c_str(), n_bytes); - goto unlock_and_return; - } - - // check if pollRetx timer expired (Section 5.2.2.3 in TS 36.322) - if (poll_retx()) { - // if both tx and retx buffer are empty, retransmit next PDU to be ack'ed - log->debug("Poll reTx timer expired (lcid=%d)\n", lcid); - if ((tx_window.size() > 0 && retx_queue.size() == 0 && tx_sdu_queue.size() == 0)) { - std::map::iterator it = tx_window.find(vt_s - 1); - if (it != tx_window.end()) { - log->info("Schedule last PDU (SN=%d) for reTx.\n", vt_s - 1); - rlc_amd_retx_t retx; - retx.is_segment = false; - retx.so_start = 0; - retx.so_end = tx_window[vt_s - 1].buf->N_bytes; - retx.sn = vt_s - 1; - retx_queue.push_back(retx); - } else { - log->error("Found invalid PDU in tx_window.\n"); - } - poll_retx_timeout.start(cfg.t_poll_retx); - } + if(do_status() && not status_prohibited) { + n_bytes += parent->rx.get_status(&tx_status); + log->debug("%s Buffer state - total status report: %d bytes\n", RB_NAME, n_bytes); } // Bytes needed for retx @@ -324,20 +366,19 @@ uint32_t rlc_am::get_buffer_state() if(tx_window.end() != tx_window.find(retx.sn)) { int req_bytes = required_buffer_size(retx); if (req_bytes < 0) { - log->error("In get_buffer_state(): Removing retx.sn=%d from queue\n", retx.sn); + log->error("In get_total_buffer_state(): Removing retx.sn=%d from queue\n", retx.sn); retx_queue.pop_front(); - goto unlock_and_return; + } else { + n_bytes += req_bytes; + log->debug("Buffer state - retx: %d bytes\n", n_bytes); } - n_bytes = (uint32_t) req_bytes; - log->debug("Buffer state - retx: %d bytes\n", n_bytes); - goto unlock_and_return; } } // Bytes needed for tx SDUs if(tx_window.size() < 1024) { n_sdus = tx_sdu_queue.size(); - n_bytes = tx_sdu_queue.size_bytes(); + n_bytes += tx_sdu_queue.size_bytes(); if(tx_sdu) { n_sdus++; @@ -355,12 +396,36 @@ uint32_t rlc_am::get_buffer_state() log->debug("Buffer state - tx SDUs: %d bytes\n", n_bytes); } -unlock_and_return: pthread_mutex_unlock(&mutex); return n_bytes; } -int rlc_am::read_pdu(uint8_t *payload, uint32_t nof_bytes) +void rlc_am::rlc_am_tx::write_sdu(byte_buffer_t *sdu, bool blocking) +{ + if (!tx_enabled) { + byte_buffer_pool::get_instance()->deallocate(sdu); + return; + } + if (sdu) { + if (blocking) { + // block on write to queue + tx_sdu_queue.write(sdu); + log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU (%d B, tx_sdu_queue_len=%d)", RB_NAME, sdu->N_bytes, tx_sdu_queue.size()); + } else { + // non-blocking write + if (tx_sdu_queue.try_write(sdu)) { + log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU (%d B, tx_sdu_queue_len=%d)", RB_NAME, sdu->N_bytes, tx_sdu_queue.size()); + } else { + log->info_hex(sdu->msg, sdu->N_bytes, "[Dropped SDU] %s Tx SDU (%d B, tx_sdu_queue_len=%d)", RB_NAME, sdu->N_bytes, tx_sdu_queue.size()); + pool->deallocate(sdu); + } + } + } else { + log->warning("NULL SDU pointer in write_sdu()\n"); + } +} + +int rlc_am::rlc_am_tx::read_pdu(uint8_t *payload, uint32_t nof_bytes) { pthread_mutex_lock(&mutex); int pdu_size = 0; @@ -369,7 +434,7 @@ int rlc_am::read_pdu(uint8_t *payload, uint32_t nof_bytes) log->debug("tx_window size - %zu PDUs\n", tx_window.size()); // Tx STATUS if requested - if(do_status && !status_prohibited()) { + if(do_status() && not status_prohibited) { pdu_size = build_status_pdu(payload, nof_bytes); goto unlock_and_exit; } @@ -406,156 +471,109 @@ unlock_and_exit: return pdu_size; } -void rlc_am::write_pdu(uint8_t *payload, uint32_t nof_bytes) +void rlc_am::rlc_am_tx::timer_expired(uint32_t timeout_id) { - if (nof_bytes < 1) return; - pthread_mutex_lock(&mutex); - num_rx_bytes += nof_bytes; - - if(rlc_am_is_control_pdu(payload)) { - handle_control_pdu(payload, nof_bytes); - } else { - rlc_amd_pdu_header_t header; - rlc_am_read_data_pdu_header(&payload, &nof_bytes, &header); - if(header.rf) { - handle_data_pdu_segment(payload, nof_bytes, header); - }else{ - handle_data_pdu(payload, nof_bytes, header); + if (poll_retx_timer_id == timeout_id) { + // if both tx and retx buffer are empty, retransmit next PDU to be ack'ed (Section 5.2.2.3 in TS 36.322) + log->debug("Poll reTx timer expired (lcid=%d)\n", parent->lcid); + if ((tx_window.size() > 0 && retx_queue.size() == 0 && tx_sdu_queue.size() == 0)) { + std::map::iterator it = tx_window.find(vt_s - 1); + if (it != tx_window.end()) { + log->info("Schedule last PDU (SN=%d) for reTx.\n", vt_s - 1); + rlc_amd_retx_t retx; + retx.is_segment = false; + retx.so_start = 0; + retx.so_end = tx_window[vt_s - 1].buf->N_bytes; + retx.sn = vt_s - 1; + retx_queue.push_back(retx); + } else { + log->error("Found invalid PDU in tx_window.\n"); + } } + } else + if (status_prohibit_timer_id == timeout_id) { + status_prohibited = true; + status_prohibit_timer->reset(); } pthread_mutex_unlock(&mutex); } -uint32_t rlc_am::get_num_tx_bytes() +uint32_t rlc_am::rlc_am_tx::get_num_tx_bytes() { return num_tx_bytes; } -uint32_t rlc_am::get_num_rx_bytes() -{ - return num_rx_bytes; -} - -void rlc_am::reset_metrics() +void rlc_am::rlc_am_tx::reset_metrics() { pthread_mutex_lock(&mutex); - num_rx_bytes = 0; num_tx_bytes = 0; pthread_mutex_unlock(&mutex); } - /**************************************************************************** - * Timer checks + * Helper functions ***************************************************************************/ -bool rlc_am::status_prohibited() +bool rlc_am::rlc_am_tx::poll_required() { - return (status_prohibit_timeout.is_running() && !status_prohibit_timeout.expired()); -} - -bool rlc_am::poll_retx() -{ - return (poll_retx_timeout.is_running() && poll_retx_timeout.expired()); -} - -void rlc_am::check_reordering_timeout() -{ - if(reordering_timeout.is_running() && reordering_timeout.expired()) - { - reordering_timeout.reset(); - log->debug("%s reordering timeout expiry - updating vr_ms\n", rrc->get_rb_name(lcid).c_str()); - - // 36.322 v10 Section 5.1.3.2.4 - vr_ms = vr_x; - std::map::iterator it = rx_window.find(vr_ms); - while(rx_window.end() != it) - { - vr_ms = (vr_ms + 1)%MOD; - it = rx_window.find(vr_ms); - } - if(poll_received) - do_status = true; - - if(RX_MOD_BASE(vr_h) > RX_MOD_BASE(vr_ms)) - { - reordering_timeout.start(cfg.t_reordering); - vr_x = vr_h; - } - - debug_state(); + if (cfg.poll_pdu > 0 && pdu_without_poll > (uint32_t)cfg.poll_pdu) { + return true; } -} -/**************************************************************************** - * Helpers - ***************************************************************************/ - -bool rlc_am::poll_required() -{ - if(cfg.poll_pdu > 0 && pdu_without_poll > (uint32_t)cfg.poll_pdu) + if (cfg.poll_byte > 0 && byte_without_poll > (uint32_t)cfg.poll_byte) { return true; - if(cfg.poll_byte > 0 && byte_without_poll > (uint32_t)cfg.poll_byte) - return true; - if(poll_retx()) + } + + if (poll_retx_timer->is_expired()) { + // re-arm timer + poll_retx_timer->reset(); + poll_retx_timer->set(this, cfg.t_poll_retx); + poll_retx_timer->run(); return true; + } - if(tx_sdu_queue.size() == 0 && retx_queue.size() == 0) + if (tx_sdu_queue.size() == 0 && retx_queue.size() == 0) { return true; + } /* According to 5.2.2.1 in 36.322 v13.3.0 a poll should be requested if * the entire AM window is unacknowledged, i.e. no new PDU can be transmitted. * However, it seems more appropiate to request more often if polling * is disabled otherwise, e.g. every N PDUs. */ - if (cfg.poll_pdu == 0 && cfg.poll_byte == 0 && vt_s % poll_periodicity == 0) + if (cfg.poll_pdu == 0 && cfg.poll_byte == 0 && vt_s % poll_periodicity == 0) { return true; - - return false; -} - -int rlc_am::prepare_status() -{ - status.N_nack = 0; - status.ack_sn = vr_ms; - - // We don't use segment NACKs - just NACK the full PDU - - uint32_t i = vr_r; - while(RX_MOD_BASE(i) < RX_MOD_BASE(vr_ms)) - { - if(rx_window.find(i) == rx_window.end()) - status.nacks[status.N_nack++].nack_sn = i; - i = (i + 1)%MOD; } - return rlc_am_packed_length(&status); + return false; } -int rlc_am::build_status_pdu(uint8_t *payload, uint32_t nof_bytes) +int rlc_am::rlc_am_tx::build_status_pdu(uint8_t *payload, uint32_t nof_bytes) { - int pdu_len = rlc_am_packed_length(&status); - if(pdu_len > 0 && nof_bytes >= (uint32_t)pdu_len) + int pdu_len = parent->rx.get_status(&tx_status); + if (pdu_len > 0 && nof_bytes >= (uint32_t)pdu_len) { log->info("%s Tx status PDU - %s\n", - rrc->get_rb_name(lcid).c_str(), rlc_am_to_string(&status).c_str()); + RB_NAME, rlc_am_to_string(&tx_status).c_str()); - do_status = false; - poll_received = false; + parent->rx.reset_status(); - if(cfg.t_status_prohibit > 0) - status_prohibit_timeout.start(cfg.t_status_prohibit); + if(cfg.t_status_prohibit > 0 && status_prohibit_timer) { + status_prohibited = false; + status_prohibit_timer->set(this, cfg.t_status_prohibit); + status_prohibit_timer->run(); + } debug_state(); - return rlc_am_write_status_pdu(&status, payload); + return rlc_am_write_status_pdu(&tx_status, payload); }else{ log->warning("%s Cannot tx status PDU - %d bytes available, %d bytes required\n", - rrc->get_rb_name(lcid).c_str(), nof_bytes, pdu_len); + RB_NAME, nof_bytes, pdu_len); return 0; } } -int rlc_am::build_retx_pdu(uint8_t *payload, uint32_t nof_bytes) +int rlc_am::rlc_am_tx::build_retx_pdu(uint8_t *payload, uint32_t nof_bytes) { // Check there is at least 1 element before calling front() if (retx_queue.empty()) { @@ -584,7 +602,7 @@ int rlc_am::build_retx_pdu(uint8_t *payload, uint32_t nof_bytes) return -1; } if(retx.is_segment || req_size > (int)nof_bytes) { - log->debug("%s build_retx_pdu - resegmentation required\n", rrc->get_rb_name(lcid).c_str()); + log->debug("%s build_retx_pdu - resegmentation required\n", RB_NAME); return build_segment(payload, nof_bytes, retx); } @@ -595,15 +613,17 @@ int rlc_am::build_retx_pdu(uint8_t *payload, uint32_t nof_bytes) // Set poll bit pdu_without_poll++; byte_without_poll += (tx_window[retx.sn].buf->N_bytes + rlc_am_packed_length(&new_header)); - log->info("%s pdu_without_poll: %d\n", rrc->get_rb_name(lcid).c_str(), pdu_without_poll); - log->info("%s byte_without_poll: %d\n", rrc->get_rb_name(lcid).c_str(), byte_without_poll); - if(poll_required()) - { + log->info("%s pdu_without_poll: %d\n", RB_NAME, pdu_without_poll); + log->info("%s byte_without_poll: %d\n", RB_NAME, byte_without_poll); + if (poll_required()) { new_header.p = 1; poll_sn = vt_s; pdu_without_poll = 0; byte_without_poll = 0; - poll_retx_timeout.start(cfg.t_poll_retx); + if (poll_retx_timer) { + poll_retx_timer->set(this, cfg.t_poll_retx); + poll_retx_timer->run(); + } } uint8_t *ptr = payload; @@ -612,16 +632,18 @@ int rlc_am::build_retx_pdu(uint8_t *payload, uint32_t nof_bytes) retx_queue.pop_front(); tx_window[retx.sn].retx_count++; - if(tx_window[retx.sn].retx_count >= cfg.max_retx_thresh) - rrc->max_retx_attempted(); + if (tx_window[retx.sn].retx_count >= cfg.max_retx_thresh) { + parent->rrc->max_retx_attempted(); + } + log->info("%s Retx PDU scheduled for tx. SN: %d, retx count: %d\n", - rrc->get_rb_name(lcid).c_str(), retx.sn, tx_window[retx.sn].retx_count); + RB_NAME, retx.sn, tx_window[retx.sn].retx_count); debug_state(); return (ptr-payload) + tx_window[retx.sn].buf->N_bytes; } -int rlc_am::build_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_retx_t retx) +int rlc_am::rlc_am_tx::build_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_retx_t retx) { if (!tx_window[retx.sn].buf) { log->error("In build_segment: retx.sn=%d has null buffer\n", retx.sn); @@ -638,8 +660,8 @@ int rlc_am::build_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_retx_t r pdu_without_poll++; byte_without_poll += (tx_window[retx.sn].buf->N_bytes + rlc_am_packed_length(&new_header)); - log->info("%s pdu_without_poll: %d\n", rrc->get_rb_name(lcid).c_str(), pdu_without_poll); - log->info("%s byte_without_poll: %d\n", rrc->get_rb_name(lcid).c_str(), byte_without_poll); + log->info("%s pdu_without_poll: %d\n", RB_NAME, pdu_without_poll); + log->info("%s byte_without_poll: %d\n", RB_NAME, byte_without_poll); new_header.dc = RLC_DC_FIELD_DATA_PDU; new_header.rf = 1; @@ -651,12 +673,15 @@ int rlc_am::build_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_retx_t r new_header.p = 0; if(poll_required()) { - log->debug("%s setting poll bit to request status\n", rrc->get_rb_name(lcid).c_str()); + log->debug("%s setting poll bit to request status\n", RB_NAME); new_header.p = 1; poll_sn = vt_s; pdu_without_poll = 0; byte_without_poll = 0; - poll_retx_timeout.start(cfg.t_poll_retx); + if (poll_retx_timer) { + poll_retx_timer->set(this, cfg.t_poll_retx); + poll_retx_timer->run(); + } } uint32_t head_len = 0; @@ -671,7 +696,7 @@ int rlc_am::build_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_retx_t r if(nof_bytes <= head_len) { log->warning("%s Cannot build a PDU segment - %d bytes available, %d bytes required for header\n", - rrc->get_rb_name(lcid).c_str(), nof_bytes, head_len); + RB_NAME, nof_bytes, head_len); return 0; } @@ -748,21 +773,21 @@ int rlc_am::build_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_retx_t r memcpy(ptr, data, len); log->info("%s Retx PDU segment scheduled for tx. SN: %d, SO: %d\n", - rrc->get_rb_name(lcid).c_str(), retx.sn, retx.so_start); + RB_NAME, retx.sn, retx.so_start); debug_state(); int pdu_len = (ptr-payload) + len; if(pdu_len > (int)nof_bytes) { log->error("%s Retx PDU segment length error. Available: %d, Used: %d\n", - rrc->get_rb_name(lcid).c_str(), nof_bytes, pdu_len); + RB_NAME, nof_bytes, pdu_len); log->debug("%s Retx PDU segment length error. Header len: %ld, Payload len: %d, N_li: %d\n", - rrc->get_rb_name(lcid).c_str(), (ptr-payload), len, new_header.N_li); + RB_NAME, (ptr-payload), len, new_header.N_li); } return pdu_len; } -int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) +int rlc_am::rlc_am_tx::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) { if(!tx_sdu && tx_sdu_queue.size() == 0) { @@ -815,13 +840,13 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) if(pdu_space <= head_len + 1) { log->warning("%s Cannot build a PDU - %d bytes available, %d bytes required for header\n", - rrc->get_rb_name(lcid).c_str(), nof_bytes, head_len); + RB_NAME, nof_bytes, head_len); pool->deallocate(pdu); return 0; } log->debug("%s Building PDU - pdu_space: %d, head_len: %d \n", - rrc->get_rb_name(lcid).c_str(), pdu_space, head_len); + RB_NAME, pdu_space, head_len); // Check for SDU segment if(tx_sdu) @@ -836,7 +861,7 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) if(tx_sdu->N_bytes == 0) { log->debug("%s Complete SDU scheduled for tx. Stack latency: %ld us\n", - rrc->get_rb_name(lcid).c_str(), tx_sdu->get_latency_us()); + RB_NAME, tx_sdu->get_latency_us()); pool->deallocate(tx_sdu); tx_sdu = NULL; } @@ -847,7 +872,7 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) header.fi |= RLC_FI_FIELD_NOT_START_ALIGNED; // First byte does not correspond to first byte of SDU log->debug("%s Building PDU - added SDU segment (len:%d) - pdu_space: %d, head_len: %d \n", - rrc->get_rb_name(lcid).c_str(), to_move, pdu_space, head_len); + RB_NAME, to_move, pdu_space, head_len); } // Pull SDUs from queue @@ -871,7 +896,7 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) if(tx_sdu->N_bytes == 0) { log->debug("%s Complete SDU scheduled for tx. Stack latency: %ld us\n", - rrc->get_rb_name(lcid).c_str(), tx_sdu->get_latency_us()); + RB_NAME, tx_sdu->get_latency_us()); pool->deallocate(tx_sdu); tx_sdu = NULL; } @@ -881,7 +906,7 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) pdu_space = 0; log->debug("%s Building PDU - added SDU segment (len:%d) - pdu_space: %d, head_len: %d \n", - rrc->get_rb_name(lcid).c_str(), to_move, pdu_space, head_len); + RB_NAME, to_move, pdu_space, head_len); } // Make sure, at least one SDU (segment) has been added until this point @@ -896,16 +921,19 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) // Set Poll bit pdu_without_poll++; byte_without_poll += (pdu->N_bytes + head_len); - log->debug("%s pdu_without_poll: %d\n", rrc->get_rb_name(lcid).c_str(), pdu_without_poll); - log->debug("%s byte_without_poll: %d\n", rrc->get_rb_name(lcid).c_str(), byte_without_poll); + log->debug("%s pdu_without_poll: %d\n", RB_NAME, pdu_without_poll); + log->debug("%s byte_without_poll: %d\n", RB_NAME, byte_without_poll); if(poll_required()) { - log->debug("%s setting poll bit to request status\n", rrc->get_rb_name(lcid).c_str()); + log->debug("%s setting poll bit to request status\n", RB_NAME); header.p = 1; poll_sn = vt_s; pdu_without_poll = 0; byte_without_poll = 0; - poll_retx_timeout.start(cfg.t_poll_retx); + if (poll_retx_timer) { + poll_retx_timer->set(this, cfg.t_poll_retx); + poll_retx_timer->run(); + } } // Set SN @@ -921,37 +949,37 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) uint8_t *ptr = payload; rlc_am_write_data_pdu_header(&header, &ptr); memcpy(ptr, pdu->msg, pdu->N_bytes); - log->info_hex(payload, pdu->N_bytes, "%s PDU scheduled for tx. SN: %d (%d B)\n", rrc->get_rb_name(lcid).c_str(), header.sn, pdu->N_bytes); + log->info_hex(payload, pdu->N_bytes, "%s PDU scheduled for tx. SN: %d (%d B)\n", RB_NAME, header.sn, pdu->N_bytes); debug_state(); return (ptr-payload) + pdu->N_bytes; } -void rlc_am::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes, rlc_amd_pdu_header_t &header) +void rlc_am::rlc_am_rx::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes, rlc_amd_pdu_header_t &header) { std::map::iterator it; log->info_hex(payload, nof_bytes, "%s Rx data PDU SN: %d (%d B), %s", - rrc->get_rb_name(lcid).c_str(), header.sn, nof_bytes, rlc_fi_field_text[header.fi]); + RB_NAME, header.sn, nof_bytes, rlc_fi_field_text[header.fi]); if(!inside_rx_window(header.sn)) { if(header.p) { - log->info("%s Status packet requested through polling bit\n", rrc->get_rb_name(lcid).c_str()); + log->info("%s Status packet requested through polling bit\n", RB_NAME); do_status = true; } log->info("%s SN: %d outside rx window [%d:%d] - discarding\n", - rrc->get_rb_name(lcid).c_str(), header.sn, vr_r, vr_mr); + RB_NAME, header.sn, vr_r, vr_mr); return; } it = rx_window.find(header.sn); if(rx_window.end() != it) { if(header.p) { - log->info("%s Status packet requested through polling bit\n", rrc->get_rb_name(lcid).c_str()); + log->info("%s Status packet requested through polling bit\n", RB_NAME); do_status = true; } log->info("%s Discarding duplicate SN: %d\n", - rrc->get_rb_name(lcid).c_str(), header.sn); + RB_NAME, header.sn); return; } @@ -971,7 +999,7 @@ void rlc_am::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes, rlc_amd_pdu_h // check available space for payload if (nof_bytes > pdu.buf->get_tailroom()) { log->error("%s Discarding SN: %d of size %d B (available space %d B)\n", - rrc->get_rb_name(lcid).c_str(), header.sn, nof_bytes, pdu.buf->get_tailroom()); + RB_NAME, header.sn, nof_bytes, pdu.buf->get_tailroom()); pool->deallocate(pdu.buf); return; } @@ -982,21 +1010,20 @@ void rlc_am::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes, rlc_amd_pdu_h rx_window[header.sn] = pdu; // Update vr_h - if(RX_MOD_BASE(header.sn) >= RX_MOD_BASE(vr_h)) - vr_h = (header.sn + 1)%MOD; + if(RX_MOD_BASE(header.sn) >= RX_MOD_BASE(vr_h)) { + vr_h = (header.sn + 1) % MOD; + } // Update vr_ms it = rx_window.find(vr_ms); - while(rx_window.end() != it) - { + while(rx_window.end() != it) { vr_ms = (vr_ms + 1)%MOD; it = rx_window.find(vr_ms); } // Check poll bit - if(header.p) - { - log->info("%s Status packet requested through polling bit\n", rrc->get_rb_name(lcid).c_str()); + if(header.p) { + log->info("%s Status packet requested through polling bit\n", RB_NAME); poll_received = true; // 36.322 v10 Section 5.2.3 @@ -1012,40 +1039,328 @@ void rlc_am::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes, rlc_amd_pdu_h reassemble_rx_sdus(); // Update reordering variables and timers (36.322 v10.0.0 Section 5.1.3.2.3) - if(reordering_timeout.is_running()) + if (reordering_timer->is_running()) { + if(vr_x == vr_r || (!inside_rx_window(vr_x) && vr_x != vr_mr)) { + reordering_timer->reset(); + } + } + + if (not reordering_timer->is_running()) { + if(RX_MOD_BASE(vr_h) > RX_MOD_BASE(vr_r)) { + reordering_timer->set(this, cfg.t_reordering); + reordering_timer->run(); + vr_x = vr_h; + } + } + + debug_state(); +} + +void rlc_am::rlc_am_tx::handle_control_pdu(uint8_t *payload, uint32_t nof_bytes) +{ + pthread_mutex_lock(&mutex); + + log->info_hex(payload, nof_bytes, "%s Rx control PDU", RB_NAME); + + rlc_status_pdu_t status; + rlc_am_read_status_pdu(payload, nof_bytes, &status); + + log->info("%s Rx Status PDU: %s\n", RB_NAME, rlc_am_to_string(&status).c_str()); + + poll_retx_timer->reset(); + + // flush retx queue to avoid unordered SNs, we expect the Rx to request lost PDUs again + if (status.N_nack > 0) { + retx_queue.clear(); + } + + // Handle ACKs and NACKs + std::map::iterator it; + bool update_vt_a = true; + uint32_t i = vt_a; + + while(TX_MOD_BASE(i) < TX_MOD_BASE(status.ack_sn) && + TX_MOD_BASE(i) < TX_MOD_BASE(vt_s)) { - if(vr_x == vr_r || (!inside_rx_window(vr_x) && vr_x != vr_mr)) - { - reordering_timeout.reset(); + bool nack = false; + for(uint32_t j=0;jsecond.buf->N_bytes; + + if(status.nacks[j].has_so) { + // sanity check + if (status.nacks[j].so_start >= it->second.buf->N_bytes) { + // print error but try to send original PDU again + log->info("SO_start is larger than original PDU (%d >= %d)\n", + status.nacks[j].so_start, + it->second.buf->N_bytes); + status.nacks[j].so_start = 0; + } + + // check for special SO_end value + if(status.nacks[j].so_end == 0x7FFF) { + status.nacks[j].so_end = it->second.buf->N_bytes; + }else{ + retx.so_end = status.nacks[j].so_end + 1; + } + + if(status.nacks[j].so_start < it->second.buf->N_bytes && + status.nacks[j].so_end <= it->second.buf->N_bytes) { + retx.is_segment = true; + retx.so_start = status.nacks[j].so_start; + } else { + log->warning("%s invalid segment NACK received for SN %d. so_start: %d, so_end: %d, N_bytes: %d\n", + RB_NAME, i, status.nacks[j].so_start, status.nacks[j].so_end, it->second.buf->N_bytes); + } + } + + retx.sn = i; + retx_queue.push_back(retx); + } + } + } + } + + if(!nack) { + //ACKed SNs get marked and removed from tx_window if possible + if(tx_window.count(i) > 0) { + it = tx_window.find(i); + if (it != tx_window.end()) { + if(update_vt_a) { + if(it->second.buf) { + pool->deallocate(it->second.buf); + it->second.buf = 0; + } + tx_window.erase(it); + vt_a = (vt_a + 1)%MOD; + vt_ms = (vt_ms + 1)%MOD; + } + } + } + } + i = (i+1)%MOD; + } + + debug_state(); + + pthread_mutex_unlock(&mutex); +} + + +void rlc_am::rlc_am_tx::debug_state() +{ + log->debug("%s vt_a = %d, vt_ms = %d, vt_s = %d, poll_sn = %d\n", + RB_NAME, vt_a, vt_ms, vt_s, poll_sn); +} + + +int rlc_am::rlc_am_tx::required_buffer_size(rlc_amd_retx_t retx) +{ + if (!retx.is_segment) { + if (tx_window.count(retx.sn)) { + if (tx_window[retx.sn].buf) { + return rlc_am_packed_length(&tx_window[retx.sn].header) + tx_window[retx.sn].buf->N_bytes; + } else { + log->warning("retx.sn=%d has null ptr in required_buffer_size()\n", retx.sn); + return -1; + } + } else { + log->warning("retx.sn=%d does not exist in required_buffer_size()\n", retx.sn); + return -1; + } + } + + // Construct new header + rlc_amd_pdu_header_t new_header; + rlc_amd_pdu_header_t old_header = tx_window[retx.sn].header; + + new_header.dc = RLC_DC_FIELD_DATA_PDU; + new_header.rf = 1; + new_header.p = 0; + new_header.fi = RLC_FI_FIELD_NOT_START_OR_END_ALIGNED; + new_header.sn = old_header.sn; + new_header.lsf = 0; + new_header.so = retx.so_start; + new_header.N_li = 0; + + uint32_t head_len = 0; + + // Need to rebuild the li table & update fi based on so_start and so_end + if(retx.so_start != 0 && rlc_am_start_aligned(old_header.fi)) + new_header.fi &= RLC_FI_FIELD_NOT_END_ALIGNED; // segment is start aligned + + uint32_t lower = 0; + uint32_t upper = 0; + uint32_t li = 0; + + for(uint32_t i=0; i= retx.so_end) + break; + + upper += old_header.li[i]; + + head_len = rlc_am_packed_length(&new_header); + + if(upper > retx.so_start && lower < retx.so_end) { // Current SDU is needed + li = upper - lower; + if(upper > retx.so_end) + li -= upper - retx.so_end; + if(lower < retx.so_start) + li -= retx.so_start - lower; + if(lower > 0 && lower == retx.so_start) + new_header.fi &= RLC_FI_FIELD_NOT_END_ALIGNED; // segment start is aligned with this SDU + if(upper == retx.so_end) { + new_header.fi &= RLC_FI_FIELD_NOT_START_ALIGNED; // segment end is aligned with this SDU + } + new_header.li[new_header.N_li++] = li; + } + + lower += old_header.li[i]; + } + +// if(tx_window[retx.sn].buf->N_bytes != retx.so_end) { +// if(new_header.N_li > 0) +// new_header.N_li--; // No li for last segment +// } + + return rlc_am_packed_length(&new_header) + (retx.so_end-retx.so_start); +} + +bool rlc_am::rlc_am_tx::retx_queue_has_sn(uint32_t sn) +{ + std::deque::iterator q_it; + for(q_it = retx_queue.begin(); q_it != retx_queue.end(); q_it++) { + if(q_it->sn == sn) + return true; + } + return false; +} + + + +/**************************************************************************** + * Rx subclass implementation + ***************************************************************************/ + +rlc_am::rlc_am_rx::rlc_am_rx(rlc_am* parent_) + :parent(parent_) + ,pool(byte_buffer_pool::get_instance()) + ,log(NULL) + ,cfg() + ,reordering_timer(NULL) + ,reordering_timer_id(0) + ,vr_r(0) + ,vr_mr(RLC_AM_WINDOW_SIZE) + ,vr_x(0) + ,vr_ms(0) + ,vr_h(0) + ,num_rx_bytes(0) + ,poll_received(false) + ,do_status(false) + ,rx_sdu(NULL) +{ + pthread_mutex_init(&mutex, NULL); +} + +rlc_am::rlc_am_rx::~rlc_am_rx() +{ + pthread_mutex_destroy(&mutex); +} + +void rlc_am::rlc_am_rx::init() +{ + log = parent->log; + if (parent->mac_timers) { + reordering_timer_id = parent->mac_timers->timer_get_unique_id(); + reordering_timer = parent->mac_timers->timer_get(reordering_timer_id); + } +} + +bool rlc_am::rlc_am_rx::configure(srslte_rlc_am_config_t cfg_) +{ + // TODO: add config checks + cfg = cfg_; + + // check timers + if (not reordering_timer) { + return false; + } + + return true; +} + +void rlc_am::rlc_am_rx::reestablish() +{ + stop(); +} + +void rlc_am::rlc_am_rx::stop() +{ + pthread_mutex_lock(&mutex); + reordering_timer->reset(); + + if (rx_sdu) { + pool->deallocate(rx_sdu); + rx_sdu = NULL; + } + + vr_r = 0; + vr_mr = RLC_AM_WINDOW_SIZE; + vr_x = 0; + vr_ms = 0; + vr_h = 0; + + poll_received = false; + do_status = false; + + // Drop all messages in RX segments + std::map::iterator rxsegsit; + std::list::iterator segit; + for(rxsegsit = rx_segments.begin(); rxsegsit != rx_segments.end(); rxsegsit++) { + std::list l = rxsegsit->second.segments; + for(segit = l.begin(); segit != l.end(); segit++) { + pool->deallocate(segit->buf); } + l.clear(); } - if(!reordering_timeout.is_running()) - { - if(RX_MOD_BASE(vr_h) > RX_MOD_BASE(vr_r)) - { - reordering_timeout.start(cfg.t_reordering); - vr_x = vr_h; - } + rx_segments.clear(); + + // Drop all messages in RX window + std::map::iterator rxit; + for(rxit = rx_window.begin(); rxit != rx_window.end(); rxit++) { + pool->deallocate(rxit->second.buf); } + rx_window.clear(); - debug_state(); + pthread_mutex_unlock(&mutex); } -void rlc_am::handle_data_pdu_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_pdu_header_t &header) + + +void rlc_am::rlc_am_rx::handle_data_pdu_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_pdu_header_t &header) { std::map::iterator it; log->info_hex(payload, nof_bytes, "%s Rx data PDU segment. SN: %d, SO: %d", - rrc->get_rb_name(lcid).c_str(), header.sn, header.so); + RB_NAME, header.sn, header.so); // Check inside rx window if(!inside_rx_window(header.sn)) { if(header.p) { - log->info("%s Status packet requested through polling bit\n", rrc->get_rb_name(lcid).c_str()); + log->info("%s Status packet requested through polling bit\n", RB_NAME); do_status = true; } log->info("%s SN: %d outside rx window [%d:%d] - discarding\n", - rrc->get_rb_name(lcid).c_str(), header.sn, vr_r, vr_mr); + RB_NAME, header.sn, vr_r, vr_mr); return; } @@ -1070,7 +1385,7 @@ void rlc_am::handle_data_pdu_segment(uint8_t *payload, uint32_t nof_bytes, rlc_a if(rx_segments.end() != it) { if(header.p) { - log->info("%s Status packet requested through polling bit\n", rrc->get_rb_name(lcid).c_str()); + log->info("%s Status packet requested through polling bit\n", RB_NAME); do_status = true; } @@ -1100,7 +1415,7 @@ void rlc_am::handle_data_pdu_segment(uint8_t *payload, uint32_t nof_bytes, rlc_a // Check poll bit if(header.p) { - log->info("%s Status packet requested through polling bit\n", rrc->get_rb_name(lcid).c_str()); + log->info("%s Status packet requested through polling bit\n", RB_NAME); poll_received = true; // 36.322 v10 Section 5.2.3 @@ -1118,102 +1433,8 @@ void rlc_am::handle_data_pdu_segment(uint8_t *payload, uint32_t nof_bytes, rlc_a debug_state(); } -void rlc_am::handle_control_pdu(uint8_t *payload, uint32_t nof_bytes) -{ - log->info_hex(payload, nof_bytes, "%s Rx control PDU", rrc->get_rb_name(lcid).c_str()); - - rlc_status_pdu_t status; - rlc_am_read_status_pdu(payload, nof_bytes, &status); - - log->info("%s Rx Status PDU: %s\n", rrc->get_rb_name(lcid).c_str(), rlc_am_to_string(&status).c_str()); - - poll_retx_timeout.reset(); - - // flush retx queue to avoid unordered SNs, we expect the Rx to request lost PDUs again - if (status.N_nack > 0) { - retx_queue.clear(); - } - - // Handle ACKs and NACKs - std::map::iterator it; - bool update_vt_a = true; - uint32_t i = vt_a; - - while(TX_MOD_BASE(i) < TX_MOD_BASE(status.ack_sn) && - TX_MOD_BASE(i) < TX_MOD_BASE(vt_s)) - { - bool nack = false; - for(uint32_t j=0;jsecond.buf->N_bytes; - - if(status.nacks[j].has_so) { - // sanity check - if (status.nacks[j].so_start >= it->second.buf->N_bytes) { - // print error but try to send original PDU again - log->info("SO_start is larger than original PDU (%d >= %d)\n", - status.nacks[j].so_start, - it->second.buf->N_bytes); - status.nacks[j].so_start = 0; - } - - // check for special SO_end value - if(status.nacks[j].so_end == 0x7FFF) { - status.nacks[j].so_end = it->second.buf->N_bytes; - }else{ - retx.so_end = status.nacks[j].so_end + 1; - } - - if(status.nacks[j].so_start < it->second.buf->N_bytes && - status.nacks[j].so_end <= it->second.buf->N_bytes) { - retx.is_segment = true; - retx.so_start = status.nacks[j].so_start; - } else { - log->warning("%s invalid segment NACK received for SN %d. so_start: %d, so_end: %d, N_bytes: %d\n", - rrc->get_rb_name(lcid).c_str(), i, status.nacks[j].so_start, status.nacks[j].so_end, it->second.buf->N_bytes); - } - } - - retx.sn = i; - retx_queue.push_back(retx); - } - } - } - } - - if(!nack) { - //ACKed SNs get marked and removed from tx_window if possible - if(tx_window.count(i) > 0) { - it = tx_window.find(i); - if (it != tx_window.end()) { - if(update_vt_a) { - if(it->second.buf) { - pool->deallocate(it->second.buf); - it->second.buf = 0; - } - tx_window.erase(it); - vt_a = (vt_a + 1)%MOD; - vt_ms = (vt_ms + 1)%MOD; - } - } - } - } - i = (i+1)%MOD; - } - - debug_state(); -} -void rlc_am::reassemble_rx_sdus() +void rlc_am::rlc_am_rx::reassemble_rx_sdus() { uint32_t len = 0; if(!rx_sdu) { @@ -1247,9 +1468,9 @@ void rlc_am::reassemble_rx_sdus() rx_sdu->N_bytes += len; rx_window[vr_r].buf->msg += len; rx_window[vr_r].buf->N_bytes -= len; - log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU (%d B)", rrc->get_rb_name(lcid).c_str(), rx_sdu->N_bytes); + log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU (%d B)", RB_NAME, rx_sdu->N_bytes); rx_sdu->set_timestamp(); - pdcp->write_pdu(lcid, rx_sdu); + parent->pdcp->write_pdu(parent->lcid, rx_sdu); rx_sdu = pool_allocate_blocking; if (!rx_sdu) { @@ -1286,9 +1507,9 @@ void rlc_am::reassemble_rx_sdus() } if(rlc_am_end_aligned(rx_window[vr_r].header.fi)) { - log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU (%d B)", rrc->get_rb_name(lcid).c_str(), rx_sdu->N_bytes); + log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU (%d B)", RB_NAME, rx_sdu->N_bytes); rx_sdu->set_timestamp(); - pdcp->write_pdu(lcid, rx_sdu); + parent->pdcp->write_pdu(parent->lcid, rx_sdu); rx_sdu = pool_allocate_blocking; if (!rx_sdu) { #ifdef RLC_AM_BUFFER_DEBUG @@ -1310,37 +1531,104 @@ exit: } } -bool rlc_am::inside_tx_window(uint16_t sn) +void rlc_am::rlc_am_rx::reset_status() { - if(RX_MOD_BASE(sn) >= RX_MOD_BASE(vt_a) && - RX_MOD_BASE(sn) < RX_MOD_BASE(vt_ms)) - { - return true; - }else{ - return false; + pthread_mutex_lock(&mutex); + do_status = false; + poll_received = false; + pthread_mutex_unlock(&mutex); +} + +bool rlc_am::rlc_am_rx::get_do_status() +{ + return do_status; +} + +uint32_t rlc_am::rlc_am_rx::get_num_rx_bytes() +{ + return num_rx_bytes; +} + +void rlc_am::rlc_am_rx::reset_metrics() +{ + pthread_mutex_lock(&mutex); + num_rx_bytes = 0; + pthread_mutex_unlock(&mutex); +} + +void rlc_am::rlc_am_rx::write_pdu(uint8_t *payload, uint32_t nof_bytes) +{ + if (nof_bytes < 1) return; + + pthread_mutex_lock(&mutex); + num_rx_bytes += nof_bytes; + + if (rlc_am_is_control_pdu(payload)) { + // unlock mutex and pass to Tx subclass + pthread_mutex_unlock(&mutex); + parent->tx.handle_control_pdu(payload, nof_bytes); + } else { + rlc_amd_pdu_header_t header; + rlc_am_read_data_pdu_header(&payload, &nof_bytes, &header); + if (header.rf) { + handle_data_pdu_segment(payload, nof_bytes, header); + } else{ + handle_data_pdu(payload, nof_bytes, header); + } + pthread_mutex_unlock(&mutex); } } -bool rlc_am::inside_rx_window(uint16_t sn) +void rlc_am::rlc_am_rx::timer_expired(uint32_t timeout_id) { - if(RX_MOD_BASE(sn) >= RX_MOD_BASE(vr_r) && - RX_MOD_BASE(sn) < RX_MOD_BASE(vr_mr)) - { - return true; - }else{ - return false; + pthread_mutex_lock(&mutex); + if (reordering_timer_id == timeout_id) { + reordering_timer->reset(); + log->debug("%s reordering timeout expiry - updating vr_ms\n", RB_NAME); + + // 36.322 v10 Section 5.1.3.2.4 + vr_ms = vr_x; + std::map::iterator it = rx_window.find(vr_ms); + while (rx_window.end() != it) { + vr_ms = (vr_ms + 1) % MOD; + it = rx_window.find(vr_ms); + } + + if (poll_received) { + do_status = true; + } + + if (RX_MOD_BASE(vr_h) > RX_MOD_BASE(vr_ms)) { + reordering_timer->set(this, cfg.t_reordering); + reordering_timer->run(); + vr_x = vr_h; + } + + debug_state(); } + pthread_mutex_unlock(&mutex); } -void rlc_am::debug_state() +// Called from Tx object (packs status PDU and returns length of it) +int rlc_am::rlc_am_rx::get_status(rlc_status_pdu_t* status) { - log->debug("%s vt_a = %d, vt_ms = %d, vt_s = %d, poll_sn = %d " - "vr_r = %d, vr_mr = %d, vr_x = %d, vr_ms = %d, vr_h = %d\n", - rrc->get_rb_name(lcid).c_str(), vt_a, vt_ms, vt_s, poll_sn, - vr_r, vr_mr, vr_x, vr_ms, vr_h); + pthread_mutex_lock(&mutex); + status->N_nack = 0; + status->ack_sn = vr_ms; + + // We don't use segment NACKs - just NACK the full PDU + uint32_t i = vr_r; + while(RX_MOD_BASE(i) < RX_MOD_BASE(vr_ms)) { + if(rx_window.find(i) == rx_window.end()) { + status->nacks[status->N_nack++].nack_sn = i; + } + i = (i + 1)%MOD; + } + pthread_mutex_unlock(&mutex); + return rlc_am_packed_length(status); } -void rlc_am::print_rx_segments() +void rlc_am::rlc_am_rx::print_rx_segments() { std::map::iterator it; std::stringstream ss; @@ -1354,7 +1642,7 @@ void rlc_am::print_rx_segments() log->debug("%s\n", ss.str().c_str()); } -bool rlc_am::add_segment_and_check(rlc_amd_rx_pdu_segments_t *pdu, rlc_amd_rx_pdu_t *segment) +bool rlc_am::rlc_am_rx::add_segment_and_check(rlc_amd_rx_pdu_segments_t *pdu, rlc_amd_rx_pdu_t *segment) { // Check for first segment if(0 == segment->header.so) { @@ -1454,88 +1742,24 @@ bool rlc_am::add_segment_and_check(rlc_amd_rx_pdu_segments_t *pdu, rlc_amd_rx_pd return true; } -int rlc_am::required_buffer_size(rlc_amd_retx_t retx) +bool rlc_am::rlc_am_rx::inside_rx_window(uint16_t sn) { - if(!retx.is_segment){ - if (tx_window.count(retx.sn)) { - if (tx_window[retx.sn].buf) { - return rlc_am_packed_length(&tx_window[retx.sn].header) + tx_window[retx.sn].buf->N_bytes; - } else { - log->warning("retx.sn=%d has null ptr in required_buffer_size()\n", retx.sn); - return -1; - } - } else { - log->warning("retx.sn=%d does not exist in required_buffer_size()\n", retx.sn); - return -1; - } - } - - // Construct new header - rlc_amd_pdu_header_t new_header; - rlc_amd_pdu_header_t old_header = tx_window[retx.sn].header; - - new_header.dc = RLC_DC_FIELD_DATA_PDU; - new_header.rf = 1; - new_header.p = 0; - new_header.fi = RLC_FI_FIELD_NOT_START_OR_END_ALIGNED; - new_header.sn = old_header.sn; - new_header.lsf = 0; - new_header.so = retx.so_start; - new_header.N_li = 0; - - uint32_t head_len = 0; - - // Need to rebuild the li table & update fi based on so_start and so_end - if(retx.so_start != 0 && rlc_am_start_aligned(old_header.fi)) - new_header.fi &= RLC_FI_FIELD_NOT_END_ALIGNED; // segment is start aligned - - uint32_t lower = 0; - uint32_t upper = 0; - uint32_t li = 0; - - for(uint32_t i=0; i= retx.so_end) - break; - - upper += old_header.li[i]; - - head_len = rlc_am_packed_length(&new_header); - - if(upper > retx.so_start && lower < retx.so_end) { // Current SDU is needed - li = upper - lower; - if(upper > retx.so_end) - li -= upper - retx.so_end; - if(lower < retx.so_start) - li -= retx.so_start - lower; - if(lower > 0 && lower == retx.so_start) - new_header.fi &= RLC_FI_FIELD_NOT_END_ALIGNED; // segment start is aligned with this SDU - if(upper == retx.so_end) { - new_header.fi &= RLC_FI_FIELD_NOT_START_ALIGNED; // segment end is aligned with this SDU - } - new_header.li[new_header.N_li++] = li; - } - - lower += old_header.li[i]; + if(RX_MOD_BASE(sn) >= RX_MOD_BASE(vr_r) && + RX_MOD_BASE(sn) < RX_MOD_BASE(vr_mr)) + { + return true; + }else{ + return false; } - -// if(tx_window[retx.sn].buf->N_bytes != retx.so_end) { -// if(new_header.N_li > 0) -// new_header.N_li--; // No li for last segment -// } - - return rlc_am_packed_length(&new_header) + (retx.so_end-retx.so_start); } -bool rlc_am::retx_queue_has_sn(uint32_t sn) +void rlc_am::rlc_am_rx::debug_state() { - std::deque::iterator q_it; - for(q_it = retx_queue.begin(); q_it != retx_queue.end(); q_it++) { - if(q_it->sn == sn) - return true; - } - return false; + log->debug("%s vr_r = %d, vr_mr = %d, vr_x = %d, vr_ms = %d, vr_h = %d\n", + RB_NAME, vr_r, vr_mr, vr_x, vr_ms, vr_h); } + /**************************************************************************** * Header pack/unpack helper functions * Ref: 3GPP TS 36.322 v10.0.0 Section 6.2.1 diff --git a/lib/src/upper/rlc_um.cc b/lib/src/upper/rlc_um.cc index 6b2b8d041..c4fa72d2a 100644 --- a/lib/src/upper/rlc_um.cc +++ b/lib/src/upper/rlc_um.cc @@ -149,7 +149,6 @@ void rlc_um::write_sdu(byte_buffer_t *sdu, bool blocking) } else { tx.try_write_sdu(sdu); } - } /**************************************************************************** @@ -199,7 +198,7 @@ void rlc_um::reset_metrics() std::string rlc_um::get_rb_name(srsue::rrc_interface_rlc *rrc, uint32_t lcid, bool is_mrb) { - if(is_mrb) { + if (is_mrb) { std::stringstream ss; ss << "MRB" << lcid; return ss.str(); From f3eceab242b7a2feaeba00a2447fff33d7064ba9 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Fri, 7 Sep 2018 13:08:45 +0200 Subject: [PATCH 08/10] small re-factor of RLC_AM class (reorder methods) --- lib/src/upper/rlc_am.cc | 204 ++++++++++++++++++++-------------------- 1 file changed, 103 insertions(+), 101 deletions(-) diff --git a/lib/src/upper/rlc_am.cc b/lib/src/upper/rlc_am.cc index 9932b9c32..02aedd62f 100644 --- a/lib/src/upper/rlc_am.cc +++ b/lib/src/upper/rlc_am.cc @@ -955,107 +955,6 @@ int rlc_am::rlc_am_tx::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) return (ptr-payload) + pdu->N_bytes; } -void rlc_am::rlc_am_rx::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes, rlc_amd_pdu_header_t &header) -{ - std::map::iterator it; - - log->info_hex(payload, nof_bytes, "%s Rx data PDU SN: %d (%d B), %s", - RB_NAME, header.sn, nof_bytes, rlc_fi_field_text[header.fi]); - - if(!inside_rx_window(header.sn)) { - if(header.p) { - log->info("%s Status packet requested through polling bit\n", RB_NAME); - do_status = true; - } - log->info("%s SN: %d outside rx window [%d:%d] - discarding\n", - RB_NAME, header.sn, vr_r, vr_mr); - return; - } - - it = rx_window.find(header.sn); - if(rx_window.end() != it) { - if(header.p) { - log->info("%s Status packet requested through polling bit\n", RB_NAME); - do_status = true; - } - log->info("%s Discarding duplicate SN: %d\n", - RB_NAME, header.sn); - return; - } - - // Write to rx window - rlc_amd_rx_pdu_t pdu; - pdu.buf = pool_allocate_blocking; - if (!pdu.buf) { -#ifdef RLC_AM_BUFFER_DEBUG - log->console("Fatal Error: Couldn't allocate PDU in handle_data_pdu().\n"); - exit(-1); -#else - log->error("Fatal Error: Couldn't allocate PDU in handle_data_pdu().\n"); - return; -#endif - } - - // check available space for payload - if (nof_bytes > pdu.buf->get_tailroom()) { - log->error("%s Discarding SN: %d of size %d B (available space %d B)\n", - RB_NAME, header.sn, nof_bytes, pdu.buf->get_tailroom()); - pool->deallocate(pdu.buf); - return; - } - memcpy(pdu.buf->msg, payload, nof_bytes); - pdu.buf->N_bytes = nof_bytes; - memcpy(&pdu.header, &header, sizeof(rlc_amd_pdu_header_t)); - - rx_window[header.sn] = pdu; - - // Update vr_h - if(RX_MOD_BASE(header.sn) >= RX_MOD_BASE(vr_h)) { - vr_h = (header.sn + 1) % MOD; - } - - // Update vr_ms - it = rx_window.find(vr_ms); - while(rx_window.end() != it) { - vr_ms = (vr_ms + 1)%MOD; - it = rx_window.find(vr_ms); - } - - // Check poll bit - if(header.p) { - log->info("%s Status packet requested through polling bit\n", RB_NAME); - poll_received = true; - - // 36.322 v10 Section 5.2.3 - if(RX_MOD_BASE(header.sn) < RX_MOD_BASE(vr_ms) || - RX_MOD_BASE(header.sn) >= RX_MOD_BASE(vr_mr)) - { - do_status = true; - } - // else delay for reordering timer - } - - // Reassemble and deliver SDUs - reassemble_rx_sdus(); - - // Update reordering variables and timers (36.322 v10.0.0 Section 5.1.3.2.3) - if (reordering_timer->is_running()) { - if(vr_x == vr_r || (!inside_rx_window(vr_x) && vr_x != vr_mr)) { - reordering_timer->reset(); - } - } - - if (not reordering_timer->is_running()) { - if(RX_MOD_BASE(vr_h) > RX_MOD_BASE(vr_r)) { - reordering_timer->set(this, cfg.t_reordering); - reordering_timer->run(); - vr_x = vr_h; - } - } - - debug_state(); -} - void rlc_am::rlc_am_tx::handle_control_pdu(uint8_t *payload, uint32_t nof_bytes) { pthread_mutex_lock(&mutex); @@ -1345,6 +1244,109 @@ void rlc_am::rlc_am_rx::stop() } +void rlc_am::rlc_am_rx::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes, rlc_amd_pdu_header_t &header) +{ + std::map::iterator it; + + log->info_hex(payload, nof_bytes, "%s Rx data PDU SN: %d (%d B), %s", + RB_NAME, header.sn, nof_bytes, rlc_fi_field_text[header.fi]); + + if(!inside_rx_window(header.sn)) { + if(header.p) { + log->info("%s Status packet requested through polling bit\n", RB_NAME); + do_status = true; + } + log->info("%s SN: %d outside rx window [%d:%d] - discarding\n", + RB_NAME, header.sn, vr_r, vr_mr); + return; + } + + it = rx_window.find(header.sn); + if(rx_window.end() != it) { + if(header.p) { + log->info("%s Status packet requested through polling bit\n", RB_NAME); + do_status = true; + } + log->info("%s Discarding duplicate SN: %d\n", + RB_NAME, header.sn); + return; + } + + // Write to rx window + rlc_amd_rx_pdu_t pdu; + pdu.buf = pool_allocate_blocking; + if (!pdu.buf) { +#ifdef RLC_AM_BUFFER_DEBUG + log->console("Fatal Error: Couldn't allocate PDU in handle_data_pdu().\n"); + exit(-1); +#else + log->error("Fatal Error: Couldn't allocate PDU in handle_data_pdu().\n"); + return; +#endif + } + + // check available space for payload + if (nof_bytes > pdu.buf->get_tailroom()) { + log->error("%s Discarding SN: %d of size %d B (available space %d B)\n", + RB_NAME, header.sn, nof_bytes, pdu.buf->get_tailroom()); + pool->deallocate(pdu.buf); + return; + } + memcpy(pdu.buf->msg, payload, nof_bytes); + pdu.buf->N_bytes = nof_bytes; + memcpy(&pdu.header, &header, sizeof(rlc_amd_pdu_header_t)); + + rx_window[header.sn] = pdu; + + // Update vr_h + if(RX_MOD_BASE(header.sn) >= RX_MOD_BASE(vr_h)) { + vr_h = (header.sn + 1) % MOD; + } + + // Update vr_ms + it = rx_window.find(vr_ms); + while(rx_window.end() != it) { + vr_ms = (vr_ms + 1)%MOD; + it = rx_window.find(vr_ms); + } + + // Check poll bit + if(header.p) { + log->info("%s Status packet requested through polling bit\n", RB_NAME); + poll_received = true; + + // 36.322 v10 Section 5.2.3 + if(RX_MOD_BASE(header.sn) < RX_MOD_BASE(vr_ms) || + RX_MOD_BASE(header.sn) >= RX_MOD_BASE(vr_mr)) + { + do_status = true; + } + // else delay for reordering timer + } + + // Reassemble and deliver SDUs + reassemble_rx_sdus(); + + // Update reordering variables and timers (36.322 v10.0.0 Section 5.1.3.2.3) + if (reordering_timer) { + if (reordering_timer->is_running()) { + if(vr_x == vr_r || (!inside_rx_window(vr_x) && vr_x != vr_mr)) { + reordering_timer->reset(); + } + } + + if (not reordering_timer->is_running()) { + if(RX_MOD_BASE(vr_h) > RX_MOD_BASE(vr_r)) { + reordering_timer->set(this, cfg.t_reordering); + reordering_timer->run(); + vr_x = vr_h; + } + } + } + + debug_state(); +} + void rlc_am::rlc_am_rx::handle_data_pdu_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_pdu_header_t &header) { From 02e38c7c9f7062f461b91a361c6a940bc346bd06 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Fri, 7 Sep 2018 13:10:22 +0200 Subject: [PATCH 09/10] fix stopping of RLC_AM timer and protect access --- lib/src/upper/rlc_am.cc | 40 +++++++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/lib/src/upper/rlc_am.cc b/lib/src/upper/rlc_am.cc index 02aedd62f..3a655c6b8 100644 --- a/lib/src/upper/rlc_am.cc +++ b/lib/src/upper/rlc_am.cc @@ -235,11 +235,22 @@ bool rlc_am::rlc_am_tx::configure(srslte_rlc_am_config_t cfg_) void rlc_am::rlc_am_tx::stop() { - empty_queue(); pthread_mutex_lock(&mutex); + if (parent->mac_timers && poll_retx_timer) { + poll_retx_timer->stop(); + parent->mac_timers->timer_release_id(poll_retx_timer_id); + poll_retx_timer = NULL; + } + + if (parent->mac_timers && status_prohibit_timer) { + status_prohibit_timer->stop(); + parent->mac_timers->timer_release_id(status_prohibit_timer_id); + status_prohibit_timer = NULL; + } + vt_a = 0; vt_ms = RLC_AM_WINDOW_SIZE; vt_s = 0; @@ -474,7 +485,7 @@ unlock_and_exit: void rlc_am::rlc_am_tx::timer_expired(uint32_t timeout_id) { pthread_mutex_lock(&mutex); - if (poll_retx_timer_id == timeout_id) { + if (poll_retx_timer && poll_retx_timer_id == timeout_id) { // if both tx and retx buffer are empty, retransmit next PDU to be ack'ed (Section 5.2.2.3 in TS 36.322) log->debug("Poll reTx timer expired (lcid=%d)\n", parent->lcid); if ((tx_window.size() > 0 && retx_queue.size() == 0 && tx_sdu_queue.size() == 0)) { @@ -492,7 +503,7 @@ void rlc_am::rlc_am_tx::timer_expired(uint32_t timeout_id) } } } else - if (status_prohibit_timer_id == timeout_id) { + if (status_prohibit_timer && status_prohibit_timer_id == timeout_id) { status_prohibited = true; status_prohibit_timer->reset(); } @@ -525,12 +536,14 @@ bool rlc_am::rlc_am_tx::poll_required() return true; } - if (poll_retx_timer->is_expired()) { - // re-arm timer - poll_retx_timer->reset(); - poll_retx_timer->set(this, cfg.t_poll_retx); - poll_retx_timer->run(); - return true; + if (poll_retx_timer) { + if (poll_retx_timer->is_expired()) { + // re-arm timer + poll_retx_timer->reset(); + poll_retx_timer->set(this, cfg.t_poll_retx); + poll_retx_timer->run(); + return true; + } } if (tx_sdu_queue.size() == 0 && retx_queue.size() == 0) { @@ -1205,7 +1218,12 @@ void rlc_am::rlc_am_rx::reestablish() void rlc_am::rlc_am_rx::stop() { pthread_mutex_lock(&mutex); - reordering_timer->reset(); + + if (parent->mac_timers && reordering_timer) { + reordering_timer->stop(); + parent->mac_timers->timer_release_id(reordering_timer_id); + reordering_timer = NULL; + } if (rx_sdu) { pool->deallocate(rx_sdu); @@ -1584,7 +1602,7 @@ void rlc_am::rlc_am_rx::write_pdu(uint8_t *payload, uint32_t nof_bytes) void rlc_am::rlc_am_rx::timer_expired(uint32_t timeout_id) { pthread_mutex_lock(&mutex); - if (reordering_timer_id == timeout_id) { + if (reordering_timer && reordering_timer_id == timeout_id) { reordering_timer->reset(); log->debug("%s reordering timeout expiry - updating vr_ms\n", RB_NAME); From d03f5017dffe7206919743fb4aab3f579eb46c4b Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Fri, 7 Sep 2018 14:04:57 +0200 Subject: [PATCH 10/10] fix RLC mode printf and timer access --- lib/src/upper/rlc.cc | 2 +- lib/src/upper/rlc_am.cc | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/src/upper/rlc.cc b/lib/src/upper/rlc.cc index 237891430..67002fd37 100644 --- a/lib/src/upper/rlc.cc +++ b/lib/src/upper/rlc.cc @@ -440,7 +440,7 @@ void rlc::add_bearer(uint32_t lcid, srslte_rlc_config_t cnfg) rlc_log->error("Error instantiating RLC\n"); goto delete_and_exit; } - rlc_log->warning("Added radio bearer %s with mode %s\n", rrc->get_rb_name(lcid).c_str(), liblte_rrc_rlc_mode_text[cnfg.rlc_mode]); + rlc_log->warning("Added radio bearer %s in %s\n", rrc->get_rb_name(lcid).c_str(), rlc_mode_text[cnfg.rlc_mode]); goto unlock_and_exit; } else { rlc_log->warning("Bearer %s already created.\n", rrc->get_rb_name(lcid).c_str()); diff --git a/lib/src/upper/rlc_am.cc b/lib/src/upper/rlc_am.cc index 3a655c6b8..5c5964288 100644 --- a/lib/src/upper/rlc_am.cc +++ b/lib/src/upper/rlc_am.cc @@ -979,7 +979,9 @@ void rlc_am::rlc_am_tx::handle_control_pdu(uint8_t *payload, uint32_t nof_bytes) log->info("%s Rx Status PDU: %s\n", RB_NAME, rlc_am_to_string(&status).c_str()); - poll_retx_timer->reset(); + if (poll_retx_timer) { + poll_retx_timer->reset(); + } // flush retx queue to avoid unordered SNs, we expect the Rx to request lost PDUs again if (status.N_nack > 0) {