diff --git a/CHANGELOG b/CHANGELOG index 1c4296df6..72831718a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,12 @@ Change Log for Releases ============================== +## 18.06.1 + * Fixed RLC reestablish + * Fixed aperiodic QCI retx + * Fixed eNB instability + * Fixed Debian packaging + ## 18.06 * Added eMBMS support in srsUE/srsENB/srsEPC * Added support for hard SIM cards diff --git a/cmake/modules/SRSLTEVersion.cmake b/cmake/modules/SRSLTEVersion.cmake index db0087290..e79f7f88e 100644 --- a/cmake/modules/SRSLTEVersion.cmake +++ b/cmake/modules/SRSLTEVersion.cmake @@ -20,5 +20,5 @@ SET(SRSLTE_VERSION_MAJOR 18) SET(SRSLTE_VERSION_MINOR 6) -SET(SRSLTE_VERSION_PATCH 0) +SET(SRSLTE_VERSION_PATCH 1) SET(SRSLTE_VERSION_STRING "${SRSLTE_VERSION_MAJOR}.${SRSLTE_VERSION_MINOR}.${SRSLTE_VERSION_PATCH}") diff --git a/debian/changelog b/debian/changelog index 036025343..51063a6db 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,11 +1,17 @@ +srslte (18.06.1-0ubuntu1) bionic; urgency=medium + + * Update to srsLTE 18.06.1 + + -- Andre Puschmann Wed, 18 Jul 2018 11:34:00 +0200 + srslte (18.05~SNAPSHOT-0ubuntu2) bionic; urgency=medium * Update pkg deps - -- Andre Puschmann Tue, 01 June 2018 15:10:00 +0200 + -- Andre Puschmann Tue, 01 Jun 2018 15:10:00 +0200 srslte (18.05~SNAPSHOT-0ubuntu1) bionic; urgency=medium * Initial release of deb's - -- Andre Puschmann Tue, 01 June 2018 14:10:00 +0200 + -- Andre Puschmann Tue, 01 Jun 2018 14:10:00 +0200 diff --git a/debian/control b/debian/control index a20f8df6f..e69e54d61 100644 --- a/debian/control +++ b/debian/control @@ -22,14 +22,13 @@ Vcs-Browser: https://github.com/srsLTE/srsLTE/ Package: srslte Architecture: any Depends: - libfftw3-3 (>= 3.3.3-1), - libboost-program-options1.62.0 (>= 1.62.0), - libmbedcrypto1 (>= 2.8.0-1), - libconfig++9v5 (>= 1.5-0.2), - libsctp1 (>= 1.0.16+dfsg-3), - uhd-host (>= 3.9.2-1), - libuhd003.010.003 (>= 3.10.3.0-2), - ${shlibs:Depends}, + libfftw3-3, + libboost-program-options1.55.0 | libboost-program-options1.62.0, + libmbedcrypto0 | libmbedcrypto1, + libconfig++9v5, + libsctp1, + uhd-host, + libuhd003 | libuhd003.010.003, ${misc:Depends} Description: This is srsLTE, a free and open-source LTE software suite. This software allows you to run a full end-to-end, open-source LTE system. diff --git a/debian/rules b/debian/rules old mode 100644 new mode 100755 index 3b7e3ced4..b1a2e7f2b --- a/debian/rules +++ b/debian/rules @@ -8,8 +8,11 @@ export DH_OPTIONS %: dh $@ --parallel +override_dh_shlibdeps: + dh_shlibdeps --dpkg-shlibdeps-params=--ignore-missing-info + override_dh_auto_configure: - dh_auto_configure --buildsystem=cmake -- $(extraopts) $(CEPH_EXTRA_CMAKE_ARGS) -DCMAKE_BUILD_TYPE=Release + dh_auto_configure --buildsystem=cmake -- $(extraopts) $(CEPH_EXTRA_CMAKE_ARGS) -DCMAKE_BUILD_TYPE=RelWithDebInfo override_dh_auto_test: # skip executing tests diff --git a/lib/examples/CMakeLists.txt b/lib/examples/CMakeLists.txt index 3577af08e..2ab3d45fa 100644 --- a/lib/examples/CMakeLists.txt +++ b/lib/examples/CMakeLists.txt @@ -63,10 +63,10 @@ endif(SRSGUI_FOUND) if(RF_FOUND) add_executable(cell_search cell_search.c) - target_link_libraries(cell_search srslte_phy srslte_rf) + target_link_libraries(cell_search srslte_phy srslte_common srslte_rf) add_executable(cell_measurement cell_measurement.c) - target_link_libraries(cell_measurement srslte_phy srslte_rf) + target_link_libraries(cell_measurement srslte_phy srslte_common srslte_rf) add_executable(usrp_capture usrp_capture.c) target_link_libraries(usrp_capture srslte_phy srslte_rf) diff --git a/lib/examples/cell_measurement.c b/lib/examples/cell_measurement.c index 3185b74f1..421be629c 100644 --- a/lib/examples/cell_measurement.c +++ b/lib/examples/cell_measurement.c @@ -40,6 +40,7 @@ #include "srslte/srslte.h" #include "srslte/phy/rf/rf.h" #include "srslte/phy/rf/rf_utils.h" +#include "srslte/common/crash_handler.h" cell_search_cfg_t cell_detect_config = { SRSLTE_DEFAULT_MAX_FRAMES_PBCH, diff --git a/lib/examples/cell_search.c b/lib/examples/cell_search.c index 025be3c59..7e1a056c7 100644 --- a/lib/examples/cell_search.c +++ b/lib/examples/cell_search.c @@ -38,6 +38,7 @@ #include "srslte/srslte.h" #include "srslte/phy/rf/rf_utils.h" +#include "srslte/common/crash_handler.h" #ifndef DISABLE_RF diff --git a/lib/examples/pdsch_enodeb.c b/lib/examples/pdsch_enodeb.c index 2ecfee771..882273ac2 100644 --- a/lib/examples/pdsch_enodeb.c +++ b/lib/examples/pdsch_enodeb.c @@ -33,6 +33,7 @@ #include #include #include +#include "srslte/common/crash_handler.h" #include #include #include "srslte/common/gen_mch_tables.h" diff --git a/lib/examples/pdsch_ue.c b/lib/examples/pdsch_ue.c index 3b84afb71..91c1bddfe 100644 --- a/lib/examples/pdsch_ue.c +++ b/lib/examples/pdsch_ue.c @@ -37,6 +37,7 @@ #include #include #include "srslte/common/gen_mch_tables.h" +#include "srslte/common/crash_handler.h" #include #include "srslte/phy/io/filesink.h" #include "srslte/srslte.h" @@ -821,7 +822,7 @@ int main(int argc, char **argv) { PRINT_LINE(" nof layers: %d", ue_dl.pdsch_cfg.nof_layers); PRINT_LINE("nof codewords: %d", SRSLTE_RA_DL_GRANT_NOF_TB(&ue_dl.pdsch_cfg.grant)); PRINT_LINE(" CFO: %+7.2f Hz", srslte_ue_sync_get_cfo(&ue_sync)); - PRINT_LINE(" RSRP: %+5.1f dBm | %+5.1f dBm", 10 * log10(rsrp0), 10 * log10(rsrp1)); + PRINT_LINE(" RSRP: %+5.1f dBm | %+5.1f dBm", 10 * log10(rsrp0)+30, 10 * log10(rsrp1)+30); PRINT_LINE(" SNR: %+5.1f dB | %+5.1f dB", 10 * log10(rsrp0 / noise), 10 * log10(rsrp1 / noise)); PRINT_LINE(" Rb: %6.2f / %6.2f / %6.2f Mbps (net/maximum/processing)", uerate, enodebrate, procrate); PRINT_LINE(" PDCCH-Miss: %5.2f%%", 100 * (1 - (float) ue_dl.nof_detected / nof_trials)); diff --git a/lib/include/srslte/common/buffer_pool.h b/lib/include/srslte/common/buffer_pool.h index 0a87c0df1..bfd021d1b 100644 --- a/lib/include/srslte/common/buffer_pool.h +++ b/lib/include/srslte/common/buffer_pool.h @@ -38,6 +38,7 @@ INCLUDES *******************************************************************************/ +#include "srslte/common/log.h" #include "srslte/common/common.h" namespace srslte { @@ -63,6 +64,7 @@ public: nof_buffers = (uint32_t) capacity_; } pthread_mutex_init(&mutex, NULL); + pthread_cond_init(&cv_not_empty, NULL); for(uint32_t i=0;i 0) - { + if (available.size() > 0) { b = available.top(); used.push_back(b); available.pop(); - + if (is_almost_empty()) { - printf("Warning buffer pool capacity is %f %%\n", (float) 100*available.size()/capacity); + printf("Warning buffer pool capacity is %f %%\n", (float) 100 * available.size() / capacity); } #ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED - if (debug_name) { - strncpy(b->debug_name, debug_name, SRSLTE_BUFFER_POOL_LOG_NAME_LEN); - b->debug_name[SRSLTE_BUFFER_POOL_LOG_NAME_LEN-1] = 0; - } + if (debug_name) { + strncpy(b->debug_name, debug_name, SRSLTE_BUFFER_POOL_LOG_NAME_LEN); + b->debug_name[SRSLTE_BUFFER_POOL_LOG_NAME_LEN - 1] = 0; + } #endif - - } else { + } else if (blocking) { + // blocking allocation + while(available.size() == 0) { + pthread_cond_wait(&cv_not_empty, &mutex); + } + + // retrieve the new buffer + b = available.top(); + used.push_back(b); + available.pop(); + + // do not print any warning + } + else { printf("Error - buffer pool is empty\n"); #ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED @@ -148,16 +162,18 @@ public: available.push(b); ret = true; } + pthread_cond_signal(&cv_not_empty); pthread_mutex_unlock(&mutex); return ret; } private: - static const int POOL_SIZE = 2048; + static const int POOL_SIZE = 4096; std::stack available; std::vector used; - pthread_mutex_t mutex; + pthread_mutex_t mutex; + pthread_cond_t cv_not_empty; uint32_t capacity; }; @@ -169,13 +185,17 @@ public: static byte_buffer_pool* get_instance(int capacity = -1); static void cleanup(void); byte_buffer_pool(int capacity = -1) { + log = NULL; pool = new buffer_pool(capacity); } ~byte_buffer_pool() { delete pool; } - byte_buffer_t* allocate(const char *debug_name = NULL) { - return pool->allocate(debug_name); + byte_buffer_t* allocate(const char *debug_name = NULL, bool blocking = false) { + return pool->allocate(debug_name, blocking); + } + void set_log(srslte::log *log) { + this->log = log; } void deallocate(byte_buffer_t *b) { if(!b) { @@ -183,7 +203,11 @@ public: } b->reset(); if (!pool->deallocate(b)) { - printf("Error deallocating PDU: Addr=0x%lx not found in pool\n", (uint64_t) b); + if (log) { + log->error("Deallocating PDU: Addr=0x%lx, name=%s not found in pool\n", (uint64_t) b, b->debug_name); + } else { + printf("Error deallocating PDU: Addr=0x%lx, name=%s not found in pool\n", (uint64_t) b, b->debug_name); + } } b = NULL; } @@ -191,6 +215,7 @@ public: pool->print_all_buffers(); } private: + srslte::log *log; buffer_pool *pool; }; diff --git a/lib/include/srslte/common/common.h b/lib/include/srslte/common/common.h index 3313d0eb4..ed5c9acc1 100644 --- a/lib/include/srslte/common/common.h +++ b/lib/include/srslte/common/common.h @@ -69,6 +69,7 @@ #ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED #define pool_allocate (pool->allocate(__PRETTY_FUNCTION__)) +#define pool_allocate_blocking (pool->allocate(__PRETTY_FUNCTION__, true)) #define SRSLTE_BUFFER_POOL_LOG_NAME_LEN 128 #else #define pool_allocate (pool->allocate()) diff --git a/lib/include/srslte/common/crash_handler.h b/lib/include/srslte/common/crash_handler.h new file mode 100644 index 000000000..dec3940e1 --- /dev/null +++ b/lib/include/srslte/common/crash_handler.h @@ -0,0 +1,50 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsLTE library. + * + * srsLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +/****************************************************************************** + * File: debug.h + * + * Description: Debug output utilities. + * + * Reference: + *****************************************************************************/ + +#ifndef SRSLTE_CRASH_HANDLER_H +#define SRSLTE_CRASH_HANDLER_H + +#include +#include "srslte/config.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void srslte_debug_handle_crash(int argc, char **argv); + +#ifdef __cplusplus +} +#endif // __cplusplus +#endif // SRSLTE_CRASH_HANDLER_H diff --git a/lib/include/srslte/interfaces/ue_interfaces.h b/lib/include/srslte/interfaces/ue_interfaces.h index a4fb2b2cb..959635afc 100644 --- a/lib/include/srslte/interfaces/ue_interfaces.h +++ b/lib/include/srslte/interfaces/ue_interfaces.h @@ -146,7 +146,7 @@ class nas_interface_ue { public: virtual bool attach_request() = 0; - virtual bool deattach_request() = 0; + virtual bool detach_request() = 0; }; // NAS interface for UE @@ -228,8 +228,8 @@ public: class pdcp_interface_gw { public: - virtual void write_sdu(uint32_t lcid, srslte::byte_buffer_t *sdu) = 0; - virtual bool is_drb_enabled(uint32_t lcid) = 0; + virtual void write_sdu(uint32_t lcid, srslte::byte_buffer_t *sdu, bool blocking) = 0; + virtual bool is_lcid_enabled(uint32_t lcid) = 0; }; // PDCP interface for RRC @@ -238,7 +238,7 @@ class pdcp_interface_rrc public: virtual void reestablish() = 0; virtual void reset() = 0; - virtual void write_sdu(uint32_t lcid, srslte::byte_buffer_t *sdu) = 0; + virtual void write_sdu(uint32_t lcid, srslte::byte_buffer_t *sdu, bool blocking = true) = 0; virtual void add_bearer(uint32_t lcid, srslte::srslte_pdcp_config_t cnfg = srslte::srslte_pdcp_config_t()) = 0; virtual void config_security(uint32_t lcid, uint8_t *k_enc_, @@ -251,6 +251,8 @@ public: srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo_) = 0; virtual void enable_integrity(uint32_t lcid) = 0; virtual void enable_encryption(uint32_t lcid) = 0; + virtual uint32_t get_dl_count(uint32_t lcid) = 0; + virtual uint32_t get_ul_count(uint32_t lcid) = 0; }; // PDCP interface for RLC @@ -274,6 +276,7 @@ public: virtual void add_bearer(uint32_t lcid) = 0; virtual void add_bearer(uint32_t lcid, srslte::srslte_rlc_config_t cnfg) = 0; virtual void add_bearer_mrb(uint32_t lcid) = 0; + virtual void del_bearer(uint32_t lcid) = 0; }; // RLC interface for PDCP @@ -282,7 +285,7 @@ class rlc_interface_pdcp public: /* PDCP calls RLC to push an RLC SDU. SDU gets placed into the RLC buffer and MAC pulls * RLC PDUs according to TB size. */ - virtual void write_sdu(uint32_t lcid, srslte::byte_buffer_t *sdu) = 0; + virtual void write_sdu(uint32_t lcid, srslte::byte_buffer_t *sdu, bool blocking = true) = 0; virtual bool rb_is_um(uint32_t lcid) = 0; }; diff --git a/lib/include/srslte/phy/fec/crc.h b/lib/include/srslte/phy/fec/crc.h index 030e7c6bb..9bc864831 100644 --- a/lib/include/srslte/phy/fec/crc.h +++ b/lib/include/srslte/phy/fec/crc.h @@ -63,7 +63,21 @@ SRSLTE_API uint32_t srslte_crc_attach(srslte_crc_t *h, SRSLTE_API uint32_t srslte_crc_attach_byte(srslte_crc_t *h, uint8_t *data, - int len); + int len); + +static inline void srslte_crc_checksum_put_byte(srslte_crc_t *h, uint8_t byte) { + + // Polynom order 8, 16, 24 or 32 only. + int ord = h->order - 8; + uint64_t crc = h->crcinit; + + crc = (crc << 8) ^ h->table[((crc >> (ord)) & 0xff) ^ byte]; + h->crcinit = crc; +} + +static inline uint64_t srslte_crc_checksum_get(srslte_crc_t *h) { + return (h->crcinit & h->crcmask); +} SRSLTE_API uint32_t srslte_crc_checksum_byte(srslte_crc_t *h, uint8_t *data, diff --git a/lib/include/srslte/phy/fec/turbocoder.h b/lib/include/srslte/phy/fec/turbocoder.h index 485e83ff3..4da697461 100644 --- a/lib/include/srslte/phy/fec/turbocoder.h +++ b/lib/include/srslte/phy/fec/turbocoder.h @@ -40,6 +40,7 @@ #include "srslte/config.h" #include "srslte/phy/fec/tc_interl.h" +#include "srslte/phy/fec/crc.h" #define SRSLTE_TCOD_MAX_LEN_CB_BYTES (6144/8) @@ -68,7 +69,8 @@ SRSLTE_API int srslte_tcod_encode(srslte_tcod_t *h, uint8_t *output, uint32_t long_cb); -SRSLTE_API int srslte_tcod_encode_lut(srslte_tcod_t *h, +SRSLTE_API int srslte_tcod_encode_lut(srslte_tcod_t *h, + srslte_crc_t *crc, uint8_t *input, uint8_t *parity, uint32_t cblen_idx); diff --git a/lib/include/srslte/phy/utils/debug.h b/lib/include/srslte/phy/utils/debug.h index 9a07272b6..7fe532eb4 100644 --- a/lib/include/srslte/phy/utils/debug.h +++ b/lib/include/srslte/phy/utils/debug.h @@ -78,6 +78,4 @@ SRSLTE_API extern int handler_registered; else{srslte_phy_log_print(LOG_LEVEL_ERROR, _fmt, ##__VA_ARGS__);} // #endif /* CMAKE_BUILD_TYPE==Debug */ -void srslte_debug_handle_crash(int argc, char **argv); - #endif // SRSLTE_DEBUG_H diff --git a/lib/include/srslte/srslte.h b/lib/include/srslte/srslte.h index f87a1bf2c..c675e0fe7 100644 --- a/lib/include/srslte/srslte.h +++ b/lib/include/srslte/srslte.h @@ -31,7 +31,7 @@ #ifdef __cplusplus extern "C" { #endif - + #include #include @@ -49,7 +49,7 @@ #include "srslte/phy/common/sequence.h" #include "srslte/phy/common/phy_common.h" #include "srslte/phy/common/phy_logger.h" - + #include "srslte/phy/ch_estimation/chest_ul.h" #include "srslte/phy/ch_estimation/chest_dl.h" #include "srslte/phy/ch_estimation/refsignal_dl.h" @@ -104,7 +104,7 @@ #include "srslte/phy/phch/regs.h" #include "srslte/phy/phch/sch.h" #include "srslte/phy/phch/uci.h" - + #include "srslte/phy/ue/ue_sync.h" #include "srslte/phy/ue/ue_mib.h" #include "srslte/phy/ue/ue_cell_search.h" diff --git a/lib/include/srslte/upper/pdcp.h b/lib/include/srslte/upper/pdcp.h index d4cca957a..e4be9d548 100644 --- a/lib/include/srslte/upper/pdcp.h +++ b/lib/include/srslte/upper/pdcp.h @@ -41,7 +41,7 @@ class pdcp { public: pdcp(); - virtual ~pdcp(){} + virtual ~pdcp(); void init(srsue::rlc_interface_pdcp *rlc_, srsue::rrc_interface_pdcp *rrc_, srsue::gw_interface_pdcp *gw_, @@ -51,15 +51,16 @@ public: void stop(); // GW interface - bool is_drb_enabled(uint32_t lcid); + bool is_lcid_enabled(uint32_t lcid); // RRC interface void reestablish(); void reset(); - void write_sdu(uint32_t lcid, byte_buffer_t *sdu); + void write_sdu(uint32_t lcid, byte_buffer_t *sdu, bool blocking = true); void write_sdu_mch(uint32_t lcid, byte_buffer_t *sdu); void add_bearer(uint32_t lcid, srslte_pdcp_config_t cnfg = srslte_pdcp_config_t()); void add_bearer_mrb(uint32_t lcid, srslte_pdcp_config_t cnfg = srslte_pdcp_config_t()); + void del_bearer(uint32_t lcid); void config_security(uint32_t lcid, uint8_t *k_enc, uint8_t *k_int, @@ -71,6 +72,8 @@ public: INTEGRITY_ALGORITHM_ID_ENUM integ_algo); void enable_integrity(uint32_t lcid); void enable_encryption(uint32_t lcid); + uint32_t get_dl_count(uint32_t lcid); + uint32_t get_ul_count(uint32_t lcid); // RLC interface void write_pdu(uint32_t lcid, byte_buffer_t *sdu); @@ -78,18 +81,22 @@ public: void write_pdu_bcch_bch(byte_buffer_t *sdu); void write_pdu_bcch_dlsch(byte_buffer_t *sdu); void write_pdu_pcch(byte_buffer_t *sdu); - private: srsue::rlc_interface_pdcp *rlc; srsue::rrc_interface_pdcp *rrc; srsue::gw_interface_pdcp *gw; - log *pdcp_log; - pdcp_entity pdcp_array[SRSLTE_N_RADIO_BEARERS]; - pdcp_entity pdcp_array_mrb[SRSLTE_N_MCH_LCIDS]; - uint32_t lcid; // default LCID that is maintained active by PDCP instance - uint8_t direction; + typedef std::map pdcp_map_t; + typedef std::pair pdcp_map_pair_t; + + log *pdcp_log; + pdcp_map_t pdcp_array, pdcp_array_mrb; + pthread_rwlock_t rwlock; + + // default PDCP entity that is maintained active by PDCP instance + srslte_pdcp_config_t default_cnfg; + uint32_t default_lcid; bool valid_lcid(uint32_t lcid); bool valid_mch_lcid(uint32_t lcid); diff --git a/lib/include/srslte/upper/pdcp_entity.h b/lib/include/srslte/upper/pdcp_entity.h index de51ed1de..aea49462c 100644 --- a/lib/include/srslte/upper/pdcp_entity.h +++ b/lib/include/srslte/upper/pdcp_entity.h @@ -33,6 +33,7 @@ #include "srslte/interfaces/ue_interfaces.h" #include "srslte/common/security.h" #include "srslte/common/threads.h" +#include "pdcp_interface.h" namespace srslte { @@ -59,7 +60,7 @@ static const char pdcp_d_c_text[PDCP_D_C_N_ITEMS][20] = {"Control PDU", * PDCP Entity interface * Common interface for all PDCP entities ***************************************************************************/ -class pdcp_entity +class pdcp_entity : public pdcp_entity_interface { public: pdcp_entity(); @@ -75,13 +76,15 @@ public: bool is_active(); // RRC interface - void write_sdu(byte_buffer_t *sdu); + void write_sdu(byte_buffer_t *sdu, bool blocking); void config_security(uint8_t *k_enc_, uint8_t *k_int_, CIPHERING_ALGORITHM_ID_ENUM cipher_algo_, INTEGRITY_ALGORITHM_ID_ENUM integ_algo_); void enable_integrity(); void enable_encryption(); + uint32_t get_dl_count(); + uint32_t get_ul_count(); // RLC interface void write_pdu(byte_buffer_t *pdu); diff --git a/lib/include/srslte/upper/pdcp_interface.h b/lib/include/srslte/upper/pdcp_interface.h new file mode 100644 index 000000000..9c4df085e --- /dev/null +++ b/lib/include/srslte/upper/pdcp_interface.h @@ -0,0 +1,75 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#ifndef SRSLTE_PDCP_INTERFACE_H +#define SRSLTE_PDCP_INTERFACE_H + +#include "srslte/common/buffer_pool.h" +#include "srslte/common/log.h" +#include "srslte/common/common.h" +#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/common/security.h" +#include "srslte/common/threads.h" + + +namespace srslte { + +/**************************************************************************** + * Virtual PDCP interface common for all PDCP entities + ***************************************************************************/ +class pdcp_entity_interface +{ +public: + virtual ~pdcp_entity_interface() {}; + virtual void init(srsue::rlc_interface_pdcp *rlc_, + srsue::rrc_interface_pdcp *rrc_, + srsue::gw_interface_pdcp *gw_, + srslte::log *log_, + uint32_t lcid_, + srslte_pdcp_config_t cfg_) = 0; + virtual void reset() = 0; + virtual void reestablish() = 0; + virtual bool is_active() = 0; + + // RRC interface + virtual void write_sdu(byte_buffer_t *sdu, bool blocking) = 0; + virtual void config_security(uint8_t *k_enc_, + uint8_t *k_int_, + CIPHERING_ALGORITHM_ID_ENUM cipher_algo_, + INTEGRITY_ALGORITHM_ID_ENUM integ_algo_) = 0; + virtual void enable_integrity() = 0; + virtual void enable_encryption() = 0; + virtual uint32_t get_dl_count() = 0; + virtual uint32_t get_ul_count() = 0; + + // RLC interface + virtual void write_pdu(byte_buffer_t *pdu) = 0; +}; + +} // namespace srslte + + +#endif // SRSLTE_PDCP_INTERFACE_H diff --git a/lib/include/srslte/upper/rlc.h b/lib/include/srslte/upper/rlc.h index 8d6eb2fd5..a56f48eff 100644 --- a/lib/include/srslte/upper/rlc.h +++ b/lib/include/srslte/upper/rlc.h @@ -31,7 +31,6 @@ #include "srslte/common/log.h" #include "srslte/common/common.h" #include "srslte/interfaces/ue_interfaces.h" -#include "srslte/upper/rlc_entity.h" #include "srslte/upper/rlc_metrics.h" #include "srslte/upper/rlc_common.h" @@ -50,7 +49,7 @@ class rlc { public: rlc(); - virtual ~rlc() {} + virtual ~rlc(); void init(srsue::pdcp_interface_rlc *pdcp_, srsue::rrc_interface_rlc *rrc_, srsue::ue_interface *ue_, @@ -63,8 +62,7 @@ public: void get_metrics(rlc_metrics_t &m); // PDCP interface - void write_sdu(uint32_t lcid, byte_buffer_t *sdu); - void write_sdu_nb(uint32_t lcid, byte_buffer_t *sdu); + void write_sdu(uint32_t lcid, byte_buffer_t *sdu, bool blocking = true); void write_sdu_mch(uint32_t lcid, byte_buffer_t *sdu); bool rb_is_um(uint32_t lcid); @@ -88,7 +86,8 @@ public: void add_bearer(uint32_t lcid); void add_bearer(uint32_t lcid, srslte_rlc_config_t cnfg); void add_bearer_mrb(uint32_t lcid); - void add_bearer_mrb_enb(uint32_t lcid); + void del_bearer(uint32_t lcid); + private: void reset_metrics(); @@ -98,14 +97,17 @@ private: srsue::rrc_interface_rlc *rrc; srslte::mac_interface_timers *mac_timers; srsue::ue_interface *ue; - srslte::rlc_entity rlc_array[SRSLTE_N_RADIO_BEARERS]; - srslte::rlc_um rlc_array_mrb[SRSLTE_N_MCH_LCIDS]; + + typedef std::map rlc_map_t; + typedef std::pair rlc_map_pair_t; + + rlc_map_t rlc_array, rlc_array_mrb; + pthread_rwlock_t rwlock; + uint32_t default_lcid; int buffer_size; - long ul_tput_bytes[SRSLTE_N_RADIO_BEARERS]; - long dl_tput_bytes[SRSLTE_N_RADIO_BEARERS]; - long dl_tput_bytes_mrb[SRSLTE_N_MCH_LCIDS]; + // Timer needed for metrics calculation struct timeval metrics_time[3]; bool valid_lcid(uint32_t lcid); diff --git a/lib/include/srslte/upper/rlc_am.h b/lib/include/srslte/upper/rlc_am.h index cfaee6c5c..ab2c6cd63 100644 --- a/lib/include/srslte/upper/rlc_am.h +++ b/lib/include/srslte/upper/rlc_am.h @@ -66,8 +66,7 @@ struct rlc_amd_retx_t{ }; -class rlc_am - :public rlc_common +class rlc_am : public rlc_common { public: rlc_am(uint32_t queue_len = 16); @@ -77,7 +76,7 @@ public: srsue::pdcp_interface_rlc *pdcp_, srsue::rrc_interface_rlc *rrc_, mac_interface_timers *mac_timers); - void configure(srslte_rlc_config_t cnfg); + bool configure(srslte_rlc_config_t cnfg); void reestablish(); void stop(); @@ -87,8 +86,7 @@ public: uint32_t get_bearer(); // PDCP interface - void write_sdu(byte_buffer_t *sdu); - void write_sdu_nb(byte_buffer_t *sdu); + void write_sdu(byte_buffer_t *sdu, bool blocking = true); // MAC interface uint32_t get_buffer_state(); @@ -96,6 +94,10 @@ public: int read_pdu(uint8_t *payload, uint32_t nof_bytes); void write_pdu(uint8_t *payload, uint32_t nof_bytes); + uint32_t get_num_tx_bytes(); + uint32_t get_num_rx_bytes(); + void reset_metrics(); + private: byte_buffer_pool *pool; @@ -128,6 +130,10 @@ private: 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 diff --git a/lib/include/srslte/upper/rlc_common.h b/lib/include/srslte/upper/rlc_common.h index c9655efae..71fe934df 100644 --- a/lib/include/srslte/upper/rlc_common.h +++ b/lib/include/srslte/upper/rlc_common.h @@ -38,15 +38,7 @@ namespace srslte { #define RLC_AM_WINDOW_SIZE 512 -typedef enum{ - RLC_MODE_TM = 0, - RLC_MODE_UM, - RLC_MODE_AM, - RLC_MODE_N_ITEMS, -}rlc_mode_t; -static const char rlc_mode_text[RLC_MODE_N_ITEMS][20] = {"Transparent Mode", - "Unacknowledged Mode", - "Acknowledged Mode"}; + typedef enum{ RLC_FI_FIELD_START_AND_END_ALIGNED = 0, @@ -161,7 +153,7 @@ public: srsue::pdcp_interface_rlc *pdcp_, srsue::rrc_interface_rlc *rrc_, srslte::mac_interface_timers *mac_timers_) = 0; - virtual void configure(srslte_rlc_config_t cnfg) = 0; + virtual bool configure(srslte_rlc_config_t cnfg) = 0; virtual void stop() = 0; virtual void reestablish() = 0; virtual void empty_queue() = 0; @@ -169,9 +161,12 @@ public: virtual rlc_mode_t get_mode() = 0; virtual uint32_t get_bearer() = 0; + virtual uint32_t get_num_tx_bytes() = 0; + virtual uint32_t get_num_rx_bytes() = 0; + virtual void reset_metrics() = 0; + // PDCP interface - virtual void write_sdu(byte_buffer_t *sdu) = 0; - virtual void write_sdu_nb(byte_buffer_t *sdu) = 0; + virtual void write_sdu(byte_buffer_t *sdu, bool blocking) = 0; // MAC interface virtual uint32_t get_buffer_state() = 0; diff --git a/lib/include/srslte/upper/rlc_entity.h b/lib/include/srslte/upper/rlc_entity.h deleted file mode 100644 index 894572c14..000000000 --- a/lib/include/srslte/upper/rlc_entity.h +++ /dev/null @@ -1,87 +0,0 @@ -/** - * - * \section COPYRIGHT - * - * Copyright 2013-2015 Software Radio Systems Limited - * - * \section LICENSE - * - * This file is part of the srsUE library. - * - * srsUE is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * srsUE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * A copy of the GNU Affero General Public License can be found in - * the LICENSE file in the top-level directory of this distribution - * and at http://www.gnu.org/licenses/. - * - */ - -#ifndef SRSLTE_RLC_ENTITY_H -#define SRSLTE_RLC_ENTITY_H - -#include "srslte/common/log.h" -#include "srslte/common/common.h" -#include "srslte/interfaces/ue_interfaces.h" -#include "srslte/upper/rlc_common.h" -#include "srslte/upper/rlc_tm.h" -#include "srslte/upper/rlc_um.h" -#include "srslte/upper/rlc_am.h" - -namespace srslte { - - - -/**************************************************************************** - * RLC Entity - * Common container for all RLC entities - ***************************************************************************/ -class rlc_entity -{ -public: - rlc_entity(); - void init(rlc_mode_t mode, - log *rlc_entity_log_, - uint32_t lcid_, - srsue::pdcp_interface_rlc *pdcp_, - srsue::rrc_interface_rlc *rrc_, - mac_interface_timers *mac_timers_, - int buffer_size = -1); // use -1 for default buffer sizes - - void configure(srslte_rlc_config_t cnfg); - void reestablish(); - void stop(); - void empty_queue(); - bool active(); - - rlc_mode_t get_mode(); - uint32_t get_bearer(); - - // PDCP interface - void write_sdu(byte_buffer_t *sdu); - void write_sdu_nb(byte_buffer_t *sdu); - - // MAC interface - uint32_t get_buffer_state(); - uint32_t get_total_buffer_state(); - int read_pdu(uint8_t *payload, uint32_t nof_bytes); - void write_pdu(uint8_t *payload, uint32_t nof_bytes); - - -private: - rlc_mode_t mode; - uint32_t lcid; - rlc_common *rlc; -}; - -} // namespace srslte - - -#endif // SRSLTE_RLC_ENTITY_H diff --git a/lib/include/srslte/upper/rlc_interface.h b/lib/include/srslte/upper/rlc_interface.h index b1d211527..4201717dd 100644 --- a/lib/include/srslte/upper/rlc_interface.h +++ b/lib/include/srslte/upper/rlc_interface.h @@ -28,10 +28,19 @@ #define SRSLTE_RLC_INTERFACE_H // for custom constructors -#include "srslte/asn1/liblte_rrc.h" +#include namespace srslte { +typedef enum{ + RLC_MODE_TM = 0, + RLC_MODE_UM, + RLC_MODE_AM, + RLC_MODE_N_ITEMS, +}rlc_mode_t; +static const char rlc_mode_text[RLC_MODE_N_ITEMS][20] = {"Transparent Mode", + "Unacknowledged Mode", + "Acknowledged Mode"}; typedef enum{ RLC_UMD_SN_SIZE_5_BITS = 0, @@ -80,19 +89,22 @@ typedef struct { class srslte_rlc_config_t { public: - LIBLTE_RRC_RLC_MODE_ENUM rlc_mode; + rlc_mode_t rlc_mode; srslte_rlc_am_config_t am; srslte_rlc_um_config_t um; // Default ctor - srslte_rlc_config_t(): rlc_mode(LIBLTE_RRC_RLC_MODE_AM), am(), um() {}; + srslte_rlc_config_t(): rlc_mode(RLC_MODE_TM), am(), um() {}; // Constructor based on liblte's RLC config - srslte_rlc_config_t(LIBLTE_RRC_RLC_CONFIG_STRUCT *cnfg) : rlc_mode(cnfg->rlc_mode), am(), um() + srslte_rlc_config_t(LIBLTE_RRC_RLC_CONFIG_STRUCT *cnfg) : rlc_mode(RLC_MODE_AM), am(), um() { + // update RLC mode to internal mode struct + rlc_mode = (cnfg->rlc_mode == LIBLTE_RRC_RLC_MODE_AM) ? RLC_MODE_AM : RLC_MODE_UM; + switch(rlc_mode) { - case LIBLTE_RRC_RLC_MODE_AM: + case RLC_MODE_AM: am.t_poll_retx = liblte_rrc_t_poll_retransmit_num[cnfg->ul_am_rlc.t_poll_retx]; am.poll_pdu = liblte_rrc_poll_pdu_num[cnfg->ul_am_rlc.poll_pdu]; am.poll_byte = liblte_rrc_poll_byte_num[cnfg->ul_am_rlc.poll_byte]*1000; // KB @@ -100,7 +112,7 @@ public: am.t_reordering = liblte_rrc_t_reordering_num[cnfg->dl_am_rlc.t_reordering]; am.t_status_prohibit = liblte_rrc_t_status_prohibit_num[cnfg->dl_am_rlc.t_status_prohibit]; break; - case LIBLTE_RRC_RLC_MODE_UM_BI: + case RLC_MODE_UM: um.t_reordering = liblte_rrc_t_reordering_num[cnfg->dl_um_bi_rlc.t_reordering]; um.rx_sn_field_length = (rlc_umd_sn_size_t)cnfg->dl_um_bi_rlc.sn_field_len; um.rx_window_size = (RLC_UMD_SN_SIZE_5_BITS == um.rx_sn_field_length) ? 16 : 512; @@ -108,16 +120,6 @@ public: um.tx_sn_field_length = (rlc_umd_sn_size_t)cnfg->ul_um_bi_rlc.sn_field_len; um.tx_mod = (RLC_UMD_SN_SIZE_5_BITS == um.tx_sn_field_length) ? 32 : 1024; break; - case LIBLTE_RRC_RLC_MODE_UM_UNI_UL: - um.tx_sn_field_length = (rlc_umd_sn_size_t)cnfg->ul_um_uni_rlc.sn_field_len; - um.tx_mod = (RLC_UMD_SN_SIZE_5_BITS == um.tx_sn_field_length) ? 32 : 1024; - break; - case LIBLTE_RRC_RLC_MODE_UM_UNI_DL: - um.t_reordering = liblte_rrc_t_reordering_num[cnfg->dl_um_uni_rlc.t_reordering]; - um.rx_sn_field_length = (rlc_umd_sn_size_t)cnfg->dl_um_uni_rlc.sn_field_len; - um.rx_window_size = (RLC_UMD_SN_SIZE_5_BITS == um.rx_sn_field_length) ? 16 : 512; - um.rx_mod = (RLC_UMD_SN_SIZE_5_BITS == um.rx_sn_field_length) ? 32 : 1024; - break; default: // Handle default case break; @@ -128,7 +130,7 @@ public: static srslte_rlc_config_t mch_config() { srslte_rlc_config_t cfg; - cfg.rlc_mode = LIBLTE_RRC_RLC_MODE_UM_UNI_DL; + cfg.rlc_mode = RLC_MODE_UM; cfg.um.t_reordering = 0; cfg.um.rx_sn_field_length = RLC_UMD_SN_SIZE_5_BITS; cfg.um.rx_window_size = 0; diff --git a/lib/include/srslte/upper/rlc_tm.h b/lib/include/srslte/upper/rlc_tm.h index d78ab59c4..b1fa03ac6 100644 --- a/lib/include/srslte/upper/rlc_tm.h +++ b/lib/include/srslte/upper/rlc_tm.h @@ -36,8 +36,7 @@ namespace srslte { -class rlc_tm - :public rlc_common +class rlc_tm : public rlc_common { public: rlc_tm(uint32_t queue_len = 16); @@ -47,7 +46,7 @@ public: srsue::pdcp_interface_rlc *pdcp_, srsue::rrc_interface_rlc *rrc_, mac_interface_timers *mac_timers); - void configure(srslte_rlc_config_t cnfg); + bool configure(srslte_rlc_config_t cnfg); void stop(); void reestablish(); void empty_queue(); @@ -55,9 +54,12 @@ public: rlc_mode_t get_mode(); uint32_t get_bearer(); + uint32_t get_num_tx_bytes(); + uint32_t get_num_rx_bytes(); + void reset_metrics(); + // PDCP interface - void write_sdu(byte_buffer_t *sdu); - void write_sdu_nb(byte_buffer_t *sdu); + void write_sdu(byte_buffer_t *sdu, bool blocking); // MAC interface uint32_t get_buffer_state(); @@ -75,6 +77,9 @@ private: bool tx_enabled; + uint32_t num_tx_bytes; + uint32_t num_rx_bytes; + // Thread-safe queues for MAC messages rlc_tx_queue ul_queue; }; diff --git a/lib/include/srslte/upper/rlc_um.h b/lib/include/srslte/upper/rlc_um.h index f099f60cf..f866417d2 100644 --- a/lib/include/srslte/upper/rlc_um.h +++ b/lib/include/srslte/upper/rlc_um.h @@ -45,8 +45,7 @@ struct rlc_umd_pdu_t{ }; class rlc_um - :public timer_callback - ,public rlc_common + :public rlc_common { public: rlc_um(uint32_t queue_len = 32); @@ -56,18 +55,17 @@ public: srsue::pdcp_interface_rlc *pdcp_, srsue::rrc_interface_rlc *rrc_, mac_interface_timers *mac_timers_); - void configure(srslte_rlc_config_t cnfg); + bool configure(srslte_rlc_config_t cnfg); void reestablish(); void stop(); - void empty_queue(); + void empty_queue(); bool is_mrb(); rlc_mode_t get_mode(); uint32_t get_bearer(); // PDCP interface - void write_sdu(byte_buffer_t *sdu); - void write_sdu_nb(byte_buffer_t *sdu); + void write_sdu(byte_buffer_t *sdu, bool blocking = true); // MAC interface uint32_t get_buffer_state(); @@ -75,72 +73,148 @@ public: int read_pdu(uint8_t *payload, uint32_t nof_bytes); void write_pdu(uint8_t *payload, uint32_t nof_bytes); int get_increment_sequence_num(); - // Timeout callback interface - void timer_expired(uint32_t timeout_id); - bool reordering_timeout_running(); + uint32_t get_num_tx_bytes(); + uint32_t get_num_rx_bytes(); + void reset_metrics(); private: - byte_buffer_pool *pool; - srslte::log *log; - uint32_t lcid; - srsue::pdcp_interface_rlc *pdcp; - srsue::rrc_interface_rlc *rrc; - mac_interface_timers *mac_timers; - - // TX SDU buffers - rlc_tx_queue tx_sdu_queue; - byte_buffer_t *tx_sdu; - byte_buffer_t tx_sdu_temp; - - // Rx window - std::map rx_window; - - // RX SDU buffers - byte_buffer_t *rx_sdu; - uint32_t vr_ur_in_rx_sdu; - - // Mutexes - pthread_mutex_t mutex; - - /**************************************************************************** - * Configurable parameters - * Ref: 3GPP TS 36.322 v10.0.0 Section 7 - ***************************************************************************/ - - srslte_rlc_um_config_t cfg; - - /**************************************************************************** - * State variables and counters - * Ref: 3GPP TS 36.322 v10.0.0 Section 7 - ***************************************************************************/ - - // Tx state variables - uint32_t vt_us; // Send state. SN to be assigned for next PDU. - - // Rx state variables - uint32_t vr_ur; // Receive state. SN of earliest PDU still considered for reordering. - uint32_t vr_ux; // t_reordering state. SN following PDU which triggered t_reordering. - uint32_t vr_uh; // Highest rx state. SN following PDU with highest SN among rxed PDUs. - - /**************************************************************************** - * Timers - * Ref: 3GPP TS 36.322 v10.0.0 Section 7 - ***************************************************************************/ - srslte::timers::timer *reordering_timer; - uint32_t reordering_timer_id; - - bool tx_enabled; - bool pdu_lost; - - int build_data_pdu(uint8_t *payload, uint32_t nof_bytes); - void handle_data_pdu(uint8_t *payload, uint32_t nof_bytes); - void reassemble_rx_sdus(); - bool inside_reordering_window(uint16_t sn); - void debug_state(); - - std::string rb_name(); + // Transmitter sub-class + class rlc_um_tx + { + public: + rlc_um_tx(uint32_t queue_len); + ~rlc_um_tx(); + void init(srslte::log *log_); + bool configure(srslte_rlc_config_t cfg, std::string rb_name); + int build_data_pdu(uint8_t *payload, uint32_t nof_bytes); + void stop(); + void reestablish(); + void empty_queue(); + void write_sdu(byte_buffer_t *sdu); + void try_write_sdu(byte_buffer_t *sdu); + uint32_t get_num_tx_bytes(); + void reset_metrics(); + uint32_t get_buffer_size_bytes(); + + private: + byte_buffer_pool *pool; + srslte::log *log; + std::string rb_name; + + /**************************************************************************** + * Configurable parameters + * Ref: 3GPP TS 36.322 v10.0.0 Section 7 + ***************************************************************************/ + srslte_rlc_um_config_t cfg; + + // TX SDU buffers + rlc_tx_queue tx_sdu_queue; + byte_buffer_t *tx_sdu; + + /**************************************************************************** + * State variables and counters + * Ref: 3GPP TS 36.322 v10.0.0 Section 7 + ***************************************************************************/ + uint32_t vt_us; // Send state. SN to be assigned for next PDU. + + // Mutexes + pthread_mutex_t mutex; + + bool tx_enabled; + + uint32_t num_tx_bytes; + + // helper functions + void debug_state(); + const char* get_rb_name(); + }; + + // Receiver sub-class + class rlc_um_rx : public timer_callback { + public: + rlc_um_rx(); + ~rlc_um_rx(); + void init(srslte::log *log_, + uint32_t lcid_, + srsue::pdcp_interface_rlc *pdcp_, + srsue::rrc_interface_rlc *rrc_, + srslte::mac_interface_timers *mac_timers_); + void stop(); + void reestablish(); + bool configure(srslte_rlc_config_t cfg, std::string rb_name); + void handle_data_pdu(uint8_t *payload, uint32_t nof_bytes); + void reassemble_rx_sdus(); + bool inside_reordering_window(uint16_t sn); + uint32_t get_num_rx_bytes(); + void reset_metrics(); + + // Timeout callback interface + void timer_expired(uint32_t timeout_id); + + private: + byte_buffer_pool *pool; + srslte::log *log; + mac_interface_timers *mac_timers; + std::string rb_name; + + /**************************************************************************** + * Configurable parameters + * Ref: 3GPP TS 36.322 v10.0.0 Section 7 + ***************************************************************************/ + srslte_rlc_um_config_t cfg; + + // Rx window + std::map rx_window; + + // RX SDU buffers + byte_buffer_t *rx_sdu; + uint32_t vr_ur_in_rx_sdu; + + // Rx state variables and counter + uint32_t vr_ur; // Receive state. SN of earliest PDU still considered for reordering. + uint32_t vr_ux; // t_reordering state. SN following PDU which triggered t_reordering. + uint32_t vr_uh; // Highest rx state. SN following PDU with highest SN among rxed PDUs. + bool pdu_lost; + + uint32_t num_rx_bytes; + + // Upper layer handles and variables + srsue::pdcp_interface_rlc *pdcp; + srsue::rrc_interface_rlc *rrc; + uint32_t lcid; + + // Mutexes + pthread_mutex_t mutex; + + bool rx_enabled; + + /**************************************************************************** + * Timers + * Ref: 3GPP TS 36.322 v10.0.0 Section 7 + ***************************************************************************/ + srslte::timers::timer *reordering_timer; + uint32_t reordering_timer_id; + + // helper functions + void debug_state(); + bool reordering_timeout_running(); + const char* get_rb_name(); + }; + + // Rx and Tx objects + rlc_um_tx tx; + rlc_um_rx rx; + + // Common variables needed by parent class + srsue::rrc_interface_rlc *rrc; + srslte::log *log; + uint32_t lcid; + srslte_rlc_um_config_t cfg; + std::string rb_name; + + std::string get_rb_name(srsue::rrc_interface_rlc *rrc, uint32_t lcid, bool is_mrb); }; /**************************************************************************** diff --git a/lib/src/common/crash_handler.c b/lib/src/common/crash_handler.c new file mode 100644 index 000000000..658f70181 --- /dev/null +++ b/lib/src/common/crash_handler.c @@ -0,0 +1,90 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsLTE library. + * + * srsLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include +#include +#include +#include +#include + +#include "srslte/version.h" +#include "srslte/common/crash_handler.h" + +const static char crash_file_name[] = "./srsLTE.backtrace.crash"; +static int bt_argc; +static char **bt_argv; + +static void crash_handler(int sig) { + void *array[128]; + int size; + + + /* Get all stack traces */ + size = backtrace(array, 128); + + FILE *f = fopen(crash_file_name, "a"); + if (!f) { + printf("srsLTE crashed... we could not save backtrace in '%s'...\n", crash_file_name); + } else { + char **symbols = backtrace_symbols(array, size); + + time_t lnTime; + struct tm *stTime; + char strdate[32]; + + time(&lnTime); + stTime = localtime(&lnTime); + + strftime(strdate, 32, "%d/%m/%Y %H:%M:%S", stTime); + + fprintf(f, "--- command='"); + for (int i = 0; i < bt_argc; i++) { + fprintf(f, "%s%s", (i == 0) ? "" : " ", bt_argv[i]); + } + fprintf(f, "' version=%s signal=%d date='%s' ---\n", SRSLTE_VERSION_STRING, sig, strdate); + + for (int i = 0; i < size; i++) { + fprintf(f, "\t%s\n", symbols[i]); + } + fprintf(f, "\n"); + + printf("srsLTE crashed... backtrace saved in '%s'...\n", crash_file_name); + fclose(f); + } + printf("--- exiting ---\n"); + exit(1); +} + +void srslte_debug_handle_crash(int argc, char **argv) { + bt_argc = argc; + bt_argv = argv; + + signal(SIGSEGV, crash_handler); + signal(SIGABRT, crash_handler); + signal(SIGILL, crash_handler); + signal(SIGFPE, crash_handler); + signal(SIGPIPE, crash_handler); +} diff --git a/lib/src/phy/fec/crc.c b/lib/src/phy/fec/crc.c index a2f6d7931..c97bdd6f9 100644 --- a/lib/src/phy/fec/crc.c +++ b/lib/src/phy/fec/crc.c @@ -48,17 +48,6 @@ void gen_crc_table(srslte_crc_t *h) { } } -uint64_t crctable(srslte_crc_t *h, uint8_t byte) { - - // Polynom order 8, 16, 24 or 32 only. - int ord = h->order - 8; - uint64_t crc = h->crcinit; - - crc = (crc << 8) ^ h->table[((crc >> (ord)) & 0xff) ^ byte]; - h->crcinit = crc; - return (crc & h->crcmask); -} - uint64_t reversecrcbit(uint32_t crc, int nbits, srslte_crc_t *h) { uint64_t m, rmask = 0x1; @@ -137,8 +126,9 @@ uint32_t srslte_crc_checksum(srslte_crc_t *h, uint8_t *data, int len) { } else { byte = (uint8_t) (srslte_bit_pack(&pter, 8) & 0xFF); } - crc = crctable(h, byte); + srslte_crc_checksum_put_byte(h, byte); } + crc = (uint32_t) srslte_crc_checksum_get(h); // Reverse CRC res8 positions if (a == 1) { @@ -159,8 +149,9 @@ uint32_t srslte_crc_checksum_byte(srslte_crc_t *h, uint8_t *data, int len) { // Calculate CRC for (i = 0; i < len/8; i++) { - crc = crctable(h, data[i]); + srslte_crc_checksum_put_byte(h, data[i]); } + crc = (uint32_t) srslte_crc_checksum_get(h); return crc; diff --git a/lib/src/phy/fec/rm_turbo.c b/lib/src/phy/fec/rm_turbo.c index b327500c8..3e06a9de2 100644 --- a/lib/src/phy/fec/rm_turbo.c +++ b/lib/src/phy/fec/rm_turbo.c @@ -259,6 +259,7 @@ void srslte_rm_turbo_free_tables () { } rm_turbo_tables_generated = false; } + rm_turbo_tables_generated = false; } /** diff --git a/lib/src/phy/fec/test/turbocoder_test.c b/lib/src/phy/fec/test/turbocoder_test.c index f8219a4e2..59f057919 100644 --- a/lib/src/phy/fec/test/turbocoder_test.c +++ b/lib/src/phy/fec/test/turbocoder_test.c @@ -97,7 +97,7 @@ int main(int argc, char **argv) { } srslte_tcod_encode(&tcod, input_bits, output_bits, long_cb); - srslte_tcod_encode_lut(&tcod, input_bytes, parity, len); + srslte_tcod_encode_lut(&tcod, NULL, input_bytes, parity, len); srslte_bit_unpack_vector(parity, parity_bits, 2*(long_cb+4)); diff --git a/lib/src/phy/fec/turbocoder.c b/lib/src/phy/fec/turbocoder.c index 69f40dd46..e45c9a6b2 100644 --- a/lib/src/phy/fec/turbocoder.c +++ b/lib/src/phy/fec/turbocoder.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "srslte/phy/fec/cbsegm.h" #include "srslte/phy/fec/turbocoder.h" @@ -40,9 +41,13 @@ #define RATE 3 #define TOTALTAIL 12 -uint8_t tcod_lut_next_state[188][8][256]; -uint8_t tcod_lut_output[188][8][256]; -uint16_t tcod_per_fw[188][6144]; +typedef struct { + uint8_t next_state; + uint8_t output; +} tcod_lut_t; + +static tcod_lut_t tcod_lut[8][256]; +static uint16_t tcod_per_fw[188][6144]; static srslte_bit_interleaver_t tcod_interleavers[188]; static bool table_initiated = false; @@ -60,11 +65,12 @@ int srslte_tcod_init(srslte_tcod_t *h, uint32_t max_long_cb) { } void srslte_tcod_free(srslte_tcod_t *h) { + h->max_long_cb = 0; + if (h->temp) { + free(h->temp); + } + if (table_initiated) { - h->max_long_cb = 0; - if (h->temp) { - free(h->temp); - } for (int i = 0; i < 188; i++) { srslte_bit_interleaver_free(&tcod_interleavers[i]); } @@ -187,23 +193,59 @@ int srslte_tcod_encode(srslte_tcod_t *h, uint8_t *input, uint8_t *output, uint32 } /* Expects bytes and produces bytes. The systematic and parity bits are interlaced in the output */ -int srslte_tcod_encode_lut(srslte_tcod_t *h, uint8_t *input, uint8_t *parity, uint32_t cblen_idx) +int srslte_tcod_encode_lut(srslte_tcod_t *h, srslte_crc_t *crc, uint8_t *input, uint8_t *parity, uint32_t cblen_idx) { if (cblen_idx < 188) { - uint32_t long_cb = srslte_cbsegm_cbsize(cblen_idx); + uint32_t long_cb = (uint32_t) srslte_cbsegm_cbsize(cblen_idx); if (long_cb % 8) { fprintf(stderr, "Turbo coder LUT implementation long_cb must be multiple of 8\n"); return -1; } - + + /* Reset CRC */ + if (crc) { + srslte_crc_set_init(crc, 0); + } + /* Parity bits for the 1st constituent encoders */ - uint8_t state0 = 0; - for (uint32_t i=0;iorder) / 8; i++) { + uint8_t in = input[i]; + + /* Put byte in CRC and save latest checksum */ + srslte_crc_checksum_put_byte(crc, in); + + /* Run actual encoder */ + tcod_lut_t l = tcod_lut[state0][in]; + parity[i] = l.output; + state0 = l.next_state; + } + + uint32_t checksum = (uint32_t) srslte_crc_checksum_get(crc); + for (int i = 0; i < crc->order / 8; i++) { + int mask_shift = 8 * (crc->order / 8 - i - 1); + int idx = (long_cb - crc->order) / 8 + i; + uint8_t in = (uint8_t) ((checksum >> mask_shift) & 0xff); + + input[idx] = in; + tcod_lut_t l = tcod_lut[state0][in]; + parity[idx] = l.output; + state0 = l.next_state; + } + + } else { + /* No CRC given */ + for (uint32_t i = 0; i < long_cb / 8; i++) { + tcod_lut_t l = tcod_lut[state0][input[i]]; + parity[i] = l.output; + state0 = l.next_state; + } } - parity[long_cb/8] = 0; // will put tail here later + parity[long_cb / 8] = 0; // will put tail here later /* Interleave input */ srslte_bit_interleaver_run(&tcod_interleavers[cblen_idx], input, h->temp, 0); @@ -212,10 +254,11 @@ int srslte_tcod_encode_lut(srslte_tcod_t *h, uint8_t *input, uint8_t *parity, ui /* Parity bits for the 2nd constituent encoders */ uint8_t state1 = 0; for (uint32_t i=0;itemp[i]]; + tcod_lut_t l = tcod_lut[state1][h->temp[i]]; + uint8_t out = l.output; parity[long_cb/8+i] |= (out&0xf0)>>4; - parity[long_cb/8+i+1] = (out&0xf)<<4; - state1 = tcod_lut_next_state[cblen_idx][state1][h->temp[i]] % 8; + parity[long_cb/8+i+1] = (out&0xf)<<4; + state1 = l.next_state; } /* Tail bits */ @@ -302,40 +345,40 @@ void srslte_tcod_gentable() { return; } // Save fw/bw permutation tables - for (uint32_t i=0;i>2; - reg_1 = (state&2)>>1; - reg_2 = state&1; - - tcod_lut_output[len][state][data] = 0; - uint8_t bit, in, out; - for (uint32_t i = 0; i < 8; i++) { - bit = (data&(1<<(7-i)))?1:0; - - in = bit ^ (reg_2 ^ reg_1); - out = reg_2 ^ (reg_0 ^ in); - - reg_2 = reg_1; - reg_1 = reg_0; - reg_0 = in; - - tcod_lut_output[len][state][data] |= out<<(7-i); - - } - tcod_lut_next_state[len][state][data] = reg_0<<2 | reg_1<<1 | reg_2; + } + // Compute state transitions + for (uint32_t state=0;state<8;state++) { + for (uint32_t data=0;data<256;data++) { + + uint8_t reg_0, reg_1, reg_2; + reg_0 = (state&4)>>2; + reg_1 = (state&2)>>1; + reg_2 = state&1; + + tcod_lut[state][data].output = 0; + uint8_t bit, in, out; + for (uint32_t i = 0; i < 8; i++) { + bit = (data&(1<<(7-i)))?1:0; + + in = bit ^ (reg_2 ^ reg_1); + out = reg_2 ^ (reg_0 ^ in); + + reg_2 = reg_1; + reg_1 = reg_0; + reg_0 = in; + + tcod_lut[state][data].output |= out<<(7-i); + } - } + tcod_lut[state][data].next_state = (uint8_t) ((reg_0 << 2 | reg_1 << 1 | reg_2) % 8); + } } srslte_tc_interl_free(&interl); diff --git a/lib/src/phy/phch/pdsch.c b/lib/src/phy/phch/pdsch.c index b38cfdbd8..e6dd9f52b 100644 --- a/lib/src/phy/phch/pdsch.c +++ b/lib/src/phy/phch/pdsch.c @@ -427,6 +427,8 @@ int srslte_pdsch_set_rnti(srslte_pdsch_t *q, uint16_t rnti) { return -1; } } + q->users[rnti_idx]->sequence_generated = false; + for (int i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { for (int j = 0; j < SRSLTE_MAX_CODEWORDS; j++) { if (srslte_sequence_pdsch(&q->users[rnti_idx]->seq[j][i], rnti, j, 2 * i, q->cell.id, diff --git a/lib/src/phy/phch/pusch.c b/lib/src/phy/phch/pusch.c index aa049f7c0..43bd08537 100644 --- a/lib/src/phy/phch/pusch.c +++ b/lib/src/phy/phch/pusch.c @@ -444,6 +444,7 @@ int srslte_pusch_set_rnti(srslte_pusch_t *q, uint16_t rnti) { return -1; } } + q->users[rnti_idx]->sequence_generated = false; for (i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { if (srslte_sequence_pusch(&q->users[rnti_idx]->seq[i], rnti, 2 * i, q->cell.id, q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM))) diff --git a/lib/src/phy/phch/sch.c b/lib/src/phy/phch/sch.c index aa1f297d7..2d7290e9d 100644 --- a/lib/src/phy/phch/sch.c +++ b/lib/src/phy/phch/sch.c @@ -264,15 +264,12 @@ static int encode_tb_off(srslte_sch_t *q, /* Append Transport Block parity bits to the last CB */ memcpy(q->cb_in, &data[rp/8], (rlen - 24) * sizeof(uint8_t)/8); memcpy(&q->cb_in[(rlen - 24)/8], parity, 3 * sizeof(uint8_t)); - } - - /* Attach Codeblock CRC */ - if (cb_segm->C > 1) { - srslte_crc_attach_byte(&q->crc_cb, q->cb_in, rlen); } - /* Turbo Encoding */ - srslte_tcod_encode_lut(&q->encoder, q->cb_in, q->parity_bits, cblen_idx); + /* Turbo Encoding + * If Codeblock CRC is required it is given the CRC instance pointer, otherwise CRC pointer shall be NULL + */ + srslte_tcod_encode_lut(&q->encoder, (cb_segm->C > 1) ? &q->crc_cb : NULL, q->cb_in, q->parity_bits, cblen_idx); } DEBUG("RM cblen_idx=%d, n_e=%d, wp=%d, nof_e_bits=%d\n",cblen_idx, n_e, wp, nof_e_bits); diff --git a/lib/src/phy/rf/rf_uhd_imp.c b/lib/src/phy/rf/rf_uhd_imp.c index 7fe291497..202b47b8d 100644 --- a/lib/src/phy/rf/rf_uhd_imp.c +++ b/lib/src/phy/rf/rf_uhd_imp.c @@ -371,12 +371,13 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels) clock_src = DEFAULT; } +#if HAVE_ASYNC_THREAD bool start_async_thread = true; - if (strstr(args, "silent")) { REMOVE_SUBSTRING_WITHCOMAS(args, "silent"); start_async_thread = false; } +#endif // Set over the wire format char *otw_format = "sc16"; @@ -615,8 +616,13 @@ int rf_uhd_close(void *h) uhd_tx_metadata_free(&handler->tx_md); uhd_rx_metadata_free(&handler->rx_md_first); uhd_rx_metadata_free(&handler->rx_md); - handler->async_thread_running = false; - pthread_join(handler->async_thread, NULL); + +#if HAVE_ASYNC_THREAD + if (handler->async_thread_running) { + handler->async_thread_running = false; + pthread_join(handler->async_thread, NULL); + } +#endif uhd_tx_streamer_free(&handler->tx_stream); uhd_rx_streamer_free(&handler->rx_stream); @@ -797,7 +803,7 @@ int rf_uhd_recv_with_time_multi(void *h, rxd_samples = 0; uhd_error error = uhd_rx_streamer_recv(handler->rx_stream, buffs_ptr, - num_rx_samples, md, 0.5, false, &rxd_samples); + num_rx_samples, md, 1.0, false, &rxd_samples); if (error) { fprintf(stderr, "Error receiving from UHD: %d\n", error); log_rx_error(handler); @@ -907,7 +913,7 @@ int rf_uhd_send_timed_multi(void *h, buffs_ptr[i] = buff; } uhd_error error = uhd_tx_streamer_send(handler->tx_stream, buffs_ptr, - tx_samples, &handler->tx_md, 0.5, &txd_samples); + tx_samples, &handler->tx_md, 1.0, &txd_samples); if (error) { fprintf(stderr, "Error sending to UHD: %d\n", error); goto unlock; diff --git a/lib/src/phy/utils/debug.c b/lib/src/phy/utils/debug.c index 4b65e8d6d..dc37800cd 100644 --- a/lib/src/phy/utils/debug.c +++ b/lib/src/phy/utils/debug.c @@ -24,14 +24,8 @@ * */ -#include -#include -#include -#include #include - #include "srslte/phy/utils/debug.h" -#include "srslte/version.h" int srslte_verbose = 0; int handler_registered = 0; @@ -45,57 +39,3 @@ void get_time_interval(struct timeval * tdata) { tdata[0].tv_usec += 1000000; } } - -const static char crash_file_name[] = "./srsLTE.backtrace.crash"; -static int bt_argc; -static char **bt_argv; - -static void crash_handler(int sig) { - void *array[128]; - int size; - - /* Get all stack traces */ - size = backtrace(array, 128); - - FILE *f = fopen(crash_file_name, "a"); - if (!f) { - printf("srsLTE crashed... we could not save backtrace in '%s'...\n", crash_file_name); - } else { - char **symbols = backtrace_symbols(array, size); - - time_t lnTime; - struct tm *stTime; - char strdate[32]; - - time(&lnTime); - stTime = localtime(&lnTime); - - strftime(strdate, 32, "%d/%m/%Y %H:%M:%S", stTime); - - fprintf(f, "--- command='"); - for (int i = 0; i < bt_argc; i++) { - fprintf(f, "%s%s", (i == 0) ? "" : " ", bt_argv[i]); - } - fprintf(f, "' version=%s signal=%d date='%s' ---\n", SRSLTE_VERSION_STRING, sig, strdate); - - for (int i = 0; i < size; i++) { - fprintf(f, "\t%s\n", symbols[i]); - } - fprintf(f, "\n"); - - printf("srsLTE crashed... backtrace saved in '%s'...\n", crash_file_name); - fclose(f); - } - printf("--- exiting ---\n"); - exit(1); -} - -void srslte_debug_handle_crash(int argc, char **argv) { - bt_argc = argc; - bt_argv = argv; - - signal(SIGSEGV, crash_handler); - signal(SIGABRT, crash_handler); - signal(SIGILL, crash_handler); - signal(SIGFPE, crash_handler); -} diff --git a/lib/src/upper/pdcp.cc b/lib/src/upper/pdcp.cc index e577a12ce..c8391518b 100644 --- a/lib/src/upper/pdcp.cc +++ b/lib/src/upper/pdcp.cc @@ -35,114 +35,170 @@ pdcp::pdcp() rrc = NULL; gw = NULL; pdcp_log = NULL; - lcid = 0; - direction = 0; + default_lcid = 0; + pthread_rwlock_init(&rwlock, NULL); +} + +pdcp::~pdcp() +{ + // destroy all remaining entities + pthread_rwlock_wrlock(&rwlock); + for (pdcp_map_t::iterator it = pdcp_array.begin(); it != pdcp_array.end(); ++it) { + delete(it->second); + } + pdcp_array.clear(); + + pthread_rwlock_unlock(&rwlock); + pthread_rwlock_destroy(&rwlock); } void pdcp::init(srsue::rlc_interface_pdcp *rlc_, srsue::rrc_interface_pdcp *rrc_, srsue::gw_interface_pdcp *gw_, log *pdcp_log_, uint32_t lcid_, uint8_t direction_) { - rlc = rlc_; - rrc = rrc_; - gw = gw_; - pdcp_log = pdcp_log_; - lcid = lcid_; - direction = direction_; + rlc = rlc_; + rrc = rrc_; + gw = gw_; + pdcp_log = pdcp_log_; + default_lcid = lcid_; // Default config - srslte_pdcp_config_t cnfg; - cnfg.is_control = false; - cnfg.is_data = false; - cnfg.direction = direction_; + default_cnfg.is_control = false; + default_cnfg.is_data = false; + default_cnfg.direction = direction_; - pdcp_array[0].init(rlc, rrc, gw, pdcp_log, lcid, cnfg); + // create default PDCP entity for SRB0 + add_bearer(0, default_cnfg); } void pdcp::stop() { + // destroy default entity + pthread_rwlock_wrlock(&rwlock); + if (valid_lcid(0)) { + pdcp_map_t::iterator it = pdcp_array.find(0); + delete(it->second); + pdcp_array.erase(it); + } + pthread_rwlock_unlock(&rwlock); } void pdcp::reestablish() { - for(uint32_t i=0;isecond->reestablish(); } + pthread_rwlock_unlock(&rwlock); } void pdcp::reset() { - for(uint32_t i=0;isecond->reset(); + delete(it->second); + pdcp_array.erase(it); } + pthread_rwlock_unlock(&rwlock); - pdcp_array[0].init(rlc, rrc, gw, pdcp_log, lcid, direction); + // add default SRB0 again + add_bearer(0, default_cnfg); } /******************************************************************************* RRC/GW interface *******************************************************************************/ -bool pdcp::is_drb_enabled(uint32_t lcid) +bool pdcp::is_lcid_enabled(uint32_t lcid) { - if(lcid >= SRSLTE_N_RADIO_BEARERS) { - pdcp_log->error("Radio bearer id must be in [0:%d] - %d\n", SRSLTE_N_RADIO_BEARERS, lcid); - return false; + pthread_rwlock_rdlock(&rwlock); + bool ret = false; + if (valid_lcid(lcid)) { + ret = pdcp_array.at(lcid)->is_active(); } - return pdcp_array[lcid].is_active(); + pthread_rwlock_unlock(&rwlock); + return ret; } -void pdcp::write_sdu(uint32_t lcid, byte_buffer_t *sdu) +void pdcp::write_sdu(uint32_t lcid, byte_buffer_t *sdu, bool blocking) { - if(valid_lcid(lcid)) { - pdcp_array[lcid].write_sdu(sdu); + pthread_rwlock_rdlock(&rwlock); + if (valid_lcid(lcid)) { + pdcp_array.at(lcid)->write_sdu(sdu, blocking); } else { pdcp_log->warning("Writing sdu: lcid=%d. Deallocating sdu\n", lcid); byte_buffer_pool::get_instance()->deallocate(sdu); } + pthread_rwlock_unlock(&rwlock); } void pdcp::write_sdu_mch(uint32_t lcid, byte_buffer_t *sdu) { - if(valid_mch_lcid(lcid)){ - pdcp_array_mrb[lcid].write_sdu(sdu); + pthread_rwlock_rdlock(&rwlock); + if (valid_mch_lcid(lcid)){ + pdcp_array_mrb.at(lcid)->write_sdu(sdu, true); } + pthread_rwlock_unlock(&rwlock); } + void pdcp::add_bearer(uint32_t lcid, srslte_pdcp_config_t cfg) { - if(lcid >= SRSLTE_N_RADIO_BEARERS) { - pdcp_log->error("Radio bearer id must be in [0:%d] - %d\n", SRSLTE_N_RADIO_BEARERS, lcid); - return; - } - if (!pdcp_array[lcid].is_active()) { - pdcp_array[lcid].init(rlc, rrc, gw, pdcp_log, lcid, cfg); + pthread_rwlock_wrlock(&rwlock); + if (not valid_lcid(lcid)) { + if (not pdcp_array.insert(pdcp_map_pair_t(lcid, new pdcp_entity())).second) { + pdcp_log->error("Error inserting PDCP entity in to array\n."); + goto unlock_and_exit; + } + pdcp_array.at(lcid)->init(rlc, rrc, gw, pdcp_log, lcid, cfg); pdcp_log->info("Added bearer %s\n", rrc->get_rb_name(lcid).c_str()); } else { pdcp_log->warning("Bearer %s already configured. Reconfiguration not supported\n", rrc->get_rb_name(lcid).c_str()); } +unlock_and_exit: + pthread_rwlock_unlock(&rwlock); } - void pdcp::add_bearer_mrb(uint32_t lcid, srslte_pdcp_config_t cfg) { - if(lcid >= SRSLTE_N_RADIO_BEARERS) { - pdcp_log->error("Radio bearer id must be in [0:%d] - %d\n", SRSLTE_N_RADIO_BEARERS, lcid); - return; - } - if (!pdcp_array_mrb[lcid].is_active()) { - pdcp_array_mrb[lcid].init(rlc, rrc, gw, pdcp_log, lcid, cfg); + pthread_rwlock_wrlock(&rwlock); + if (not valid_mch_lcid(lcid)) { + if (not pdcp_array_mrb.insert(pdcp_map_pair_t(lcid, new pdcp_entity())).second) { + pdcp_log->error("Error inserting PDCP entity in to array\n."); + goto unlock_and_exit; + } + pdcp_array_mrb.at(lcid)->init(rlc, rrc, gw, pdcp_log, lcid, cfg); pdcp_log->info("Added bearer %s\n", rrc->get_rb_name(lcid).c_str()); } else { pdcp_log->warning("Bearer %s already configured. Reconfiguration not supported\n", rrc->get_rb_name(lcid).c_str()); } +unlock_and_exit: + pthread_rwlock_unlock(&rwlock); +} + +void pdcp::del_bearer(uint32_t lcid) +{ + pthread_rwlock_wrlock(&rwlock); + if (valid_lcid(lcid)) { + pdcp_map_t::iterator it = pdcp_array.find(lcid); + delete(it->second); + pdcp_array.erase(it); + pdcp_log->warning("Deleted PDCP bearer %s\n", rrc->get_rb_name(lcid).c_str()); + } else { + pdcp_log->warning("Can't delete bearer %s. Bearer doesn't exist.\n", rrc->get_rb_name(lcid).c_str()); + } + pthread_rwlock_unlock(&rwlock); } + void pdcp::config_security(uint32_t lcid, uint8_t *k_enc, uint8_t *k_int, CIPHERING_ALGORITHM_ID_ENUM cipher_algo, INTEGRITY_ALGORITHM_ID_ENUM integ_algo) { - if(valid_lcid(lcid)) - pdcp_array[lcid].config_security(k_enc, k_int, cipher_algo, integ_algo); + pthread_rwlock_rdlock(&rwlock); + if (valid_lcid(lcid)) { + pdcp_array.at(lcid)->config_security(k_enc, k_int, cipher_algo, integ_algo); + } + pthread_rwlock_unlock(&rwlock); } void pdcp::config_security_all(uint8_t *k_enc, @@ -150,42 +206,74 @@ void pdcp::config_security_all(uint8_t *k_enc, CIPHERING_ALGORITHM_ID_ENUM cipher_algo, INTEGRITY_ALGORITHM_ID_ENUM integ_algo) { - for(uint32_t i=0;isecond->config_security(k_enc, k_int, cipher_algo, integ_algo); } + pthread_rwlock_unlock(&rwlock); } void pdcp::enable_integrity(uint32_t lcid) { - if(valid_lcid(lcid)) - pdcp_array[lcid].enable_integrity(); + pthread_rwlock_rdlock(&rwlock); + if (valid_lcid(lcid)) { + pdcp_array.at(lcid)->enable_integrity(); + } + pthread_rwlock_unlock(&rwlock); } void pdcp::enable_encryption(uint32_t lcid) { - if(valid_lcid(lcid)) - pdcp_array[lcid].enable_encryption(); + pthread_rwlock_rdlock(&rwlock); + if (valid_lcid(lcid)) { + pdcp_array.at(lcid)->enable_encryption(); + } + pthread_rwlock_unlock(&rwlock); +} + +uint32_t pdcp::get_dl_count(uint32_t lcid) +{ + int ret = 0; + pthread_rwlock_rdlock(&rwlock); + if (valid_lcid(lcid)) { + ret = pdcp_array.at(lcid)->get_dl_count(); + } + pthread_rwlock_unlock(&rwlock); + return ret; } +uint32_t pdcp::get_ul_count(uint32_t lcid) +{ + int ret = 0; + pthread_rwlock_rdlock(&rwlock); + if (valid_lcid(lcid)) { + ret = pdcp_array.at(lcid)->get_ul_count(); + } + pthread_rwlock_unlock(&rwlock); + return ret; +} + + /******************************************************************************* RLC interface *******************************************************************************/ void pdcp::write_pdu(uint32_t lcid, byte_buffer_t *pdu) { - if(valid_lcid(lcid)) { - pdcp_array[lcid].write_pdu(pdu); + pthread_rwlock_rdlock(&rwlock); + if (valid_lcid(lcid)) { + pdcp_array.at(lcid)->write_pdu(pdu); } else { pdcp_log->warning("Writing pdu: lcid=%d. Deallocating pdu\n", lcid); byte_buffer_pool::get_instance()->deallocate(pdu); } + pthread_rwlock_unlock(&rwlock); } void pdcp::write_pdu_bcch_bch(byte_buffer_t *sdu) { rrc->write_pdu_bcch_bch(sdu); } + void pdcp::write_pdu_bcch_dlsch(byte_buffer_t *sdu) { rrc->write_pdu_bcch_dlsch(sdu); @@ -198,7 +286,7 @@ void pdcp::write_pdu_pcch(byte_buffer_t *sdu) void pdcp::write_pdu_mch(uint32_t lcid, byte_buffer_t *sdu) { - if(0 == lcid) { + if (0 == lcid) { rrc->write_pdu_mch(lcid, sdu); } else { gw->write_pdu_mch(lcid, sdu); @@ -206,31 +294,33 @@ void pdcp::write_pdu_mch(uint32_t lcid, byte_buffer_t *sdu) } /******************************************************************************* - Helpers + Helpers (Lock must be hold when calling those) *******************************************************************************/ bool pdcp::valid_lcid(uint32_t lcid) { - if(lcid >= SRSLTE_N_RADIO_BEARERS) { + if (lcid >= SRSLTE_N_RADIO_BEARERS) { pdcp_log->error("Radio bearer id must be in [0:%d] - %d", SRSLTE_N_RADIO_BEARERS, lcid); return false; } - if(!pdcp_array[lcid].is_active()) { - pdcp_log->error("PDCP entity for logical channel %d has not been activated\n", lcid); + + if (pdcp_array.find(lcid) == pdcp_array.end()) { return false; } + return true; } bool pdcp::valid_mch_lcid(uint32_t lcid) { - if(lcid >= SRSLTE_N_MCH_LCIDS) { + if (lcid >= SRSLTE_N_MCH_LCIDS) { pdcp_log->error("Radio bearer id must be in [0:%d] - %d", SRSLTE_N_RADIO_BEARERS, lcid); return false; } - if(!pdcp_array_mrb[lcid].is_active()) { - pdcp_log->error("PDCP entity for logical channel %d has not been activated\n", lcid); + + if (pdcp_array_mrb.find(lcid) == pdcp_array_mrb.end()) { return false; } + return true; } diff --git a/lib/src/upper/pdcp_entity.cc b/lib/src/upper/pdcp_entity.cc index c2c829549..65bb07fae 100644 --- a/lib/src/upper/pdcp_entity.cc +++ b/lib/src/upper/pdcp_entity.cc @@ -70,11 +70,11 @@ void pdcp_entity::init(srsue::rlc_interface_pdcp *rlc_, cfg.sn_len = 0; sn_len_bytes = 0; - if(cfg.is_control) { + if (cfg.is_control) { cfg.sn_len = 5; sn_len_bytes = 1; } - if(cfg.is_data) { + if (cfg.is_data) { cfg.sn_len = 12; sn_len_bytes = 2; } @@ -89,6 +89,7 @@ void pdcp_entity::reestablish() { tx_count = 0; rx_count = 0; } else { + // Only reset counter in RLC-UM if (rlc->rb_is_um(lcid)) { tx_count = 0; rx_count = 0; @@ -96,11 +97,13 @@ void pdcp_entity::reestablish() { } } +// Used to stop/pause the entity (called on RRC conn release) void pdcp_entity::reset() { - active = false; - if(log) + active = false; + if (log) { log->debug("Reset %s\n", rrc->get_rb_name(lcid).c_str()); + } } bool pdcp_entity::is_active() @@ -108,8 +111,8 @@ bool pdcp_entity::is_active() return active; } -// RRC interface -void pdcp_entity::write_sdu(byte_buffer_t *sdu) +// GW/RRC interface +void pdcp_entity::write_sdu(byte_buffer_t *sdu, bool blocking) { log->info_hex(sdu->msg, sdu->N_bytes, "TX %s SDU, SN: %d, do_integrity = %s, do_encryption = %s", @@ -141,7 +144,7 @@ void pdcp_entity::write_sdu(byte_buffer_t *sdu) } tx_count++; - rlc->write_sdu(lcid, sdu); + rlc->write_sdu(lcid, sdu, blocking); } void pdcp_entity::config_security(uint8_t *k_enc_, @@ -211,10 +214,13 @@ void pdcp_entity::write_pdu(byte_buffer_t *pdu) } if (do_integrity) { - integrity_verify(pdu->msg, + if (not integrity_verify(pdu->msg, rx_count, pdu->N_bytes - 4, - &(pdu->msg[pdu->N_bytes - 4])); + &(pdu->msg[pdu->N_bytes - 4]))) { + log->error_hex(pdu->msg, pdu->N_bytes, "RX %s PDU SN: %d", rrc->get_rb_name(lcid).c_str(), sn); + goto exit; + } } pdcp_unpack_control_pdu(pdu, &sn); @@ -223,6 +229,7 @@ void pdcp_entity::write_pdu(byte_buffer_t *pdu) // pass to RRC rrc->write_pdu(lcid, pdu); } +exit: rx_count++; } @@ -401,6 +408,17 @@ uint8_t pdcp_entity::get_bearer_id(uint8_t lcid) } +uint32_t pdcp_entity::get_dl_count() +{ + return rx_count; +} + + +uint32_t pdcp_entity::get_ul_count() +{ + return tx_count; +} + /**************************************************************************** * Pack/Unpack helper functions * Ref: 3GPP TS 36.323 v10.1.0 diff --git a/lib/src/upper/rlc.cc b/lib/src/upper/rlc.cc index c24f0076b..237891430 100644 --- a/lib/src/upper/rlc.cc +++ b/lib/src/upper/rlc.cc @@ -25,6 +25,7 @@ */ +#include #include "srslte/upper/rlc.h" #include "srslte/upper/rlc_tm.h" #include "srslte/upper/rlc_um.h" @@ -42,8 +43,25 @@ rlc::rlc() ue = NULL; default_lcid = 0; bzero(metrics_time, sizeof(metrics_time)); - bzero(ul_tput_bytes, sizeof(ul_tput_bytes)); - bzero(dl_tput_bytes, sizeof(dl_tput_bytes)); + pthread_rwlock_init(&rwlock, NULL); +} + +rlc::~rlc() +{ + // destroy all remaining entities + pthread_rwlock_wrlock(&rwlock); + for (rlc_map_t::iterator it = rlc_array.begin(); it != rlc_array.end(); ++it) { + delete(it->second); + } + rlc_array.clear(); + + for (rlc_map_t::iterator it = rlc_array_mrb.begin(); it != rlc_array_mrb.end(); ++it) { + delete(it->second); + } + rlc_array_mrb.clear(); + + pthread_rwlock_unlock(&rwlock); + pthread_rwlock_destroy(&rwlock); } void rlc::init(srsue::pdcp_interface_rlc *pdcp_, @@ -63,109 +81,159 @@ void rlc::init(srsue::pdcp_interface_rlc *pdcp_, buffer_size = buffer_size_; gettimeofday(&metrics_time[1], NULL); - reset_metrics(); + reset_metrics(); - rlc_array[0].init(RLC_MODE_TM, rlc_log, default_lcid, pdcp, rrc, mac_timers, buffer_size); // SRB0 + // create default RLC_TM bearer for SRB0 + add_bearer(default_lcid, srslte_rlc_config_t()); } void rlc::reset_metrics() { - bzero(dl_tput_bytes, sizeof(long)*SRSLTE_N_RADIO_BEARERS); - bzero(ul_tput_bytes, sizeof(long)*SRSLTE_N_RADIO_BEARERS); + for (rlc_map_t::iterator it = rlc_array.begin(); it != rlc_array.end(); ++it) { + it->second->reset_metrics(); + } + + for (rlc_map_t::iterator it = rlc_array_mrb.begin(); it != rlc_array_mrb.end(); ++it) { + it->second->reset_metrics(); + } } void rlc::stop() { - for(uint32_t i=0; isecond->stop(); } + for (rlc_map_t::iterator it = rlc_array_mrb.begin(); it != rlc_array_mrb.end(); ++it) { + it->second->stop(); + } + pthread_rwlock_unlock(&rwlock); } void rlc::get_metrics(rlc_metrics_t &m) { - + pthread_rwlock_rdlock(&rwlock); + gettimeofday(&metrics_time[2], NULL); get_time_interval(metrics_time); double secs = (double)metrics_time[0].tv_sec + metrics_time[0].tv_usec*1e-6; m.dl_tput_mbps = 0; - m.ul_tput_mbps = 0; - for (int i=0;iinfo("LCID=%d, RX throughput: %4.6f Mbps. TX throughput: %4.6f Mbps.\n", - i, - (dl_tput_bytes[i]*8/(double)1e6)/secs, - (ul_tput_bytes[i]*8/(double)1e6)/secs); - } + m.ul_tput_mbps = 0; + + for (rlc_map_t::iterator it = rlc_array.begin(); it != rlc_array.end(); ++it) { + m.dl_tput_mbps += (it->second->get_num_rx_bytes()*8/(double)1e6)/secs; + m.ul_tput_mbps += (it->second->get_num_tx_bytes()*8/(double)1e6)/secs; + rlc_log->info("LCID=%d, RX throughput: %4.6f Mbps. TX throughput: %4.6f Mbps.\n", + it->first, + (it->second->get_num_rx_bytes()*8/(double)1e6)/secs, + (it->second->get_num_tx_bytes()*8/(double)1e6)/secs); } // Add multicast metrics - for (int i=0;iinfo("MCH_LCID=%d, RX throughput: %4.6f Mbps.\n", - i, - (dl_tput_bytes_mrb[i]*8/(double)1e6)/secs); - } + for (rlc_map_t::iterator it = rlc_array_mrb.begin(); it != rlc_array_mrb.end(); ++it) { + m.dl_tput_mbps += (it->second->get_num_rx_bytes()*8/(double)1e6)/secs; + rlc_log->info("MCH_LCID=%d, RX throughput: %4.6f Mbps\n", + it->first, + (it->second->get_num_rx_bytes()*8/(double)1e6)/secs); } memcpy(&metrics_time[1], &metrics_time[2], sizeof(struct timeval)); reset_metrics(); + + pthread_rwlock_unlock(&rwlock); } // A call to reestablish stops all lcids but does not delete the instances. The mapping lcid to rlc mode can not change -void rlc::reestablish() { - for(uint32_t i=0; isecond->reestablish(); + } + + for (rlc_map_t::iterator it = rlc_array_mrb.begin(); it != rlc_array_mrb.end(); ++it) { + it->second->reestablish(); } + + pthread_rwlock_unlock(&rwlock); } -// Resetting the RLC layer returns the object to the state after the call to init(): All lcids are stopped and -// defaul lcid=0 is created +// Resetting the RLC layer returns the object to the state after the call to init(): +// All LCIDs are removed, except SRB0 void rlc::reset() { - stop(); - rlc_array[0].init(RLC_MODE_TM, rlc_log, default_lcid, pdcp, rrc, mac_timers, buffer_size); // SRB0 + pthread_rwlock_wrlock(&rwlock); + + for (rlc_map_t::iterator it = rlc_array.begin(); it != rlc_array.end(); ++it) { + it->second->stop(); + delete(it->second); + } + rlc_array.clear(); + + for (rlc_map_t::iterator it = rlc_array_mrb.begin(); it != rlc_array_mrb.end(); ++it) { + it->second->stop(); + delete(it->second); + } + rlc_array_mrb.clear(); + + pthread_rwlock_unlock(&rwlock); + + // Add SRB0 again + add_bearer(default_lcid, srslte_rlc_config_t()); } void rlc::empty_queue() { - for(uint32_t i=0; isecond->empty_queue(); } + pthread_rwlock_unlock(&rwlock); } /******************************************************************************* PDCP interface *******************************************************************************/ -void rlc::write_sdu(uint32_t lcid, byte_buffer_t *sdu) + +void rlc::write_sdu(uint32_t lcid, byte_buffer_t *sdu, bool blocking) { - if(valid_lcid(lcid)) { - rlc_array[lcid].write_sdu(sdu); + pthread_rwlock_rdlock(&rwlock); + if (valid_lcid(lcid)) { + rlc_array.at(lcid)->write_sdu(sdu, blocking); + } else { + rlc_log->warning("RLC LCID %d doesn't exist. Deallocating SDU\n", lcid); + byte_buffer_pool::get_instance()->deallocate(sdu); } + pthread_rwlock_unlock(&rwlock); } -void rlc::write_sdu_nb(uint32_t lcid, byte_buffer_t *sdu) + +void rlc::write_sdu_mch(uint32_t lcid, byte_buffer_t *sdu) { - if(valid_lcid(lcid)) { - rlc_array[lcid].write_sdu_nb(sdu); + pthread_rwlock_rdlock(&rwlock); + if (valid_lcid_mrb(lcid)) { + rlc_array_mrb.at(lcid)->write_sdu(sdu, false); // write in non-blocking mode by default + } else { + rlc_log->warning("RLC LCID %d doesn't exist. Deallocating SDU\n", lcid); + byte_buffer_pool::get_instance()->deallocate(sdu); } + pthread_rwlock_unlock(&rwlock); } -void rlc::write_sdu_mch(uint32_t lcid, byte_buffer_t *sdu) + + +bool rlc::rb_is_um(uint32_t lcid) { - if(valid_lcid_mrb(lcid)) { - rlc_array_mrb[lcid].write_sdu(sdu); + bool ret = false; + + pthread_rwlock_rdlock(&rwlock); + if (valid_lcid(lcid)) { + ret = rlc_array.at(lcid)->get_mode() == RLC_MODE_UM; } -} + pthread_rwlock_unlock(&rwlock); -bool rlc::rb_is_um(uint32_t lcid) { - return rlc_array[lcid].get_mode()==RLC_MODE_UM; + return ret; } /******************************************************************************* @@ -173,61 +241,82 @@ bool rlc::rb_is_um(uint32_t lcid) { *******************************************************************************/ uint32_t rlc::get_buffer_state(uint32_t lcid) { - if(valid_lcid(lcid)) { - return rlc_array[lcid].get_buffer_state(); - } else { - return 0; + uint32_t ret = 0; + + pthread_rwlock_rdlock(&rwlock); + if (valid_lcid(lcid)) { + ret = rlc_array.at(lcid)->get_buffer_state(); } + pthread_rwlock_unlock(&rwlock); + + return ret; } uint32_t rlc::get_total_buffer_state(uint32_t lcid) { - if(valid_lcid(lcid)) { - return rlc_array[lcid].get_total_buffer_state(); - } else { - return 0; + uint32_t ret = 0; + + pthread_rwlock_rdlock(&rwlock); + if (valid_lcid(lcid)) { + ret = rlc_array.at(lcid)->get_total_buffer_state(); } + pthread_rwlock_unlock(&rwlock); + + return ret; } uint32_t rlc::get_total_mch_buffer_state(uint32_t lcid) { - if(valid_lcid_mrb(lcid)) { - return rlc_array_mrb[lcid].get_total_buffer_state(); - } else { - return 0; + uint32_t ret = 0; + + pthread_rwlock_rdlock(&rwlock); + if (valid_lcid(lcid)) { + ret = rlc_array_mrb.at(lcid)->get_total_buffer_state(); } + pthread_rwlock_unlock(&rwlock); + + return ret; } int rlc::read_pdu(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes) { - if(valid_lcid(lcid)) { - ul_tput_bytes[lcid] += nof_bytes; - return rlc_array[lcid].read_pdu(payload, nof_bytes); + uint32_t ret = 0; + + pthread_rwlock_rdlock(&rwlock); + if (valid_lcid(lcid)) { + ret = rlc_array.at(lcid)->read_pdu(payload, nof_bytes); } - return 0; + pthread_rwlock_unlock(&rwlock); + + return ret; } int rlc::read_pdu_mch(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes) { - if(valid_lcid_mrb(lcid)) { - ul_tput_bytes[lcid] += nof_bytes; - return rlc_array_mrb[lcid].read_pdu(payload, nof_bytes); + uint32_t ret = 0; + + pthread_rwlock_rdlock(&rwlock); + if (valid_lcid(lcid)) { + ret = rlc_array_mrb.at(lcid)->read_pdu(payload, nof_bytes); } - return 0; + pthread_rwlock_unlock(&rwlock); + + return ret; } void rlc::write_pdu(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes) { - if(valid_lcid(lcid)) { - dl_tput_bytes[lcid] += nof_bytes; - rlc_array[lcid].write_pdu(payload, nof_bytes); + pthread_rwlock_rdlock(&rwlock); + if (valid_lcid(lcid)) { + rlc_array.at(lcid)->write_pdu(payload, nof_bytes); } + pthread_rwlock_unlock(&rwlock); } +// Pass directly to PDCP, no DL througput counting done void rlc::write_pdu_bcch_bch(uint8_t *payload, uint32_t nof_bytes) { rlc_log->info_hex(payload, nof_bytes, "BCCH BCH message received."); - dl_tput_bytes[0] += nof_bytes; byte_buffer_t *buf = pool_allocate; if (buf) { memcpy(buf->msg, payload, nof_bytes); @@ -239,10 +328,10 @@ void rlc::write_pdu_bcch_bch(uint8_t *payload, uint32_t nof_bytes) } } +// Pass directly to PDCP, no DL througput counting done void rlc::write_pdu_bcch_dlsch(uint8_t *payload, uint32_t nof_bytes) { rlc_log->info_hex(payload, nof_bytes, "BCCH TXSCH message received."); - dl_tput_bytes[0] += nof_bytes; byte_buffer_t *buf = pool_allocate; if (buf) { memcpy(buf->msg, payload, nof_bytes); @@ -254,10 +343,10 @@ void rlc::write_pdu_bcch_dlsch(uint8_t *payload, uint32_t nof_bytes) } } +// Pass directly to PDCP, no DL througput counting done void rlc::write_pdu_pcch(uint8_t *payload, uint32_t nof_bytes) { rlc_log->info_hex(payload, nof_bytes, "PCCH message received."); - dl_tput_bytes[0] += nof_bytes; byte_buffer_t *buf = pool_allocate; if (buf) { memcpy(buf->msg, payload, nof_bytes); @@ -271,117 +360,188 @@ void rlc::write_pdu_pcch(uint8_t *payload, uint32_t nof_bytes) void rlc::write_pdu_mch(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes) { - if(valid_lcid_mrb(lcid)) { - dl_tput_bytes_mrb[lcid] += nof_bytes; - rlc_array_mrb[lcid].write_pdu(payload, nof_bytes); + pthread_rwlock_rdlock(&rwlock); + if (valid_lcid_mrb(lcid)) { + rlc_array_mrb.at(lcid)->write_pdu(payload, nof_bytes); } + pthread_rwlock_unlock(&rwlock); } /******************************************************************************* RRC interface *******************************************************************************/ + +// FIXME: Remove function to forbid implicit configuration void rlc::add_bearer(uint32_t lcid) { - // No config provided - use defaults for SRB1 and SRB2 - if(lcid < 3) { - if (!rlc_array[lcid].active()) { - LIBLTE_RRC_RLC_CONFIG_STRUCT cnfg; - cnfg.rlc_mode = LIBLTE_RRC_RLC_MODE_AM; - cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS45; - cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_INFINITY; - cnfg.ul_am_rlc.poll_byte = LIBLTE_RRC_POLL_BYTE_INFINITY; - cnfg.ul_am_rlc.max_retx_thresh = LIBLTE_RRC_MAX_RETX_THRESHOLD_T4; - cnfg.dl_am_rlc.t_reordering = LIBLTE_RRC_T_REORDERING_MS35; - cnfg.dl_am_rlc.t_status_prohibit = LIBLTE_RRC_T_STATUS_PROHIBIT_MS0; - add_bearer(lcid, srslte_rlc_config_t(&cnfg)); - } else { - rlc_log->warning("Bearer %s already configured. Reconfiguration not supported\n", rrc->get_rb_name(lcid).c_str()); - } - }else{ + if (lcid > 2) { rlc_log->error("Radio bearer %s does not support default RLC configuration.\n", rrc->get_rb_name(lcid).c_str()); + return; + } + + // No config provided - use defaults for SRB0, SRB1, and SRB2 + if (lcid == 0) { + // SRB0 is TM + add_bearer(lcid, srslte_rlc_config_t()); + } else { + // SRB1 and SRB2 are AM + LIBLTE_RRC_RLC_CONFIG_STRUCT cnfg; + cnfg.rlc_mode = LIBLTE_RRC_RLC_MODE_AM; + cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS45; + cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_INFINITY; + cnfg.ul_am_rlc.poll_byte = LIBLTE_RRC_POLL_BYTE_INFINITY; + cnfg.ul_am_rlc.max_retx_thresh = LIBLTE_RRC_MAX_RETX_THRESHOLD_T4; + cnfg.dl_am_rlc.t_reordering = LIBLTE_RRC_T_REORDERING_MS35; + cnfg.dl_am_rlc.t_status_prohibit = LIBLTE_RRC_T_STATUS_PROHIBIT_MS0; + add_bearer(lcid, srslte_rlc_config_t(&cnfg)); } } + void rlc::add_bearer(uint32_t lcid, srslte_rlc_config_t cnfg) { - if(lcid >= SRSLTE_N_RADIO_BEARERS) { - rlc_log->error("Radio bearer id must be in [0:%d] - %d\n", SRSLTE_N_RADIO_BEARERS, lcid); - return; - } + pthread_rwlock_wrlock(&rwlock); - if (!rlc_array[lcid].active()) { - rlc_log->warning("Adding radio bearer %s with mode %s\n", - rrc->get_rb_name(lcid).c_str(), liblte_rrc_rlc_mode_text[cnfg.rlc_mode]); + rlc_common *rlc_entity = NULL; + + if (not valid_lcid(lcid)) { switch(cnfg.rlc_mode) { - case LIBLTE_RRC_RLC_MODE_AM: - rlc_array[lcid].init(RLC_MODE_AM, rlc_log, lcid, pdcp, rrc, mac_timers, buffer_size); - break; - case LIBLTE_RRC_RLC_MODE_UM_BI: - rlc_array[lcid].init(RLC_MODE_UM, rlc_log, lcid, pdcp, rrc, mac_timers, buffer_size); - break; - case LIBLTE_RRC_RLC_MODE_UM_UNI_DL: - rlc_array[lcid].init(RLC_MODE_UM, rlc_log, lcid, pdcp, rrc, mac_timers, buffer_size); - break; - case LIBLTE_RRC_RLC_MODE_UM_UNI_UL: - rlc_array[lcid].init(RLC_MODE_UM, rlc_log, lcid, pdcp, rrc, mac_timers, buffer_size); - break; - default: - rlc_log->error("Cannot add RLC entity - invalid mode\n"); - return; + case RLC_MODE_TM: + rlc_entity = new rlc_tm(); + break; + case RLC_MODE_AM: + rlc_entity = new rlc_am(); + break; + case RLC_MODE_UM: + rlc_entity = new rlc_um(); + break; + default: + rlc_log->error("Cannot add RLC entity - invalid mode\n"); + goto unlock_and_exit; } + + if (rlc_entity) { + // configure and add to array + rlc_entity->init(rlc_log, lcid, pdcp, rrc, mac_timers); + + if (cnfg.rlc_mode != RLC_MODE_TM) { + if (rlc_entity->configure(cnfg) == false) { + rlc_log->error("Error configuring RLC entity\n."); + goto delete_and_exit; + } + } + + if (not rlc_array.insert(rlc_map_pair_t(lcid, rlc_entity)).second) { + rlc_log->error("Error inserting RLC entity in to array\n."); + goto delete_and_exit; + } + } else { + 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]); + goto unlock_and_exit; } else { rlc_log->warning("Bearer %s already created.\n", rrc->get_rb_name(lcid).c_str()); } - rlc_array[lcid].configure(cnfg); +delete_and_exit: + if (rlc_entity) { + delete(rlc_entity); + } + +unlock_and_exit: + pthread_rwlock_unlock(&rwlock); } + void rlc::add_bearer_mrb(uint32_t lcid) { - // 36.321 Table 6.2.1-4 - if(lcid >= SRSLTE_N_MCH_LCIDS) { - rlc_log->error("Radio bearer id must be in [0:%d] - %d\n", SRSLTE_N_MCH_LCIDS, lcid); - return; + pthread_rwlock_wrlock(&rwlock); + rlc_common *rlc_entity = NULL; + + if (not valid_lcid_mrb(lcid)) { + rlc_entity = new rlc_um(); + if (rlc_entity) { + // configure and add to array + rlc_entity->init(rlc_log, lcid, pdcp, rrc, mac_timers); + if (rlc_entity->configure(srslte_rlc_config_t::mch_config()) == false) { + rlc_log->error("Error configuring RLC entity\n."); + goto delete_and_exit; + } + if (not rlc_array_mrb.insert(rlc_map_pair_t(lcid, rlc_entity)).second) { + rlc_log->error("Error inserting RLC entity in to array\n."); + goto delete_and_exit; + } + } else { + rlc_log->error("Error instantiating RLC\n"); + goto delete_and_exit; + } + rlc_log->warning("Added radio bearer %s with mode RLC_UM\n", rrc->get_rb_name(lcid).c_str()); + goto unlock_and_exit; + } else { + rlc_log->warning("Bearer %s already created.\n", rrc->get_rb_name(lcid).c_str()); + } + +delete_and_exit: + if (rlc_entity) { + delete(rlc_entity); } - rlc_array_mrb[lcid].init(rlc_log, lcid, pdcp, rrc, mac_timers); - rlc_array_mrb[lcid].configure(srslte_rlc_config_t::mch_config()); + +unlock_and_exit: + pthread_rwlock_unlock(&rwlock); } -void rlc::add_bearer_mrb_enb(uint32_t lcid) + +void rlc::del_bearer(uint32_t lcid) { - if(lcid >= SRSLTE_N_MCH_LCIDS) { - rlc_log->error("Radio bearer id must be in [0:%d] - %d\n", SRSLTE_N_MCH_LCIDS, lcid); - return; + pthread_rwlock_wrlock(&rwlock); + + if (valid_lcid_mrb(lcid)) { + rlc_map_t::iterator it = rlc_array.find(lcid); + it->second->stop(); + delete(it->second); + rlc_array.erase(it); + rlc_log->warning("Deleted RLC bearer %s\n", rrc->get_rb_name(lcid).c_str()); + } else { + rlc_log->warning("Can't delete bearer %s. Bearer doesn't exist.\n", rrc->get_rb_name(lcid).c_str()); } - rlc_array_mrb[lcid].init(rlc_log,lcid,pdcp,rrc,mac_timers); - rlc_array_mrb[lcid].configure(srslte_rlc_config_t::mch_config()); + + pthread_rwlock_unlock(&rwlock); } + /******************************************************************************* - Helpers + Helpers (Lock must be hold when calling those) *******************************************************************************/ + bool rlc::valid_lcid(uint32_t lcid) { - if(lcid >= SRSLTE_N_RADIO_BEARERS) { - rlc_log->warning("Invalid LCID=%d\n", lcid); + if (lcid >= SRSLTE_N_RADIO_BEARERS) { + rlc_log->error("Radio bearer id must be in [0:%d] - %d", SRSLTE_N_RADIO_BEARERS, lcid); return false; - } else if(!rlc_array[lcid].active()) { + } + + if (rlc_array.find(lcid) == rlc_array.end()) { return false; } + return true; } bool rlc::valid_lcid_mrb(uint32_t lcid) { - if(lcid >= SRSLTE_N_MCH_LCIDS) { + if (lcid >= SRSLTE_N_MCH_LCIDS) { + rlc_log->error("Radio bearer id must be in [0:%d] - %d", SRSLTE_N_RADIO_BEARERS, lcid); return false; } - if(!rlc_array_mrb[lcid].is_mrb()) { + + if (rlc_array_mrb.find(lcid) == rlc_array_mrb.end()) { return false; } + return true; } - } // namespace srsue diff --git a/lib/src/upper/rlc_am.cc b/lib/src/upper/rlc_am.cc index 768f50089..4b15e9bc5 100644 --- a/lib/src/upper/rlc_am.cc +++ b/lib/src/upper/rlc_am.cc @@ -61,6 +61,9 @@ rlc_am::rlc_am(uint32_t queue_len) : tx_sdu_queue(queue_len) vr_ms = 0; vr_h = 0; + num_tx_bytes = 0; + num_rx_bytes = 0; + pdu_without_poll = 0; byte_without_poll = 0; @@ -88,23 +91,27 @@ void rlc_am::init(srslte::log *log_, tx_enabled = true; } -void rlc_am::configure(srslte_rlc_config_t cfg_) +bool rlc_am::configure(srslte_rlc_config_t cfg_) { 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); + + return true; } 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_sdu_queue.reset(); + pthread_mutex_unlock(&mutex); } void rlc_am::reestablish() { @@ -192,32 +199,25 @@ uint32_t rlc_am::get_bearer() * PDCP interface ***************************************************************************/ -void rlc_am::write_sdu(byte_buffer_t *sdu) +void rlc_am::write_sdu(byte_buffer_t *sdu, bool blocking) { if (!tx_enabled) { byte_buffer_pool::get_instance()->deallocate(sdu); return; } if (sdu) { - 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 { - log->warning("NULL SDU pointer in write_sdu()\n"); - } -} - -void rlc_am::write_sdu_nb(byte_buffer_t *sdu) -{ - if (!tx_enabled) { - byte_buffer_pool::get_instance()->deallocate(sdu); - return; - } - if (sdu) { - if (tx_sdu_queue.try_write(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 { - log->debug_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); + // 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"); @@ -238,7 +238,7 @@ uint32_t rlc_am::get_total_buffer_state() check_reordering_timeout(); if(do_status && !status_prohibited()) { n_bytes += prepare_status(); - log->debug("Buffer state - status report: %d bytes\n", n_bytes); + log->debug("%s Buffer state - total status report: %d bytes\n", rrc->get_rb_name(lcid).c_str(), n_bytes); } // Bytes needed for retx @@ -292,7 +292,7 @@ uint32_t rlc_am::get_buffer_state() check_reordering_timeout(); if(do_status && !status_prohibited()) { n_bytes = prepare_status(); - log->debug("Buffer state - status report: %d bytes\n", n_bytes); + log->debug("%s Buffer state - status report: %d bytes\n", rrc->get_rb_name(lcid).c_str(), n_bytes); goto unlock_and_return; } @@ -363,14 +363,15 @@ unlock_and_return: int rlc_am::read_pdu(uint8_t *payload, uint32_t nof_bytes) { pthread_mutex_lock(&mutex); + int pdu_size = 0; log->debug("MAC opportunity - %d bytes\n", nof_bytes); log->debug("tx_window size - %zu PDUs\n", tx_window.size()); // Tx STATUS if requested if(do_status && !status_prohibited()) { - pthread_mutex_unlock(&mutex); - return build_status_pdu(payload, nof_bytes); + pdu_size = build_status_pdu(payload, nof_bytes); + goto unlock_and_exit; } // if tx_window is full and retx_queue empty, retransmit next PDU to be ack'ed @@ -390,25 +391,27 @@ int rlc_am::read_pdu(uint8_t *payload, uint32_t nof_bytes) // RETX if required if(retx_queue.size() > 0) { - int ret = build_retx_pdu(payload, nof_bytes); - if (ret > 0) { - pthread_mutex_unlock(&mutex); - return ret; + pdu_size = build_retx_pdu(payload, nof_bytes); + if (pdu_size > 0) { + goto unlock_and_exit; } } // Build a PDU from SDUs - int ret = build_data_pdu(payload, nof_bytes); + pdu_size = build_data_pdu(payload, nof_bytes); +unlock_and_exit: + num_tx_bytes += pdu_size; pthread_mutex_unlock(&mutex); - return ret; + return pdu_size; } void rlc_am::write_pdu(uint8_t *payload, uint32_t nof_bytes) { - if(nof_bytes < 1) - return; + 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); @@ -424,6 +427,25 @@ void rlc_am::write_pdu(uint8_t *payload, uint32_t nof_bytes) pthread_mutex_unlock(&mutex); } +uint32_t rlc_am::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() +{ + pthread_mutex_lock(&mutex); + num_rx_bytes = 0; + num_tx_bytes = 0; + pthread_mutex_unlock(&mutex); +} + + /**************************************************************************** * Timer checks ***************************************************************************/ @@ -641,6 +663,11 @@ int rlc_am::build_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_retx_t r uint32_t pdu_space = 0; head_len = rlc_am_packed_length(&new_header); + if (old_header.N_li > 0) { + // Make sure we can fit at least one N_li element if old header contained at least one + head_len += 2; + } + if(nof_bytes <= head_len) { log->warning("%s Cannot build a PDU segment - %d bytes available, %d bytes required for header\n", @@ -749,7 +776,7 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) return 0; } - byte_buffer_t *pdu = pool_allocate; + byte_buffer_t *pdu = pool_allocate_blocking; if (!pdu) { #ifdef RLC_AM_BUFFER_DEBUG log->console("Fatal Error: Could not allocate PDU in build_data_pdu()\n"); @@ -930,7 +957,7 @@ void rlc_am::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes, rlc_amd_pdu_h // Write to rx window rlc_amd_rx_pdu_t pdu; - pdu.buf = pool_allocate; + 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"); @@ -1023,7 +1050,7 @@ void rlc_am::handle_data_pdu_segment(uint8_t *payload, uint32_t nof_bytes, rlc_a } rlc_amd_rx_pdu_t segment; - segment.buf = pool_allocate; + segment.buf = pool_allocate_blocking; if (!segment.buf) { #ifdef RLC_AM_BUFFER_DEBUG log->console("Fatal Error: Couldn't allocate PDU in handle_data_pdu_segment().\n"); @@ -1190,7 +1217,7 @@ void rlc_am::reassemble_rx_sdus() { uint32_t len = 0; if(!rx_sdu) { - rx_sdu = pool_allocate; + rx_sdu = pool_allocate_blocking; if (!rx_sdu) { #ifdef RLC_AM_BUFFER_DEBUG log->console("Fatal Error: Could not allocate PDU in reassemble_rx_sdus() (1)\n"); @@ -1224,7 +1251,7 @@ void rlc_am::reassemble_rx_sdus() rx_sdu->set_timestamp(); pdcp->write_pdu(lcid, rx_sdu); - rx_sdu = pool_allocate; + rx_sdu = pool_allocate_blocking; if (!rx_sdu) { #ifdef RLC_AM_BUFFER_DEBUG log->console("Fatal Error: Could not allocate PDU in reassemble_rx_sdus() (2)\n"); @@ -1262,7 +1289,7 @@ void rlc_am::reassemble_rx_sdus() 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); rx_sdu->set_timestamp(); pdcp->write_pdu(lcid, rx_sdu); - rx_sdu = pool_allocate; + rx_sdu = pool_allocate_blocking; if (!rx_sdu) { #ifdef RLC_AM_BUFFER_DEBUG log->console("Fatal Error: Could not allocate PDU in reassemble_rx_sdus() (3)\n"); @@ -1407,7 +1434,7 @@ bool rlc_am::add_segment_and_check(rlc_amd_rx_pdu_segments_t *pdu, rlc_amd_rx_pd } // Copy data - byte_buffer_t *full_pdu = pool_allocate; + byte_buffer_t *full_pdu = pool_allocate_blocking; if (!full_pdu) { #ifdef RLC_AM_BUFFER_DEBUG log->console("Fatal Error: Could not allocate PDU in add_segment_and_check()\n"); diff --git a/lib/src/upper/rlc_entity.cc b/lib/src/upper/rlc_entity.cc deleted file mode 100644 index 783a14982..000000000 --- a/lib/src/upper/rlc_entity.cc +++ /dev/null @@ -1,170 +0,0 @@ -/** - * - * \section COPYRIGHT - * - * Copyright 2013-2015 Software Radio Systems Limited - * - * \section LICENSE - * - * This file is part of the srsUE library. - * - * srsUE is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * srsUE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * A copy of the GNU Affero General Public License can be found in - * the LICENSE file in the top-level directory of this distribution - * and at http://www.gnu.org/licenses/. - * - */ - -#include "srslte/upper/rlc_entity.h" - -namespace srslte { - -rlc_entity::rlc_entity() - :rlc(NULL) -{ -} - -void rlc_entity::init(rlc_mode_t mode_, - log *rlc_entity_log_, - uint32_t lcid_, - srsue::pdcp_interface_rlc *pdcp_, - srsue::rrc_interface_rlc *rrc_, - mac_interface_timers *mac_timers_, - int buffer_size) -{ - - if (buffer_size <= 0) { - buffer_size = rlc_common::RLC_BUFFER_NOF_PDU; - } - // Create the RLC instance the first time init() is called. - // If called to reestablished, the entity is stopped but not destroyed - // Next call to init() must use same mode - if (rlc == NULL) { - switch(mode_) - { - case RLC_MODE_TM: - rlc = new rlc_tm((uint32_t) buffer_size); - break; - case RLC_MODE_UM: - rlc = new rlc_um((uint32_t) buffer_size); - break; - case RLC_MODE_AM: - rlc = new rlc_am((uint32_t) buffer_size); - break; - default: - rlc_entity_log_->error("Invalid RLC mode - defaulting to TM\n"); - rlc = new rlc_tm((uint32_t) buffer_size); - break; - } - lcid = lcid_; - mode = mode_; - } else { - if (lcid != lcid_) { - rlc_entity_log_->warning("Reestablishing RLC instance. LCID changed from %d to %d\n", lcid, lcid_); - lcid = lcid_; - } - if (mode != mode_) { - rlc_entity_log_->console("Error reestablishing RLC instance. Mode changed from %d to %d. \n", mode, mode_); - } - } - rlc->init(rlc_entity_log_, lcid_, pdcp_, rrc_, mac_timers_); -} - -void rlc_entity::configure(srslte_rlc_config_t cnfg) -{ - if(rlc) - rlc->configure(cnfg); -} - -// Reestablishment stops the entity but does not destroy it. Mode will not change -void rlc_entity::reestablish() { - rlc->reestablish(); -} - -// A call to stop() stops the entity and clears deletes the instance. Next time this entity can be used for other mode. -void rlc_entity::stop() -{ - rlc->stop(); - delete rlc; - rlc = NULL; -} - -void rlc_entity::empty_queue() -{ - rlc->empty_queue(); -} - -bool rlc_entity::active() -{ - return (rlc != NULL); -} - -rlc_mode_t rlc_entity::get_mode() -{ - if(rlc) - return rlc->get_mode(); - else - return RLC_MODE_TM; -} - -uint32_t rlc_entity::get_bearer() -{ - if(rlc) - return rlc->get_bearer(); - else - return 0; -} - -// PDCP interface -void rlc_entity::write_sdu(byte_buffer_t *sdu) -{ - if(rlc) - rlc->write_sdu(sdu); -} - -void rlc_entity::write_sdu_nb(byte_buffer_t *sdu) -{ - if(rlc) - rlc->write_sdu_nb(sdu); -} - -// MAC interface -uint32_t rlc_entity::get_buffer_state() -{ - if(rlc) - return rlc->get_buffer_state(); - else - return 0; -} - -uint32_t rlc_entity::get_total_buffer_state() -{ - if(rlc) - return rlc->get_total_buffer_state(); - else - return 0; -} - -int rlc_entity::read_pdu(uint8_t *payload, uint32_t nof_bytes) -{ - if(rlc) - return rlc->read_pdu(payload, nof_bytes); - else - return 0; -} -void rlc_entity::write_pdu(uint8_t *payload, uint32_t nof_bytes) -{ - if(rlc) - rlc->write_pdu(payload, nof_bytes); -} - -} // namespace srsue diff --git a/lib/src/upper/rlc_tm.cc b/lib/src/upper/rlc_tm.cc index 988acf2af..14cfe37ea 100644 --- a/lib/src/upper/rlc_tm.cc +++ b/lib/src/upper/rlc_tm.cc @@ -35,6 +35,8 @@ rlc_tm::rlc_tm(uint32_t queue_len) : ul_queue(queue_len) pdcp = NULL; rrc = NULL; lcid = 0; + num_tx_bytes = 0; + num_rx_bytes = 0; pool = byte_buffer_pool::get_instance(); } @@ -56,16 +58,17 @@ void rlc_tm::init(srslte::log *log_, tx_enabled = true; } -void rlc_tm::configure(srslte_rlc_config_t cnfg) +bool rlc_tm::configure(srslte_rlc_config_t cnfg) { log->error("Attempted to configure TM RLC entity\n"); + return true; } void rlc_tm::empty_queue() { // Drop all messages in TX queue byte_buffer_t *buf; - while(ul_queue.try_read(&buf)) { + while (ul_queue.try_read(&buf)) { pool->deallocate(buf); } ul_queue.reset(); @@ -93,35 +96,26 @@ uint32_t rlc_tm::get_bearer() } // PDCP interface -void rlc_tm::write_sdu(byte_buffer_t *sdu) +void rlc_tm::write_sdu(byte_buffer_t *sdu, bool blocking) { if (!tx_enabled) { byte_buffer_pool::get_instance()->deallocate(sdu); return; } if (sdu) { - ul_queue.write(sdu); - log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU, queue size=%d, bytes=%d", - rrc->get_rb_name(lcid).c_str(), ul_queue.size(), ul_queue.size_bytes()); - } else { - log->warning("NULL SDU pointer in write_sdu()\n"); - } -} - -void rlc_tm::write_sdu_nb(byte_buffer_t *sdu) -{ - if (!tx_enabled) { - byte_buffer_pool::get_instance()->deallocate(sdu); - return; - } - if (sdu) { - if (ul_queue.try_write(sdu)) { + if (blocking) { + ul_queue.write(sdu); log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU, queue size=%d, bytes=%d", rrc->get_rb_name(lcid).c_str(), ul_queue.size(), ul_queue.size_bytes()); } else { - log->debug_hex(sdu->msg, sdu->N_bytes, "[Dropped SDU] %s Tx SDU, queue size=%d, bytes=%d", + if (ul_queue.try_write(sdu)) { + log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU, queue size=%d, bytes=%d", + rrc->get_rb_name(lcid).c_str(), ul_queue.size(), ul_queue.size_bytes()); + } else { + log->info_hex(sdu->msg, sdu->N_bytes, "[Dropped SDU] %s Tx SDU, queue size=%d, bytes=%d", rrc->get_rb_name(lcid).c_str(), ul_queue.size(), ul_queue.size_bytes()); - pool->deallocate(sdu); + pool->deallocate(sdu); + } } } else { log->warning("NULL SDU pointer in write_sdu()\n"); @@ -139,11 +133,26 @@ uint32_t rlc_tm::get_total_buffer_state() return get_buffer_state(); } +uint32_t rlc_tm::get_num_tx_bytes() +{ + return num_tx_bytes; +} + +uint32_t rlc_tm::get_num_rx_bytes() +{ + return num_rx_bytes; +} + +void rlc_tm::reset_metrics() +{ + num_tx_bytes = 0; + num_rx_bytes = 0; +} + int rlc_tm::read_pdu(uint8_t *payload, uint32_t nof_bytes) { uint32_t pdu_size = ul_queue.size_tail_bytes(); - if(pdu_size > nof_bytes) - { + if (pdu_size > nof_bytes) { log->error("TX %s PDU size larger than MAC opportunity\n", rrc->get_rb_name(lcid).c_str()); return -1; } @@ -156,6 +165,8 @@ int rlc_tm::read_pdu(uint8_t *payload, uint32_t nof_bytes) pool->deallocate(buf); log->info_hex(payload, pdu_size, "TX %s, %s PDU, queue size=%d, bytes=%d", rrc->get_rb_name(lcid).c_str(), rlc_mode_text[RLC_MODE_TM], ul_queue.size(), ul_queue.size_bytes()); + + num_tx_bytes += pdu_size; return pdu_size; } else { log->warning("Queue empty while trying to read\n"); @@ -174,6 +185,7 @@ void rlc_tm::write_pdu(uint8_t *payload, uint32_t nof_bytes) memcpy(buf->msg, payload, nof_bytes); buf->N_bytes = nof_bytes; buf->set_timestamp(); + num_rx_bytes += nof_bytes; pdcp->write_pdu(lcid, buf); } else { log->error("Fatal Error: Couldn't allocate buffer in rlc_tm::write_pdu().\n"); diff --git a/lib/src/upper/rlc_um.cc b/lib/src/upper/rlc_um.cc index f0466c9e1..0c6c8dfec 100644 --- a/lib/src/upper/rlc_um.cc +++ b/lib/src/upper/rlc_um.cc @@ -33,40 +33,19 @@ namespace srslte { -rlc_um::rlc_um(uint32_t queue_len) : tx_sdu_queue(queue_len) -{ - log = NULL; - pdcp = NULL; - rrc = NULL; - reordering_timer = NULL; - lcid = 0; - reordering_timer_id = 0; +rlc_um::rlc_um(uint32_t queue_len) + :lcid(0) + ,tx(queue_len) + ,rrc(NULL) + ,log(NULL) +{ bzero(&cfg, sizeof(srslte_rlc_um_config_t)); - - tx_sdu = NULL; - - rx_sdu = NULL; - pool = byte_buffer_pool::get_instance(); - - pthread_mutex_init(&mutex, NULL); - - vt_us = 0; - vr_ur = 0; - vr_ux = 0; - vr_uh = 0; - - vr_ur_in_rx_sdu = 0; - - mac_timers = NULL; - - pdu_lost = false; } // Warning: must call stop() to properly deallocate all buffers rlc_um::~rlc_um() { - pthread_mutex_destroy(&mutex); - pool = NULL; + stop(); } void rlc_um::init(srslte::log *log_, @@ -75,106 +54,81 @@ void rlc_um::init(srslte::log *log_, srsue::rrc_interface_rlc *rrc_, srslte::mac_interface_timers *mac_timers_) { - log = log_; - lcid = lcid_; - pdcp = pdcp_; - rrc = rrc_; - mac_timers = mac_timers_; - reordering_timer_id = mac_timers->timer_get_unique_id(); - reordering_timer = mac_timers->timer_get(reordering_timer_id); - tx_enabled = true; + tx.init(log_); + rx.init(log_, lcid_, pdcp_, rrc_, mac_timers_); + lcid = lcid_; + rrc = rrc_; // needed to determine bearer name during configuration + log = log_; } -void rlc_um::configure(srslte_rlc_config_t cnfg_) + +bool rlc_um::configure(srslte_rlc_config_t cnfg_) { - cfg = cnfg_.um; - if(cnfg_.um.is_mrb){ - tx_sdu_queue.resize(512); + // determine bearer name and configure Rx/Tx objects + rb_name = get_rb_name(rrc, lcid, cnfg_.um.is_mrb); + + if (not rx.configure(cnfg_, rb_name)) { + return false; } - switch(cnfg_.rlc_mode) - { - case LIBLTE_RRC_RLC_MODE_UM_BI: - 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(), liblte_rrc_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]); - break; - case LIBLTE_RRC_RLC_MODE_UM_UNI_UL: - log->warning("%s configured in %s mode: tx_sn_field_length=%u bits\n", - rrc->get_rb_name(lcid).c_str(), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode], - - rlc_umd_sn_size_num[cfg.rx_sn_field_length]); - break; - case LIBLTE_RRC_RLC_MODE_UM_UNI_DL: - log->warning("%s configured in %s mode: " - "t_reordering=%d ms, rx_sn_field_length=%u bits\n", - rb_name().c_str(), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode], - cfg.t_reordering, rlc_umd_sn_size_num[cfg.rx_sn_field_length]); - break; - default: - log->error("RLC configuration mode not recognized\n"); + + if (not tx.configure(cnfg_, rb_name)) { + 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; + + return true; +} + + +bool rlc_um::rlc_um_rx::configure(srslte_rlc_config_t cnfg_, std::string rb_name_) +{ + cfg = cnfg_.um; + + if (cfg.rx_mod == 0) { + log->error("Error configuring %s RLC UM: rx_mod==0\n", get_rb_name()); + return false; + } + + rb_name = rb_name_; + + rx_enabled = true; + + return true; } + void rlc_um::empty_queue() { // Drop all messages in TX SDU queue - byte_buffer_t *buf; - while(tx_sdu_queue.try_read(&buf)) { - pool->deallocate(buf); - } - tx_sdu_queue.reset(); + tx.empty_queue(); } + bool rlc_um::is_mrb() { return cfg.is_mrb; } -void rlc_um::reestablish() { - stop(); - tx_enabled = true; -} -void rlc_um::stop() +void rlc_um::reestablish() { - // Empty tx_sdu_queue before locking the mutex - tx_enabled = false; - empty_queue(); - - pthread_mutex_lock(&mutex); - vt_us = 0; - vr_ur = 0; - vr_ux = 0; - vr_uh = 0; - pdu_lost = false; - if(rx_sdu) { - pool->deallocate(rx_sdu); - rx_sdu = NULL; - } - - if(tx_sdu) { - pool->deallocate(tx_sdu); - tx_sdu = NULL; - } - - if(reordering_timer) { - reordering_timer->stop(); - } + tx.reestablish(); // calls stop and enables tx again + rx.reestablish(); // nothing else needed +} - // Drop all messages in RX window - std::map::iterator it; - for(it = rx_window.begin(); it != rx_window.end(); it++) { - pool->deallocate(it->second.buf); - } - rx_window.clear(); - pthread_mutex_unlock(&mutex); - if (mac_timers && reordering_timer) { - mac_timers->timer_release_id(reordering_timer_id); - reordering_timer = NULL; - } +void rlc_um::stop() +{ + tx.stop(); + rx.stop(); } + rlc_mode_t rlc_um::get_mode() { return RLC_MODE_UM; @@ -188,147 +142,247 @@ uint32_t rlc_um::get_bearer() /**************************************************************************** * PDCP interface ***************************************************************************/ -void rlc_um::write_sdu(byte_buffer_t *sdu) +void rlc_um::write_sdu(byte_buffer_t *sdu, bool blocking) { - if (!tx_enabled) { - byte_buffer_pool::get_instance()->deallocate(sdu); - return; - } - if (sdu) { - 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()); + if (blocking) { + tx.write_sdu(sdu); } else { - log->warning("NULL SDU pointer in write_sdu()\n"); + tx.try_write_sdu(sdu); } + } -void rlc_um::write_sdu_nb(byte_buffer_t *sdu) +/**************************************************************************** + * MAC interface + ***************************************************************************/ + +uint32_t rlc_um::get_buffer_state() { - if (!tx_enabled) { - byte_buffer_pool::get_instance()->deallocate(sdu); - return; - } - if (sdu) { - 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->debug_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); - } + return tx.get_buffer_size_bytes(); +} + +uint32_t rlc_um::get_total_buffer_state() +{ + return get_buffer_state(); +} + +int rlc_um::read_pdu(uint8_t *payload, uint32_t nof_bytes) +{ + return tx.build_data_pdu(payload, nof_bytes); +} + +void rlc_um::write_pdu(uint8_t *payload, uint32_t nof_bytes) +{ + rx.handle_data_pdu(payload, nof_bytes); +} + +uint32_t rlc_um::get_num_tx_bytes() +{ + return tx.get_num_tx_bytes(); +} + +uint32_t rlc_um::get_num_rx_bytes() +{ + return rx.get_num_rx_bytes(); +} + +void rlc_um::reset_metrics() +{ + tx.reset_metrics(); + rx.reset_metrics(); +} + + +/**************************************************************************** + * Helper functions + ***************************************************************************/ + +std::string rlc_um::get_rb_name(srsue::rrc_interface_rlc *rrc, uint32_t lcid, bool is_mrb) +{ + if(is_mrb) { + std::stringstream ss; + ss << "MRB" << lcid; + return ss.str(); } else { - log->warning("NULL SDU pointer in write_sdu()\n"); + return rrc->get_rb_name(lcid); } } + /**************************************************************************** - * MAC interface + * Tx subclass implementation ***************************************************************************/ -uint32_t rlc_um::get_buffer_state() +rlc_um::rlc_um_tx::rlc_um_tx(uint32_t queue_len) + :tx_sdu_queue(queue_len) + ,pool(byte_buffer_pool::get_instance()) + ,log(NULL) + ,tx_sdu(NULL) + ,vt_us(0) + ,tx_enabled(false) + ,num_tx_bytes(0) { - // Bytes needed for tx SDUs - uint32_t n_sdus = tx_sdu_queue.size(); + pthread_mutex_init(&mutex, NULL); +} - uint32_t n_bytes = tx_sdu_queue.size_bytes(); - if(tx_sdu) - { - n_sdus++; - n_bytes += tx_sdu->N_bytes; + +rlc_um::rlc_um_tx::~rlc_um_tx() +{ + pthread_mutex_destroy(&mutex); +} + + +void rlc_um::rlc_um_tx::init(srslte::log *log_) +{ + log = log_; +} + + +bool rlc_um::rlc_um_tx::configure(srslte_rlc_config_t cnfg_, std::string rb_name_) +{ + cfg = cnfg_.um; + + if (cfg.tx_mod == 0) { + log->error("Error configuring %s RLC UM: tx_mod==0\n", get_rb_name()); + return false; } - // Room needed for header extensions? (integer rounding) - if(n_sdus > 1) - n_bytes += ((n_sdus-1)*1.5)+0.5; + if(cfg.is_mrb){ + tx_sdu_queue.resize(512); + } - // Room needed for fixed header? - if(n_bytes > 0) - n_bytes += (cfg.is_mrb)?2:3; + rb_name = rb_name_; + tx_enabled = true; - return n_bytes; + return true; } -uint32_t rlc_um::get_total_buffer_state() + +void rlc_um::rlc_um_tx::stop() { - return get_buffer_state(); + tx_enabled = false; + empty_queue(); } -int rlc_um::read_pdu(uint8_t *payload, uint32_t nof_bytes) + +void rlc_um::rlc_um_tx::reestablish() +{ + stop(); + tx_enabled = true; +} + + +void rlc_um::rlc_um_tx::empty_queue() { - int r; - log->debug("MAC opportunity - %d bytes\n", nof_bytes); pthread_mutex_lock(&mutex); - r = build_data_pdu(payload, nof_bytes); + + // 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); - return r; } -void rlc_um::write_pdu(uint8_t *payload, uint32_t nof_bytes) + +uint32_t rlc_um::rlc_um_tx::get_num_tx_bytes() +{ + return num_tx_bytes; +} + + +void rlc_um::rlc_um_tx::reset_metrics() { pthread_mutex_lock(&mutex); - handle_data_pdu(payload, nof_bytes); + num_tx_bytes = 0; pthread_mutex_unlock(&mutex); } -/**************************************************************************** - * Timeout callback interface - ***************************************************************************/ -void rlc_um::timer_expired(uint32_t timeout_id) +uint32_t rlc_um::rlc_um_tx::get_buffer_size_bytes() { - if(reordering_timer_id == timeout_id) - { - pthread_mutex_lock(&mutex); + // Bytes needed for tx SDUs + uint32_t n_sdus = tx_sdu_queue.size(); + uint32_t n_bytes = tx_sdu_queue.size_bytes(); + if(tx_sdu) { + n_sdus++; + n_bytes += tx_sdu->N_bytes; + } - // 36.322 v10 Section 5.1.2.2.4 - log->info("%s reordering timeout expiry - updating vr_ur and reassembling\n", - rb_name().c_str()); + // Room needed for header extensions? (integer rounding) + if(n_sdus > 1) { + n_bytes += ((n_sdus-1)*1.5)+0.5; + } - log->warning("Lost PDU SN: %d\n", vr_ur); - pdu_lost = true; - rx_sdu->reset(); - while(RX_MOD_BASE(vr_ur) < RX_MOD_BASE(vr_ux)) - { - vr_ur = (vr_ur + 1)%cfg.rx_mod; - log->debug("Entering Reassemble from timeout id=%d\n", timeout_id); - reassemble_rx_sdus(); - log->debug("Finished reassemble from timeout id=%d\n", timeout_id); - } - reordering_timer->stop(); - if(RX_MOD_BASE(vr_uh) > RX_MOD_BASE(vr_ur)) - { - reordering_timer->set(this, cfg.t_reordering); - reordering_timer->run(); - vr_ux = vr_uh; - } + // Room needed for fixed header? + if(n_bytes > 0) + n_bytes += (cfg.is_mrb)?2:3; - debug_state(); - pthread_mutex_unlock(&mutex); + return n_bytes; +} + + +void rlc_um::rlc_um_tx::write_sdu(byte_buffer_t *sdu) +{ + if (!tx_enabled) { + byte_buffer_pool::get_instance()->deallocate(sdu); + return; + } + + if (sdu) { + tx_sdu_queue.write(sdu); + log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU (%d B, tx_sdu_queue_len=%d)", get_rb_name(), sdu->N_bytes, tx_sdu_queue.size()); + } else { + log->warning("NULL SDU pointer in write_sdu()\n"); } } -bool rlc_um::reordering_timeout_running() + +void rlc_um::rlc_um_tx::try_write_sdu(byte_buffer_t *sdu) { - return reordering_timer->is_running(); + if (!tx_enabled) { + byte_buffer_pool::get_instance()->deallocate(sdu); + return; + } + + if (sdu) { + 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)", get_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)", get_rb_name(), sdu->N_bytes, tx_sdu_queue.size()); + pool->deallocate(sdu); + } + } else { + log->warning("NULL SDU pointer in write_sdu()\n"); + } } -/**************************************************************************** - * Helpers - ***************************************************************************/ -int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) +int rlc_um::rlc_um_tx::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) { - if(!tx_sdu && tx_sdu_queue.size() == 0) - { + pthread_mutex_lock(&mutex); + log->debug("MAC opportunity - %d bytes\n", nof_bytes); + if(!tx_sdu && tx_sdu_queue.size() == 0) { log->info("No data available to be sent\n"); + pthread_mutex_unlock(&mutex); return 0; } byte_buffer_t *pdu = pool_allocate; - if(!pdu || pdu->N_bytes != 0) - { + if(!pdu || pdu->N_bytes != 0) { log->error("Failed to allocate PDU buffer\n"); - return -1; + pthread_mutex_unlock(&mutex); + return 0; } + rlc_umd_pdu_header_t header; header.fi = RLC_FI_FIELD_START_AND_END_ALIGNED; header.sn = vt_us; @@ -346,17 +400,17 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) { pool->deallocate(pdu); log->warning("%s Cannot build a PDU - %d bytes available, %d bytes required for header\n", - rb_name().c_str(), nof_bytes, head_len); + get_rb_name(), nof_bytes, head_len); + pthread_mutex_unlock(&mutex); return 0; } // Check for SDU segment - if(tx_sdu) - { + if(tx_sdu) { uint32_t space = pdu_space-head_len; to_move = space >= tx_sdu->N_bytes ? tx_sdu->N_bytes : space; log->debug("%s adding remainder of SDU segment - %d bytes of %d remaining\n", - rb_name().c_str(), to_move, tx_sdu->N_bytes); + get_rb_name(), to_move, tx_sdu->N_bytes); memcpy(pdu_ptr, tx_sdu->msg, to_move); last_li = to_move; pdu_ptr += to_move; @@ -366,7 +420,7 @@ int rlc_um::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()); + get_rb_name(), tx_sdu->get_latency_us()); pool->deallocate(tx_sdu); tx_sdu = NULL; @@ -376,8 +430,7 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) } // Pull SDUs from queue - while(pdu_space > head_len + 1 && tx_sdu_queue.size() > 0) - { + while(pdu_space > head_len + 1 && tx_sdu_queue.size() > 0) { log->debug("pdu_space=%d, head_len=%d\n", pdu_space, head_len); if(last_li > 0) header.li[header.N_li++] = last_li; @@ -386,17 +439,16 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) uint32_t space = pdu_space-head_len; to_move = space >= tx_sdu->N_bytes ? tx_sdu->N_bytes : space; log->debug("%s adding new SDU segment - %d bytes of %d remaining\n", - rb_name().c_str(), to_move, tx_sdu->N_bytes); + get_rb_name(), to_move, tx_sdu->N_bytes); memcpy(pdu_ptr, tx_sdu->msg, to_move); last_li = to_move; pdu_ptr += to_move; pdu->N_bytes += to_move; tx_sdu->N_bytes -= to_move; tx_sdu->msg += to_move; - if(tx_sdu->N_bytes == 0) - { + 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()); + get_rb_name(), tx_sdu->get_latency_us()); pool->deallocate(tx_sdu); tx_sdu = NULL; @@ -404,89 +456,193 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) pdu_space -= to_move; } - if(tx_sdu) + if(tx_sdu) { header.fi |= RLC_FI_FIELD_NOT_END_ALIGNED; // Last byte does not correspond to last byte of SDU + } // Set SN - header.sn = vt_us; vt_us = (vt_us + 1)%cfg.tx_mod; // Add header and TX - log->debug("%s packing PDU with length %d\n", rb_name().c_str(), pdu->N_bytes); + log->debug("%s packing PDU with length %d\n", get_rb_name(), pdu->N_bytes); rlc_um_write_data_pdu_header(&header, pdu); memcpy(payload, pdu->msg, pdu->N_bytes); uint32_t ret = pdu->N_bytes; - log->debug("%s returning length %d\n", rrc->get_rb_name(lcid).c_str(), pdu->N_bytes); + log->debug("%s returning length %d\n", get_rb_name(), pdu->N_bytes); pool->deallocate(pdu); debug_state(); + + num_tx_bytes += ret; + + pthread_mutex_unlock(&mutex); return ret; } -void rlc_um::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes) + +const char* rlc_um::rlc_um_tx::get_rb_name() +{ + return rb_name.c_str(); +} + + +void rlc_um::rlc_um_tx::debug_state() +{ + log->debug("%s vt_us = %d\n", get_rb_name(), vt_us); +} + +/**************************************************************************** + * Rx subclass implementation + ***************************************************************************/ + +rlc_um::rlc_um_rx::rlc_um_rx() + :reordering_timer(NULL) + ,reordering_timer_id(0) + ,pool(byte_buffer_pool::get_instance()) + ,log(NULL) + ,pdcp(NULL) + ,rrc(NULL) + ,rx_sdu(NULL) + ,vr_ur(0) + ,vr_ux (0) + ,vr_uh(0) + ,vr_ur_in_rx_sdu(0) + ,pdu_lost(false) + ,mac_timers(NULL) + ,lcid(0) + ,num_rx_bytes(0) + ,rx_enabled(false) +{ + pthread_mutex_init(&mutex, NULL); +} + + +rlc_um::rlc_um_rx::~rlc_um_rx() +{ + pthread_mutex_destroy(&mutex); +} + + +void rlc_um::rlc_um_rx::init(srslte::log *log_, uint32_t lcid_, srsue::pdcp_interface_rlc *pdcp_, srsue::rrc_interface_rlc *rrc_, srslte::mac_interface_timers *mac_timers_) +{ + log = log_; + lcid = lcid_; + pdcp = pdcp_; + rrc = rrc_; + mac_timers = mac_timers_; + reordering_timer_id = mac_timers->timer_get_unique_id(); + reordering_timer = mac_timers->timer_get(reordering_timer_id); +} + + +void rlc_um::rlc_um_rx::reestablish() +{ + stop(); +} + + +void rlc_um::rlc_um_rx::stop() +{ + pthread_mutex_lock(&mutex); + if(reordering_timer) { + reordering_timer->stop(); + } + vr_ur = 0; + vr_ux = 0; + vr_uh = 0; + pdu_lost = false; + rx_enabled = false; + + if(rx_sdu) { + pool->deallocate(rx_sdu); + rx_sdu = NULL; + } + + if (mac_timers && reordering_timer) { + mac_timers->timer_release_id(reordering_timer_id); + reordering_timer = NULL; + } + + // Drop all messages in RX window + std::map::iterator it; + for(it = rx_window.begin(); it != rx_window.end(); it++) { + pool->deallocate(it->second.buf); + } + rx_window.clear(); + pthread_mutex_unlock(&mutex); +} + + +void rlc_um::rlc_um_rx::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes) { + pthread_mutex_lock(&mutex); + + rlc_umd_pdu_t pdu; + int header_len = 0; std::map::iterator it; rlc_umd_pdu_header_t header; + + if (!rx_enabled) { + goto unlock_and_exit; + } + + num_rx_bytes += nof_bytes; + rlc_um_read_data_pdu_header(payload, nof_bytes, cfg.rx_sn_field_length, &header); - log->info_hex(payload, nof_bytes, "RX %s Rx data PDU SN: %d", - rb_name().c_str(), header.sn); + log->info_hex(payload, nof_bytes, "RX %s Rx data PDU SN: %d", get_rb_name(), header.sn); if(RX_MOD_BASE(header.sn) >= RX_MOD_BASE(vr_uh-cfg.rx_window_size) && RX_MOD_BASE(header.sn) < RX_MOD_BASE(vr_ur)) { log->info("%s SN: %d outside rx window [%d:%d] - discarding\n", - rb_name().c_str(), header.sn, vr_ur, vr_uh); - return; + get_rb_name(), header.sn, vr_ur, vr_uh); + goto unlock_and_exit; } it = rx_window.find(header.sn); if(rx_window.end() != it) { - log->info("%s Discarding duplicate SN: %d\n", - rb_name().c_str(), header.sn); - return; + log->info("%s Discarding duplicate SN: %d\n", get_rb_name(), header.sn); + goto unlock_and_exit; } // Write to rx window - rlc_umd_pdu_t pdu; pdu.buf = pool_allocate; if (!pdu.buf) { log->error("Discarting packet: no space in buffer pool\n"); - return; + goto unlock_and_exit; } memcpy(pdu.buf->msg, payload, nof_bytes); pdu.buf->N_bytes = nof_bytes; //Strip header from PDU - int header_len = rlc_um_packed_length(&header); + header_len = rlc_um_packed_length(&header); pdu.buf->msg += header_len; pdu.buf->N_bytes -= header_len; pdu.header = header; rx_window[header.sn] = pdu; - + // Update vr_uh - if(!inside_reordering_window(header.sn)) + if(!inside_reordering_window(header.sn)) { vr_uh = (header.sn + 1)%cfg.rx_mod; + } // Reassemble and deliver SDUs, while updating vr_ur log->debug("Entering Reassemble from received PDU\n"); reassemble_rx_sdus(); log->debug("Finished reassemble from received PDU\n"); - + // Update reordering variables and timers - if(reordering_timer->is_running()) - { + if(reordering_timer->is_running()) { if(RX_MOD_BASE(vr_ux) <= RX_MOD_BASE(vr_ur) || (!inside_reordering_window(vr_ux) && vr_ux != vr_uh)) { reordering_timer->stop(); } } - if(!reordering_timer->is_running()) - { - if(RX_MOD_BASE(vr_uh) > RX_MOD_BASE(vr_ur)) - { + if(!reordering_timer->is_running()) { + if(RX_MOD_BASE(vr_uh) > RX_MOD_BASE(vr_ur)) { reordering_timer->set(this, cfg.t_reordering); reordering_timer->run(); vr_ux = vr_uh; @@ -494,9 +650,14 @@ void rlc_um::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes) } debug_state(); + +unlock_and_exit: + pthread_mutex_unlock(&mutex); } -void rlc_um::reassemble_rx_sdus() + +// No locking required as only called from within handle_data_pdu and timer_expired which lock +void rlc_um::rlc_um_rx::reassemble_rx_sdus() { if(!rx_sdu) { rx_sdu = pool_allocate; @@ -536,7 +697,7 @@ void rlc_um::reassemble_rx_sdus() log->warning("Dropping remainder of lost PDU (lower edge middle segments, vr_ur=%d, vr_ur_in_rx_sdu=%d)\n", vr_ur, vr_ur_in_rx_sdu); rx_sdu->reset(); } else { - log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d, i=%d (lower edge middle segments)", rb_name().c_str(), vr_ur, i); + log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d, i=%d (lower edge middle segments)", get_rb_name(), vr_ur, i); rx_sdu->set_timestamp(); if(cfg.is_mrb){ pdcp->write_pdu_mch(lcid, rx_sdu); @@ -553,7 +714,6 @@ void rlc_um::reassemble_rx_sdus() } // Handle last segment - if (rx_sdu->N_bytes > 0 || rlc_um_start_aligned(rx_window[vr_ur].header.fi)) { log->debug("Writing last segment in SDU buffer. Lower edge vr_ur=%d, Buffer size=%d, segment size=%d\n", vr_ur, rx_sdu->N_bytes, rx_window[vr_ur].buf->N_bytes); @@ -567,7 +727,7 @@ void rlc_um::reassemble_rx_sdus() log->warning("Dropping remainder of lost PDU (lower edge last segments)\n"); rx_sdu->reset(); } else { - log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d (lower edge last segments)", rrc->get_rb_name(lcid).c_str(), vr_ur); + log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d (lower edge last segments)", get_rb_name(), vr_ur); rx_sdu->set_timestamp(); if(cfg.is_mrb){ pdcp->write_pdu_mch(lcid, rx_sdu); @@ -592,13 +752,10 @@ void rlc_um::reassemble_rx_sdus() vr_ur = (vr_ur + 1)%cfg.rx_mod; } - // Now update vr_ur until we reach an SN we haven't yet received - while(rx_window.end() != rx_window.find(vr_ur)) - { + while(rx_window.end() != rx_window.find(vr_ur)) { // Handle any SDU segments - for(uint32_t i=0; idebug("Concatenating %d bytes in to current length %d. rx_window remaining bytes=%d, vr_ur_in_rx_sdu=%d, vr_ur=%d, rx_mod=%d, last_mod=%d\n", - len, rx_sdu->N_bytes, rx_window[vr_ur].buf->N_bytes, vr_ur_in_rx_sdu, vr_ur, cfg.rx_mod, (vr_ur_in_rx_sdu+1)%cfg.rx_mod); + len, rx_sdu->N_bytes, rx_window[vr_ur].buf->N_bytes, vr_ur_in_rx_sdu, vr_ur, cfg.rx_mod, (vr_ur_in_rx_sdu+1)%cfg.rx_mod); memcpy(&rx_sdu->msg[rx_sdu->N_bytes], rx_window[vr_ur].buf->msg, len); rx_sdu->N_bytes += len; rx_window[vr_ur].buf->msg += len; @@ -628,7 +785,7 @@ void rlc_um::reassemble_rx_sdus() log->warning("Dropping remainder of lost PDU (update vr_ur middle segments, vr_ur=%d, vr_ur_in_rx_sdu=%d)\n", vr_ur, vr_ur_in_rx_sdu); rx_sdu->reset(); } else { - log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d, i=%d, (update vr_ur middle segments)", rb_name().c_str(), vr_ur, i); + log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d, i=%d, (update vr_ur middle segments)", get_rb_name(), vr_ur, i); rx_sdu->set_timestamp(); if(cfg.is_mrb){ pdcp->write_pdu_mch(lcid, rx_sdu); @@ -665,13 +822,12 @@ void rlc_um::reassemble_rx_sdus() rx_sdu->N_bytes, rx_window[vr_ur].buf->N_bytes, vr_ur); } vr_ur_in_rx_sdu = vr_ur; - if(rlc_um_end_aligned(rx_window[vr_ur].header.fi)) - { + if(rlc_um_end_aligned(rx_window[vr_ur].header.fi)) { if(pdu_lost && !rlc_um_start_aligned(rx_window[vr_ur].header.fi)) { log->warning("Dropping remainder of lost PDU (update vr_ur last segments)\n"); rx_sdu->reset(); } else { - log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d (update vr_ur last segments)", rb_name().c_str(), vr_ur); + log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d (update vr_ur last segments)", get_rb_name(), vr_ur); rx_sdu->set_timestamp(); if(cfg.is_mrb){ pdcp->write_pdu_mch(lcid, rx_sdu); @@ -687,7 +843,7 @@ void rlc_um::reassemble_rx_sdus() pdu_lost = false; } -clean_up_rx_window: + clean_up_rx_window: // Clean up rx_window pool->deallocate(rx_window[vr_ur].buf); @@ -697,7 +853,8 @@ clean_up_rx_window: } } -bool rlc_um::inside_reordering_window(uint16_t sn) +// Only called when lock is hold +bool rlc_um::rlc_um_rx::inside_reordering_window(uint16_t sn) { if(cfg.rx_window_size == 0) { return true; @@ -711,23 +868,78 @@ bool rlc_um::inside_reordering_window(uint16_t sn) } } -void rlc_um::debug_state() + +uint32_t rlc_um::rlc_um_rx::get_num_rx_bytes() { - log->debug("%s vt_us = %d, vr_ur = %d, vr_ux = %d, vr_uh = %d \n", - rb_name().c_str(), vt_us, vr_ur, vr_ux, vr_uh); + return num_rx_bytes; +} + +void rlc_um::rlc_um_rx::reset_metrics() +{ + pthread_mutex_lock(&mutex); + num_rx_bytes = 0; + pthread_mutex_unlock(&mutex); } -std::string rlc_um::rb_name() { - if(cfg.is_mrb) { - std::stringstream ss; - ss << "MRB" << lcid; - return ss.str(); - } else { - return rrc->get_rb_name(lcid); + +/**************************************************************************** + * Timeout callback interface + ***************************************************************************/ + +void rlc_um::rlc_um_rx::timer_expired(uint32_t timeout_id) +{ + if(reordering_timer_id == timeout_id) + { + pthread_mutex_lock(&mutex); + + // 36.322 v10 Section 5.1.2.2.4 + log->info("%s reordering timeout expiry - updating vr_ur and reassembling\n", + get_rb_name()); + + log->warning("Lost PDU SN: %d\n", vr_ur); + pdu_lost = true; + rx_sdu->reset(); + while(RX_MOD_BASE(vr_ur) < RX_MOD_BASE(vr_ux)) + { + vr_ur = (vr_ur + 1)%cfg.rx_mod; + log->debug("Entering Reassemble from timeout id=%d\n", timeout_id); + reassemble_rx_sdus(); + log->debug("Finished reassemble from timeout id=%d\n", timeout_id); + } + reordering_timer->stop(); + if(RX_MOD_BASE(vr_uh) > RX_MOD_BASE(vr_ur)) + { + reordering_timer->set(this, cfg.t_reordering); + reordering_timer->run(); + vr_ux = vr_uh; + } + + debug_state(); + pthread_mutex_unlock(&mutex); } } +bool rlc_um::rlc_um_rx::reordering_timeout_running() +{ + return reordering_timer->is_running(); +} + +/**************************************************************************** + * Helper functions + ***************************************************************************/ + +void rlc_um::rlc_um_rx::debug_state() +{ + log->debug("%s vr_ur = %d, vr_ux = %d, vr_uh = %d\n", get_rb_name(), vr_ur, vr_ux, vr_uh); +} + +const char* rlc_um::rlc_um_rx::get_rb_name() +{ + return rb_name.c_str(); +} + + /**************************************************************************** * Header pack/unpack helper functions * Ref: 3GPP TS 36.322 v10.0.0 Section 6.2.1 diff --git a/lib/test/phy/phy_dl_test.c b/lib/test/phy/phy_dl_test.c index 8c400c3b4..50ea25a1e 100644 --- a/lib/test/phy/phy_dl_test.c +++ b/lib/test/phy/phy_dl_test.c @@ -30,6 +30,8 @@ #include "srslte/srslte.h" +#define MAX_DATABUFFER_SIZE (6144 * 16 * 3 / 8) + srslte_cell_t cell = { .nof_prb = 100, .nof_ports = 1, @@ -39,14 +41,14 @@ srslte_cell_t cell = { .phich_length = SRSLTE_PHICH_NORM }; -uint32_t tm = 0; +uint32_t transmission_mode = 1; srslte_mimo_type_t mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; -uint32_t sf_idx = 5; -uint32_t cfi = 3; +uint32_t cfi = 1; uint32_t nof_rx_ant = 1; -uint32_t nof_subframes = 10; +uint32_t nof_subframes = 100; uint16_t rnti = 0x1234; bool print_dci_table; +uint32_t mcs = 28; void usage(char *prog) { printf("Usage: %s [cfpndvs]\n", prog); @@ -56,12 +58,13 @@ void usage(char *prog) { printf("\t-s number of subframes to simulate [Default %d]\n", nof_subframes); printf("\t-d Print DCI table [Default %s]\n", print_dci_table ? "yes" : "no"); printf("\t-x MIMO Type: single, diversity, cdd, multiplex [Default %s]\n", srslte_mimotype2str(mimo_type)); + printf("\t-m mcs [Default %d]\n", mcs); printf("\t-v [set srslte_verbose to debug, default none]\n"); } void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "cfpndvsx")) != -1) { + while ((opt = getopt(argc, argv, "cfpndvsxm")) != -1) { switch (opt) { case 'x': if (srslte_str2mimotype(argv[optind], &mimo_type)) { @@ -72,18 +75,25 @@ void parse_args(int argc, char **argv) { if (mimo_type == SRSLTE_MIMO_TYPE_SINGLE_ANTENNA) { cell.nof_ports = 1; nof_rx_ant = 1; - tm = 0; + transmission_mode = 1; } else { cell.nof_ports = 2; nof_rx_ant = 2; if (mimo_type == SRSLTE_MIMO_TYPE_TX_DIVERSITY) { - tm = 2; + transmission_mode = 2; + } else if (mimo_type == SRSLTE_MIMO_TYPE_CDD) { + transmission_mode = 3; + } else { + transmission_mode = 4; } } break; case 'f': cfi = (uint32_t) atoi(argv[optind]); break; + case 'm': + mcs = (uint32_t) atoi(argv[optind]); + break; case 'p': cell.nof_prb = (uint32_t) atoi(argv[optind]); break; @@ -109,6 +119,53 @@ void parse_args(int argc, char **argv) { int prbset_num = 1, last_prbset_num = 1; int prbset_orig = 0; +int work_enb(srslte_enb_dl_t *enb_dl, + srslte_dci_format_t dci_format, + srslte_ra_dl_dci_t *dci, + srslte_ra_dl_grant_t *grant, + srslte_softbuffer_tx_t **softbuffer_tx, + uint32_t sf_idx, uint8_t **data_tx) { + int ret = SRSLTE_ERROR; + + srslte_dci_location_t location = { + .ncce = 8, + .L = 3 + }; + + srslte_enb_dl_clear_sf(enb_dl); + + srslte_enb_dl_put_base(enb_dl, sf_idx); + + if (srslte_enb_dl_put_pdcch_dl(enb_dl, + dci, + dci_format, + location, + rnti, + sf_idx % 10) < 0) { + fprintf(stderr, "Error putting PDCCH\n"); + goto quit; + } + + if (srslte_enb_dl_put_pdsch(enb_dl, + grant, + softbuffer_tx, + rnti, + (int[SRSLTE_MAX_CODEWORDS]) {dci->rv_idx, dci->rv_idx_1}, + sf_idx % 10, + data_tx, + mimo_type) < 0) { + fprintf(stderr, "Error putting PDSCH\n"); + goto quit; + } + + srslte_enb_dl_gen_signal(enb_dl); + + ret = SRSLTE_SUCCESS; + + quit: + return ret; +} + unsigned int reverse(register unsigned int x) { x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1)); @@ -131,13 +188,17 @@ 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_softbuffer_tx_t *softbuffer_tx[SRSLTE_MAX_TB] = {}; srslte_softbuffer_rx_t *softbuffer_rx[SRSLTE_MAX_TB] = {}; uint8_t *data_tx[SRSLTE_MAX_TB] = {}; uint8_t *data_rx[SRSLTE_MAX_TB] = {}; - uint32_t count_failures = 0; + uint32_t count_failures = 0, count_tbs = 0; + size_t pdsch_decode_us = 0; + size_t pdsch_encode_us = 0; int ret = -1; @@ -179,13 +240,13 @@ int main(int argc, char **argv) { goto quit; } - data_tx[i] = srslte_vec_malloc(sizeof(uint8_t) * 150000); + data_tx[i] = srslte_vec_malloc(sizeof(uint8_t) * MAX_DATABUFFER_SIZE); if (!data_tx[i]) { fprintf(stderr, "Error allocating data tx\n"); goto quit; } - data_rx[i] = srslte_vec_malloc(sizeof(uint8_t) * 150000); + data_rx[i] = srslte_vec_malloc(sizeof(uint8_t) * MAX_DATABUFFER_SIZE); if (!data_rx[i]) { fprintf(stderr, "Error allocating data tx\n"); goto quit; @@ -223,42 +284,53 @@ int main(int argc, char **argv) { srslte_ue_dl_set_rnti(&ue_dl, rnti); + srslte_chest_dl_average_subframe(&ue_dl.chest, true); + //srslte_chest_dl_set_smooth_filter_gauss(&ue_dl.chest, 4, 1.0f); + /* * Loop */ + INFO("--- Starting test ---\n"); for (uint32_t sf_idx = 0; sf_idx < nof_subframes; sf_idx++) { bool acks[SRSLTE_MAX_TB] = {}; - /* Run eNodeB */ - srslte_enb_dl_clear_sf(&enb_dl); - - srslte_enb_dl_put_base(&enb_dl, sf_idx); + /* Generate random data */ + for (int t = 0; t < SRSLTE_MAX_TB; t++) { + for (int i = 0; i < MAX_DATABUFFER_SIZE; i++) { + data_tx[t][i] = (uint8_t) (rand() & 0xff); + } + } + /* + * Run eNodeB + */ srslte_ra_dl_dci_t dci = {}; srslte_dci_format_t dci_format = SRSLTE_DCI_FORMAT1A; srslte_ra_dl_grant_t grant = {}; + prbset_num = (int) ceilf((float) cell.nof_prb / srslte_ra_type0_P(cell.nof_prb)); + last_prbset_num = prbset_num; + /* Pupulate TB Common */ dci.harq_process = 0; /* Pupulate TB0 */ - dci.mcs_idx = 0; + dci.mcs_idx = mcs; dci.ndi = 0; dci.rv_idx = 0; dci.tb_en[0] = true; if (mimo_type == SRSLTE_MIMO_TYPE_CDD || mimo_type == SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX) { - dci_format = SRSLTE_DCI_FORMAT2B; + dci_format = (transmission_mode == 3) ? SRSLTE_DCI_FORMAT2A : SRSLTE_DCI_FORMAT2; /* Pupulate TB1 */ - dci.mcs_idx_1 = 0; + dci.mcs_idx_1 = mcs; dci.ndi_1 = 0; dci.rv_idx_1 = 0; dci.tb_en[1] = true; /* Pupulate Allocation */ dci.alloc_type = SRSLTE_RA_ALLOC_TYPE0; - dci.alloc_type = SRSLTE_RA_ALLOC_TYPE0; dci.type0_alloc.rbg_bitmask = prbset_to_bitmask(); } else { dci_format = SRSLTE_DCI_FORMAT1A; @@ -275,62 +347,62 @@ int main(int argc, char **argv) { dci.dci_is_1c = (dci_format == SRSLTE_DCI_FORMAT1C); srslte_ra_dl_dci_to_grant(&dci, cell.nof_prb, rnti, &grant); + INFO("--- Process Uplink ---\n"); - srslte_dci_location_t location = { - .ncce = 0, - .L = 2 - }; - - for (int t = 0; t < SRSLTE_RA_DL_GRANT_NOF_TB(&grant); t++) { - for (int i = 0; i < grant.mcs->tbs; i++) { - data_tx[t][i] = (uint8_t) (rand() & 0xff); - } - } - - if (srslte_enb_dl_put_pdcch_dl(&enb_dl, - &dci, - dci_format, - location, - rnti, - sf_idx % 10) < 0) { - fprintf(stderr, "Error putting PDCCH\n"); + gettimeofday(&t[1], NULL); + if (work_enb(&enb_dl, dci_format, &dci, &grant, softbuffer_tx, sf_idx, data_tx)) { goto quit; } - - if (srslte_enb_dl_put_pdsch(&enb_dl, - &grant, - softbuffer_tx, - rnti, - (int[SRSLTE_MAX_CODEWORDS]) {dci.rv_idx, dci.rv_idx_1}, - sf_idx % 10, - data_tx, - mimo_type) < 0) { - fprintf(stderr, "Error putting PDSCH\n"); - goto quit; - } - - srslte_enb_dl_gen_signal(&enb_dl); - - /* Run UE */ - int n = srslte_ue_dl_decode(&ue_dl, data_rx, tm, sf_idx, acks); + gettimeofday(&t[2], NULL); + get_time_interval(t); + pdsch_encode_us += t[0].tv_sec * 1e6 + t[0].tv_usec; + + /* + * Run UE + */ + INFO("--- Process Downlink ---\n"); + gettimeofday(&t[1], NULL); + int n = srslte_ue_dl_decode(&ue_dl, data_rx, transmission_mode - 1, sf_idx, acks); if (n < 0) { fprintf(stderr, "Error decoding PDSCH\n"); goto quit; } + gettimeofday(&t[2], NULL); + get_time_interval(t); + pdsch_decode_us += t[0].tv_sec * 1e6 + t[0].tv_usec; for (int i = 0; i < SRSLTE_RA_DL_GRANT_NOF_TB(&grant); i++) { - if (!acks[i]) { - INFO("UE Failed decoding subframe %d\n", sf_idx); + if (!acks[i] || memcmp(data_tx[i], data_rx[i], grant.mcs[i].tbs / 8) != 0) { + printf("UE Failed decoding tb %d in subframe %d\n", i, sf_idx); + srslte_vec_fprint_hex(stdout, data_tx[i], grant.mcs[i].tbs / 8); + srslte_vec_fprint_hex(stdout, data_rx[i], grant.mcs[i].tbs / 8); count_failures++; } + count_tbs++; } + + tx_nof_bits += (enb_dl.pdsch_cfg.grant.tb_en[0] ? enb_dl.pdsch_cfg.grant.mcs[0].tbs : 0); + tx_nof_bits += (enb_dl.pdsch_cfg.grant.tb_en[1] ? enb_dl.pdsch_cfg.grant.mcs[1].tbs : 0); + rx_nof_bits += (acks[0] ? ue_dl.pdsch_cfg.grant.mcs[0].tbs : 0); + rx_nof_bits += (acks[1] ? ue_dl.pdsch_cfg.grant.mcs[1].tbs : 0); } - printf("Finished! The UE failed decoding %d of %d.\n", count_failures, nof_subframes); + printf("Finished! The UE failed decoding %d of %d transport blocks.\n", count_failures, count_tbs); if (!count_failures) { ret = SRSLTE_SUCCESS; } + printf("%ld were transmitted, %ld bits were received.\n", tx_nof_bits, rx_nof_bits); + printf("[Rates in Mbps] Granted Processed\n"); + printf(" eNb: %5.1f %5.1f\n", + (float) tx_nof_bits / (float) nof_subframes / 1000.0f, + (float) rx_nof_bits / pdsch_encode_us); + printf(" UE: %5.1f %5.1f\n", + (float) rx_nof_bits / (float) nof_subframes / 1000.0f, + (float) rx_nof_bits / pdsch_decode_us); + + printf("BLER: %5.1f%%\n", (float) count_failures / (float) count_tbs * 100.0f); + quit: srslte_enb_dl_free(&enb_dl); srslte_ue_dl_free(&ue_dl); diff --git a/lib/test/upper/rlc_am_test.cc b/lib/test/upper/rlc_am_test.cc index ef04062cc..00793e7d3 100644 --- a/lib/test/upper/rlc_am_test.cc +++ b/lib/test/upper/rlc_am_test.cc @@ -27,11 +27,13 @@ #include #include "srslte/common/log_filter.h" #include "srslte/common/logger_stdout.h" +#include "srslte/common/threads.h" #include "srslte/upper/rlc_am.h" #include "srslte/common/rlc_pcap.h" #include #define NBUFS 5 #define HAVE_PCAP 0 +#define SDU_SIZE 500 using namespace srsue; using namespace srslte; @@ -91,6 +93,48 @@ public: rlc_pcap *pcap; }; +class ul_writer : public thread +{ +public: + ul_writer(rlc_am* rlc_) : rlc(rlc_), running(false) {} + ~ul_writer() { stop(); } + void stop() + { + running = false; + int cnt=0; + while(running && cnt<100) { + usleep(10000); + cnt++; + } + wait_thread_finish(); + } + +private: + void run_thread() { + int sn = 0; + running = true; + while(running) { + byte_buffer_t *pdu = byte_buffer_pool::get_instance()->allocate("rlc_tester::run_thread", true); + if (!pdu) { + printf("Error: Could not allocate PDU in rlc_tester::run_thread\n\n\n"); + // backoff for a bit + usleep(1000); + continue; + } + for (uint32_t i = 0; i < SDU_SIZE; i++) { + pdu->msg[i] = sn; + } + sn++; + pdu->N_bytes = SDU_SIZE; + rlc->write_sdu(pdu); + } + running = false; + } + + rlc_am* rlc; + bool running; +}; + void basic_test() { srslte::log_filter log1("RLC_AM_1"); @@ -169,6 +213,10 @@ void basic_test() assert(tester.sdus[i]->N_bytes == 1); assert(*(tester.sdus[i]->msg) == i); } + + // Check statistics + assert(rlc1.get_num_tx_bytes() == rlc2.get_num_rx_bytes()); + assert(rlc2.get_num_tx_bytes() == rlc1.get_num_rx_bytes()); } void concat_test() @@ -234,6 +282,10 @@ void concat_test() assert(tester.sdus[i]->N_bytes == 1); assert(*(tester.sdus[i]->msg) == i); } + + // check statistics + assert(rlc1.get_num_tx_bytes() == rlc2.get_num_rx_bytes()); + assert(rlc2.get_num_tx_bytes() == rlc1.get_num_rx_bytes()); } void segment_test() @@ -317,6 +369,9 @@ void segment_test() for(int j=0;j<10;j++) 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()); } void retx_test() @@ -710,14 +765,14 @@ void resegment_test_3() // Read the retx PDU from RLC1 and force resegmentation byte_buffer_t retx1; - retx1.N_bytes = rlc1.read_pdu(retx1.msg, 14); // 4 byte header + 10 data + retx1.N_bytes = rlc1.read_pdu(retx1.msg, 16); // 6 byte header + 10 data // Write the retx PDU to RLC2 rlc2.write_pdu(retx1.msg, retx1.N_bytes); // Read the remaining segment byte_buffer_t retx2; - retx2.N_bytes = rlc1.read_pdu(retx2.msg, 14); // 4 byte header + 10 data + retx2.N_bytes = rlc1.read_pdu(retx2.msg, 16); // 6 byte header + 10 data // Write the retx PDU to RLC2 rlc2.write_pdu(retx2.msg, retx2.N_bytes); @@ -1187,7 +1242,7 @@ void resegment_test_7() byte_buffer_t retx2[4]; for (uint32_t i = 0; i < 4; i++) { assert(rlc1.get_buffer_state() != 0); - retx2[i].N_bytes = rlc1.read_pdu(retx2[i].msg, 7); + retx2[i].N_bytes = rlc1.read_pdu(retx2[i].msg, 9); assert(retx2[i].N_bytes != 0); rlc2.write_pdu(retx2[i].msg, retx2[i].N_bytes); @@ -1337,9 +1392,9 @@ void resegment_test_8() // second round of retx, reduce grant size to force different segment sizes byte_buffer_t retx2[20]; - for (uint32_t i = 0; i < 9; i++) { + for (uint32_t i = 0; i < 7; i++) { assert(rlc1.get_buffer_state() != 0); - retx2[i].N_bytes = rlc1.read_pdu(retx2[i].msg, 7); + retx2[i].N_bytes = rlc1.read_pdu(retx2[i].msg, 9); assert(retx2[i].N_bytes != 0); rlc2.write_pdu(retx2[i].msg, retx2[i].N_bytes); #if HAVE_PCAP @@ -1421,6 +1476,42 @@ void reset_test() assert(0 == rlc1.get_buffer_state()); } +void stop_test() +{ + srslte::log_filter log1("RLC_AM_1"); + log1.set_level(srslte::LOG_LEVEL_DEBUG); + log1.set_hex_limit(-1); + rlc_am_tester tester; + mac_dummy_timers timers; + + rlc_am rlc1; + + log1.set_level(srslte::LOG_LEVEL_DEBUG); + + rlc1.init(&log1, 1, &tester, &tester, &timers); + + LIBLTE_RRC_RLC_CONFIG_STRUCT cnfg; + cnfg.rlc_mode = LIBLTE_RRC_RLC_MODE_AM; + cnfg.dl_am_rlc.t_reordering = LIBLTE_RRC_T_REORDERING_MS5; + cnfg.dl_am_rlc.t_status_prohibit = LIBLTE_RRC_T_STATUS_PROHIBIT_MS5; + cnfg.ul_am_rlc.max_retx_thresh = LIBLTE_RRC_MAX_RETX_THRESHOLD_T4; + cnfg.ul_am_rlc.poll_byte = LIBLTE_RRC_POLL_BYTE_KB25; + 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); + + // start thread reading + ul_writer writer(&rlc1); + writer.start(-2); + + // let writer thread block on tx_queue + usleep(1e6); + + // stop RLC1 + rlc1.stop(); +} + int main(int argc, char **argv) { basic_test(); byte_buffer_pool::get_instance()->cleanup(); @@ -1460,4 +1551,7 @@ int main(int argc, char **argv) { reset_test(); byte_buffer_pool::get_instance()->cleanup(); + + stop_test(); + byte_buffer_pool::get_instance()->cleanup(); } diff --git a/lib/test/upper/rlc_stress_test.cc b/lib/test/upper/rlc_stress_test.cc index 3a6f40a99..ec02a699a 100644 --- a/lib/test/upper/rlc_stress_test.cc +++ b/lib/test/upper/rlc_stress_test.cc @@ -113,7 +113,6 @@ public: fail_rate = fail_rate_; opp_sdu_ratio = opp_sdu_ratio_; run_enable = true; - running = false; pdu_tx_delay_usec = pdu_tx_delay_usec_; pcap = pcap_; is_dl = is_dl_; @@ -123,21 +122,12 @@ public: void stop() { run_enable = false; - int cnt=0; - while(running && cnt<100) { - usleep(10000); - cnt++; - } - if(running) { - thread_cancel(); - } wait_thread_finish(); } private: void run_thread() { - running = true; byte_buffer_t *pdu = byte_buffer_pool::get_instance()->allocate("mac_reader::run_thread"); if (!pdu) { printf("Fatal Error: Could not allocate PDU in mac_reader::run_thread\n"); @@ -163,7 +153,6 @@ private: } } } - running = false; byte_buffer_pool::get_instance()->deallocate(pdu); } @@ -175,9 +164,7 @@ private: rlc_pcap *pcap; uint32_t lcid; bool is_dl; - bool run_enable; - bool running; }; class mac_dummy @@ -227,7 +214,6 @@ public: rlc_tester(rlc_interface_pdcp *rlc_, std::string name_, uint32_t sdu_gen_delay_usec_, uint32_t lcid_){ rlc = rlc_; run_enable = true; - running = false; rx_pdus = 0; name = name_; sdu_gen_delay_usec = sdu_gen_delay_usec_; @@ -237,14 +223,6 @@ public: void stop() { run_enable = false; - int cnt=0; - while(running && cnt<100) { - usleep(10000); - cnt++; - } - if(running) { - thread_cancel(); - } wait_thread_finish(); } @@ -275,7 +253,6 @@ private: void run_thread() { uint8_t sn = 0; - running = true; while(run_enable) { byte_buffer_t *pdu = byte_buffer_pool::get_instance()->allocate("rlc_tester::run_thread"); if (!pdu) { @@ -292,11 +269,9 @@ private: rlc->write_sdu(lcid, pdu); if (sdu_gen_delay_usec) usleep(sdu_gen_delay_usec); } - running = false; } bool run_enable; - bool running; long rx_pdus; uint32_t lcid; @@ -325,7 +300,7 @@ void stress_test(stress_test_args_t args) srslte_rlc_config_t cnfg_; if (args.mode == "AM") { // config RLC AM bearer - cnfg_.rlc_mode = LIBLTE_RRC_RLC_MODE_AM; + cnfg_.rlc_mode = RLC_MODE_AM; cnfg_.am.max_retx_thresh = 4; cnfg_.am.poll_byte = 25*1000; cnfg_.am.poll_pdu = 4; @@ -334,7 +309,7 @@ void stress_test(stress_test_args_t args) cnfg_.am.t_status_prohibit = 5; } else if (args.mode == "UM") { // config UM bearer - cnfg_.rlc_mode = LIBLTE_RRC_RLC_MODE_UM_BI; + cnfg_.rlc_mode = RLC_MODE_UM; cnfg_.um.t_reordering = 5; cnfg_.um.rx_mod = 32; cnfg_.um.rx_sn_field_length = RLC_UMD_SN_SIZE_5_BITS; @@ -381,6 +356,10 @@ void stress_test(stress_test_args_t args) usleep(1e6); } + // Stop RLC instances first to release blocking writers + rlc1.stop(); + rlc2.stop(); + tester1.stop(); tester2.stop(); mac.stop(); @@ -388,15 +367,23 @@ void stress_test(stress_test_args_t args) pcap.close(); } - printf("RLC1 received %d SDUs in %ds (%.2f PDU/s)\n", + rlc_metrics_t metrics; + rlc1.get_metrics(metrics); + + printf("RLC1 received %d SDUs in %ds (%.2f PDU/s), Throughput: DL=%4.2f Mbps, UL=%4.2f Mbps\n", tester1.get_nof_rx_pdus(), args.test_duration_sec, - (float)tester1.get_nof_rx_pdus()/args.test_duration_sec); + (float)tester1.get_nof_rx_pdus()/args.test_duration_sec, + metrics.dl_tput_mbps, + metrics.ul_tput_mbps); - printf("RLC2 received %d SDUs in %ds (%.2f PDU/s)\n", + rlc2.get_metrics(metrics); + printf("RLC2 received %d SDUs in %ds (%.2f PDU/s), Throughput: DL=%4.2f Mbps, UL=%4.2f Mbps\n", tester2.get_nof_rx_pdus(), args.test_duration_sec, - (float)tester2.get_nof_rx_pdus()/args.test_duration_sec); + (float)tester2.get_nof_rx_pdus()/args.test_duration_sec, + metrics.dl_tput_mbps, + metrics.ul_tput_mbps); } diff --git a/lib/test/upper/rlc_um_test.cc b/lib/test/upper/rlc_um_test.cc index 58cc217f1..cbeb2d3f6 100644 --- a/lib/test/upper/rlc_um_test.cc +++ b/lib/test/upper/rlc_um_test.cc @@ -130,8 +130,8 @@ void basic_test() cnfg.dl_um_bi_rlc.sn_field_len = LIBLTE_RRC_SN_FIELD_LENGTH_SIZE10; cnfg.ul_um_bi_rlc.sn_field_len = LIBLTE_RRC_SN_FIELD_LENGTH_SIZE10; - rlc1.configure(&cnfg); - rlc2.configure(&cnfg); + assert(rlc1.configure(&cnfg) == true); + assert(rlc2.configure(&cnfg) == true); tester.set_expected_sdu_len(1); diff --git a/srsenb/enb.conf.example b/srsenb/enb.conf.example index 1c7c93214..0eb65bd92 100644 --- a/srsenb/enb.conf.example +++ b/srsenb/enb.conf.example @@ -12,6 +12,7 @@ # mnc: Mobile Network Code # mme_addr: IP address of MME for S1 connnection # gtp_bind_addr: Local IP address to bind for GTP connection +# s1c_bind_addr: Local IP address to bind for S1AP connection # n_prb: Number of Physical Resource Blocks (6,15,25,50,75,100) # tm: Transmission mode 1-4 (TM1 default) # nof_ports: Number of Tx ports (1 port default, set to 2 for TM2/3/4) @@ -112,7 +113,7 @@ filename = /tmp/enb.pcap # If set to negative, a single log file will be created. ##################################################################### [log] -all_level = info +all_level = warning all_hex_limit = 32 filename = /tmp/enb.log file_max_size = -1 diff --git a/srsenb/hdr/enb.h b/srsenb/hdr/enb.h index b483d021b..08f75bc1e 100644 --- a/srsenb/hdr/enb.h +++ b/srsenb/hdr/enb.h @@ -201,6 +201,7 @@ private: srslte::log_filter rrc_log; srslte::log_filter gtpu_log; srslte::log_filter s1ap_log; + srslte::log_filter pool_log; srslte::byte_buffer_pool *pool; diff --git a/srsenb/hdr/upper/pdcp.h b/srsenb/hdr/upper/pdcp.h index 9624958e4..1dc555fee 100644 --- a/srsenb/hdr/upper/pdcp.h +++ b/srsenb/hdr/upper/pdcp.h @@ -39,7 +39,7 @@ class pdcp : public pdcp_interface_rlc, public pdcp_interface_rrc { public: - + virtual ~pdcp() {}; void init(rlc_interface_pdcp *rlc_, rrc_interface_pdcp *rrc_, gtpu_interface_pdcp *gtpu_, srslte::log *pdcp_log_); void stop(); @@ -68,7 +68,7 @@ private: uint16_t rnti; srsenb::rlc_interface_pdcp *rlc; // rlc_interface_pdcp - void write_sdu(uint32_t lcid, srslte::byte_buffer_t *sdu); + void write_sdu(uint32_t lcid, srslte::byte_buffer_t *sdu, bool blocking); bool rb_is_um(uint32_t lcid); }; diff --git a/srsenb/src/enb.cc b/srsenb/src/enb.cc index c5660e0f0..911fb1d48 100644 --- a/srsenb/src/enb.cc +++ b/srsenb/src/enb.cc @@ -99,6 +99,10 @@ bool enb::init(all_args_t *args_) gtpu_log.init("GTPU", logger); s1ap_log.init("S1AP", logger); + pool_log.init("POOL", logger); + pool_log.set_level(srslte::LOG_LEVEL_ERROR); + pool->set_log(&pool_log); + // Init logs rf_log.set_level(srslte::LOG_LEVEL_INFO); for (int i=0;iexpert.phy.nof_phy_threads;i++) { diff --git a/srsenb/src/mac/mac.cc b/srsenb/src/mac/mac.cc index d16279f15..fb1a71c4a 100644 --- a/srsenb/src/mac/mac.cc +++ b/srsenb/src/mac/mac.cc @@ -734,7 +734,8 @@ int mac::get_mch_sched(bool is_mcch, dl_sched_t *dl_sched_res) dl_sched_res->sched_grants[0].data[0] = ue_db[SRSLTE_MRNTI]->generate_mch_pdu(mch, 1, mcs_data.tbs/8); } } else { - //TRANSMIT NOTHING + dl_sched_res->sched_grants[0].rnti = 0; + dl_sched_res->sched_grants[0].data[0] = NULL; } mch.current_sf_allocation_num++; } diff --git a/srsenb/src/main.cc b/srsenb/src/main.cc index 3622f8d05..9c15ef25c 100644 --- a/srsenb/src/main.cc +++ b/srsenb/src/main.cc @@ -31,6 +31,7 @@ #include #include "srslte/common/config_file.h" +#include "srslte/common/crash_handler.h" #include #include diff --git a/srsenb/src/upper/pdcp.cc b/srsenb/src/upper/pdcp.cc index 6f07e4ece..4d242bdc1 100644 --- a/srsenb/src/upper/pdcp.cc +++ b/srsenb/src/upper/pdcp.cc @@ -56,7 +56,7 @@ void pdcp::add_user(uint16_t rnti) { pthread_rwlock_rdlock(&rwlock); if (users.count(rnti) == 0) { - srslte::pdcp *obj = new srslte::pdcp; + srslte::pdcp *obj = new srslte::pdcp; obj->init(&users[rnti].rlc_itf, &users[rnti].rrc_itf, &users[rnti].gtpu_itf, log_h, RB_ID_SRB0, SECURITY_DIRECTION_DOWNLINK); users[rnti].rlc_itf.rnti = rnti; users[rnti].gtpu_itf.rnti = rnti; @@ -154,9 +154,8 @@ void pdcp::user_interface_gtpu::write_pdu(uint32_t lcid, srslte::byte_buffer_t * gtpu->write_pdu(rnti, lcid, pdu); } -void pdcp::user_interface_rlc::write_sdu(uint32_t lcid, srslte::byte_buffer_t* sdu) +void pdcp::user_interface_rlc::write_sdu(uint32_t lcid, srslte::byte_buffer_t* sdu, bool blocking) { - rlc->write_sdu(rnti, lcid, sdu); } diff --git a/srsenb/src/upper/rlc.cc b/srsenb/src/upper/rlc.cc index 6c97391d7..aa62ac1e1 100644 --- a/srsenb/src/upper/rlc.cc +++ b/srsenb/src/upper/rlc.cc @@ -123,7 +123,7 @@ void rlc::add_bearer_mrb(uint16_t rnti, uint32_t lcid) { pthread_rwlock_rdlock(&rwlock); if (users.count(rnti)) { - users[rnti].rlc->add_bearer_mrb_enb(lcid); + users[rnti].rlc->add_bearer_mrb(lcid); } pthread_rwlock_unlock(&rwlock); } @@ -190,7 +190,7 @@ void rlc::write_sdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t* sdu) pthread_rwlock_rdlock(&rwlock); if (users.count(rnti)) { if(rnti != SRSLTE_MRNTI){ - users[rnti].rlc->write_sdu_nb(lcid, sdu); + users[rnti].rlc->write_sdu(lcid, sdu, false); tx_queue = users[rnti].rlc->get_total_buffer_state(lcid); }else { users[rnti].rlc->write_sdu_mch(lcid, sdu); diff --git a/srsepc/src/CMakeLists.txt b/srsepc/src/CMakeLists.txt index 9fb56ce30..f411eace5 100644 --- a/srsepc/src/CMakeLists.txt +++ b/srsepc/src/CMakeLists.txt @@ -34,17 +34,17 @@ if (RPATH) endif (RPATH) -add_executable(srsepc main.cc ) -target_link_libraries(srsepc srsepc_mme - srsepc_hss - srsepc_sgw - srslte_upper - srslte_common - ${CMAKE_THREAD_LIBS_INIT} - ${Boost_LIBRARIES} - ${SEC_LIBRARIES} - ${LIBCONFIGPP_LIBRARIES} - ${SCTP_LIBRARIES}) +add_executable(srsepc main.cc) +target_link_libraries( srsepc srsepc_mme + srsepc_hss + srsepc_sgw + srslte_upper + srslte_common + ${CMAKE_THREAD_LIBS_INIT} + ${Boost_LIBRARIES} + ${SEC_LIBRARIES} + ${LIBCONFIGPP_LIBRARIES} + ${SCTP_LIBRARIES}) add_executable(srsmbms mbms-gw/main.cc ) target_link_libraries(srsmbms srsepc_mbms_gw diff --git a/srsepc/src/main.cc b/srsepc/src/main.cc index c2c40d01b..599564c6f 100644 --- a/srsepc/src/main.cc +++ b/srsepc/src/main.cc @@ -27,6 +27,7 @@ #include #include #include +#include "srslte/common/crash_handler.h" #include "srslte/common/bcd_helpers.h" #include "srslte/common/config_file.h" #include "srsepc/hdr/mme/mme.h" @@ -39,7 +40,7 @@ namespace bpo = boost::program_options; bool running = true; -void +void sig_int_handler(int signo){ running = false; } @@ -289,11 +290,13 @@ level(std::string l) int main (int argc,char * argv[] ) { - cout << endl <<"--- Software Radio Systems EPC ---" << endl << endl; signal(SIGINT, sig_int_handler); signal(SIGTERM, sig_int_handler); signal(SIGKILL, sig_int_handler); + cout << endl <<"--- Software Radio Systems EPC ---" << endl << endl; + srslte_debug_handle_crash(argc, argv); + all_args_t args; parse_args(&args, argc, argv); diff --git a/srsue/hdr/ue.h b/srsue/hdr/ue.h index 7d33749b1..12072f6f3 100644 --- a/srsue/hdr/ue.h +++ b/srsue/hdr/ue.h @@ -69,8 +69,8 @@ public: bool init(all_args_t *args_); void stop(); - bool attach(); - bool deattach(); + bool switch_on(); + bool switch_off(); bool is_attached(); void start_plot(); void print_mbms(); @@ -115,6 +115,7 @@ private: srslte::log_filter nas_log; srslte::log_filter gw_log; srslte::log_filter usim_log; + srslte::log_filter pool_log; all_args_t *args; bool started; diff --git a/srsue/hdr/ue_base.h b/srsue/hdr/ue_base.h index c41a951bb..6e4853dfd 100644 --- a/srsue/hdr/ue_base.h +++ b/srsue/hdr/ue_base.h @@ -159,8 +159,8 @@ public: virtual bool init(all_args_t *args_) = 0; virtual void stop() = 0; - virtual bool attach() = 0; - virtual bool deattach() = 0; + virtual bool switch_on() = 0; + virtual bool switch_off() = 0; virtual bool is_attached() = 0; virtual void start_plot() = 0; diff --git a/srsue/hdr/upper/nas.h b/srsue/hdr/upper/nas.h index 32f6898f9..70ccbea35 100644 --- a/srsue/hdr/upper/nas.h +++ b/srsue/hdr/upper/nas.h @@ -90,7 +90,7 @@ public: // UE interface bool attach_request(); - bool deattach_request(); + bool detach_request(); // PCAP void start_pcap(srslte::nas_pcap *pcap_); @@ -173,6 +173,7 @@ private: void parse_service_reject(uint32_t lcid, byte_buffer_t *pdu); void parse_esm_information_request(uint32_t lcid, byte_buffer_t *pdu); void parse_emm_information(uint32_t lcid, byte_buffer_t *pdu); + void parse_detach_request(uint32_t lcid, byte_buffer_t *pdu); // Packet generators void gen_attach_request(byte_buffer_t *msg); @@ -186,6 +187,8 @@ private: void send_authentication_failure(const uint8_t cause, const uint8_t* auth_fail_param); void gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg); void send_security_mode_reject(uint8_t cause); + void send_detach_request(bool switch_off); + void send_detach_accept(); // security context persistence file bool read_ctxt_file(nas_sec_ctxt *ctxt); diff --git a/srsue/hdr/upper/rrc.h b/srsue/hdr/upper/rrc.h index dfef5e723..4a064c105 100644 --- a/srsue/hdr/upper/rrc.h +++ b/srsue/hdr/upper/rrc.h @@ -280,7 +280,7 @@ public: void stop(); rrc_state_t get_state(); - void set_args(rrc_args_t *args); + void set_args(rrc_args_t args); // Timeout callback interface void timer_expired(uint32_t timeout_id); @@ -326,10 +326,12 @@ private: typedef struct { enum { + PDU, PCCH, STOP } command; byte_buffer_t *pdu; + uint16_t lcid; } cmd_msg_t; bool running; @@ -477,7 +479,8 @@ private: typedef struct { uint32_t earfcn; float q_offset; - std::map cells; + std::map meas_cells; + std::map found_cells; } meas_obj_t; typedef struct { @@ -606,6 +609,7 @@ private: void send_rrc_ue_cap_info(); // Parsers + void process_pdu(uint32_t lcid, byte_buffer_t *pdu); void parse_dl_ccch(byte_buffer_t *pdu); void parse_dl_dcch(uint32_t lcid, byte_buffer_t *pdu); void parse_dl_info_transfer(uint32_t lcid, byte_buffer_t *pdu); @@ -634,8 +638,8 @@ private: void handle_rrc_con_reconfig(uint32_t lcid, LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT *reconfig); void add_srb(LIBLTE_RRC_SRB_TO_ADD_MOD_STRUCT *srb_cnfg); void add_drb(LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT *drb_cnfg); - void release_drb(uint8_t lcid); - void add_mrb(uint32_t lcid, uint32_t port); + void release_drb(uint32_t drb_id); + void add_mrb(uint32_t lcid, uint32_t port); bool apply_rr_config_dedicated(LIBLTE_RRC_RR_CONFIG_DEDICATED_STRUCT *cnfg); void apply_phy_config_dedicated(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *phy_cnfg, bool apply_defaults); void apply_mac_config_dedicated(LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT *mac_cfg, bool apply_defaults); diff --git a/srsue/src/main.cc b/srsue/src/main.cc index f71f9ac6f..cc1638169 100644 --- a/srsue/src/main.cc +++ b/srsue/src/main.cc @@ -38,6 +38,7 @@ #include "srsue/hdr/ue.h" #include "srslte/common/config_file.h" +#include "srslte/common/crash_handler.h" #include "srslte/srslte.h" #include "srsue/hdr/metrics_stdout.h" #include "srsue/hdr/metrics_csv.h" @@ -544,7 +545,7 @@ int main(int argc, char *argv[]) pthread_create(&input, NULL, &input_loop, &args); printf("Attaching UE...\n"); - while (!ue->attach() && running) { + while (!ue->switch_on() && running) { sleep(1); } if (running) { @@ -584,6 +585,7 @@ int main(int argc, char *argv[]) } sleep(1); } + ue->switch_off(); pthread_cancel(input); metricshub.stop(); ue->stop(); diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index 7f83ac731..7c1f8329a 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -86,6 +86,7 @@ phch_worker::~phch_worker() void phch_worker::reset() { + pthread_mutex_lock(&mutex); bzero(&dl_metrics, sizeof(dl_metrics_t)); bzero(&ul_metrics, sizeof(ul_metrics_t)); bzero(&dmrs_cfg, sizeof(srslte_refsignal_dmrs_pusch_cfg_t)); @@ -101,6 +102,7 @@ void phch_worker::reset() I_sr = 0; cfi = 0; rssi_read_cnt = 0; + pthread_mutex_unlock(&mutex); } void phch_worker::enable_pdsch_coworker() { @@ -1402,6 +1404,7 @@ void phch_worker::enable_pregen_signals(bool enabled) void phch_worker::set_ul_params(bool pregen_disabled) { + pthread_mutex_lock(&mutex); phy_interface_rrc::phy_cfg_common_t *common = &phy->config->common; LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *dedicated = &phy->config->dedicated; @@ -1504,7 +1507,9 @@ void phch_worker::set_ul_params(bool pregen_disabled) /* SR configuration */ I_sr = dedicated->sched_request_cnfg.sr_cnfg_idx; sr_configured = true; - + + pthread_mutex_unlock(&mutex); + if (pregen_enabled && !pregen_disabled) { Info("Pre-generating UL signals worker=%d\n", get_id()); srslte_ue_ul_pregen_signals(&ue_ul); diff --git a/srsue/src/ue.cc b/srsue/src/ue.cc index 1218a322c..56e8b6c44 100644 --- a/srsue/src/ue.cc +++ b/srsue/src/ue.cc @@ -89,6 +89,10 @@ bool ue::init(all_args_t *args_) { gw_log.init("GW ", logger); usim_log.init("USIM", logger); + pool_log.init("POOL", logger); + pool_log.set_level(srslte::LOG_LEVEL_ERROR); + byte_buffer_pool::get_instance()->set_log(&pool_log); + // Init logs rf_log.set_level(srslte::LOG_LEVEL_INFO); rf_log.info("Starting UE\n"); @@ -222,13 +226,15 @@ bool ue::init(all_args_t *args_) { nas.init(usim, &rrc, &gw, &nas_log, nas_cfg); gw.init(&pdcp, &nas, &gw_log, 3 /* RB_ID_DRB1 */); gw.set_netmask(args->expert.ip_netmask); - rrc.init(&phy, &mac, &rlc, &pdcp, &nas, usim, &gw, &mac, &rrc_log); // Get current band from provided EARFCN args->rrc.supported_bands[0] = srslte_band_get_band(args->rf.dl_earfcn); args->rrc.nof_supported_bands = 1; args->rrc.ue_category = atoi(args->ue_category_str.c_str()); - rrc.set_args(&args->rrc); + + // set args and initialize RRC + rrc.set_args(args->rrc); + rrc.init(&phy, &mac, &rlc, &pdcp, &nas, usim, &gw, &mac, &rrc_log); // Currently EARFCN list is set to only one frequency as indicated in ue.conf std::vector earfcn_list; @@ -295,12 +301,27 @@ void ue::stop() } } -bool ue::attach() { +bool ue::switch_on() { return nas.attach_request(); } -bool ue::deattach() { - return nas.deattach_request(); +bool ue::switch_off() { + // generate detach request + nas.detach_request(); + + // wait for max. 5s for it to be sent (according to TS 24.301 Sec 25.5.2.2) + const uint32_t RB_ID_SRB1 = 1; + int cnt = 0, timeout = 5; + while (rlc.get_buffer_state(RB_ID_SRB1) && ++cnt <= timeout) { + sleep(1); + } + bool detach_sent = true; + if (rlc.get_buffer_state(RB_ID_SRB1)) { + nas_log.warning("Detach couldn't be sent after %ds.\n", timeout); + detach_sent = false; + } + + return detach_sent; } bool ue::is_attached() diff --git a/srsue/src/ue_base.cc b/srsue/src/ue_base.cc index b3fc56132..ed3bd4ee9 100644 --- a/srsue/src/ue_base.cc +++ b/srsue/src/ue_base.cc @@ -133,6 +133,9 @@ std::string ue_base::get_build_mode() std::string ue_base::get_build_info() { + if (std::string(srslte_get_build_info()) == "") { + return std::string(srslte_get_version()); + } return std::string(srslte_get_build_info()); } diff --git a/srsue/src/upper/gw.cc b/srsue/src/upper/gw.cc index 3d91791b2..e78bd70bb 100644 --- a/srsue/src/upper/gw.cc +++ b/srsue/src/upper/gw.cc @@ -343,7 +343,7 @@ void gw::run_thread() { gw_log->info_hex(pdu->msg, pdu->N_bytes, "TX PDU"); - while(run_enable && !pdcp->is_drb_enabled(cfg.lcid) && attach_wait < ATTACH_WAIT_TOUT) { + while(run_enable && !pdcp->is_lcid_enabled(cfg.lcid) && attach_wait < ATTACH_WAIT_TOUT) { if (!attach_wait) { gw_log->info("LCID=%d not active, requesting NAS attach (%d/%d)\n", cfg.lcid, attach_wait, ATTACH_WAIT_TOUT); if (!nas->attach_request()) { @@ -361,11 +361,10 @@ void gw::run_thread() } // Send PDU directly to PDCP - if (pdcp->is_drb_enabled(cfg.lcid)) { + if (pdcp->is_lcid_enabled(cfg.lcid)) { pdu->set_timestamp(); ul_tput_bytes += pdu->N_bytes; - pdcp->write_sdu(cfg.lcid, pdu); - + pdcp->write_sdu(cfg.lcid, pdu, false); do { pdu = pool_allocate; if (!pdu) { diff --git a/srsue/src/upper/nas.cc b/srsue/src/upper/nas.cc index 5601896b5..0109be17f 100644 --- a/srsue/src/upper/nas.cc +++ b/srsue/src/upper/nas.cc @@ -172,9 +172,25 @@ bool nas::attach_request() { return false; } -bool nas::deattach_request() { - state = EMM_STATE_DEREGISTERED_INITIATED; - nas_log->info("Dettach request not supported\n"); +bool nas::detach_request() { + // attempt detach for 5s + nas_log->info("Detach Request\n"); + + switch (state) { + case EMM_STATE_DEREGISTERED: + // do nothing .. + break; + case EMM_STATE_REGISTERED: + // send detach request + send_detach_request(true); + state = EMM_STATE_DEREGISTERED_INITIATED; + break; + case EMM_STATE_DEREGISTERED_INITIATED: + // do nothing .. + break; + default: + break; + } return false; } @@ -209,7 +225,12 @@ bool nas::rrc_connect() { } // Generate service request or attach request message - byte_buffer_t *dedicatedInfoNAS = pool_allocate; + byte_buffer_t *dedicatedInfoNAS = pool_allocate_blocking; + if (!dedicatedInfoNAS) { + nas_log->error("Fatal Error: Couldn't allocate PDU in rrc_connect().\n"); + return false; + } + if (state == EMM_STATE_REGISTERED) { gen_service_request(dedicatedInfoNAS); } else { @@ -350,6 +371,9 @@ void nas::write_pdu(uint32_t lcid, byte_buffer_t *pdu) { case LIBLTE_MME_MSG_TYPE_EMM_INFORMATION: parse_emm_information(lcid, pdu); break; + case LIBLTE_MME_MSG_TYPE_DETACH_REQUEST: + parse_detach_request(lcid, pdu); + break; default: nas_log->error("Not handling NAS message with MSG_TYPE=%02X\n", msg_type); pool->deallocate(pdu); @@ -954,6 +978,23 @@ void nas::parse_emm_information(uint32_t lcid, byte_buffer_t *pdu) { pool->deallocate(pdu); } +void nas::parse_detach_request(uint32_t lcid, byte_buffer_t *pdu) +{ + LIBLTE_MME_DETACH_REQUEST_MSG_STRUCT detach_request; + liblte_mme_unpack_detach_request_msg((LIBLTE_BYTE_MSG_STRUCT *) pdu, &detach_request); + ctxt.rx_count++; + pool->deallocate(pdu); + + if (state == EMM_STATE_REGISTERED) { + nas_log->info("Received Detach request (type=%d)\n", detach_request.detach_type.type_of_detach); + state = EMM_STATE_DEREGISTERED; + // send accept + send_detach_accept(); + } else { + nas_log->warning("Received detach request in invalid state (state=%d)\n", state); + } +} + /******************************************************************************* * Senders ******************************************************************************/ @@ -1111,7 +1152,7 @@ void nas::gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg) { } void nas::send_security_mode_reject(uint8_t cause) { - byte_buffer_t *msg = pool_allocate; + byte_buffer_t *msg = pool_allocate_blocking; if (!msg) { nas_log->error("Fatal Error: Couldn't allocate PDU in send_security_mode_reject().\n"); return; @@ -1127,9 +1168,107 @@ void nas::send_security_mode_reject(uint8_t cause) { rrc->write_sdu(cfg.lcid, msg); } +void nas::send_detach_request(bool switch_off) +{ + byte_buffer_t *pdu = pool_allocate_blocking; + if (!pdu) { + nas_log->error("Fatal Error: Couldn't allocate PDU in %s().\n", __FUNCTION__); + return; + } + + LIBLTE_MME_DETACH_REQUEST_MSG_STRUCT 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; + } else { + detach_request.detach_type.switch_off = 0; + detach_request.detach_type.type_of_detach = LIBLTE_MME_SO_FLAG_NORMAL_DETACH; + } + + // GUTI or IMSI detach + if (have_guti && have_ctxt) { + detach_request.eps_mobile_id.type_of_id = LIBLTE_MME_EPS_MOBILE_ID_TYPE_GUTI; + memcpy(&detach_request.eps_mobile_id.guti, &ctxt.guti, sizeof(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT)); + detach_request.nas_ksi.tsc_flag = LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_NATIVE; + detach_request.nas_ksi.nas_ksi = ctxt.ksi; + nas_log->info("Requesting Detach with GUTI\n"); + liblte_mme_pack_detach_request_msg(&detach_request, + LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED, + ctxt.tx_count, + (LIBLTE_BYTE_MSG_STRUCT *) pdu); + + if(pcap != NULL) { + pcap->write_nas(pdu->msg, pdu->N_bytes); + } + + // Add MAC + if (pdu->N_bytes > 5) { + cipher_encrypt(pdu); + integrity_generate(&k_nas_int[16], + ctxt.tx_count, + SECURITY_DIRECTION_UPLINK, + &pdu->msg[5], + pdu->N_bytes - 5, + &pdu->msg[1]); + } else { + nas_log->error("Invalid PDU size %d\n", pdu->N_bytes); + } + } else { + detach_request.eps_mobile_id.type_of_id = LIBLTE_MME_EPS_MOBILE_ID_TYPE_IMSI; + detach_request.nas_ksi.tsc_flag = LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_NATIVE; + detach_request.nas_ksi.nas_ksi = 0; + usim->get_imsi_vec(detach_request.eps_mobile_id.imsi, 15); + nas_log->info("Requesting IMSI detach (IMSI=%s)\n", usim->get_imsi_str().c_str()); + liblte_mme_pack_detach_request_msg(&detach_request, LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS, ctxt.tx_count, (LIBLTE_BYTE_MSG_STRUCT *) pdu); + + if(pcap != NULL) { + pcap->write_nas(pdu->msg, pdu->N_bytes); + } + } + + nas_log->info("Sending detach request\n"); + rrc->write_sdu(cfg.lcid, pdu); +} + +void nas::send_detach_accept() +{ + byte_buffer_t *pdu = pool_allocate_blocking; + if (!pdu) { + nas_log->error("Fatal Error: Couldn't allocate PDU in %s().\n", __FUNCTION__); + return; + } + + LIBLTE_MME_DETACH_ACCEPT_MSG_STRUCT detach_accept; + bzero(&detach_accept, sizeof(detach_accept)); + liblte_mme_pack_detach_accept_msg(&detach_accept, + LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED, + ctxt.tx_count, + (LIBLTE_BYTE_MSG_STRUCT *) pdu); + + if(pcap != NULL) { + pcap->write_nas(pdu->msg, pdu->N_bytes); + } + + // Encrypt and add MAC + if (pdu->N_bytes > 5) { + cipher_encrypt(pdu); + integrity_generate(&k_nas_int[16], + ctxt.tx_count, + SECURITY_DIRECTION_UPLINK, + &pdu->msg[5], + pdu->N_bytes - 5, + &pdu->msg[1]); + } else { + nas_log->error("Invalid PDU size %d\n", pdu->N_bytes); + } + + nas_log->info("Sending detach accept\n"); + rrc->write_sdu(cfg.lcid, pdu); +} + void nas::send_authentication_response(const uint8_t* res, const size_t res_len, const uint8_t sec_hdr_type) { - byte_buffer_t *pdu = pool_allocate; + byte_buffer_t *pdu = pool_allocate_blocking; if (!pdu) { nas_log->error("Fatal Error: Couldn't allocate PDU in send_authentication_response().\n"); return; @@ -1164,7 +1303,7 @@ void nas::send_authentication_response(const uint8_t* res, const size_t res_len, void nas::send_authentication_failure(const uint8_t cause, const uint8_t* auth_fail_param) { - byte_buffer_t *msg = pool_allocate; + byte_buffer_t *msg = pool_allocate_blocking; if (!msg) { nas_log->error("Fatal Error: Couldn't allocate PDU in send_authentication_failure().\n"); return; @@ -1192,7 +1331,7 @@ void nas::send_authentication_failure(const uint8_t cause, const uint8_t* auth_f void nas::send_identity_response() {} void nas::send_service_request() { - byte_buffer_t *msg = pool_allocate; + byte_buffer_t *msg = pool_allocate_blocking; if (!msg) { nas_log->error("Fatal Error: Couldn't allocate PDU in send_service_request().\n"); return; diff --git a/srsue/src/upper/rrc.cc b/srsue/src/upper/rrc.cc index 440b4a318..e4ffe6a82 100644 --- a/srsue/src/upper/rrc.cc +++ b/srsue/src/upper/rrc.cc @@ -237,8 +237,8 @@ bool rrc::have_drb() { return drb_up; } -void rrc::set_args(rrc_args_t *args) { - memcpy(&this->args, args, sizeof(rrc_args_t)); +void rrc::set_args(rrc_args_t args_) { + args = args_; } /* @@ -248,11 +248,14 @@ void rrc::run_thread() { while(running) { cmd_msg_t msg = cmd_q.wait_pop(); switch(msg.command) { - case cmd_msg_t::STOP: - return; + case cmd_msg_t::PDU: + process_pdu(msg.lcid, msg.pdu); + break; case cmd_msg_t::PCCH: process_pcch(msg.pdu); break; + case cmd_msg_t::STOP: + return; } } } @@ -1939,6 +1942,16 @@ void rrc::write_sdu(uint32_t lcid, byte_buffer_t *sdu) { void rrc::write_pdu(uint32_t lcid, byte_buffer_t *pdu) { rrc_log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU", get_rb_name(lcid).c_str()); + // add PDU to command queue + cmd_msg_t msg; + msg.pdu = pdu; + msg.command = cmd_msg_t::PDU; + msg.lcid = lcid; + cmd_q.push(msg); +} + +void rrc::process_pdu(uint32_t lcid, byte_buffer_t *pdu) +{ switch (lcid) { case RB_ID_SRB0: parse_dl_ccch(pdu); @@ -2008,6 +2021,7 @@ void rrc::parse_dl_ccch(byte_buffer_t *pdu) { void rrc::parse_dl_dcch(uint32_t lcid, byte_buffer_t *pdu) { srslte_bit_unpack_vector(pdu->msg, bit_buf.msg, pdu->N_bytes * 8); bit_buf.N_bits = pdu->N_bytes * 8; + bzero(&dl_dcch_msg, sizeof(dl_dcch_msg)); liblte_rrc_unpack_dl_dcch_msg((LIBLTE_BIT_MSG_STRUCT *) &bit_buf, &dl_dcch_msg); rrc_log->info("%s - Received %s\n", @@ -2686,8 +2700,16 @@ void rrc::add_drb(LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT *drb_cnfg) { rrc_log->info("Added radio bearer %s\n", get_rb_name(lcid).c_str()); } -void rrc::release_drb(uint8_t lcid) { - // TODO +void rrc::release_drb(uint32_t drb_id) +{ + uint32_t lcid = RB_ID_SRB2 + drb_id; + + if (drbs.find(drb_id) != drbs.end()) { + rrc_log->info("Releasing radio bearer %s\n", get_rb_name(lcid).c_str()); + drbs.erase(lcid); + } else { + rrc_log->error("Couldn't release radio bearer %s. Doesn't exist.\n", get_rb_name(lcid).c_str()); + } } void rrc::add_mrb(uint32_t lcid, uint32_t port) @@ -2833,9 +2855,9 @@ void rrc::rrc_meas::new_phy_meas(uint32_t earfcn, uint32_t pci, float rsrp, floa if (objects[m->object_id].earfcn == earfcn) { // If it's a newly discovered cell, add it to objects if (!m->cell_values.count(pci)) { - uint32_t cell_idx = objects[m->object_id].cells.size(); - objects[m->object_id].cells[cell_idx].pci = pci; - objects[m->object_id].cells[cell_idx].q_offset = 0; + uint32_t cell_idx = objects[m->object_id].found_cells.size(); + objects[m->object_id].found_cells[cell_idx].pci = pci; + objects[m->object_id].found_cells[cell_idx].q_offset = 0; } // Update or add cell L3_filter(&m->cell_values[pci], values); @@ -2873,7 +2895,7 @@ bool rrc::rrc_meas::find_earfcn_cell(uint32_t earfcn, uint32_t pci, meas_obj_t * if (object) { *object = &obj->second; } - for (std::map::iterator c = obj->second.cells.begin(); c != obj->second.cells.end(); ++c) { + for (std::map::iterator c = obj->second.found_cells.begin(); c != obj->second.found_cells.end(); ++c) { if (c->second.pci == pci) { if (cell_idx) { *cell_idx = c->first; @@ -2999,7 +3021,7 @@ void rrc::rrc_meas::calculate_triggers(uint32_t tti) if (find_earfcn_cell(phy->get_current_earfcn(), phy->get_current_pci(), &serving_object, &serving_cell_idx)) { Ofp = serving_object->q_offset; if (serving_cell_idx >= 0) { - Ocp = serving_object->cells[serving_cell_idx].q_offset; + Ocp = serving_object->found_cells[serving_cell_idx].q_offset; } } else { log_h->warning("Can't find current eafcn=%d, pci=%d in objects list. Using Ofp=0, Ocp=0\n", @@ -3044,7 +3066,7 @@ void rrc::rrc_meas::calculate_triggers(uint32_t tti) // Rest are evaluated for every cell in frequency } else { meas_obj_t *obj = &objects[m->second.object_id]; - for (std::map::iterator cell = obj->cells.begin(); cell != obj->cells.end(); ++cell) { + for (std::map::iterator cell = obj->found_cells.begin(); cell != obj->found_cells.end(); ++cell) { if (m->second.cell_values.count(cell->second.pci)) { float Ofn = obj->q_offset; float Ocn = cell->second.q_offset; @@ -3201,18 +3223,18 @@ bool rrc::rrc_meas::parse_meas_config(LIBLTE_RRC_MEAS_CONFIG_STRUCT *cfg) if (src_obj->black_cells_to_remove_list_present) { for (uint32_t j=0;jblack_cells_to_remove_list.N_cell_idx;j++) { - dst_obj->cells.erase(src_obj->black_cells_to_remove_list.cell_idx[j]); + dst_obj->meas_cells.erase(src_obj->black_cells_to_remove_list.cell_idx[j]); } } for (uint32_t j=0;jN_cells_to_add_mod;j++) { - dst_obj->cells[src_obj->cells_to_add_mod_list[j].cell_idx].q_offset = liblte_rrc_q_offset_range_num[src_obj->cells_to_add_mod_list[j].cell_offset]; - dst_obj->cells[src_obj->cells_to_add_mod_list[j].cell_idx].pci = src_obj->cells_to_add_mod_list[j].pci; + dst_obj->meas_cells[src_obj->cells_to_add_mod_list[j].cell_idx].q_offset = liblte_rrc_q_offset_range_num[src_obj->cells_to_add_mod_list[j].cell_offset]; + dst_obj->meas_cells[src_obj->cells_to_add_mod_list[j].cell_idx].pci = src_obj->cells_to_add_mod_list[j].pci; log_h->info("MEAS: Added measObjectId=%d, earfcn=%d, q_offset=%f, pci=%d, offset_cell=%f\n", cfg->meas_obj_to_add_mod_list.meas_obj_list[i].meas_obj_id, dst_obj->earfcn, dst_obj->q_offset, - dst_obj->cells[src_obj->cells_to_add_mod_list[j].cell_idx].pci, - dst_obj->cells[src_obj->cells_to_add_mod_list[j].cell_idx].q_offset); + dst_obj->meas_cells[src_obj->cells_to_add_mod_list[j].cell_idx].pci, + dst_obj->meas_cells[src_obj->cells_to_add_mod_list[j].cell_idx].q_offset); } @@ -3335,12 +3357,11 @@ bool rrc::rrc_meas::parse_meas_config(LIBLTE_RRC_MEAS_CONFIG_STRUCT *cfg) void rrc::rrc_meas::update_phy() { phy->meas_reset(); - for(std::map::iterator iter=active.begin(); iter!=active.end(); ++iter) { - meas_t m = iter->second; - meas_obj_t o = objects[m.object_id]; + for(std::map::iterator iter=objects.begin(); iter!=objects.end(); ++iter) { + meas_obj_t o = iter->second; // Instruct PHY to look for neighbour cells on this frequency phy->meas_start(o.earfcn); - for(std::map::iterator iter=o.cells.begin(); iter!=o.cells.end(); ++iter) { + for(std::map::iterator iter=o.meas_cells.begin(); iter!=o.meas_cells.end(); ++iter) { // Instruct PHY to look for cells IDs on this frequency phy->meas_start(o.earfcn, iter->second.pci); } diff --git a/srsue/ue.conf.example b/srsue/ue.conf.example index 3d56d19fb..5822ab0c9 100644 --- a/srsue/ue.conf.example +++ b/srsue/ue.conf.example @@ -77,7 +77,7 @@ nas_filename = /tmp/nas.pcap # If set to negative, a single log file will be created. ##################################################################### [log] -all_level = info +all_level = warning phy_lib_level = none all_hex_limit = 32 filename = /tmp/ue.log @@ -209,7 +209,7 @@ enable = false #ip_netmask = 255.255.255.0 #mbms_service = -1 #rssi_sensor_enabled = false -#rx_gain_offset = 72 +#rx_gain_offset = 62 #prach_gain = 30 #cqi_max = 15 #cqi_fixed = 10