Merge branch 'next' into nas_cleanup

master
Pedro Alvarez 6 years ago
commit 7077530a29

@ -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

@ -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}")

10
debian/changelog vendored

@ -1,11 +1,17 @@
srslte (18.06.1-0ubuntu1) bionic; urgency=medium
* Update to srsLTE 18.06.1
-- Andre Puschmann <andre@softwareradiosystems.com> Wed, 18 Jul 2018 11:34:00 +0200
srslte (18.05~SNAPSHOT-0ubuntu2) bionic; urgency=medium
* Update pkg deps
-- Andre Puschmann <andre@softwareradiosystems.com> Tue, 01 June 2018 15:10:00 +0200
-- Andre Puschmann <andre@softwareradiosystems.com> Tue, 01 Jun 2018 15:10:00 +0200
srslte (18.05~SNAPSHOT-0ubuntu1) bionic; urgency=medium
* Initial release of deb's
-- Andre Puschmann <andre@softwareradiosystems.com> Tue, 01 June 2018 14:10:00 +0200
-- Andre Puschmann <andre@softwareradiosystems.com> Tue, 01 Jun 2018 14:10:00 +0200

15
debian/control vendored

@ -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.

5
debian/rules vendored

@ -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

@ -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)

@ -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,

@ -38,6 +38,7 @@
#include "srslte/srslte.h"
#include "srslte/phy/rf/rf_utils.h"
#include "srslte/common/crash_handler.h"
#ifndef DISABLE_RF

@ -33,6 +33,7 @@
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
#include "srslte/common/crash_handler.h"
#include <srslte/phy/common/phy_common.h>
#include <srslte/phy/phch/pdsch_cfg.h>
#include "srslte/common/gen_mch_tables.h"

@ -37,6 +37,7 @@
#include <pthread.h>
#include <semaphore.h>
#include "srslte/common/gen_mch_tables.h"
#include "srslte/common/crash_handler.h"
#include <srslte/phy/common/phy_common.h>
#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));

@ -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<nof_buffers;i++) {
buffer_t *b = new buffer_t;
available.push(b);
@ -80,6 +82,8 @@ public:
for (uint32_t i = 0; i < used.size(); i++) {
delete used[i];
}
pthread_cond_destroy(&cv_not_empty);
pthread_mutex_destroy(&mutex);
}
void print_all_buffers()
@ -105,28 +109,38 @@ public:
return available.size() < capacity/20;
}
buffer_t* allocate(const char *debug_name = NULL)
{
buffer_t* allocate(const char *debug_name = NULL, bool blocking = false) {
pthread_mutex_lock(&mutex);
buffer_t* b = NULL;
buffer_t *b = NULL;
if(available.size() > 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 if (blocking) {
// blocking allocation
while(available.size() == 0) {
pthread_cond_wait(&cv_not_empty, &mutex);
}
} else {
// 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<buffer_t*> available;
std::vector<buffer_t*> used;
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<byte_buffer_t>(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<byte_buffer_t> *pool;
};

@ -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())

@ -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 <stdio.h>
#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

@ -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;
};

@ -65,6 +65,20 @@ SRSLTE_API uint32_t srslte_crc_attach_byte(srslte_crc_t *h,
uint8_t *data,
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,
int len);

@ -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)
@ -69,6 +70,7 @@ SRSLTE_API int srslte_tcod_encode(srslte_tcod_t *h,
uint32_t long_cb);
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);

@ -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

@ -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);
@ -79,17 +82,21 @@ public:
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<uint16_t, pdcp_entity_interface*> pdcp_map_t;
typedef std::pair<uint16_t, pdcp_entity_interface*> 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);

@ -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);

@ -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

@ -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<uint16_t, rlc_common*> rlc_map_t;
typedef std::pair<uint16_t, rlc_common*> 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);

@ -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

@ -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;

@ -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

@ -28,10 +28,19 @@
#define SRSLTE_RLC_INTERFACE_H
// for custom constructors
#include "srslte/asn1/liblte_rrc.h"
#include <srslte/asn1/liblte_rrc.h>
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;

@ -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;
};

@ -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,7 +55,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();
void empty_queue();
@ -66,8 +65,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();
@ -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<uint32_t, rlc_umd_pdu_t> 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<uint32_t, rlc_umd_pdu_t> 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);
};
/****************************************************************************

@ -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 <pthread.h>
#include <stdio.h>
#include <execinfo.h>
#include <signal.h>
#include <stdlib.h>
#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);
}

@ -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;

@ -259,6 +259,7 @@ void srslte_rm_turbo_free_tables () {
}
rm_turbo_tables_generated = false;
}
rm_turbo_tables_generated = false;
}
/**

@ -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));

@ -29,6 +29,7 @@
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <srslte/phy/fec/crc.h>
#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;i<long_cb/8;i++) {
parity[i] = tcod_lut_output[cblen_idx][state0][input[i]];
state0 = tcod_lut_next_state[cblen_idx][state0][input[i]] % 8;
if (crc) {
/* if CRC pointer is given */
for (int i = 0; i < (long_cb - crc->order) / 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;i<long_cb/8;i++) {
uint8_t out = tcod_lut_output[cblen_idx][state1][h->temp[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;
state1 = l.next_state;
}
/* Tail bits */
@ -302,39 +345,39 @@ void srslte_tcod_gentable() {
return;
}
// Save fw/bw permutation tables
for (uint32_t i=0;i<long_cb;i++) {
for (uint32_t i = 0; i < long_cb; i++) {
tcod_per_fw[len][i] = interl.forward[i];
}
srslte_bit_interleaver_init(&tcod_interleavers[len], tcod_per_fw[len], long_cb);
for (uint32_t i=long_cb;i<6144;i++) {
for (uint32_t i = long_cb; i < 6144; i++) {
tcod_per_fw[len][i] = 0;
}
// Compute state transitions
for (uint32_t state=0;state<8;state++) {
for (uint32_t data=0;data<256;data++) {
}
// 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;
uint8_t reg_0, reg_1, reg_2;
reg_0 = (state&4)>>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;
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);
in = bit ^ (reg_2 ^ reg_1);
out = reg_2 ^ (reg_0 ^ in);
reg_2 = reg_1;
reg_1 = reg_0;
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[state][data].output |= out<<(7-i);
}
tcod_lut_next_state[len][state][data] = reg_0<<2 | reg_1<<1 | reg_2;
}
tcod_lut[state][data].next_state = (uint8_t) ((reg_0 << 2 | reg_1 << 1 | reg_2) % 8);
}
}

@ -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,

@ -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)))

@ -266,13 +266,10 @@ static int encode_tb_off(srslte_sch_t *q,
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);

@ -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;

@ -24,14 +24,8 @@
*
*/
#include <pthread.h>
#include <stdio.h>
#include <execinfo.h>
#include <signal.h>
#include <stdlib.h>
#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);
}

@ -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;i<SRSLTE_N_RADIO_BEARERS;i++) {
if (pdcp_array[i].is_active()) {
pdcp_array[i].reestablish();
}
pthread_rwlock_rdlock(&rwlock);
for (pdcp_map_t::iterator it = pdcp_array.begin(); it != pdcp_array.end(); ++it) {
it->second->reestablish();
}
pthread_rwlock_unlock(&rwlock);
}
void pdcp::reset()
{
for(uint32_t i=0;i<SRSLTE_N_RADIO_BEARERS;i++) {
pdcp_array[i].reset();
// destroy all bearers
pthread_rwlock_wrlock(&rwlock);
for (pdcp_map_t::iterator it = pdcp_array.begin(); it != pdcp_array.end(); ++it) {
it->second->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;i<SRSLTE_N_RADIO_BEARERS;i++) {
if (pdcp_array[i].is_active()) {
pdcp_array[i].config_security(k_enc, k_int, cipher_algo, integ_algo);
}
pthread_rwlock_rdlock(&rwlock);
for (pdcp_map_t::iterator it = pdcp_array.begin(); it != pdcp_array.end(); ++it) {
it->second->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;
}

@ -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

@ -25,6 +25,7 @@
*/
#include <srslte/asn1/liblte_rrc.h>
#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_,
@ -65,26 +83,36 @@ void rlc::init(srsue::pdcp_interface_rlc *pdcp_,
gettimeofday(&metrics_time[1], NULL);
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; i<SRSLTE_N_RADIO_BEARERS; i++) {
if(rlc_array[i].active()) {
rlc_array[i].stop();
}
pthread_rwlock_rdlock(&rwlock);
for (rlc_map_t::iterator it = rlc_array.begin(); it != rlc_array.end(); ++it) {
it->second->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);
@ -92,80 +120,120 @@ void rlc::get_metrics(rlc_metrics_t &m)
m.dl_tput_mbps = 0;
m.ul_tput_mbps = 0;
for (int i=0;i<SRSLTE_N_RADIO_BEARERS;i++) {
m.dl_tput_mbps += (dl_tput_bytes[i]*8/(double)1e6)/secs;
m.ul_tput_mbps += (ul_tput_bytes[i]*8/(double)1e6)/secs;
if(rlc_array[i].active()) {
rlc_log->info("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);
}
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;i<SRSLTE_N_MCH_LCIDS;i++) {
m.dl_tput_mbps += (dl_tput_bytes_mrb[i]*8/(double)1e6)/secs;
if(rlc_array_mrb[i].is_mrb()) {
rlc_log->info("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; i<SRSLTE_N_RADIO_BEARERS; i++) {
if(rlc_array[i].active()) {
rlc_array[i].reestablish();
}
void rlc::reestablish()
{
pthread_rwlock_rdlock(&rwlock);
for (rlc_map_t::iterator it = rlc_array.begin(); it != rlc_array.end(); ++it) {
it->second->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; i<SRSLTE_N_RADIO_BEARERS; i++) {
if(rlc_array[i].active())
rlc_array[i].empty_queue();
// Empty Tx queue, not needed for MCH bearers
pthread_rwlock_rdlock(&rwlock);
for (rlc_map_t::iterator it = rlc_array.begin(); it != rlc_array.end(); ++it) {
it->second->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

@ -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");

@ -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

@ -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");

File diff suppressed because it is too large Load Diff

@ -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);

@ -27,11 +27,13 @@
#include <iostream>
#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 <assert.h>
#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();
}

@ -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);
}

@ -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);

@ -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

@ -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;

@ -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);
};

@ -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;i<args->expert.phy.nof_phy_threads;i++) {

@ -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++;
}

@ -31,6 +31,7 @@
#include <pthread.h>
#include "srslte/common/config_file.h"
#include "srslte/common/crash_handler.h"
#include <iostream>
#include <string>

@ -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);
}

@ -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);

@ -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

@ -27,6 +27,7 @@
#include <signal.h>
#include <boost/program_options.hpp>
#include <boost/algorithm/string.hpp>
#include "srslte/common/crash_handler.h"
#include "srslte/common/bcd_helpers.h"
#include "srslte/common/config_file.h"
#include "srsepc/hdr/mme/mme.h"
@ -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);

@ -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;

@ -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;

@ -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);

@ -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<uint32_t, meas_cell_t> cells;
std::map<uint32_t, meas_cell_t> meas_cells;
std::map<uint32_t, meas_cell_t> 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);

@ -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();

@ -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;
@ -1505,6 +1508,8 @@ void phch_worker::set_ul_params(bool pregen_disabled)
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);

@ -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<uint32_t> 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()

@ -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());
}

@ -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) {

@ -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;

@ -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<uint32_t, meas_cell_t>::iterator c = obj->second.cells.begin(); c != obj->second.cells.end(); ++c) {
for (std::map<uint32_t, meas_cell_t>::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<uint32_t, meas_cell_t>::iterator cell = obj->cells.begin(); cell != obj->cells.end(); ++cell) {
for (std::map<uint32_t, meas_cell_t>::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;j<src_obj->black_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;j<src_obj->N_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<uint32_t, meas_t>::iterator iter=active.begin(); iter!=active.end(); ++iter) {
meas_t m = iter->second;
meas_obj_t o = objects[m.object_id];
for(std::map<uint32_t, meas_obj_t>::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<uint32_t, meas_cell_t>::iterator iter=o.cells.begin(); iter!=o.cells.end(); ++iter) {
for(std::map<uint32_t, meas_cell_t>::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);
}

@ -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

Loading…
Cancel
Save