mirror of https://github.com/PentHertz/srsLTE.git
Merge branch 'next' into nas_cleanup
This commit is contained in:
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}")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 {
|
||||
} else if (blocking) {
|
||||
// blocking allocation
|
||||
while(available.size() == 0) {
|
||||
pthread_cond_wait(&cv_not_empty, &mutex);
|
||||
}
|
||||
|
||||
// retrieve the new buffer
|
||||
b = available.top();
|
||||
used.push_back(b);
|
||||
available.pop();
|
||||
|
||||
// do not print any warning
|
||||
}
|
||||
else {
|
||||
printf("Error - buffer pool is empty\n");
|
||||
|
||||
#ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED
|
||||
|
@ -148,16 +162,18 @@ public:
|
|||
available.push(b);
|
||||
ret = true;
|
||||
}
|
||||
pthread_cond_signal(&cv_not_empty);
|
||||
pthread_mutex_unlock(&mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
static const int POOL_SIZE = 2048;
|
||||
static const int POOL_SIZE = 4096;
|
||||
std::stack<buffer_t*> available;
|
||||
std::vector<buffer_t*> used;
|
||||
pthread_mutex_t mutex;
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t cv_not_empty;
|
||||
uint32_t capacity;
|
||||
};
|
||||
|
||||
|
@ -169,13 +185,17 @@ public:
|
|||
static byte_buffer_pool* get_instance(int capacity = -1);
|
||||
static void cleanup(void);
|
||||
byte_buffer_pool(int capacity = -1) {
|
||||
log = NULL;
|
||||
pool = new buffer_pool<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;
|
||||
};
|
||||
|
||||
|
|
|
@ -63,7 +63,21 @@ SRSLTE_API uint32_t srslte_crc_attach(srslte_crc_t *h,
|
|||
|
||||
SRSLTE_API uint32_t srslte_crc_attach_byte(srslte_crc_t *h,
|
||||
uint8_t *data,
|
||||
int len);
|
||||
int len);
|
||||
|
||||
static inline void srslte_crc_checksum_put_byte(srslte_crc_t *h, uint8_t byte) {
|
||||
|
||||
// Polynom order 8, 16, 24 or 32 only.
|
||||
int ord = h->order - 8;
|
||||
uint64_t crc = h->crcinit;
|
||||
|
||||
crc = (crc << 8) ^ h->table[((crc >> (ord)) & 0xff) ^ byte];
|
||||
h->crcinit = crc;
|
||||
}
|
||||
|
||||
static inline uint64_t srslte_crc_checksum_get(srslte_crc_t *h) {
|
||||
return (h->crcinit & h->crcmask);
|
||||
}
|
||||
|
||||
SRSLTE_API uint32_t srslte_crc_checksum_byte(srslte_crc_t *h,
|
||||
uint8_t *data,
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
|
||||
#include "srslte/config.h"
|
||||
#include "srslte/phy/fec/tc_interl.h"
|
||||
#include "srslte/phy/fec/crc.h"
|
||||
|
||||
#define SRSLTE_TCOD_MAX_LEN_CB_BYTES (6144/8)
|
||||
|
||||
|
@ -68,7 +69,8 @@ SRSLTE_API int srslte_tcod_encode(srslte_tcod_t *h,
|
|||
uint8_t *output,
|
||||
uint32_t long_cb);
|
||||
|
||||
SRSLTE_API int srslte_tcod_encode_lut(srslte_tcod_t *h,
|
||||
SRSLTE_API int srslte_tcod_encode_lut(srslte_tcod_t *h,
|
||||
srslte_crc_t *crc,
|
||||
uint8_t *input,
|
||||
uint8_t *parity,
|
||||
uint32_t cblen_idx);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#include <complex.h>
|
||||
#include <math.h>
|
||||
|
||||
|
@ -49,7 +49,7 @@
|
|||
#include "srslte/phy/common/sequence.h"
|
||||
#include "srslte/phy/common/phy_common.h"
|
||||
#include "srslte/phy/common/phy_logger.h"
|
||||
|
||||
|
||||
#include "srslte/phy/ch_estimation/chest_ul.h"
|
||||
#include "srslte/phy/ch_estimation/chest_dl.h"
|
||||
#include "srslte/phy/ch_estimation/refsignal_dl.h"
|
||||
|
@ -104,7 +104,7 @@
|
|||
#include "srslte/phy/phch/regs.h"
|
||||
#include "srslte/phy/phch/sch.h"
|
||||
#include "srslte/phy/phch/uci.h"
|
||||
|
||||
|
||||
#include "srslte/phy/ue/ue_sync.h"
|
||||
#include "srslte/phy/ue/ue_mib.h"
|
||||
#include "srslte/phy/ue/ue_cell_search.h"
|
||||
|
|
|
@ -41,7 +41,7 @@ class pdcp
|
|||
{
|
||||
public:
|
||||
pdcp();
|
||||
virtual ~pdcp(){}
|
||||
virtual ~pdcp();
|
||||
void init(srsue::rlc_interface_pdcp *rlc_,
|
||||
srsue::rrc_interface_pdcp *rrc_,
|
||||
srsue::gw_interface_pdcp *gw_,
|
||||
|
@ -51,15 +51,16 @@ public:
|
|||
void stop();
|
||||
|
||||
// GW interface
|
||||
bool is_drb_enabled(uint32_t lcid);
|
||||
bool is_lcid_enabled(uint32_t lcid);
|
||||
|
||||
// RRC interface
|
||||
void reestablish();
|
||||
void reset();
|
||||
void write_sdu(uint32_t lcid, byte_buffer_t *sdu);
|
||||
void write_sdu(uint32_t lcid, byte_buffer_t *sdu, bool blocking = true);
|
||||
void write_sdu_mch(uint32_t lcid, byte_buffer_t *sdu);
|
||||
void add_bearer(uint32_t lcid, srslte_pdcp_config_t cnfg = srslte_pdcp_config_t());
|
||||
void add_bearer_mrb(uint32_t lcid, srslte_pdcp_config_t cnfg = srslte_pdcp_config_t());
|
||||
void del_bearer(uint32_t lcid);
|
||||
void config_security(uint32_t lcid,
|
||||
uint8_t *k_enc,
|
||||
uint8_t *k_int,
|
||||
|
@ -71,6 +72,8 @@ public:
|
|||
INTEGRITY_ALGORITHM_ID_ENUM integ_algo);
|
||||
void enable_integrity(uint32_t lcid);
|
||||
void enable_encryption(uint32_t lcid);
|
||||
uint32_t get_dl_count(uint32_t lcid);
|
||||
uint32_t get_ul_count(uint32_t lcid);
|
||||
|
||||
// RLC interface
|
||||
void write_pdu(uint32_t lcid, byte_buffer_t *sdu);
|
||||
|
@ -78,18 +81,22 @@ public:
|
|||
void write_pdu_bcch_bch(byte_buffer_t *sdu);
|
||||
void write_pdu_bcch_dlsch(byte_buffer_t *sdu);
|
||||
void write_pdu_pcch(byte_buffer_t *sdu);
|
||||
|
||||
|
||||
private:
|
||||
srsue::rlc_interface_pdcp *rlc;
|
||||
srsue::rrc_interface_pdcp *rrc;
|
||||
srsue::gw_interface_pdcp *gw;
|
||||
|
||||
log *pdcp_log;
|
||||
pdcp_entity pdcp_array[SRSLTE_N_RADIO_BEARERS];
|
||||
pdcp_entity pdcp_array_mrb[SRSLTE_N_MCH_LCIDS];
|
||||
uint32_t lcid; // default LCID that is maintained active by PDCP instance
|
||||
uint8_t direction;
|
||||
typedef std::map<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,18 +55,17 @@ public:
|
|||
srsue::pdcp_interface_rlc *pdcp_,
|
||||
srsue::rrc_interface_rlc *rrc_,
|
||||
mac_interface_timers *mac_timers_);
|
||||
void configure(srslte_rlc_config_t cnfg);
|
||||
bool configure(srslte_rlc_config_t cnfg);
|
||||
void reestablish();
|
||||
void stop();
|
||||
void empty_queue();
|
||||
void empty_queue();
|
||||
bool is_mrb();
|
||||
|
||||
rlc_mode_t get_mode();
|
||||
uint32_t get_bearer();
|
||||
|
||||
// PDCP interface
|
||||
void write_sdu(byte_buffer_t *sdu);
|
||||
void write_sdu_nb(byte_buffer_t *sdu);
|
||||
void write_sdu(byte_buffer_t *sdu, bool blocking = true);
|
||||
|
||||
// MAC interface
|
||||
uint32_t get_buffer_state();
|
||||
|
@ -75,72 +73,148 @@ public:
|
|||
int read_pdu(uint8_t *payload, uint32_t nof_bytes);
|
||||
void write_pdu(uint8_t *payload, uint32_t nof_bytes);
|
||||
int get_increment_sequence_num();
|
||||
// Timeout callback interface
|
||||
void timer_expired(uint32_t timeout_id);
|
||||
|
||||
bool reordering_timeout_running();
|
||||
uint32_t get_num_tx_bytes();
|
||||
uint32_t get_num_rx_bytes();
|
||||
void reset_metrics();
|
||||
|
||||
private:
|
||||
|
||||
byte_buffer_pool *pool;
|
||||
srslte::log *log;
|
||||
uint32_t lcid;
|
||||
srsue::pdcp_interface_rlc *pdcp;
|
||||
srsue::rrc_interface_rlc *rrc;
|
||||
mac_interface_timers *mac_timers;
|
||||
// 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();
|
||||
|
||||
// TX SDU buffers
|
||||
rlc_tx_queue tx_sdu_queue;
|
||||
byte_buffer_t *tx_sdu;
|
||||
byte_buffer_t tx_sdu_temp;
|
||||
private:
|
||||
byte_buffer_pool *pool;
|
||||
srslte::log *log;
|
||||
std::string rb_name;
|
||||
|
||||
// Rx window
|
||||
std::map<uint32_t, rlc_umd_pdu_t> rx_window;
|
||||
/****************************************************************************
|
||||
* Configurable parameters
|
||||
* Ref: 3GPP TS 36.322 v10.0.0 Section 7
|
||||
***************************************************************************/
|
||||
srslte_rlc_um_config_t cfg;
|
||||
|
||||
// RX SDU buffers
|
||||
byte_buffer_t *rx_sdu;
|
||||
uint32_t vr_ur_in_rx_sdu;
|
||||
// TX SDU buffers
|
||||
rlc_tx_queue tx_sdu_queue;
|
||||
byte_buffer_t *tx_sdu;
|
||||
|
||||
// Mutexes
|
||||
pthread_mutex_t mutex;
|
||||
/****************************************************************************
|
||||
* 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.
|
||||
|
||||
/****************************************************************************
|
||||
* Configurable parameters
|
||||
* Ref: 3GPP TS 36.322 v10.0.0 Section 7
|
||||
***************************************************************************/
|
||||
// Mutexes
|
||||
pthread_mutex_t mutex;
|
||||
|
||||
srslte_rlc_um_config_t cfg;
|
||||
bool tx_enabled;
|
||||
|
||||
/****************************************************************************
|
||||
* State variables and counters
|
||||
* Ref: 3GPP TS 36.322 v10.0.0 Section 7
|
||||
***************************************************************************/
|
||||
uint32_t num_tx_bytes;
|
||||
|
||||
// Tx state variables
|
||||
uint32_t vt_us; // Send state. SN to be assigned for next PDU.
|
||||
// helper functions
|
||||
void debug_state();
|
||||
const char* get_rb_name();
|
||||
};
|
||||
|
||||
// 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.
|
||||
// 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();
|
||||
|
||||
/****************************************************************************
|
||||
* Timers
|
||||
* Ref: 3GPP TS 36.322 v10.0.0 Section 7
|
||||
***************************************************************************/
|
||||
srslte::timers::timer *reordering_timer;
|
||||
uint32_t reordering_timer_id;
|
||||
// Timeout callback interface
|
||||
void timer_expired(uint32_t timeout_id);
|
||||
|
||||
bool tx_enabled;
|
||||
bool pdu_lost;
|
||||
private:
|
||||
byte_buffer_pool *pool;
|
||||
srslte::log *log;
|
||||
mac_interface_timers *mac_timers;
|
||||
std::string rb_name;
|
||||
|
||||
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();
|
||||
/****************************************************************************
|
||||
* Configurable parameters
|
||||
* Ref: 3GPP TS 36.322 v10.0.0 Section 7
|
||||
***************************************************************************/
|
||||
srslte_rlc_um_config_t cfg;
|
||||
|
||||
std::string rb_name();
|
||||
// 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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
/* Reset CRC */
|
||||
if (crc) {
|
||||
srslte_crc_set_init(crc, 0);
|
||||
}
|
||||
parity[long_cb/8] = 0; // will put tail here later
|
||||
|
||||
/* Parity bits for the 1st constituent encoders */
|
||||
uint8_t state0 = 0;
|
||||
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
|
||||
|
||||
/* 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;
|
||||
parity[long_cb/8+i+1] = (out&0xf)<<4;
|
||||
state1 = l.next_state;
|
||||
}
|
||||
|
||||
/* Tail bits */
|
||||
|
@ -302,40 +345,40 @@ void srslte_tcod_gentable() {
|
|||
return;
|
||||
}
|
||||
// Save fw/bw permutation tables
|
||||
for (uint32_t i=0;i<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++) {
|
||||
|
||||
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;
|
||||
}
|
||||
// Compute state transitions
|
||||
for (uint32_t state=0;state<8;state++) {
|
||||
for (uint32_t data=0;data<256;data++) {
|
||||
|
||||
in = bit ^ (reg_2 ^ reg_1);
|
||||
out = reg_2 ^ (reg_0 ^ in);
|
||||
uint8_t reg_0, reg_1, reg_2;
|
||||
reg_0 = (state&4)>>2;
|
||||
reg_1 = (state&2)>>1;
|
||||
reg_2 = state&1;
|
||||
|
||||
reg_2 = reg_1;
|
||||
reg_1 = reg_0;
|
||||
reg_0 = in;
|
||||
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;
|
||||
|
||||
tcod_lut_output[len][state][data] |= out<<(7-i);
|
||||
in = bit ^ (reg_2 ^ reg_1);
|
||||
out = reg_2 ^ (reg_0 ^ in);
|
||||
|
||||
reg_2 = reg_1;
|
||||
reg_1 = reg_0;
|
||||
reg_0 = in;
|
||||
|
||||
tcod_lut[state][data].output |= out<<(7-i);
|
||||
|
||||
}
|
||||
tcod_lut_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);
|
||||
}
|
||||
}
|
||||
|
||||
srslte_tc_interl_free(&interl);
|
||||
|
|
|
@ -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)))
|
||||
|
|
|
@ -264,15 +264,12 @@ static int encode_tb_off(srslte_sch_t *q,
|
|||
/* Append Transport Block parity bits to the last CB */
|
||||
memcpy(q->cb_in, &data[rp/8], (rlen - 24) * sizeof(uint8_t)/8);
|
||||
memcpy(&q->cb_in[(rlen - 24)/8], parity, 3 * sizeof(uint8_t));
|
||||
}
|
||||
|
||||
/* Attach Codeblock CRC */
|
||||
if (cb_segm->C > 1) {
|
||||
srslte_crc_attach_byte(&q->crc_cb, q->cb_in, rlen);
|
||||
}
|
||||
|
||||
/* Turbo Encoding */
|
||||
srslte_tcod_encode_lut(&q->encoder, q->cb_in, q->parity_bits, cblen_idx);
|
||||
/* Turbo Encoding
|
||||
* If Codeblock CRC is required it is given the CRC instance pointer, otherwise CRC pointer shall be NULL
|
||||
*/
|
||||
srslte_tcod_encode_lut(&q->encoder, (cb_segm->C > 1) ? &q->crc_cb : NULL, q->cb_in, q->parity_bits, cblen_idx);
|
||||
}
|
||||
DEBUG("RM cblen_idx=%d, n_e=%d, wp=%d, nof_e_bits=%d\n",cblen_idx, n_e, wp, nof_e_bits);
|
||||
|
||||
|
|
|
@ -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_,
|
||||
|
@ -63,109 +81,159 @@ void rlc::init(srsue::pdcp_interface_rlc *pdcp_,
|
|||
buffer_size = buffer_size_;
|
||||
|
||||
gettimeofday(&metrics_time[1], NULL);
|
||||
reset_metrics();
|
||||
reset_metrics();
|
||||
|
||||
rlc_array[0].init(RLC_MODE_TM, rlc_log, default_lcid, pdcp, rrc, mac_timers, buffer_size); // SRB0
|
||||
// create default RLC_TM bearer for SRB0
|
||||
add_bearer(default_lcid, srslte_rlc_config_t());
|
||||
}
|
||||
|
||||
void rlc::reset_metrics()
|
||||
{
|
||||
bzero(dl_tput_bytes, sizeof(long)*SRSLTE_N_RADIO_BEARERS);
|
||||
bzero(ul_tput_bytes, sizeof(long)*SRSLTE_N_RADIO_BEARERS);
|
||||
for (rlc_map_t::iterator it = rlc_array.begin(); it != rlc_array.end(); ++it) {
|
||||
it->second->reset_metrics();
|
||||
}
|
||||
|
||||
for (rlc_map_t::iterator it = rlc_array_mrb.begin(); it != rlc_array_mrb.end(); ++it) {
|
||||
it->second->reset_metrics();
|
||||
}
|
||||
}
|
||||
|
||||
void rlc::stop()
|
||||
{
|
||||
for(uint32_t i=0; 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);
|
||||
double secs = (double)metrics_time[0].tv_sec + metrics_time[0].tv_usec*1e-6;
|
||||
|
||||
m.dl_tput_mbps = 0;
|
||||
m.ul_tput_mbps = 0;
|
||||
for (int i=0;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);
|
||||
}
|
||||
m.ul_tput_mbps = 0;
|
||||
|
||||
for (rlc_map_t::iterator it = rlc_array.begin(); it != rlc_array.end(); ++it) {
|
||||
m.dl_tput_mbps += (it->second->get_num_rx_bytes()*8/(double)1e6)/secs;
|
||||
m.ul_tput_mbps += (it->second->get_num_tx_bytes()*8/(double)1e6)/secs;
|
||||
rlc_log->info("LCID=%d, RX throughput: %4.6f Mbps. TX throughput: %4.6f Mbps.\n",
|
||||
it->first,
|
||||
(it->second->get_num_rx_bytes()*8/(double)1e6)/secs,
|
||||
(it->second->get_num_tx_bytes()*8/(double)1e6)/secs);
|
||||
}
|
||||
|
||||
// Add multicast metrics
|
||||
for (int i=0;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);
|
||||
}
|
||||
}
|
||||
void rlc::write_sdu_nb(uint32_t lcid, byte_buffer_t *sdu)
|
||||
{
|
||||
if(valid_lcid(lcid)) {
|
||||
rlc_array[lcid].write_sdu_nb(sdu);
|
||||
}
|
||||
}
|
||||
void rlc::write_sdu_mch(uint32_t lcid, byte_buffer_t *sdu)
|
||||
{
|
||||
if(valid_lcid_mrb(lcid)) {
|
||||
rlc_array_mrb[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);
|
||||
}
|
||||
|
||||
bool rlc::rb_is_um(uint32_t lcid) {
|
||||
return rlc_array[lcid].get_mode()==RLC_MODE_UM;
|
||||
void rlc::write_sdu_mch(uint32_t lcid, byte_buffer_t *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);
|
||||
}
|
||||
|
||||
|
||||
bool rlc::rb_is_um(uint32_t lcid)
|
||||
{
|
||||
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);
|
||||
|
||||
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());
|
||||
}
|
||||
rlc_array_mrb[lcid].init(rlc_log, lcid, pdcp, rrc, mac_timers);
|
||||
rlc_array_mrb[lcid].configure(srslte_rlc_config_t::mch_config());
|
||||
|
||||
delete_and_exit:
|
||||
if (rlc_entity) {
|
||||
delete(rlc_entity);
|
||||
}
|
||||
|
||||
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);
|
||||
return false;
|
||||
} else if(!rlc_array[lcid].active()) {
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
gettimeofday(&t[2], NULL);
|
||||
get_time_interval(t);
|
||||
pdsch_encode_us += t[0].tv_sec * 1e6 + t[0].tv_usec;
|
||||
|
||||
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);
|
||||
/*
|
||||
* 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>
|
||||
|
|
|
@ -56,7 +56,7 @@ void pdcp::add_user(uint16_t rnti)
|
|||
{
|
||||
pthread_rwlock_rdlock(&rwlock);
|
||||
if (users.count(rnti) == 0) {
|
||||
srslte::pdcp *obj = new srslte::pdcp;
|
||||
srslte::pdcp *obj = new srslte::pdcp;
|
||||
obj->init(&users[rnti].rlc_itf, &users[rnti].rrc_itf, &users[rnti].gtpu_itf, log_h, RB_ID_SRB0, SECURITY_DIRECTION_DOWNLINK);
|
||||
users[rnti].rlc_itf.rnti = rnti;
|
||||
users[rnti].gtpu_itf.rnti = rnti;
|
||||
|
@ -154,9 +154,8 @@ void pdcp::user_interface_gtpu::write_pdu(uint32_t lcid, srslte::byte_buffer_t *
|
|||
gtpu->write_pdu(rnti, lcid, pdu);
|
||||
}
|
||||
|
||||
void pdcp::user_interface_rlc::write_sdu(uint32_t lcid, srslte::byte_buffer_t* sdu)
|
||||
void pdcp::user_interface_rlc::write_sdu(uint32_t lcid, srslte::byte_buffer_t* sdu, bool blocking)
|
||||
{
|
||||
|
||||
rlc->write_sdu(rnti, lcid, sdu);
|
||||
}
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
@ -39,7 +40,7 @@ namespace bpo = boost::program_options;
|
|||
|
||||
bool running = true;
|
||||
|
||||
void
|
||||
void
|
||||
sig_int_handler(int signo){
|
||||
running = false;
|
||||
}
|
||||
|
@ -289,11 +290,13 @@ level(std::string l)
|
|||
int
|
||||
main (int argc,char * argv[] )
|
||||
{
|
||||
cout << endl <<"--- Software Radio Systems EPC ---" << endl << endl;
|
||||
signal(SIGINT, sig_int_handler);
|
||||
signal(SIGTERM, sig_int_handler);
|
||||
signal(SIGKILL, sig_int_handler);
|
||||
|
||||
cout << endl <<"--- Software Radio Systems EPC ---" << endl << endl;
|
||||
srslte_debug_handle_crash(argc, argv);
|
||||
|
||||
all_args_t args;
|
||||
parse_args(&args, argc, argv);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
@ -1504,7 +1507,9 @@ void phch_worker::set_ul_params(bool pregen_disabled)
|
|||
/* SR configuration */
|
||||
I_sr = dedicated->sched_request_cnfg.sr_cnfg_idx;
|
||||
sr_configured = true;
|
||||
|
||||
|
||||
pthread_mutex_unlock(&mutex);
|
||||
|
||||
if (pregen_enabled && !pregen_disabled) {
|
||||
Info("Pre-generating UL signals worker=%d\n", get_id());
|
||||
srslte_ue_ul_pregen_signals(&ue_ul);
|
||||
|
|
|
@ -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…
Reference in New Issue