Merge branch 'next'

master
Andre Puschmann 5 years ago
commit 6d62e15d2a

@ -3,10 +3,30 @@ sudo: required
before_script: before_script:
- sudo apt-get -qq update - sudo apt-get -qq update
- sudo apt-get install -qq build-essential cmake libfftw3-dev libmbedtls-dev libpcsclite-dev libboost-program-options-dev libconfig++-dev libsctp-dev - sudo apt-get install -qq build-essential cmake libfftw3-dev libmbedtls-dev libpcsclite-dev libboost-program-options-dev libconfig++-dev libsctp-dev colordiff
language: cpp language: cpp
addons:
apt:
sources:
- llvm-toolchain-trusty-8
- key_url: 'http://apt.llvm.org/llvm-snapshot.gpg.key'
packages:
- clang-format-8
script: script:
- sudo ln -s /usr/bin/clang-format-diff-8 /usr/bin/clang-format-diff
- git remote set-branches --add origin master
- git fetch
- |
if [[ "$TRAVIS_PULL_REQUEST" != "false" ]]; then
# Run only for PRs because target branch is needed to do the clang-format check
echo "Checking clang-format between TRAVIS_BRANCH=$TRAVIS_BRANCH and TRAVIS_PULL_REQUEST_BRANCH=$TRAVIS_PULL_REQUEST_BRANCH"
./run-clang-format-diff.sh "$TRAVIS_BRANCH" "$TRAVIS_PULL_REQUEST_BRANCH"
else
echo "Skipping clang-format check"
fi
- mkdir build - mkdir build
- cd build - cd build
- cmake -DRF_FOUND=True .. - cmake -DRF_FOUND=True ..

@ -1,6 +1,17 @@
Change Log for Releases Change Log for Releases
============================== ==============================
## 19.09
* Add initial support for NR in MAC/RLC/PDCP
* Add sync code for NB-IoT
* Add support for EIA3/EEA3 (i.e. ZUC)
* Add support for CSFB in srsENB
* Add adaptation layer to run TTCN-3 conformance tests for srsUE
* Add High Speed Train model to channel simulator
* Rework RRC and NAS layer and make them non-blocking
* Fixes in ZMQ, bladeRF and Soapy RF modules
* Other bug-fixes and improved stability and performance in all parts
## 19.06 ## 19.06
* Add QAM256 support in srsUE * Add QAM256 support in srsUE
* Add QoS support in srsUE * Add QoS support in srsUE

@ -55,7 +55,7 @@ set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "")
# Generate CMake to include build information # Generate CMake to include build information
configure_file( configure_file(
${CMAKE_SOURCE_DIR}/cmake/modules/SRSLTEbuildinfo.cmake.in ${PROJECT_SOURCE_DIR}/cmake/modules/SRSLTEbuildinfo.cmake.in
${CMAKE_BINARY_DIR}/SRSLTEbuildinfo.cmake ${CMAKE_BINARY_DIR}/SRSLTEbuildinfo.cmake
) )
@ -74,6 +74,8 @@ option(ENABLE_SOAPYSDR "Enable SoapySDR" ON)
option(ENABLE_ZEROMQ "Enable ZeroMQ" ON) option(ENABLE_ZEROMQ "Enable ZeroMQ" ON)
option(ENABLE_HARDSIM "Enable support for SIM cards" ON) option(ENABLE_HARDSIM "Enable support for SIM cards" ON)
option(ENABLE_TTCN3 "Enable TTCN3 test binaries" OFF)
option(BUILD_STATIC "Attempt to statically link external deps" OFF) option(BUILD_STATIC "Attempt to statically link external deps" OFF)
option(RPATH "Enable RPATH" OFF) option(RPATH "Enable RPATH" OFF)
option(ENABLE_ASAN "Enable gcc/clang address sanitizer" OFF) option(ENABLE_ASAN "Enable gcc/clang address sanitizer" OFF)
@ -194,7 +196,6 @@ else(BLADERF_FOUND OR UHD_FOUND OR SOAPYSDR_FOUND OR ZEROMQ_FOUND)
endif(BLADERF_FOUND OR UHD_FOUND OR SOAPYSDR_FOUND OR ZEROMQ_FOUND) endif(BLADERF_FOUND OR UHD_FOUND OR SOAPYSDR_FOUND OR ZEROMQ_FOUND)
# Boost # Boost
if(ENABLE_SRSUE OR ENABLE_SRSENB OR ENABLE_SRSEPC)
if(BUILD_STATIC) if(BUILD_STATIC)
set(Boost_USE_STATIC_LIBS ON) set(Boost_USE_STATIC_LIBS ON)
endif(BUILD_STATIC) endif(BUILD_STATIC)
@ -215,7 +216,13 @@ if(ENABLE_SRSUE OR ENABLE_SRSENB OR ENABLE_SRSEPC)
"1.65.0" "1.65" "1.66.0" "1.66" "1.67.0" "1.67" "1.68.0" "1.68" "1.69.0" "1.69" "1.65.0" "1.65" "1.66.0" "1.66" "1.67.0" "1.67" "1.68.0" "1.68" "1.69.0" "1.69"
) )
find_package(Boost "1.35" COMPONENTS ${BOOST_REQUIRED_COMPONENTS}) find_package(Boost "1.35" COMPONENTS ${BOOST_REQUIRED_COMPONENTS})
endif(ENABLE_SRSUE OR ENABLE_SRSENB OR ENABLE_SRSEPC)
if(Boost_FOUND)
include_directories(${Boost_INCLUDE_DIRS})
link_directories(${Boost_LIBRARY_DIRS})
else(Boost_FOUND)
message(FATAL_ERROR "Boost required to build srsLTE")
endif (Boost_FOUND)
# srsGUI # srsGUI
if(ENABLE_GUI) if(ENABLE_GUI)
@ -227,6 +234,14 @@ if(ENABLE_GUI)
endif(SRSGUI_FOUND) endif(SRSGUI_FOUND)
endif(ENABLE_GUI) endif(ENABLE_GUI)
if (ENABLE_TTCN3)
find_package(RapidJSON REQUIRED)
add_definitions(-DENABLE_TTCN3)
include_directories(${RAPIDJSON_INCLUDE_DIRS})
link_directories(${RAPIDJSON_LIBRARY_DIRS})
message(STATUS "Building with TTCN3 binaries")
endif (ENABLE_TTCN3)
######################################################################## ########################################################################
# Install Dirs # Install Dirs
######################################################################## ########################################################################
@ -248,7 +263,7 @@ set(DATA_DIR share/${CPACK_PACKAGE_NAME})
# Auto-generate config install helper and mark for installation # Auto-generate config install helper and mark for installation
configure_file( configure_file(
${CMAKE_SOURCE_DIR}/cmake/modules/SRSLTE_install_configs.sh.in ${PROJECT_SOURCE_DIR}/cmake/modules/SRSLTE_install_configs.sh.in
${CMAKE_BINARY_DIR}/srslte_install_configs.sh ${CMAKE_BINARY_DIR}/srslte_install_configs.sh
) )
install(PROGRAMS ${CMAKE_BINARY_DIR}/srslte_install_configs.sh DESTINATION ${RUNTIME_DIR}) install(PROGRAMS ${CMAKE_BINARY_DIR}/srslte_install_configs.sh DESTINATION ${RUNTIME_DIR})
@ -372,6 +387,13 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(CMAKE_SHARED_LINKER_FLAGS "-undefined dynamic_lookup") set(CMAKE_SHARED_LINKER_FLAGS "-undefined dynamic_lookup")
endif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") endif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
# Add -Werror to C/C++ flags for newer compilers
if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
endif()
message(STATUS "CMAKE_C_FLAGS is ${CMAKE_C_FLAGS}") message(STATUS "CMAKE_C_FLAGS is ${CMAKE_C_FLAGS}")
message(STATUS "CMAKE_CXX_FLAGS is ${CMAKE_CXX_FLAGS}") message(STATUS "CMAKE_CXX_FLAGS is ${CMAKE_CXX_FLAGS}")

@ -14,31 +14,37 @@
FIND_PATH(LIBCONFIG_INCLUDE_DIR libconfig.h FIND_PATH(LIBCONFIG_INCLUDE_DIR libconfig.h
/usr/local/include /usr/local/include
/usr/include /usr/include
/usr/lib/x86_64-linux-gnu/
) )
FIND_PATH(LIBCONFIGPP_INCLUDE_DIR libconfig.h++ FIND_PATH(LIBCONFIGPP_INCLUDE_DIR libconfig.h++
/usr/local/include /usr/local/include
/usr/include /usr/include
/usr/lib/x86_64-linux-gnu/
) )
FIND_LIBRARY(LIBCONFIG_LIBRARY config FIND_LIBRARY(LIBCONFIG_LIBRARY config
/usr/local/lib /usr/local/lib
/usr/lib /usr/lib
/usr/lib/x86_64-linux-gnu/
) )
FIND_LIBRARY(LIBCONFIGPP_LIBRARY config++ FIND_LIBRARY(LIBCONFIGPP_LIBRARY config++
/usr/local/lib /usr/local/lib
/usr/lib /usr/lib
/usr/lib/x86_64-linux-gnu/
) )
FIND_LIBRARY(LIBCONFIG_STATIC_LIBRARY "libconfig${CMAKE_STATIC_LIBRARY_SUFFIX}" FIND_LIBRARY(LIBCONFIG_STATIC_LIBRARY "libconfig${CMAKE_STATIC_LIBRARY_SUFFIX}"
/usr/local/lib /usr/local/lib
/usr/lib /usr/lib
/usr/lib/x86_64-linux-gnu/
) )
FIND_LIBRARY(LIBCONFIGPP_STATIC_LIBRARY "libconfig++${CMAKE_STATIC_LIBRARY_SUFFIX}" FIND_LIBRARY(LIBCONFIGPP_STATIC_LIBRARY "libconfig++${CMAKE_STATIC_LIBRARY_SUFFIX}"
/usr/local/lib /usr/local/lib
/usr/lib /usr/lib
/usr/lib/x86_64-linux-gnu/
) )

@ -0,0 +1,97 @@
# Copyright (c) 2011 Milo Yip (miloyip@gmail.com)
# Copyright (c) 2013 Rafal Jeczalik (rjeczalik@gmail.com)
# Distributed under the MIT License (see license.txt file)
# -----------------------------------------------------------------------------------
#
# Finds the rapidjson library
#
# -----------------------------------------------------------------------------------
#
# Variables used by this module, they can change the default behaviour.
# Those variables need to be either set before calling find_package
# or exported as environment variables before running CMake:
#
# RAPIDJSON_INCLUDEDIR - Set custom include path, useful when rapidjson headers are
# outside system paths
# RAPIDJSON_USE_SSE2 - Configure rapidjson to take advantage of SSE2 capabilities
# RAPIDJSON_USE_SSE42 - Configure rapidjson to take advantage of SSE4.2 capabilities
#
# -----------------------------------------------------------------------------------
#
# Variables defined by this module:
#
# RAPIDJSON_FOUND - True if rapidjson was found
# RAPIDJSON_INCLUDE_DIRS - Path to rapidjson include directory
# RAPIDJSON_CXX_FLAGS - Extra C++ flags required for compilation with rapidjson
#
# -----------------------------------------------------------------------------------
#
# Example usage:
#
# set(RAPIDJSON_USE_SSE2 ON)
# set(RAPIDJSON_INCLUDEDIR "/opt/github.com/rjeczalik/rapidjson/include")
#
# find_package(rapidjson REQUIRED)
#
# include_directories("${RAPIDJSON_INCLUDE_DIRS}")
# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${RAPIDJSON_CXX_FLAGS}")
# add_executable(foo foo.cc)
#
# -----------------------------------------------------------------------------------
foreach(opt RAPIDJSON_INCLUDEDIR RAPIDJSON_USE_SSE2 RAPIDJSON_USE_SSE42)
if(${opt} AND DEFINED ENV{${opt}} AND NOT ${opt} STREQUAL "$ENV{${opt}}")
message(WARNING "Conflicting ${opt} values: ignoring environment variable and using CMake cache entry.")
elseif(DEFINED ENV{${opt}} AND NOT ${opt})
set(${opt} "$ENV{${opt}}")
endif()
endforeach()
find_path(
RAPIDJSON_INCLUDE_DIRS
NAMES rapidjson/rapidjson.h
PATHS ${RAPIDJSON_INCLUDEDIR}
DOC "Include directory for the rapidjson library."
)
mark_as_advanced(RAPIDJSON_INCLUDE_DIRS)
if(RAPIDJSON_INCLUDE_DIRS)
set(RAPIDJSON_FOUND TRUE)
endif()
mark_as_advanced(RAPIDJSON_FOUND)
if(RAPIDJSON_USE_SSE42)
set(RAPIDJSON_CXX_FLAGS "-DRAPIDJSON_SSE42")
if(MSVC)
set(RAPIDJSON_CXX_FLAGS "${RAPIDJSON_CXX_FLAGS} /arch:SSE4.2")
else()
set(RAPIDJSON_CXX_FLAGS "${RAPIDJSON_CXX_FLAGS} -msse4.2")
endif()
else()
if(RAPIDJSON_USE_SSE2)
set(RAPIDJSON_CXX_FLAGS "-DRAPIDJSON_SSE2")
if(MSVC)
set(RAPIDJSON_CXX_FLAGS "${RAPIDJSON_CXX_FLAGS} /arch:SSE2")
else()
set(RAPIDJSON_CXX_FLAGS "${RAPIDJSON_CXX_FLAGS} -msse2")
endif()
endif()
endif()
mark_as_advanced(RAPIDJSON_CXX_FLAGS)
if(RAPIDJSON_FOUND)
if(NOT rapidjson_FIND_QUIETLY)
message(STATUS "Found rapidjson header files in ${RAPIDJSON_INCLUDE_DIRS}")
if(DEFINED RAPIDJSON_CXX_FLAGS)
message(STATUS "Found rapidjson C++ extra compilation flags: ${RAPIDJSON_CXX_FLAGS}")
endif()
endif()
elseif(RapidJSON_FIND_REQUIRED)
message(FATAL_ERROR "Could not find rapidjson")
else()
message(STATUS "Optional package rapidjson was not found")
endif()

@ -28,6 +28,7 @@ FIND_LIBRARY(
/usr/local/lib64 /usr/local/lib64
/usr/lib /usr/lib
/usr/lib64 /usr/lib64
/usr/lib/x86_64-linux-gnu/
) )
message(STATUS "SCTP LIBRARIES: " ${SCTP_LIBRARIES}) message(STATUS "SCTP LIBRARIES: " ${SCTP_LIBRARIES})

@ -19,6 +19,6 @@
# #
SET(SRSLTE_VERSION_MAJOR 19) SET(SRSLTE_VERSION_MAJOR 19)
SET(SRSLTE_VERSION_MINOR 6) SET(SRSLTE_VERSION_MINOR 9)
SET(SRSLTE_VERSION_PATCH 0) SET(SRSLTE_VERSION_PATCH 0)
SET(SRSLTE_VERSION_STRING "${SRSLTE_VERSION_MAJOR}.${SRSLTE_VERSION_MINOR}.${SRSLTE_VERSION_PATCH}") SET(SRSLTE_VERSION_STRING "${SRSLTE_VERSION_MAJOR}.${SRSLTE_VERSION_MINOR}.${SRSLTE_VERSION_PATCH}")

@ -2,20 +2,20 @@ cmake_minimum_required(VERSION 2.6)
execute_process( execute_process(
COMMAND git rev-parse --abbrev-ref HEAD COMMAND git rev-parse --abbrev-ref HEAD
WORKING_DIRECTORY "@CMAKE_SOURCE_DIR@" WORKING_DIRECTORY "@PROJECT_SOURCE_DIR@"
OUTPUT_VARIABLE GIT_BRANCH OUTPUT_VARIABLE GIT_BRANCH
OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_STRIP_TRAILING_WHITESPACE
) )
execute_process( execute_process(
COMMAND git log -1 --format=%h COMMAND git log -1 --format=%h
WORKING_DIRECTORY "@CMAKE_SOURCE_DIR@" WORKING_DIRECTORY "@PROJECT_SOURCE_DIR@"
OUTPUT_VARIABLE GIT_COMMIT_HASH OUTPUT_VARIABLE GIT_COMMIT_HASH
OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_STRIP_TRAILING_WHITESPACE
) )
message(STATUS "Generating build_info.h") message(STATUS "Generating build_info.h")
configure_file( configure_file(
@CMAKE_SOURCE_DIR@/lib/include/srslte/build_info.h.in @PROJECT_SOURCE_DIR@/lib/include/srslte/build_info.h.in
@CMAKE_BINARY_DIR@/lib/include/srslte/build_info.h @CMAKE_BINARY_DIR@/lib/include/srslte/build_info.h
) )

48
debian/changelog vendored

@ -1,8 +1,50 @@
srslte (19.03-0ubuntu1) bionic; urgency=medium srslte (19.06-0ubuntu1~srslte1~19.04) disco; urgency=medium
* Update to srsLTE 19.03 * Update to srsLTE 19.06 (Ubuntu Disco)
-- srsLTE Packagers <packagers@softwareradiosystems.com> Mon, 13 May 2019 16:50:00 +0200 -- Pedro Alvarez <pedro@softwareradiosystems.com> Fri, 30 August 2019 11:00:03 +0000
srslte (19.06-0ubuntu1~srslte1~18.10) cosmic; urgency=medium
* Update to srsLTE 19.06 (Ubuntu Cosmic)
-- Pedro Alvarez <pedro@softwareradiosystems.com> Fri, 30 August 2019 10:40:03 +0000
srslte (19.06-0ubuntu1~srslte1~18.04) bionic; urgency=medium
* Update to srsLTE 19.06 (Ubuntu Bionic)
-- Pedro Alvarez <pedro@softwareradiosystems.com> Fri, 30 August 2019 09:53:03 +0000
srslte (19.06-0ubuntu1~srslte1~16.04) xenial; urgency=medium
* Update to srsLTE 19.06 (Ubuntu Xenial)
-- Pedro Alvarez <pedro@softwareradiosystems.com> Thu, 29 August 2019 15:00:03 +0000
srslte (19.03-0ubuntu1~srslte1~16.04) xenial; urgency=medium
* Update to srsLTE 19.03 (Ubuntu Xenial)
-- Pedro Alvarez <pedro@softwareradiosystems.com> Tue, 14 May 2019 17:27:03 +0000
srslte (19.03-0ubuntu1~srslte1~19.04) disco; urgency=medium
* Update to srsLTE 19.03 (Ubuntu Disco)
-- Pedro Alvarez <pedro@softwareradiosystems.com> Tue, 14 May 2019 17:27:03 +0000
srslte (19.03-0ubuntu1~srslte1~18.10) cosmic; urgency=medium
* Update to srsLTE 19.03 (Ubuntu Cosmic)
-- Pedro Alvarez <pedro@softwareradiosystems.com> Tue, 14 May 2019 17:27:03 +0000
srslte (19.03-0ubuntu1~srslte1~18.04) bionic; urgency=medium
* Update to srsLTE 19.03 (Ubuntu Bionic)
-- Pedro Alvarez <pedro@softwareradiosystems.com> Tue, 14 May 2019 17:27:03 +0000
srslte (18.12-0ubuntu1) bionic; urgency=medium srslte (18.12-0ubuntu1) bionic; urgency=medium

44
debian/packager.sh vendored

@ -0,0 +1,44 @@
#!/bin/bash
###################################################################
#
# This file is part of srsLTE.
#
# 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/.
#
###################################################################
RELEASE=19.06
DISTRO=disco
COMMIT=eda7ca69a09933526e9318bcf553af0dc0b81598
REL_FLAG=releases
echo 'Packaging srsLTE release' $RELEASE 'for Ubuntu' $DISTRO
# Make build dir for the package
BUILD_DIR=~/build-area/srslte_$RELEASE/$REL_FLAG/$DISTRO
mkdir -p $BUILD_DIR
# Make tarball of the package source
pushd ~/srsLTE
git archive $COMMIT -o $BUILD_DIR/srslte_$DISTRO.tar.gz
popd
# Copy original tarball
cp ~/build-area/srslte_$RELEASE/$REL_FLAG/srslte_$RELEASE.orig.tar.gz $BUILD_DIR
mkdir $BUILD_DIR/srsLTE
pushd $BUILD_DIR/srsLTE
tar -vxzf ../srslte_$DISTRO.tar.gz
popd

@ -164,8 +164,6 @@ int main(int argc, char **argv) {
srslte_rf_set_rx_gain(&rf, 50); srslte_rf_set_rx_gain(&rf, 50);
} }
srslte_rf_set_master_clock_rate(&rf, 30.72e6);
// Supress RF messages // Supress RF messages
srslte_rf_suppress_stdout(&rf); srslte_rf_suppress_stdout(&rf);
@ -202,7 +200,6 @@ int main(int argc, char **argv) {
/* set rf_freq */ /* set rf_freq */
srslte_rf_set_rx_freq(&rf, 0, (double)channels[freq].fd * MHZ); srslte_rf_set_rx_freq(&rf, 0, (double)channels[freq].fd * MHZ);
srslte_rf_rx_wait_lo_locked(&rf);
INFO("Set rf_freq to %.3f MHz\n", (double) channels[freq].fd * MHZ/1000000); INFO("Set rf_freq to %.3f MHz\n", (double) channels[freq].fd * MHZ/1000000);
printf( printf(
@ -226,7 +223,7 @@ int main(int argc, char **argv) {
exit(-1); exit(-1);
} else if (n > 0) { } else if (n > 0) {
for (int i=0;i<3;i++) { for (int i=0;i<3;i++) {
if (found_cells[i].psr > 10.0) { if (found_cells[i].psr > 2.0) {
srslte_cell_t cell; srslte_cell_t cell;
cell.id = found_cells[i].cell_id; cell.id = found_cells[i].cell_id;
cell.cp = found_cells[i].cp; cell.cp = found_cells[i].cp;

@ -785,11 +785,6 @@ int main(int argc, char **argv) {
int srate = srslte_sampling_freq_hz(cell.nof_prb); int srate = srslte_sampling_freq_hz(cell.nof_prb);
if (srate != -1) { if (srate != -1) {
if (srate < 10e6) {
srslte_rf_set_master_clock_rate(&rf, 4*srate);
} else {
srslte_rf_set_master_clock_rate(&rf, srate);
}
printf("Setting sampling rate %.2f MHz\n", (float) srate/1000000); printf("Setting sampling rate %.2f MHz\n", (float) srate/1000000);
float srate_rf = srslte_rf_set_tx_srate(&rf, (double)srate); float srate_rf = srslte_rf_set_tx_srate(&rf, (double)srate);
if (srate_rf != srate) { if (srate_rf != srate) {

@ -474,12 +474,9 @@ int main(int argc, char **argv) {
sigprocmask(SIG_UNBLOCK, &sigset, NULL); sigprocmask(SIG_UNBLOCK, &sigset, NULL);
signal(SIGINT, sig_int_handler); signal(SIGINT, sig_int_handler);
srslte_rf_set_master_clock_rate(&rf, 30.72e6);
/* set receiver frequency */ /* set receiver frequency */
printf("Tunning receiver to %.3f MHz\n", (prog_args.rf_freq + prog_args.file_offset_freq) / 1000000); printf("Tunning receiver to %.3f MHz\n", (prog_args.rf_freq + prog_args.file_offset_freq) / 1000000);
srslte_rf_set_rx_freq(&rf, prog_args.rf_nof_rx_ant, prog_args.rf_freq + prog_args.file_offset_freq); srslte_rf_set_rx_freq(&rf, prog_args.rf_nof_rx_ant, prog_args.rf_freq + prog_args.file_offset_freq);
srslte_rf_rx_wait_lo_locked(&rf);
uint32_t ntrial = 0; uint32_t ntrial = 0;
do { do {
@ -501,11 +498,6 @@ int main(int argc, char **argv) {
/* set sampling frequency */ /* set sampling frequency */
int srate = srslte_sampling_freq_hz(cell.nof_prb); int srate = srslte_sampling_freq_hz(cell.nof_prb);
if (srate != -1) { if (srate != -1) {
if (srate < 10e6) {
srslte_rf_set_master_clock_rate(&rf, 4 * srate);
} else {
srslte_rf_set_master_clock_rate(&rf, srate);
}
printf("Setting sampling rate %.2f MHz\n", (float)srate / 1000000); printf("Setting sampling rate %.2f MHz\n", (float)srate / 1000000);
float srate_rf = srslte_rf_set_rx_srate(&rf, (double) srate); float srate_rf = srslte_rf_set_rx_srate(&rf, (double) srate);
if (srate_rf != srate) { if (srate_rf != srate) {
@ -606,13 +598,13 @@ int main(int argc, char **argv) {
dl_sf.tdd_config.configured = true; dl_sf.tdd_config.configured = true;
} }
srslte_chest_dl_cfg_t chest_pdsch_cfg; srslte_chest_dl_cfg_t chest_pdsch_cfg = {};
chest_pdsch_cfg.cfo_estimate_enable = prog_args.enable_cfo_ref; chest_pdsch_cfg.cfo_estimate_enable = prog_args.enable_cfo_ref;
chest_pdsch_cfg.cfo_estimate_sf_mask = 1023; chest_pdsch_cfg.cfo_estimate_sf_mask = 1023;
chest_pdsch_cfg.interpolate_subframe = !prog_args.average_subframe; chest_pdsch_cfg.interpolate_subframe = !prog_args.average_subframe;
// Special configuration for MBSFN channel estimation // Special configuration for MBSFN channel estimation
srslte_chest_dl_cfg_t chest_mbsfn_cfg; srslte_chest_dl_cfg_t chest_mbsfn_cfg = {};
chest_mbsfn_cfg.filter_type = SRSLTE_CHEST_FILTER_TRIANGLE; chest_mbsfn_cfg.filter_type = SRSLTE_CHEST_FILTER_TRIANGLE;
chest_mbsfn_cfg.filter_coef[0] = 0.1; chest_mbsfn_cfg.filter_coef[0] = 0.1;
chest_mbsfn_cfg.interpolate_subframe = true; chest_mbsfn_cfg.interpolate_subframe = true;
@ -789,7 +781,7 @@ int main(int argc, char **argv) {
dl_sf.tti = tti; dl_sf.tti = tti;
dl_sf.sf_type = sf_type; dl_sf.sf_type = sf_type;
ue_dl_cfg.cfg.tm = (srslte_tm_t)tm; ue_dl_cfg.cfg.tm = (srslte_tm_t)tm;
ue_dl_cfg.pdsch_use_tbs_index_alt = prog_args.enable_256qam; ue_dl_cfg.cfg.pdsch.use_tbs_index_alt = prog_args.enable_256qam;
if ((ue_dl_cfg.cfg.tm == SRSLTE_TM1 && cell.nof_ports == 1) || if ((ue_dl_cfg.cfg.tm == SRSLTE_TM1 && cell.nof_ports == 1) ||
(ue_dl_cfg.cfg.tm > SRSLTE_TM1 && cell.nof_ports > 1)) { (ue_dl_cfg.cfg.tm > SRSLTE_TM1 && cell.nof_ports > 1)) {

@ -158,7 +158,7 @@ int main(int argc, char **argv) {
* a) requries more memory but has less latency and is paralellizable. * a) requries more memory but has less latency and is paralellizable.
*/ */
for (N_id_2=0;N_id_2<3;N_id_2++) { for (N_id_2=0;N_id_2<3;N_id_2++) {
if (srslte_pss_init(&pss[N_id_2], frame_length)) { if (srslte_pss_init_fft(&pss[N_id_2], frame_length, symbol_sz)) {
ERROR("Error initializing PSS object\n"); ERROR("Error initializing PSS object\n");
exit(-1); exit(-1);
} }
@ -166,7 +166,7 @@ int main(int argc, char **argv) {
ERROR("Error initializing N_id_2\n"); ERROR("Error initializing N_id_2\n");
exit(-1); exit(-1);
} }
if (srslte_sss_init(&sss[N_id_2], 128)) { if (srslte_sss_init(&sss[N_id_2], symbol_sz)) {
ERROR("Error initializing SSS object\n"); ERROR("Error initializing SSS object\n");
exit(-1); exit(-1);
} }
@ -220,9 +220,14 @@ int main(int argc, char **argv) {
cfo[frame_cnt] = srslte_pss_cfo_compute(&pss[N_id_2], &input[peak_pos[N_id_2]-128]); cfo[frame_cnt] = srslte_pss_cfo_compute(&pss[N_id_2], &input[peak_pos[N_id_2]-128]);
printf("\t%d\t%d\t%d\t%d\t%.3f\t\t%3d\t%d\t%d\t%.3f\n", printf("\t%d\t%d\t%d\t%d\t%.3f\t\t%3d\t%d\t%d\t%.3f\n",
frame_cnt,N_id_2, srslte_sss_N_id_1(&sss[N_id_2], m0, m1), frame_cnt,
srslte_sss_subframe(m0, m1), peak_value[N_id_2], N_id_2,
peak_pos[N_id_2], m0, m1, srslte_sss_N_id_1(&sss[N_id_2], m0, m1, m1_value + m0_value),
srslte_sss_subframe(m0, m1),
peak_value[N_id_2],
peak_pos[N_id_2],
m0,
m1,
cfo[frame_cnt]); cfo[frame_cnt]);
} }
} }

@ -123,7 +123,6 @@ int main(int argc, char **argv) {
ERROR("Error opening rf\n"); ERROR("Error opening rf\n");
exit(-1); exit(-1);
} }
srslte_rf_set_master_clock_rate(&rf, 30.72e6);
sigset_t sigset; sigset_t sigset;
sigemptyset(&sigset); sigemptyset(&sigset);
@ -134,11 +133,6 @@ int main(int argc, char **argv) {
printf("Set RX gain: %.2f dB\n", srslte_rf_set_rx_gain(&rf, rf_gain)); printf("Set RX gain: %.2f dB\n", srslte_rf_set_rx_gain(&rf, rf_gain));
float srate = srslte_rf_set_rx_srate(&rf, rf_rate); float srate = srslte_rf_set_rx_srate(&rf, rf_rate);
if (srate != rf_rate) { if (srate != rf_rate) {
if (srate < 10e6) {
srslte_rf_set_master_clock_rate(&rf, 4*rf_rate);
} else {
srslte_rf_set_master_clock_rate(&rf, rf_rate);
}
srate = srslte_rf_set_rx_srate(&rf, rf_rate); srate = srslte_rf_set_rx_srate(&rf, rf_rate);
if (srate != rf_rate) { if (srate != rf_rate) {
ERROR("Error setting samplign frequency %.2f MHz\n", rf_rate * 1e-6); ERROR("Error setting samplign frequency %.2f MHz\n", rf_rate * 1e-6);
@ -147,7 +141,6 @@ int main(int argc, char **argv) {
} }
printf("Correctly RX rate: %.2f MHz\n", srate*1e-6); printf("Correctly RX rate: %.2f MHz\n", srate*1e-6);
srslte_rf_rx_wait_lo_locked(&rf);
srslte_rf_start_rx_stream(&rf, false); srslte_rf_start_rx_stream(&rf, false);

@ -100,7 +100,11 @@ void parse_args(int argc, char **argv) {
int srslte_rf_recv_wrapper(void *h, cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *t) { int srslte_rf_recv_wrapper(void *h, cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *t) {
DEBUG(" ---- Receive %d samples ---- \n", nsamples); DEBUG(" ---- Receive %d samples ---- \n", nsamples);
return srslte_rf_recv_with_time_multi(h, (void**)data[0], nsamples, true, NULL, NULL); void* ptr[SRSLTE_MAX_PORTS];
for (int i = 0; i < SRSLTE_MAX_PORTS; i++) {
ptr[i] = data[i];
}
return srslte_rf_recv_with_time_multi(h, ptr, nsamples, true, NULL, NULL);
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {
@ -122,7 +126,6 @@ int main(int argc, char **argv) {
ERROR("Error opening rf\n"); ERROR("Error opening rf\n");
exit(-1); exit(-1);
} }
srslte_rf_set_master_clock_rate(&rf, 30.72e6);
for (int i = 0; i < nof_rx_antennas; i++) { for (int i = 0; i < nof_rx_antennas; i++) {
buffer[i] = srslte_vec_malloc(3 * sizeof(cf_t) * SRSLTE_SF_LEN_PRB(100)); buffer[i] = srslte_vec_malloc(3 * sizeof(cf_t) * SRSLTE_SF_LEN_PRB(100));
@ -137,11 +140,6 @@ int main(int argc, char **argv) {
printf("Set RX gain: %.1f dB\n", srslte_rf_set_rx_gain(&rf, rf_gain)); printf("Set RX gain: %.1f dB\n", srslte_rf_set_rx_gain(&rf, rf_gain));
int srate = srslte_sampling_freq_hz(nof_prb); int srate = srslte_sampling_freq_hz(nof_prb);
if (srate != -1) { if (srate != -1) {
if (srate < 10e6) {
srslte_rf_set_master_clock_rate(&rf, 4*srate);
} else {
srslte_rf_set_master_clock_rate(&rf, srate);
}
printf("Setting sampling rate %.2f MHz\n", (float) srate/1000000); printf("Setting sampling rate %.2f MHz\n", (float) srate/1000000);
float srate_rf = srslte_rf_set_rx_srate(&rf, (double) srate); float srate_rf = srslte_rf_set_rx_srate(&rf, (double) srate);
if (srate_rf != srate) { if (srate_rf != srate) {
@ -152,7 +150,6 @@ int main(int argc, char **argv) {
ERROR("Invalid number of PRB %d\n", nof_prb); ERROR("Invalid number of PRB %d\n", nof_prb);
exit(-1); exit(-1);
} }
srslte_rf_rx_wait_lo_locked(&rf);
srslte_rf_start_rx_stream(&rf, false); srslte_rf_start_rx_stream(&rf, false);
cell.cp = SRSLTE_CP_NORM; cell.cp = SRSLTE_CP_NORM;

@ -136,14 +136,8 @@ int main(int argc, char **argv) {
ERROR("Error opening rf\n"); ERROR("Error opening rf\n");
exit(-1); exit(-1);
} }
srslte_rf_set_master_clock_rate(&rf, 30.72e6);
int srate = srslte_sampling_freq_hz(nof_prb); int srate = srslte_sampling_freq_hz(nof_prb);
if (srate < 10e6) {
srslte_rf_set_master_clock_rate(&rf, 4*srate);
} else {
srslte_rf_set_master_clock_rate(&rf, srate);
}
srslte_rf_set_rx_srate(&rf, (double) srate); srslte_rf_set_rx_srate(&rf, (double) srate);
srslte_rf_set_tx_srate(&rf, (double) srate); srslte_rf_set_tx_srate(&rf, (double) srate);

@ -23,6 +23,7 @@
#define SRSASN_COMMON_UTILS_H #define SRSASN_COMMON_UTILS_H
#include <algorithm> #include <algorithm>
#include <array>
#include <cmath> #include <cmath>
#include <cstring> #include <cstring>
#include <sstream> #include <sstream>
@ -80,8 +81,13 @@ ValOrError unpack_bits(uint8_t*& ptr, uint8_t& offset, uint8_t* max_ptr, uint32_
class bit_ref class bit_ref
{ {
public: public:
bit_ref(); bit_ref() = default;
bit_ref(uint8_t* start_ptr_, uint32_t max_size_); bit_ref(uint8_t* start_ptr_, uint32_t max_size_) :
ptr(start_ptr_),
start_ptr(start_ptr_),
max_ptr(max_size_ + start_ptr_)
{
}
int distance(const bit_ref& other) const; int distance(const bit_ref& other) const;
int distance(uint8_t* ref_ptr) const; int distance(uint8_t* ref_ptr) const;
@ -90,6 +96,7 @@ public:
int distance_bytes() const; int distance_bytes() const;
SRSASN_CODE pack(uint32_t val, uint32_t n_bits); SRSASN_CODE pack(uint32_t val, uint32_t n_bits);
SRSASN_CODE pack_bytes(const uint8_t* buf, uint32_t n_bytes);
template <class T> template <class T>
SRSASN_CODE unpack(T& val, uint32_t n_bits) SRSASN_CODE unpack(T& val, uint32_t n_bits)
{ {
@ -97,15 +104,17 @@ public:
val = ret.val; val = ret.val;
return ret.code; return ret.code;
} }
SRSASN_CODE unpack_bytes(uint8_t* buf, uint32_t n_bytes);
SRSASN_CODE align_bytes(); SRSASN_CODE align_bytes();
SRSASN_CODE align_bytes_zero(); SRSASN_CODE align_bytes_zero();
SRSASN_CODE advance_bits(uint32_t n_bits);
void set(uint8_t* start_ptr_, uint32_t max_size_); void set(uint8_t* start_ptr_, uint32_t max_size_);
private: private:
uint8_t* ptr; uint8_t* ptr = nullptr;
uint8_t offset; uint8_t offset = 0;
uint8_t* start_ptr; uint8_t* start_ptr = nullptr;
uint8_t* max_ptr; uint8_t* max_ptr = nullptr;
}; };
/********************* /*********************
@ -116,7 +125,7 @@ class dyn_array
{ {
public: public:
typedef T item_type; typedef T item_type;
dyn_array() : data_(NULL), size_(0), cap_(0) {} dyn_array() = default;
dyn_array(uint32_t new_size) : size_(new_size), cap_(new_size) { data_ = new T[size_]; } dyn_array(uint32_t new_size) : size_(new_size), cap_(new_size) { data_ = new T[size_]; }
dyn_array(const dyn_array<T>& other) dyn_array(const dyn_array<T>& other)
{ {
@ -183,8 +192,9 @@ public:
const T* data() const { return &data_[0]; } const T* data() const { return &data_[0]; }
private: private:
T* data_; T* data_ = nullptr;
uint32_t size_, cap_; uint32_t size_ = 0;
uint32_t cap_ = 0;
}; };
template <class T, uint32_t MAX_N> template <class T, uint32_t MAX_N>
@ -219,24 +229,6 @@ private:
uint32_t current_size; uint32_t current_size;
}; };
template <class T, uint32_t N>
class fixed_array
{
public:
typedef T item_type;
static uint32_t size() { return N; }
T& operator[](uint32_t idx) { return data_[idx]; }
const T& operator[](uint32_t idx) const { return data_[idx]; }
bool operator==(const fixed_array<T, N>& other) const { return std::equal(data_, data_ + size(), other.data_); }
T& back() { return data_[size() - 1]; }
const T& back() const { return data_[size() - 1]; }
T* data() { return &data_[0]; }
const T* data() const { return &data_[0]; }
private:
T data_[N];
};
/********************* /*********************
ext packing ext packing
*********************/ *********************/
@ -341,9 +333,9 @@ template <class IntType>
SRSASN_CODE unpack_unalign_integer(IntType& n, bit_ref& bref, IntType lb, IntType ub); SRSASN_CODE unpack_unalign_integer(IntType& n, bit_ref& bref, IntType lb, IntType ub);
template <class IntType> template <class IntType>
struct UnalignedIntegerPacker { struct UnalignedIntegerPacker {
UnalignedIntegerPacker(IntType, IntType); UnalignedIntegerPacker(IntType lb_, IntType ub_) : lb(lb_), ub(ub_) {}
IntType lb; const IntType lb;
IntType ub; const IntType ub;
SRSASN_CODE pack(bit_ref& bref, IntType n) const; SRSASN_CODE pack(bit_ref& bref, IntType n) const;
SRSASN_CODE unpack(IntType& n, bit_ref& bref) const; SRSASN_CODE unpack(IntType& n, bit_ref& bref) const;
}; };
@ -351,12 +343,11 @@ struct UnalignedIntegerPacker {
template <class IntType, IntType lb, IntType ub> template <class IntType, IntType lb, IntType ub>
struct unaligned_integer { struct unaligned_integer {
IntType value; IntType value;
const UnalignedIntegerPacker<IntType> packer; unaligned_integer() = default;
unaligned_integer() : packer(lb, ub) {} unaligned_integer(IntType value_) : value(value_) {}
unaligned_integer(IntType value_) : value(value_), packer(lb, ub) {}
operator IntType() { return value; } operator IntType() { return value; }
SRSASN_CODE pack(bit_ref& bref) const { return packer.pack(bref, value); } SRSASN_CODE pack(bit_ref& bref) const { return pack_unalign_integer(bref, value, lb, ub); }
SRSASN_CODE unpack(bit_ref& bref) { return packer.unpack(value, bref); } SRSASN_CODE unpack(bit_ref& bref) { return unpack_unalign_integer(value, bref, lb, ub); }
}; };
template <class IntType> template <class IntType>
@ -486,7 +477,7 @@ public:
SRSASN_CODE unpack(bit_ref& bref); SRSASN_CODE unpack(bit_ref& bref);
private: private:
fixed_array<uint8_t, N> octets_; std::array<uint8_t, N> octets_;
}; };
template <uint32_t N> template <uint32_t N>
@ -520,7 +511,7 @@ SRSASN_CODE fixed_octstring<N>::unpack(bit_ref& bref)
class dyn_octstring class dyn_octstring
{ {
public: public:
dyn_octstring() {} dyn_octstring() = default;
dyn_octstring(uint32_t new_size) : octets_(new_size) {} dyn_octstring(uint32_t new_size) : octets_(new_size) {}
const uint8_t& operator[](uint32_t idx) const { return octets_[idx]; } const uint8_t& operator[](uint32_t idx) const { return octets_[idx]; }
@ -621,7 +612,7 @@ public:
SRSASN_CODE unpack(bit_ref& bref, bool& ext) { return unpack_fixed_bitstring(data(), ext, bref, N); } SRSASN_CODE unpack(bit_ref& bref, bool& ext) { return unpack_fixed_bitstring(data(), ext, bref, N); }
private: private:
fixed_array<uint8_t, (uint32_t)((N + 7) / 8)> octets_; // ceil(N/8.0) std::array<uint8_t, (uint32_t)((N + 7) / 8)> octets_; // ceil(N/8.0)
}; };
/********************* /*********************
@ -874,16 +865,15 @@ template <class T>
class copy_ptr class copy_ptr
{ {
public: public:
copy_ptr() : ptr(NULL) {} explicit copy_ptr(T* ptr_ = nullptr) :
explicit copy_ptr(T* ptr_) :
ptr(ptr_) {} // it takes hold of the pointer (including destruction). You should use make_copy_ptr() in most cases ptr(ptr_) {} // it takes hold of the pointer (including destruction). You should use make_copy_ptr() in most cases
// instead of this ctor // instead of this ctor
copy_ptr(const copy_ptr<T>& other) { ptr = other.make_obj_(); } // it allocates new memory for the new object copy_ptr(const copy_ptr<T>& other) { ptr = (other.ptr == nullptr) ? nullptr : new T(*other.ptr); }
~copy_ptr() { destroy_(); } ~copy_ptr() { destroy_(); }
copy_ptr<T>& operator=(const copy_ptr<T>& other) copy_ptr<T>& operator=(const copy_ptr<T>& other)
{ {
if (this != &other) { if (this != &other) {
acquire(other.make_obj_()); reset((other.ptr == nullptr) ? nullptr : new T(*other.ptr));
} }
return *this; return *this;
} }
@ -897,15 +887,23 @@ public:
T* release() T* release()
{ {
T* ret = ptr; T* ret = ptr;
ptr = NULL; ptr = nullptr;
return ret; return ret;
} }
void acquire(T* ptr_) void reset(T* ptr_ = nullptr)
{ {
destroy_(); destroy_();
ptr = ptr_; ptr = ptr_;
} }
void reset() { acquire(NULL); } void set_present(bool flag = true)
{
if (flag) {
reset(new T());
} else {
reset();
}
}
bool is_present() const { return get() != nullptr; }
private: private:
void destroy_() void destroy_()
@ -914,7 +912,6 @@ private:
delete ptr; delete ptr;
} }
} }
T* make_obj_() const { return (ptr == NULL) ? NULL : new T(*ptr); }
T* ptr; T* ptr;
}; };
@ -928,23 +925,31 @@ copy_ptr<T> make_copy_ptr(const T& t)
ext group ext group
*********************/ *********************/
class ext_groups_header class ext_groups_packer_guard
{ {
public: public:
ext_groups_header(uint32_t max_nof_groups, uint32_t nof_nogroups_ = 0);
bool& operator[](uint32_t idx); bool& operator[](uint32_t idx);
SRSASN_CODE pack_nof_groups(bit_ref& bref) const;
SRSASN_CODE pack_group_flags(bit_ref& bref) const;
SRSASN_CODE pack(bit_ref& bref) const; SRSASN_CODE pack(bit_ref& bref) const;
SRSASN_CODE unpack_nof_groups(bit_ref& bref);
SRSASN_CODE unpack_group_flags(bit_ref& bref); private:
bounded_array<bool, 20> groups;
};
class ext_groups_unpacker_guard
{
public:
explicit ext_groups_unpacker_guard(uint32_t nof_supported_groups_);
~ext_groups_unpacker_guard();
void resize(uint32_t new_size);
bool& operator[](uint32_t idx);
SRSASN_CODE unpack(bit_ref& bref); SRSASN_CODE unpack(bit_ref& bref);
private: private:
mutable uint32_t nof_groups;
const uint32_t nof_nogroups;
bounded_array<bool, 20> groups; bounded_array<bool, 20> groups;
const uint32_t nof_supported_groups;
uint32_t nof_unpacked_groups = 0;
bit_ref* bref_tracker = nullptr;
}; };
/********************* /*********************

@ -2939,6 +2939,8 @@ typedef struct {
} LIBLTE_MME_ID_RESPONSE_MSG_STRUCT; } LIBLTE_MME_ID_RESPONSE_MSG_STRUCT;
// Functions // Functions
LIBLTE_ERROR_ENUM liblte_mme_pack_identity_response_msg(LIBLTE_MME_ID_RESPONSE_MSG_STRUCT* id_resp, LIBLTE_ERROR_ENUM liblte_mme_pack_identity_response_msg(LIBLTE_MME_ID_RESPONSE_MSG_STRUCT* id_resp,
uint8 sec_hdr_type,
uint32 count,
LIBLTE_BYTE_MSG_STRUCT* msg); LIBLTE_BYTE_MSG_STRUCT* msg);
LIBLTE_ERROR_ENUM liblte_mme_unpack_identity_response_msg(LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_ERROR_ENUM liblte_mme_unpack_identity_response_msg(LIBLTE_BYTE_MSG_STRUCT* msg,
LIBLTE_MME_ID_RESPONSE_MSG_STRUCT* id_resp); LIBLTE_MME_ID_RESPONSE_MSG_STRUCT* id_resp);

File diff suppressed because it is too large Load Diff

@ -34,6 +34,23 @@ struct plmn_id_s;
struct s_tmsi_s; struct s_tmsi_s;
struct rlc_cfg_c; struct rlc_cfg_c;
struct srb_to_add_mod_s; struct srb_to_add_mod_s;
struct sched_request_cfg_c;
struct mac_main_cfg_s;
struct rach_cfg_common_s;
struct time_align_timer_opts;
struct phys_cfg_ded_s;
struct prach_cfg_info_s;
struct pdsch_cfg_common_s;
struct pusch_cfg_common_s;
struct pucch_cfg_common_s;
struct srs_ul_cfg_common_c;
struct ul_pwr_ctrl_common_s;
struct scell_to_add_mod_r10_s;
struct mbms_notif_cfg_r9_s;
struct mbsfn_area_info_r9_s;
struct mbsfn_sf_cfg_s;
struct mcch_msg_s;
struct sib_type13_r9_s;
} // namespace rrc } // namespace rrc
} // namespace asn1 } // namespace asn1
@ -49,9 +66,41 @@ void to_asn1(asn1::rrc::plmn_id_s* asn1_type, const plmn_id_t& cfg);
s_tmsi_t make_s_tmsi_t(const asn1::rrc::s_tmsi_s& asn1_type); s_tmsi_t make_s_tmsi_t(const asn1::rrc::s_tmsi_s& asn1_type);
void to_asn1(asn1::rrc::s_tmsi_s* asn1_type, const s_tmsi_t& cfg); void to_asn1(asn1::rrc::s_tmsi_s* asn1_type, const s_tmsi_t& cfg);
/***************************
* RLC Config
**************************/
rlc_config_t make_rlc_config_t(const asn1::rrc::rlc_cfg_c& asn1_type); rlc_config_t make_rlc_config_t(const asn1::rrc::rlc_cfg_c& asn1_type);
rlc_config_t make_rlc_config_t(const asn1::rrc::srb_to_add_mod_s& asn1_type); rlc_config_t make_rlc_config_t(const asn1::rrc::srb_to_add_mod_s& asn1_type);
void to_asn1(asn1::rrc::rlc_cfg_c* asn1_type, const rlc_config_t& cfg); void to_asn1(asn1::rrc::rlc_cfg_c* asn1_type, const rlc_config_t& cfg);
}
/***************************
* MAC Config
**************************/
void set_mac_cfg_t_sched_request_cfg(mac_cfg_t* cfg, const asn1::rrc::sched_request_cfg_c& asn1_type);
void set_mac_cfg_t_main_cfg(mac_cfg_t* cfg, const asn1::rrc::mac_main_cfg_s& asn1_type);
void set_mac_cfg_t_rach_cfg_common(mac_cfg_t* cfg, const asn1::rrc::rach_cfg_common_s& asn1_type);
void set_mac_cfg_t_time_alignment(mac_cfg_t* cfg, const asn1::rrc::time_align_timer_opts asn1_type);
/***************************
* PHY Config
**************************/
void set_phy_cfg_t_dedicated_cfg(phy_cfg_t* cfg, const asn1::rrc::phys_cfg_ded_s& asn1_type);
void set_phy_cfg_t_common_prach(phy_cfg_t* cfg, const asn1::rrc::prach_cfg_info_s* asn1_type, uint32_t root_seq_idx);
void set_phy_cfg_t_common_pdsch(phy_cfg_t* cfg, const asn1::rrc::pdsch_cfg_common_s& asn1_type);
void set_phy_cfg_t_common_pusch(phy_cfg_t* cfg, const asn1::rrc::pusch_cfg_common_s& asn1_type);
void set_phy_cfg_t_common_pucch(phy_cfg_t* cfg, const asn1::rrc::pucch_cfg_common_s& asn1_type);
void set_phy_cfg_t_common_srs(phy_cfg_t* cfg, const asn1::rrc::srs_ul_cfg_common_c& asn1_type);
void set_phy_cfg_t_common_pwr_ctrl(phy_cfg_t* cfg, const asn1::rrc::ul_pwr_ctrl_common_s& asn1_type);
void set_phy_cfg_t_scell_config(phy_cfg_t* cfg, const asn1::rrc::scell_to_add_mod_r10_s& asn1_type);
void set_phy_cfg_t_enable_64qam(phy_cfg_t* cfg, const bool enabled);
// mbms
mbms_notif_cfg_t make_mbms_notif_cfg(const asn1::rrc::mbms_notif_cfg_r9_s& asn1_type);
mbsfn_area_info_t make_mbsfn_area_info(const asn1::rrc::mbsfn_area_info_r9_s& asn1_type);
mbsfn_sf_cfg_t make_mbsfn_sf_cfg(const asn1::rrc::mbsfn_sf_cfg_s& sf_cfg);
mcch_msg_t make_mcch_msg(const asn1::rrc::mcch_msg_s& asn1_type);
sib13_t make_sib13(const asn1::rrc::sib_type13_r9_s& asn1_type);
} // namespace srslte
#endif // SRSLTE_RRC_ASN1_UTILS_H #endif // SRSLTE_RRC_ASN1_UTILS_H

@ -156,14 +156,12 @@ inline bool bytes_to_mnc(const uint8_t* bytes, uint16_t* mnc, uint8_t len)
if (len != 3 && len != 2) { if (len != 3 && len != 2) {
*mnc = 0; *mnc = 0;
return false; return false;
} } else if (len == 3) {
if (len == 3) {
*mnc = 0xF000; *mnc = 0xF000;
*mnc |= ((uint16_t)bytes[0]) << 8u; *mnc |= ((uint16_t)bytes[0]) << 8u;
*mnc |= ((uint16_t)bytes[1]) << 4u; *mnc |= ((uint16_t)bytes[1]) << 4u;
*mnc |= ((uint16_t)bytes[2]) << 0u; *mnc |= ((uint16_t)bytes[2]) << 0u;
} } else if (len == 2) {
if (len == 2) {
*mnc = 0xFF00; *mnc = 0xFF00;
*mnc |= ((uint16_t)bytes[0]) << 4u; *mnc |= ((uint16_t)bytes[0]) << 4u;
*mnc |= ((uint16_t)bytes[1]) << 0u; *mnc |= ((uint16_t)bytes[1]) << 0u;

@ -242,6 +242,6 @@ allocate_unique_buffer(byte_buffer_pool& pool, const char* debug_name, bool bloc
return std::move(unique_byte_buffer_t(pool.allocate(debug_name, blocking), byte_buffer_deleter(&pool))); return std::move(unique_byte_buffer_t(pool.allocate(debug_name, blocking), byte_buffer_deleter(&pool)));
} }
} // namespace srsue } // namespace srslte
#endif // SRSLTE_BUFFER_POOL_H #endif // SRSLTE_BUFFER_POOL_H

@ -30,10 +30,7 @@ namespace srslte {
*****************************************************************************/ *****************************************************************************/
inline void uint8_to_uint32(uint8_t* buf, uint32_t* i) inline void uint8_to_uint32(uint8_t* buf, uint32_t* i)
{ {
*i = (uint32_t)buf[0] << 24 | *i = (uint32_t)buf[0] << 24 | (uint32_t)buf[1] << 16 | (uint32_t)buf[2] << 8 | (uint32_t)buf[3];
(uint32_t)buf[1] << 16 |
(uint32_t)buf[2] << 8 |
(uint32_t)buf[3];
} }
inline void uint32_to_uint8(uint32_t i, uint8_t* buf) inline void uint32_to_uint8(uint32_t i, uint8_t* buf)
@ -46,8 +43,7 @@ inline void uint32_to_uint8(uint32_t i, uint8_t *buf)
inline void uint8_to_uint16(uint8_t* buf, uint16_t* i) inline void uint8_to_uint16(uint8_t* buf, uint16_t* i)
{ {
*i = (uint32_t)buf[0] << 8 | *i = (uint32_t)buf[0] << 8 | (uint32_t)buf[1];
(uint32_t)buf[1];
} }
inline void uint16_to_uint8(uint16_t i, uint8_t* buf) inline void uint16_to_uint8(uint16_t i, uint8_t* buf)
@ -56,6 +52,17 @@ inline void uint16_to_uint8(uint16_t i, uint8_t *buf)
buf[1] = i & 0xFF; buf[1] = i & 0xFF;
} }
}; //namespace inline void uint8_to_uint24(uint8_t* buf, uint32_t* i)
{
*i = (uint32_t)buf[0] << 16 | (uint32_t)buf[1] << 8 | (uint32_t)buf[2];
}
inline void uint24_to_uint8(uint32_t i, uint8_t* buf)
{
buf[0] = (i >> 16) & 0xFF;
buf[1] = (i >> 8) & 0xFF;
buf[2] = i & 0xFF;
}
} // namespace srslte
#endif // SRSLTE_INT_HELPERS_H #endif // SRSLTE_INT_HELPERS_H

@ -67,22 +67,36 @@ public:
uint32_t lcid; uint32_t lcid;
}; };
const uint8_t PDCP_SN_LEN_5 = 5;
const uint8_t PDCP_SN_LEN_7 = 7;
const uint8_t PDCP_SN_LEN_12 = 12;
const uint8_t PDCP_SN_LEN_18 = 18;
class srslte_pdcp_config_t typedef enum { PDCP_RB_IS_SRB, PDCP_RB_IS_DRB } pdcp_rb_type_t;
class pdcp_config_t
{ {
public: public:
srslte_pdcp_config_t(uint8_t bearer_id_ = 0, bool is_control_ = false, bool is_data_ = false, uint8_t direction_ = SECURITY_DIRECTION_UPLINK) pdcp_config_t(uint8_t bearer_id_,
:bearer_id(bearer_id_) pdcp_rb_type_t rb_type_,
,direction(direction_) security_direction_t tx_direction_,
,is_control(is_control_) security_direction_t rx_direction_,
,is_data(is_data_) uint8_t sn_len_) :
,sn_len(12) {} bearer_id(bearer_id_),
rb_type(rb_type_),
uint32_t bearer_id; tx_direction(tx_direction_),
uint8_t direction; rx_direction(rx_direction_),
bool is_control; sn_len(sn_len_)
bool is_data; {
uint8_t sn_len; hdr_len_bytes = ceil((float)sn_len / 8);
}
uint8_t bearer_id = 1;
pdcp_rb_type_t rb_type = PDCP_RB_IS_DRB;
security_direction_t tx_direction = SECURITY_DIRECTION_DOWNLINK;
security_direction_t rx_direction = SECURITY_DIRECTION_UPLINK;
uint8_t sn_len = PDCP_SN_LEN_12;
uint8_t hdr_len_bytes = 2;
// TODO: Support the following configurations // TODO: Support the following configurations
// bool do_rohc; // bool do_rohc;

@ -103,6 +103,7 @@ typedef enum {
LIBLTE_SECURITY_CIPHERING_ALGORITHM_ID_EEA0 = 0, LIBLTE_SECURITY_CIPHERING_ALGORITHM_ID_EEA0 = 0,
LIBLTE_SECURITY_CIPHERING_ALGORITHM_ID_128_EEA1, LIBLTE_SECURITY_CIPHERING_ALGORITHM_ID_128_EEA1,
LIBLTE_SECURITY_CIPHERING_ALGORITHM_ID_128_EEA2, LIBLTE_SECURITY_CIPHERING_ALGORITHM_ID_128_EEA2,
LIBLTE_SECURITY_CIPHERING_ALGORITHM_ID_128_EEA3,
LIBLTE_SECURITY_CIPHERING_ALGORITHM_ID_N_ITEMS, LIBLTE_SECURITY_CIPHERING_ALGORITHM_ID_N_ITEMS,
} LIBLTE_SECURITY_CIPHERING_ALGORITHM_ID_ENUM; } LIBLTE_SECURITY_CIPHERING_ALGORITHM_ID_ENUM;
static const char liblte_security_ciphering_algorithm_id_text[LIBLTE_SECURITY_CIPHERING_ALGORITHM_ID_N_ITEMS][20] = { static const char liblte_security_ciphering_algorithm_id_text[LIBLTE_SECURITY_CIPHERING_ALGORITHM_ID_N_ITEMS][20] = {
@ -111,6 +112,7 @@ typedef enum {
LIBLTE_SECURITY_INTEGRITY_ALGORITHM_ID_EIA0 = 0, LIBLTE_SECURITY_INTEGRITY_ALGORITHM_ID_EIA0 = 0,
LIBLTE_SECURITY_INTEGRITY_ALGORITHM_ID_128_EIA1, LIBLTE_SECURITY_INTEGRITY_ALGORITHM_ID_128_EIA1,
LIBLTE_SECURITY_INTEGRITY_ALGORITHM_ID_128_EIA2, LIBLTE_SECURITY_INTEGRITY_ALGORITHM_ID_128_EIA2,
LIBLTE_SECURITY_INTEGRITY_ALGORITHM_ID_128_EIA3,
LIBLTE_SECURITY_INTEGRITY_ALGORITHM_ID_N_ITEMS, LIBLTE_SECURITY_INTEGRITY_ALGORITHM_ID_N_ITEMS,
} LIBLTE_SECURITY_INTEGRITY_ALGORITHM_ID_ENUM; } LIBLTE_SECURITY_INTEGRITY_ALGORITHM_ID_ENUM;
static const char liblte_security_integrity_algorithm_id_text[LIBLTE_SECURITY_INTEGRITY_ALGORITHM_ID_N_ITEMS][20] = { static const char liblte_security_integrity_algorithm_id_text[LIBLTE_SECURITY_INTEGRITY_ALGORITHM_ID_N_ITEMS][20] = {
@ -177,6 +179,8 @@ LIBLTE_ERROR_ENUM liblte_security_128_eia2(
uint8* key, uint32 count, uint8 bearer, uint8 direction, uint8* msg, uint32 msg_len, uint8* mac); uint8* key, uint32 count, uint8 bearer, uint8 direction, uint8* msg, uint32 msg_len, uint8* mac);
LIBLTE_ERROR_ENUM liblte_security_128_eia2( LIBLTE_ERROR_ENUM liblte_security_128_eia2(
uint8* key, uint32 count, uint8 bearer, uint8 direction, LIBLTE_BIT_MSG_STRUCT* msg, uint8* mac); uint8* key, uint32 count, uint8 bearer, uint8 direction, LIBLTE_BIT_MSG_STRUCT* msg, uint8* mac);
LIBLTE_ERROR_ENUM liblte_security_128_eia3(
uint8* key, uint32 count, uint8 bearer, uint8 direction, uint8* msg, uint32 msg_len, uint8* mac);
/********************************************************************* /*********************************************************************
Name: liblte_security_encryption_eea1 Name: liblte_security_encryption_eea1
@ -224,6 +228,12 @@ LIBLTE_ERROR_ENUM liblte_security_encryption_eea2(
LIBLTE_ERROR_ENUM liblte_security_decryption_eea2( LIBLTE_ERROR_ENUM liblte_security_decryption_eea2(
uint8* key, uint32 count, uint8 bearer, uint8 direction, uint8* ct, uint32 ct_len, uint8* out); uint8* key, uint32 count, uint8 bearer, uint8 direction, uint8* ct, uint32 ct_len, uint8* out);
LIBLTE_ERROR_ENUM liblte_security_encryption_eea3(
uint8* key, uint32 count, uint8 bearer, uint8 direction, uint8* msg, uint32 msg_len, uint8* out);
LIBLTE_ERROR_ENUM liblte_security_decryption_eea3(
uint8* key, uint32 count, uint8 bearer, uint8 direction, uint8* msg, uint32 msg_len, uint8* out);
/********************************************************************* /*********************************************************************
Name: liblte_security_milenage_f1 Name: liblte_security_milenage_f1

@ -65,9 +65,7 @@ public:
tti = 0; tti = 0;
level = LOG_LEVEL_NONE; level = LOG_LEVEL_NONE;
hex_limit = 0; hex_limit = 0;
show_layer_en = true;
add_string_en = false; add_string_en = false;
level_text_short = true;
} }
log(std::string service_name_) { log(std::string service_name_) {
@ -75,9 +73,7 @@ public:
tti = 0; tti = 0;
level = LOG_LEVEL_NONE; level = LOG_LEVEL_NONE;
hex_limit = 0; hex_limit = 0;
show_layer_en = true;
add_string_en = false; add_string_en = false;
level_text_short = true;
} }
virtual ~log() {}; virtual ~log() {};
@ -131,12 +127,6 @@ public:
int get_hex_limit() { int get_hex_limit() {
return hex_limit; return hex_limit;
} }
void set_log_level_short(bool enable) {
level_text_short = enable;
}
void show_layer(bool enable) {
show_layer_en = enable;
}
// Pure virtual methods for logging // Pure virtual methods for logging
virtual void console(const char * message, ...) __attribute__ ((format (printf, 2, 3))) = 0; virtual void console(const char * message, ...) __attribute__ ((format (printf, 2, 3))) = 0;
@ -144,6 +134,7 @@ public:
virtual void warning(const char * message, ...) __attribute__ ((format (printf, 2, 3))) = 0; virtual void warning(const char * message, ...) __attribute__ ((format (printf, 2, 3))) = 0;
virtual void info(const char * message, ...) __attribute__ ((format (printf, 2, 3))) = 0; virtual void info(const char * message, ...) __attribute__ ((format (printf, 2, 3))) = 0;
virtual void debug(const char * message, ...) __attribute__ ((format (printf, 2, 3))) = 0; virtual void debug(const char * message, ...) __attribute__ ((format (printf, 2, 3))) = 0;
virtual void debug_long(const char* message, ...) __attribute__((format(printf, 2, 3))) = 0;
// Same with hex dump // Same with hex dump
virtual void error_hex(const uint8_t *, int, const char *, ...) __attribute__((format (printf, 4, 5))) virtual void error_hex(const uint8_t *, int, const char *, ...) __attribute__((format (printf, 4, 5)))
@ -162,8 +153,6 @@ protected:
int hex_limit; int hex_limit;
std::string service_name; std::string service_name;
bool show_layer_en;
bool level_text_short;
bool add_string_en; bool add_string_en;
std::string add_string_val; std::string add_string_val;
}; };

@ -58,6 +58,7 @@ public:
void warning(const char * message, ...) __attribute__ ((format (printf, 2, 3))); void warning(const char * message, ...) __attribute__ ((format (printf, 2, 3)));
void info(const char * message, ...) __attribute__ ((format (printf, 2, 3))); void info(const char * message, ...) __attribute__ ((format (printf, 2, 3)));
void debug(const char * message, ...) __attribute__ ((format (printf, 2, 3))); void debug(const char * message, ...) __attribute__ ((format (printf, 2, 3)));
void debug_long(const char* message, ...) __attribute__((format(printf, 2, 3)));
void error_hex(const uint8_t *hex, int size, const char * message, ...) __attribute__((format (printf, 4, 5))); void error_hex(const uint8_t *hex, int size, const char * message, ...) __attribute__((format (printf, 4, 5)));
void warning_hex(const uint8_t *hex, int size, const char * message, ...) __attribute__((format (printf, 4, 5))); void warning_hex(const uint8_t *hex, int size, const char * message, ...) __attribute__((format (printf, 4, 5)));
@ -82,18 +83,24 @@ protected:
logger *logger_h; logger *logger_h;
bool do_tti; bool do_tti;
static const int char_buff_size = logger::preallocated_log_str_size - 64 * 3;
time_itf *time_src; time_itf *time_src;
time_format_t time_format; time_format_t time_format;
logger_stdout def_logger_stdout; logger_stdout def_logger_stdout;
void all_log(srslte::LOG_LEVEL_ENUM level, uint32_t tti, const char *msg); void all_log(srslte::LOG_LEVEL_ENUM level,
void all_log(srslte::LOG_LEVEL_ENUM level, uint32_t tti, const char *msg, const uint8_t *hex, int size); uint32_t tti,
void all_log_line(srslte::LOG_LEVEL_ENUM level, uint32_t tti, std::string file, int line, char *msg); const char* msg,
std::string now_time(); const uint8_t* hex = nullptr,
int size = 0,
bool long_msg = false);
void now_time(char* buffer, const uint32_t buffer_len);
void get_tti_str(const uint32_t tti_, char* buffer, const uint32_t buffer_len);
std::string hex_string(const uint8_t *hex, int size); std::string hex_string(const uint8_t *hex, int size);
}; };
} // namespace srsue } // namespace srslte
#endif // SRSLTE_LOG_FILTER_H #endif // SRSLTE_LOG_FILTER_H

@ -27,6 +27,8 @@
#ifndef SRSLTE_LOGGER_H #ifndef SRSLTE_LOGGER_H
#define SRSLTE_LOGGER_H #define SRSLTE_LOGGER_H
#include "buffer_pool.h"
#include <memory>
#include <stdio.h> #include <stdio.h>
#include <string> #include <string>
@ -35,7 +37,70 @@ namespace srslte {
class logger class logger
{ {
public: public:
virtual void log(std::string *msg) = 0; const static uint32_t preallocated_log_str_size = 1024;
logger() : pool(16 * 1024) {}
class log_str
{
public:
log_str(const char* msg_ = nullptr, uint32_t size_ = 0)
{
size = size_ ? size_ : preallocated_log_str_size;
msg = new char[size];
if (msg_) {
strncpy(msg, msg_, size);
} else {
msg[0] = '\0';
}
}
log_str(const log_str&) = delete;
log_str& operator=(const log_str&) = delete;
~log_str() { delete[] msg; }
void reset() { msg[0] = '\0'; }
char* str() { return msg; }
uint32_t get_buffer_size() { return size; }
private:
uint32_t size;
char* msg;
};
typedef buffer_pool<log_str> log_str_pool_t;
class log_str_deleter
{
public:
explicit log_str_deleter(log_str_pool_t* pool_ = nullptr) : pool(pool_) {}
void operator()(log_str* buf)
{
if (buf) {
if (pool) {
buf->reset();
pool->deallocate(buf);
} else {
delete buf;
}
}
}
private:
log_str_pool_t* pool;
};
typedef std::unique_ptr<log_str, log_str_deleter> unique_log_str_t;
void log_char(const char* msg) { log(std::move(unique_log_str_t(new log_str(msg), log_str_deleter()))); }
virtual void log(unique_log_str_t msg) = 0;
log_str_pool_t& get_pool() { return pool; }
unique_log_str_t allocate_unique_log_str()
{
return unique_log_str_t(pool.allocate(), logger::log_str_deleter(&pool));
}
private:
log_str_pool_t pool;
}; };
} // namespace srslte } // namespace srslte

@ -47,9 +47,9 @@ public:
logger_file(std::string file); logger_file(std::string file);
~logger_file(); ~logger_file();
void init(std::string file, int max_length = -1); void init(std::string file, int max_length = -1);
void stop();
// Implementation of log_out // Implementation of log_out
void log(str_ptr msg); void log(unique_log_str_t msg);
void log(const char *msg);
private: private:
void run_thread(); void run_thread();
@ -63,7 +63,8 @@ private:
std::string filename; std::string filename;
pthread_cond_t not_empty; pthread_cond_t not_empty;
pthread_mutex_t mutex; pthread_mutex_t mutex;
std::deque<str_ptr> buffer;
std::deque<unique_log_str_t> buffer;
}; };
} // namespace srslte } // namespace srslte

@ -36,12 +36,7 @@ namespace srslte {
class logger_stdout : public logger class logger_stdout : public logger
{ {
public: public:
void log(std::string *msg) { void log(unique_log_str_t log_str) { fprintf(stdout, "%s", log_str->str()); }
if (msg) {
fprintf(stdout, "%s", msg->c_str());
delete msg;
}
}
}; };
} // namespace srslte } // namespace srslte

@ -0,0 +1,65 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* 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/.
*
*/
#ifndef SRSLTE_MAC_NR_PCAP_H
#define SRSLTE_MAC_NR_PCAP_H
#include "srslte/common/pcap.h"
#include <stdint.h>
#include <string>
namespace srslte {
class mac_nr_pcap
{
public:
mac_nr_pcap();
~mac_nr_pcap();
void enable(const bool& enable_);
void open(const std::string& filename, const uint16_t& ue_id = 0);
void close();
void set_ue_id(const uint16_t& ue_id);
void write_dl_crnti(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t crnti, uint8_t harqid, uint32_t tti);
void write_ul_crnti(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti);
void write_dl_ra_rnti(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti);
void write_dl_bch(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti);
void write_dl_pch(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti);
void write_dl_si_rnti(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti);
private:
bool enable_write = false;
std::string filename;
FILE* pcap_file = nullptr;
uint32_t ue_id = 0;
void pack_and_write(uint8_t* pdu,
uint32_t pdu_len_bytes,
uint32_t tti,
uint16_t crnti_,
uint8_t harqid,
uint8_t direction,
uint8_t rnti_type);
};
} // namespace srslte
#endif // SRSLTE_MAC_NR_PCAP_H

@ -0,0 +1,118 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* 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/.
*
*/
#ifndef SRSLTE_MAC_NR_PDU_H
#define SRSLTE_MAC_NR_PDU_H
#include "srslte/common/common.h"
#include <memory>
#include <stdint.h>
#include <vector>
namespace srslte {
class mac_nr_sch_pdu;
class mac_nr_sch_subpdu
{
public:
// 3GPP 38.321 v15.3.0 Combined Tables 6.2.1-1, 6.2.1-2
typedef enum {
// Values for DL-SCH
DRX_CMD = 0b111100,
TA_CMD = 0b111101,
CON_RES_ID = 0b111110,
// Values for UL-SCH
CRNTI = 0b111010,
SHORT_TRUNC_BSR = 0b111011,
LONG_TRUNC_BSR = 0b111100,
SHORT_BSR = 0b111101,
LONG_BSR = 0b111110,
// Common
CCCH = 0b000000,
PADDING = 0b111111,
} nr_lcid_sch_t;
mac_nr_sch_subpdu(mac_nr_sch_pdu* parent_);
nr_lcid_sch_t get_type();
bool is_sdu();
bool is_var_len_ce();
uint32_t read_subheader(const uint8_t* ptr);
uint32_t get_total_length();
uint32_t get_sdu_length();
uint32_t get_lcid();
uint8_t* get_sdu();
void set_sdu(const uint32_t lcid_, const uint8_t* payload_, const uint32_t len_);
void set_padding(const uint32_t len_);
uint32_t write_subpdu(const uint8_t* start_);
private:
uint32_t sizeof_ce(uint32_t lcid, bool is_ul);
// protected:
uint32_t lcid = 0;
int header_length = 0;
int sdu_length = 0;
bool F_bit = false;
uint8_t* sdu = nullptr;
mac_nr_sch_pdu* parent = nullptr;
};
class mac_nr_sch_pdu
{
public:
mac_nr_sch_pdu(bool ulsch_ = false) : ulsch(ulsch_) {}
void pack();
void unpack(const uint8_t* payload, const uint32_t& len);
uint32_t get_num_subpdus();
const mac_nr_sch_subpdu& get_subpdu(const uint32_t& index);
bool is_ulsch();
void init_tx(byte_buffer_t* buffer_, uint32_t pdu_len_, bool is_ulsch_ = false);
uint32_t add_sdu(const uint32_t lcid_, const uint8_t* payload_, const uint32_t len_);
uint32_t get_remaing_len();
private:
uint32_t size_header_sdu(const uint32_t nbytes);
bool ulsch = false;
std::vector<mac_nr_sch_subpdu> subpdus;
byte_buffer_t* buffer = nullptr;
uint32_t pdu_len = 0;
uint32_t remaining_len = 0;
};
} // namespace srslte
#endif // SRSLTE_MAC_NR_PDU_H

@ -0,0 +1,230 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* 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: multiqueue.h
* Description: General-purpose non-blocking multiqueue. It behaves as a list
* of bounded/unbounded queues.
*****************************************************************************/
#ifndef SRSLTE_MULTIQUEUE_H
#define SRSLTE_MULTIQUEUE_H
#include <algorithm>
#include <condition_variable>
#include <mutex>
#include <queue>
#include <vector>
namespace srslte {
template <typename myobj>
class multiqueue_handler
{
// NOTE: needed to create a queue wrapper to make its move ctor noexcept.
// otherwise we couldnt use the resize method of std::vector<queue<myobj>> if myobj is move-only
class queue_wrapper : private std::queue<myobj>
{
public:
queue_wrapper() = default;
queue_wrapper(queue_wrapper&& other) noexcept : std::queue<myobj>(std::move(other)) {}
using std::queue<myobj>::push;
using std::queue<myobj>::pop;
using std::queue<myobj>::size;
using std::queue<myobj>::empty;
using std::queue<myobj>::front;
std::condition_variable cv_full;
bool active = true;
};
public:
explicit multiqueue_handler(uint32_t capacity_ = std::numeric_limits<uint32_t>::max()) : capacity(capacity_) {}
~multiqueue_handler() { reset(); }
void reset()
{
std::unique_lock<std::mutex> lock(mutex);
running = false;
while (nof_threads_waiting > 0) {
uint32_t size = queues.size();
lock.unlock();
cv_empty.notify_one();
for (uint32_t i = 0; i < size; ++i) {
queues[i].cv_full.notify_all();
}
lock.lock();
// wait for all threads to unblock
cv_exit.wait(lock);
}
queues.clear();
}
int add_queue()
{
uint32_t qidx = 0;
std::lock_guard<std::mutex> lock(mutex);
if (not running) {
return -1;
}
for (; qidx < queues.size() and queues[qidx].active; ++qidx)
;
if (qidx == queues.size()) {
// create new queue
queues.emplace_back();
} else {
queues[qidx].active = true;
}
return (int)qidx;
}
int nof_queues()
{
std::lock_guard<std::mutex> lock(mutex);
uint32_t count = 0;
for (uint32_t i = 0; i < queues.size(); ++i) {
count += queues[i].active ? 1 : 0;
}
return count;
}
template <typename FwdRef>
void push(int q_idx, FwdRef&& value)
{
{
std::unique_lock<std::mutex> lock(mutex);
while (is_queue_active_(q_idx) and queues[q_idx].size() >= capacity) {
nof_threads_waiting++;
queues[q_idx].cv_full.wait(lock);
nof_threads_waiting--;
}
if (not is_queue_active_(q_idx)) {
cv_exit.notify_one();
return;
}
queues[q_idx].push(std::forward<FwdRef>(value));
}
cv_empty.notify_one();
}
bool try_push(int q_idx, const myobj& value)
{
{
std::lock_guard<std::mutex> lock(mutex);
if (not is_queue_active_(q_idx) or queues[q_idx].size() >= capacity) {
return false;
}
queues[q_idx].push(value);
}
cv_empty.notify_one();
return true;
}
std::pair<bool, myobj> try_push(int q_idx, myobj&& value)
{
{
std::lock_guard<std::mutex> lck(mutex);
if (not is_queue_active_(q_idx) or queues[q_idx].size() >= capacity) {
return {false, std::move(value)};
}
queues[q_idx].push(std::move(value));
}
cv_empty.notify_one();
return {true, std::move(value)};
}
int wait_pop(myobj* value)
{
std::unique_lock<std::mutex> lock(mutex);
while (running) {
// Round-robin for all queues
for (const queue_wrapper& q : queues) {
spin_idx = (spin_idx + 1) % queues.size();
if (is_queue_active_(spin_idx) and not queues[spin_idx].empty()) {
if (value) {
*value = std::move(queues[spin_idx].front());
}
queues[spin_idx].pop();
if (nof_threads_waiting > 0) {
lock.unlock();
queues[spin_idx].cv_full.notify_one();
}
return spin_idx;
}
}
nof_threads_waiting++;
cv_empty.wait(lock);
nof_threads_waiting--;
}
cv_exit.notify_one();
return -1;
}
bool empty(int qidx)
{
std::lock_guard<std::mutex> lck(mutex);
return queues[qidx].empty();
}
size_t size(int qidx)
{
std::lock_guard<std::mutex> lck(mutex);
return queues[qidx].size();
}
const myobj& front(int qidx)
{
std::lock_guard<std::mutex> lck(mutex);
return queues[qidx].front();
}
void erase_queue(int qidx)
{
std::lock_guard<std::mutex> lck(mutex);
if (is_queue_active_(qidx)) {
queues[qidx].active = false;
while (not queues[qidx].empty()) {
queues[qidx].pop();
}
}
}
bool is_queue_active(int qidx)
{
std::lock_guard<std::mutex> lck(mutex);
return is_queue_active_(qidx);
}
private:
bool is_queue_active_(int qidx) const { return running and queues[qidx].active; }
std::mutex mutex;
std::condition_variable cv_empty, cv_exit;
uint32_t spin_idx = 0;
bool running = true;
std::vector<queue_wrapper> queues;
uint32_t capacity = 0;
uint32_t nof_threads_waiting = 0;
};
} // namespace srslte
#endif // SRSLTE_MULTIQUEUE_H

@ -0,0 +1,77 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* 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/.
*
*/
/*! \brief Base class for implementing socket handlers using
* the netsource object.
*
*/
#ifndef SRSLTE_NETSOURE_HANDLER_H
#define SRSLTE_NETSOURE_HANDLER_H
#include "srslte/common/log.h"
#include "srslte/common/threads.h"
#include "srslte/phy/io/netsource.h"
#include <array>
#include <iostream>
#include <memory>
class netsource_handler : public thread
{
public:
netsource_handler(const std::string name_) : thread(name_) { rx_buf = unique_byte_array_t(new byte_array_t); }
~netsource_handler(){};
void stop()
{
run_enable = false;
int cnt = 0;
while (running && cnt < 100) {
usleep(10000);
cnt++;
}
if (running) {
thread_cancel();
}
wait_thread_finish();
}
virtual void run_thread() = 0;
bool run_enable = true;
bool running = false;
bool initialized = false;
std::string net_ip = "0.0.0.0";
uint32_t net_port = 0;
const static uint32_t RX_BUF_SIZE = 1024 * 1024;
typedef std::array<uint8_t, RX_BUF_SIZE> byte_array_t;
typedef std::unique_ptr<byte_array_t> unique_byte_array_t;
unique_byte_array_t rx_buf;
srslte_netsource_t net_source;
srslte::log* log = nullptr;
};
#endif // SRSLTE_NETSOURE_HANDLER_H

@ -29,7 +29,7 @@
#define MAC_LTE_DLT 147 #define MAC_LTE_DLT 147
#define NAS_LTE_DLT 148 #define NAS_LTE_DLT 148
#define RLC_LTE_DLT 149 // UDP needs to be selected as protocol #define UDP_DLT 149 // UDP needs to be selected as protocol
#define S1AP_LTE_DLT 150 #define S1AP_LTE_DLT 150
/* This structure gets written to the start of the file */ /* This structure gets written to the start of the file */
@ -102,6 +102,25 @@ typedef struct NAS_Context_Info_s {
// No Context yet // No Context yet
} NAS_Context_Info_t; } NAS_Context_Info_t;
#define MAC_NR_START_STRING "mac-nr"
#define MAC_NR_PHR_TYPE2_OTHERCELL_TAG 0x05
#define MAC_NR_HARQID 0x06
/* Context information for every MAC NR PDU that will be logged */
typedef struct {
uint8_t radioType;
uint8_t direction;
uint8_t rntiType;
uint16_t rnti;
uint16_t ueid;
uint8_t harqid;
uint8_t phr_type2_othercell;
uint16_t system_frame_number;
uint8_t sub_frame_number;
uint16_t length;
} mac_nr_context_info_t;
/* RLC-LTE disector */ /* RLC-LTE disector */
@ -437,4 +456,93 @@ inline int LTE_PCAP_S1AP_WritePDU(FILE *fd, S1AP_Context_Info_t *context,
return 1; return 1;
} }
/**************************************************************************
* API functions for writing MAC-NR PCAP files *
**************************************************************************/
/* Write an individual NR MAC PDU (PCAP packet header + UDP header + nr-mac-context + mac-pdu) */
inline int NR_PCAP_MAC_WritePDU(FILE* fd, mac_nr_context_info_t* context, const unsigned char* PDU, unsigned int length)
{
char context_header[256] = {};
int offset = 0;
/* Can't write if file wasn't successfully opened */
if (fd == NULL) {
printf("Error: Can't write to empty file handle\n");
return 0;
}
// Add dummy UDP header, start with src and dest port
context_header[offset++] = 0xde;
context_header[offset++] = 0xad;
context_header[offset++] = 0xbe;
context_header[offset++] = 0xef;
// length
uint16_t tmp16 = htons(length + 31);
memcpy(context_header + offset, &tmp16, 2);
offset += 2;
// dummy CRC
context_header[offset++] = 0xde;
context_header[offset++] = 0xad;
// Start magic string
memcpy(&context_header[offset], MAC_NR_START_STRING, strlen(MAC_NR_START_STRING));
offset += strlen(MAC_NR_START_STRING);
/*****************************************************************/
/* Context information (same as written by UDP heuristic clients */
context_header[offset++] = context->radioType;
context_header[offset++] = context->direction;
context_header[offset++] = context->rntiType;
/* RNTI */
context_header[offset++] = MAC_LTE_RNTI_TAG;
tmp16 = htons(context->rnti);
memcpy(context_header + offset, &tmp16, 2);
offset += 2;
/* UEId */
context_header[offset++] = MAC_LTE_UEID_TAG;
tmp16 = htons(context->ueid);
memcpy(context_header + offset, &tmp16, 2);
offset += 2;
/* HARQID */
context_header[offset++] = MAC_NR_HARQID;
context_header[offset++] = context->harqid;
/* PHR Type2 other cell */
context_header[offset++] = MAC_NR_PHR_TYPE2_OTHERCELL_TAG;
context_header[offset++] = context->phr_type2_othercell;
/* Subframe Number and System Frame Number */
/* SFN is stored in 12 MSB and SF in 4 LSB */
context_header[offset++] = MAC_LTE_FRAME_SUBFRAME_TAG;
tmp16 = (context->system_frame_number << 4) | context->sub_frame_number;
tmp16 = htons(tmp16);
memcpy(context_header + offset, &tmp16, 2);
offset += 2;
/* Data tag immediately preceding PDU */
context_header[offset++] = MAC_LTE_PAYLOAD_TAG;
/****************************************************************/
/* PCAP Header */
struct timeval t;
gettimeofday(&t, NULL);
pcaprec_hdr_t packet_header;
packet_header.ts_sec = t.tv_sec;
packet_header.ts_usec = t.tv_usec;
packet_header.incl_len = offset + length;
packet_header.orig_len = offset + length;
/***************************************************************/
/* Now write everything to the file */
fwrite(&packet_header, sizeof(pcaprec_hdr_t), 1, fd);
fwrite(context_header, 1, offset, fd);
fwrite(PDU, 1, length, fd);
return 1;
}
#endif // SRSLTE_PCAP_H #endif // SRSLTE_PCAP_H

@ -136,7 +136,16 @@ public:
ret = subheaders[nof_subheaders].read_subheader(&ptr); ret = subheaders[nof_subheaders].read_subheader(&ptr);
nof_subheaders++; nof_subheaders++;
} }
} while (ret && (nof_subheaders + 1) < (int)max_subheaders);
if (ret && (ptr - init_ptr) >= pdu_len) {
// stop processing last subheader indicates another one but all bytes are consume
nof_subheaders = 0;
INFO("Corrupted MAC PDU - all bytes have been consumed (pdu_len=%d)\n", pdu_len);
if (log) {
log->info_hex(init_ptr, pdu_len, "Corrupted MAC PDU - all bytes have been consumed (pdu_len=%d)\n", pdu_len);
}
}
} while (ret && (nof_subheaders + 1) < (int)max_subheaders && pdu_len > (ptr - init_ptr));
for (int i = 0; i < nof_subheaders; i++) { for (int i = 0; i < nof_subheaders; i++) {
subheaders[i].read_payload(&ptr); subheaders[i].read_payload(&ptr);

@ -55,6 +55,6 @@ private:
uint16_t channel_id); uint16_t channel_id);
}; };
} // namespace srsue } // namespace srslte
#endif // RLCPCAP_H #endif // RLCPCAP_H

@ -29,36 +29,38 @@
#include "srslte/common/common.h" #include "srslte/common/common.h"
#define SECURITY_DIRECTION_UPLINK 0
#define SECURITY_DIRECTION_DOWNLINK 1
namespace srslte { namespace srslte {
typedef enum { typedef enum {
CIPHERING_ALGORITHM_ID_EEA0 = 0, CIPHERING_ALGORITHM_ID_EEA0 = 0,
CIPHERING_ALGORITHM_ID_128_EEA1, CIPHERING_ALGORITHM_ID_128_EEA1,
CIPHERING_ALGORITHM_ID_128_EEA2, CIPHERING_ALGORITHM_ID_128_EEA2,
CIPHERING_ALGORITHM_ID_128_EEA3,
CIPHERING_ALGORITHM_ID_N_ITEMS, CIPHERING_ALGORITHM_ID_N_ITEMS,
} CIPHERING_ALGORITHM_ID_ENUM; } CIPHERING_ALGORITHM_ID_ENUM;
static const char ciphering_algorithm_id_text[CIPHERING_ALGORITHM_ID_N_ITEMS][20] = {"EEA0", static const char ciphering_algorithm_id_text[CIPHERING_ALGORITHM_ID_N_ITEMS][20] = {
"128-EEA1", "EEA0", "128-EEA1", "128-EEA2", "128-EEA3"};
"128-EEA2"};
typedef enum { typedef enum {
INTEGRITY_ALGORITHM_ID_EIA0 = 0, INTEGRITY_ALGORITHM_ID_EIA0 = 0,
INTEGRITY_ALGORITHM_ID_128_EIA1, INTEGRITY_ALGORITHM_ID_128_EIA1,
INTEGRITY_ALGORITHM_ID_128_EIA2, INTEGRITY_ALGORITHM_ID_128_EIA2,
INTEGRITY_ALGORITHM_ID_128_EIA3,
INTEGRITY_ALGORITHM_ID_N_ITEMS, INTEGRITY_ALGORITHM_ID_N_ITEMS,
} INTEGRITY_ALGORITHM_ID_ENUM; } INTEGRITY_ALGORITHM_ID_ENUM;
static const char integrity_algorithm_id_text[INTEGRITY_ALGORITHM_ID_N_ITEMS][20] = {"EIA0", static const char integrity_algorithm_id_text[INTEGRITY_ALGORITHM_ID_N_ITEMS][20] = {
"128-EIA1", "EIA0", "128-EIA1", "128-EIA2", "128-EIA3"};
"128-EIA2"};
typedef enum {
SECURITY_DIRECTION_UPLINK = 0,
SECURITY_DIRECTION_DOWNLINK = 1,
SECURITY_DIRECTION_N_ITEMS,
} security_direction_t;
static const char security_direction_text[INTEGRITY_ALGORITHM_ID_N_ITEMS][20] = {"Uplink", "Downlink"};
/****************************************************************************** /******************************************************************************
* Key Generation * Key Generation
*****************************************************************************/ *****************************************************************************/
uint8_t security_generate_k_asme( uint8_t *ck, uint8_t security_generate_k_asme( uint8_t *ck,
uint8_t *ik, uint8_t *ik,
uint8_t *ak, uint8_t *ak,
@ -101,83 +103,45 @@ uint8_t security_generate_k_up( uint8_t *k_enb,
/****************************************************************************** /******************************************************************************
* Integrity Protection * Integrity Protection
*****************************************************************************/ *****************************************************************************/
uint8_t security_128_eia1(
uint8_t* key, uint32_t count, uint32_t bearer, uint8_t direction, uint8_t* msg, uint32_t msg_len, uint8_t* mac);
uint8_t security_128_eia1( uint8_t *key, uint8_t security_128_eia2(
uint32_t count, uint8_t* key, uint32_t count, uint32_t bearer, uint8_t direction, uint8_t* msg, uint32_t msg_len, uint8_t* mac);
uint32_t bearer,
uint8_t direction,
uint8_t *msg,
uint32_t msg_len,
uint8_t *mac);
uint8_t security_128_eia2( uint8_t *key, uint8_t security_128_eia3(
uint32_t count, uint8_t* key, uint32_t count, uint32_t bearer, uint8_t direction, uint8_t* msg, uint32_t msg_len, uint8_t* mac);
uint32_t bearer,
uint8_t direction,
uint8_t *msg,
uint32_t msg_len,
uint8_t *mac);
uint8_t security_md5(const uint8_t *input,
size_t len,
uint8_t *output);
uint8_t security_md5(const uint8_t* input, size_t len, uint8_t* output);
/****************************************************************************** /******************************************************************************
* Encryption / Decryption * Encryption / Decryption
*****************************************************************************/ *****************************************************************************/
uint8_t security_128_eea1(
uint8_t* key, uint32_t count, uint8_t bearer, uint8_t direction, uint8_t* msg, uint32_t msg_len, uint8_t* msg_out);
uint8_t security_128_eea2(
uint8_t* key, uint32_t count, uint8_t bearer, uint8_t direction, uint8_t* msg, uint32_t msg_len, uint8_t* msg_out);
uint8_t security_128_eea1( uint8_t *key, uint8_t security_128_eea3(
uint32_t count, uint8_t* key, uint32_t count, uint8_t bearer, uint8_t direction, uint8_t* msg, uint32_t msg_len, uint8_t* msg_out);
uint8_t bearer,
uint8_t direction,
uint8_t *msg,
uint32_t msg_len,
uint8_t *msg_out);
uint8_t security_128_eea2(uint8_t *key,
uint32_t count,
uint8_t bearer,
uint8_t direction,
uint8_t *msg,
uint32_t msg_len,
uint8_t *msg_out);
/****************************************************************************** /******************************************************************************
* Authentication * Authentication
*****************************************************************************/ *****************************************************************************/
uint8_t compute_opc( uint8_t *k, uint8_t compute_opc(uint8_t* k, uint8_t* op, uint8_t* opc);
uint8_t *op,
uint8_t *opc);
uint8_t security_milenage_f1( uint8_t *k, uint8_t security_milenage_f1(uint8_t* k, uint8_t* op, uint8_t* rand, uint8_t* sqn, uint8_t* amf, uint8_t* mac_a);
uint8_t *op,
uint8_t *rand,
uint8_t *sqn,
uint8_t *amf,
uint8_t *mac_a);
uint8_t security_milenage_f1_star( uint8_t *k, uint8_t security_milenage_f1_star(uint8_t* k, uint8_t* op, uint8_t* rand, uint8_t* sqn, uint8_t* amf, uint8_t* mac_s);
uint8_t *op,
uint8_t *rand,
uint8_t *sqn,
uint8_t *amf,
uint8_t *mac_s);
uint8_t security_milenage_f2345( uint8_t *k, uint8_t
uint8_t *op, security_milenage_f2345(uint8_t* k, uint8_t* op, uint8_t* rand, uint8_t* res, uint8_t* ck, uint8_t* ik, uint8_t* ak);
uint8_t *rand,
uint8_t *res,
uint8_t *ck,
uint8_t *ik,
uint8_t *ak);
uint8_t security_milenage_f5_star( uint8_t *k, uint8_t security_milenage_f5_star( uint8_t *k,
uint8_t *op, uint8_t *op,
uint8_t *rand, uint8_t *rand,
uint8_t *ak); uint8_t *ak);
} // namespace srslte } // namespace srslte
#endif // SRSLTE_SECURITY_H #endif // SRSLTE_SECURITY_H

@ -0,0 +1,317 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* 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 <functional>
#include <list>
#include <memory>
#include <mutex>
#ifndef SRSLTE_RESUMABLE_PROCEDURES_H
#define SRSLTE_RESUMABLE_PROCEDURES_H
namespace srslte {
enum class proc_state_t { on_going, success, error, inactive };
enum class proc_outcome_t { repeat, yield, success, error };
/**************************************************************************************
* class: proc_impl_t
* Provides an polymorphic interface for resumable procedures. This base can then be used
* by a task dispatch queue via the method "run()".
* Every procedure starts in inactive state, and finishes with success or error.
* With methods:
* - run() - executes a procedure, returning true if the procedure is still running
* or false, if it has completed
* - step() - method overriden by child class that will be called by run(). step()
* executes a procedure "action" based on its current internal state,
* and return a proc_outcome_t variable with possible values:
* - yield - the procedure performed the action but hasn't completed yet.
* - repeat - the same as yield, but explicitly asking that run() should
* recall step() again (probably the procedure state has changed)
* - error - the procedure has finished unsuccessfully
* - success - the procedure has completed successfully
* - stop() - called automatically when a procedure has finished. Useful for actions
* upon procedure completion, like sending back a response.
* - set_proc_state() / is_#() - setter and getters for current procedure state
************************************************************************************/
class proc_impl_t
{
public:
proc_impl_t() : proc_state(proc_state_t::inactive) {}
virtual ~proc_impl_t() = default;
virtual proc_outcome_t step() = 0;
virtual void stop() {} // may be overloaded
bool run()
{
proc_outcome_t outcome = proc_outcome_t::repeat;
while (is_running() and outcome == proc_outcome_t::repeat) {
outcome = step();
if (outcome == proc_outcome_t::error) {
set_proc_state(proc_state_t::error);
} else if (outcome == proc_outcome_t::success) {
set_proc_state(proc_state_t::success);
}
}
return is_running();
}
void set_proc_state(proc_state_t new_state)
{
proc_state = new_state;
if (proc_state == proc_state_t::error or proc_state == proc_state_t::success) {
stop();
}
}
bool is_error() const { return proc_state == proc_state_t::error; }
bool is_success() const { return proc_state == proc_state_t::success; }
bool is_running() const { return proc_state == proc_state_t::on_going; }
bool is_complete() const { return is_success() or is_error(); }
bool is_active() const { return proc_state != proc_state_t::inactive; }
private:
proc_state_t proc_state;
};
/**************************************************************************************
* class: proc_t<T>
* Handles the lifetime, of a procedure T that derives from proc_impl_t, including
* its alloc, initialization, and reset back to initial state once the procedure has been
* completed and the user has extracted its results.
* Can only be re-launched when a procedure T becomes inactive.
* It uses a unique_ptr<T> to allow the use of procedures that are forward declared.
* It provides the following methods:
* - run() - calls proc_impl_t::run(). See above.
* - launch() - initializes the procedure T by calling T::init(...). Handles the case
* of failed initialization, and forbids the initialization of procedures
* that are already active.
* - pop() - extracts the result of the procedure if it has finished, and sets
* proc_t<T> back to inactive
* - trigger_event(Event) - used for handling external events. The procedure T will
* have to define a method "trigger_event(Event)" as well,
* specifying how each event type should be handled.
************************************************************************************/
template <class T>
class proc_t
{
public:
explicit proc_t() : proc_impl_ptr(new T()) {}
T* get() { return proc_impl_ptr.get(); }
bool is_active() const { return proc_impl_ptr->is_active(); }
bool is_complete() const { return proc_impl_ptr->is_complete(); }
T* release() { return proc_impl_ptr.release(); }
bool run() { return proc_impl_ptr->run(); }
void clear()
{
// Destructs the current object, and calls default ctor (which sets proc back to inactive and ready for another run)
proc_impl_ptr->~T();
new (proc_impl_ptr.get()) T();
}
template <class Event>
void trigger_event(Event&& e)
{
if (proc_impl_ptr->is_running()) {
proc_outcome_t outcome = proc_impl_ptr->trigger_event(std::forward<Event>(e));
if (outcome == proc_outcome_t::error) {
proc_impl_ptr->set_proc_state(proc_state_t::error);
} else if (outcome == proc_outcome_t::success) {
proc_impl_ptr->set_proc_state(proc_state_t::success);
}
}
}
T pop()
{
if (not proc_impl_ptr->is_complete()) {
return T();
}
T ret(std::move(*proc_impl_ptr));
clear();
return ret;
}
template <class... Args>
bool launch(Args&&... args)
{
if (is_active()) {
// if already active
return false;
}
proc_impl_ptr->set_proc_state(proc_state_t::on_going);
proc_outcome_t init_ret = proc_impl_ptr->init(std::forward<Args>(args)...);
switch (init_ret) {
case proc_outcome_t::error:
proc_impl_ptr->set_proc_state(proc_state_t::error); // call stop as an error
clear();
return false;
case proc_outcome_t::success:
proc_impl_ptr->set_proc_state(proc_state_t::success);
break;
case proc_outcome_t::repeat:
run(); // call run right away
break;
case proc_outcome_t::yield:
break;
}
return true;
}
private:
std::unique_ptr<T> proc_impl_ptr;
};
/**************************************************************************************
* class: func_proc_t
* A proc_impl_t used to store lambda functions and other function pointers as a step()
* method, avoiding this way, always having to create a new class per procedure.
************************************************************************************/
class func_proc_t : public proc_impl_t
{
public:
proc_outcome_t init(std::function<proc_outcome_t()> step_func_)
{
step_func = std::move(step_func_);
return proc_outcome_t::yield;
}
proc_outcome_t step() final { return step_func(); }
private:
std::function<proc_outcome_t()> step_func;
};
/**************************************************************************************
* class: func_proc_t
* A helper proc_impl_t whose step()/stop() are no op, but has a trigger_event() that
* signals that the method has finished and store a result of type OutcomeType.
************************************************************************************/
template <class OutcomeType>
class query_proc_t : public proc_impl_t
{
public:
proc_outcome_t init() { return proc_outcome_t::yield; }
proc_outcome_t step() final { return proc_outcome_t::yield; }
proc_outcome_t trigger_event(const OutcomeType& outcome_)
{
outcome = outcome_;
return proc_outcome_t::success;
}
const OutcomeType& result() const { return outcome; }
private:
OutcomeType outcome;
};
/**************************************************************************************
* class: callback_list_t
* Stores procedures that derive from proc_impl_t. Its run() method calls sequentially
* all the stored procedures run() method, and removes the procedures if they have
* completed.
* There are different ways to add a procedure to the list:
* - add_proc(...) - adds a proc_t<T>, and once the procedure has completed, takes it
* out of the container without resetting it back to its initial state
* or deleting. This is useful, if the user wants to extract the
* procedure result via proc_t<T>::pop()
* - consume_proc(...) - receives a proc_t<T> as a rvalue, and calls the proc_t<T>
* destructor once the procedure has ended. Useful, for procedures
* for which the user is not interested in the result, or reusing
* - defer_proc(...) - same as add_proc(...), but once the procedure has finished, it
* automatically sets the procedure back to its initial state.
* Useful if the user is not interested in handling the result
* - defer_task(...) - same as consume_proc(...) but takes a function pointer that
* specifies a proc_impl_t step() function
************************************************************************************/
class callback_list_t
{
public:
typedef std::function<void(proc_impl_t*)> proc_deleter_t;
typedef std::unique_ptr<proc_impl_t, proc_deleter_t> callback_obj_t;
template <class T>
struct recycle_deleter_t {
void operator()(proc_impl_t* p)
{
if (p != nullptr) {
T* Tp = static_cast<T*>(p);
Tp->~T();
new (Tp) T();
}
}
};
template <class T>
void add_proc(proc_t<T>& proc)
{
if (proc.is_complete()) {
return;
}
callback_obj_t ptr(proc.get(), [](proc_impl_t* p) { /* do nothing */ });
callbacks.push_back(std::move(ptr));
}
template <class T>
void consume_proc(proc_t<T>&& proc)
{
if (proc.is_complete()) {
return;
}
callback_obj_t ptr(proc.release(), std::default_delete<proc_impl_t>());
callbacks.push_back(std::move(ptr));
}
template <class T>
void defer_proc(proc_t<T>& proc)
{
if (proc.is_complete()) {
proc.pop();
return;
}
callback_obj_t ptr(proc.get(), recycle_deleter_t<T>());
callbacks.push_back(std::move(ptr));
}
bool defer_task(std::function<proc_outcome_t()> step_func)
{
proc_t<func_proc_t> proc;
if (not proc.launch(std::move(step_func))) {
return false;
}
consume_proc(std::move(proc));
return true;
}
void run()
{
// Calls run for all callbacks. Remove the ones that have finished. The proc dtor is called.
callbacks.remove_if([](callback_obj_t& elem) { return not elem->run(); });
}
size_t size() const { return callbacks.size(); }
private:
std::list<callback_obj_t> callbacks;
};
} // namespace srslte
#endif // SRSLTE_RESUMABLE_PROCEDURES_H

@ -29,10 +29,15 @@
#ifndef SRSLTE_THREAD_POOL_H #ifndef SRSLTE_THREAD_POOL_H
#define SRSLTE_THREAD_POOL_H #define SRSLTE_THREAD_POOL_H
#include <condition_variable>
#include <functional>
#include <memory>
#include <mutex>
#include <queue>
#include <stack>
#include <stdint.h> #include <stdint.h>
#include <string> #include <string>
#include <vector> #include <vector>
#include <stack>
#include "srslte/common/threads.h" #include "srslte/common/threads.h"
@ -96,6 +101,48 @@ private:
std::vector<pthread_mutex_t> mutex; std::vector<pthread_mutex_t> mutex;
std::stack<worker*> available_workers; std::stack<worker*> available_workers;
}; };
}
class task_thread_pool
{
using task_t = std::function<void(uint32_t worker_id)>;
public:
explicit task_thread_pool(uint32_t nof_workers);
~task_thread_pool();
void start(int32_t prio = -1, uint32_t mask = 255);
void stop();
void push_task(const task_t& task);
void push_task(task_t&& task);
uint32_t nof_pending_tasks();
private:
class worker_t : public thread
{
public:
explicit worker_t(task_thread_pool* parent_, uint32_t id);
void stop();
void setup(int32_t prio, uint32_t mask);
bool is_running() const { return running; }
uint32_t id() const { return id_; }
void run_thread() override;
private:
bool wait_task(task_t* task);
task_thread_pool* parent = nullptr;
uint32_t id_ = 0;
bool running = false;
};
std::queue<task_t> pending_tasks;
std::vector<worker_t> workers;
std::mutex queue_mutex;
std::condition_variable cv_empty;
bool running;
};
} // namespace srslte
#endif // SRSLTE_THREAD_POOL_H #endif // SRSLTE_THREAD_POOL_H

@ -50,9 +50,11 @@ class thread
{ {
public: public:
thread(const std::string& name_) : _thread(0), name(name_) {} thread(const std::string& name_) : _thread(0), name(name_) {}
bool start(int prio = -1) { thread(const thread&) = delete;
return threads_new_rt_prio(&_thread, thread_function_entry, this, prio); thread(thread&&) noexcept = default;
} thread& operator=(const thread&) = delete;
thread& operator=(thread&&) noexcept = default;
bool start(int prio = -1) { return threads_new_rt_prio(&_thread, thread_function_entry, this, prio); }
bool start_cpu(int prio, int cpu) { bool start_cpu(int prio, int cpu) {
return threads_new_rt_cpu(&_thread, thread_function_entry, this, cpu, prio); return threads_new_rt_cpu(&_thread, thread_function_entry, this, cpu, prio);
} }

@ -96,7 +96,8 @@ public:
bool running; bool running;
}; };
timers(uint32_t nof_timers_) : timer_list(nof_timers_),used_timers(nof_timers_) { timers(uint32_t nof_timers_) : timer_list(nof_timers_), used_timers(nof_timers_)
{
nof_timers = nof_timers_; nof_timers = nof_timers_;
next_timer = 0; next_timer = 0;
nof_used_timers = 0; nof_used_timers = 0;

@ -70,6 +70,6 @@ class tti_sync
uint32_t consumer_cntr; uint32_t consumer_cntr;
}; };
} // namespace srsue } // namespace srslte
#endif // SRSLTE_TTI_SYNC_H #endif // SRSLTE_TTI_SYNC_H

@ -0,0 +1,48 @@
/*---------------------------------------------------------
zuc.h
Adapted from ETSI/SAGE specifications:
"Specification of the 3GPP Confidentiality
and Integrity Algorithms 128-EEA3 & 128-EIA3.
Document 2: ZUC Specification"
---------------------------------------------------------*/
#ifndef SRSLTE_ZUC_H
#define SRSLTE_ZUC_H
typedef unsigned char u8;
typedef unsigned int u32;
/* the state registers of LFSR */
typedef struct {
u32 LFSR_S0;
u32 LFSR_S1;
u32 LFSR_S2;
u32 LFSR_S3;
u32 LFSR_S4;
u32 LFSR_S5;
u32 LFSR_S6;
u32 LFSR_S7;
u32 LFSR_S8;
u32 LFSR_S9;
u32 LFSR_S10;
u32 LFSR_S11;
u32 LFSR_S12;
u32 LFSR_S13;
u32 LFSR_S14;
u32 LFSR_S15;
/* the registers of F */
u32 F_R1;
u32 F_R2;
/* the outputs of BitReorganization */
u32 BRC_X0;
u32 BRC_X1;
u32 BRC_X2;
u32 BRC_X3;
} zuc_state_t;
void zuc_initialize(zuc_state_t* state, u8* k, u8* iv);
void zuc_generate_keystream(zuc_state_t* state, int key_stream_len, u32* p_keystream);
#endif // SRSLTE_ZUC_H

@ -65,6 +65,7 @@ public:
virtual float get_tx_gain_offset() = 0; virtual float get_tx_gain_offset() = 0;
virtual float get_rx_gain_offset() = 0; virtual float get_rx_gain_offset() = 0;
virtual bool is_continuous_tx() = 0; virtual bool is_continuous_tx() = 0;
virtual bool get_is_start_of_burst(const uint32_t& radio_idx) = 0;
virtual bool is_init() = 0; virtual bool is_init() = 0;
virtual void reset() = 0; virtual void reset() = 0;
virtual srslte_rf_info_t* get_info(const uint32_t& radio_idx) = 0; virtual srslte_rf_info_t* get_info(const uint32_t& radio_idx) = 0;

@ -194,6 +194,7 @@ public:
virtual void add_bearer(uint16_t rnti, uint32_t lcid, srslte::rlc_config_t cnfg) = 0; virtual void add_bearer(uint16_t rnti, uint32_t lcid, srslte::rlc_config_t cnfg) = 0;
virtual void add_bearer_mrb(uint16_t rnti, uint32_t lcid) = 0; virtual void add_bearer_mrb(uint16_t rnti, uint32_t lcid) = 0;
virtual void write_sdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0; virtual void write_sdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0;
virtual bool has_bearer(uint16_t rnti, uint32_t lcid) = 0;
}; };
// PDCP interface for GTPU // PDCP interface for GTPU
@ -211,7 +212,7 @@ public:
virtual void add_user(uint16_t rnti) = 0; virtual void add_user(uint16_t rnti) = 0;
virtual void rem_user(uint16_t rnti) = 0; virtual void rem_user(uint16_t rnti) = 0;
virtual void write_sdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0; virtual void write_sdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0;
virtual void add_bearer(uint16_t rnti, uint32_t lcid, srslte::srslte_pdcp_config_t cnfg) = 0; virtual void add_bearer(uint16_t rnti, uint32_t lcid, srslte::pdcp_config_t cnfg) = 0;
virtual void config_security(uint16_t rnti, virtual void config_security(uint16_t rnti,
uint32_t lcid, uint32_t lcid,
uint8_t* k_rrc_enc_, uint8_t* k_rrc_enc_,

@ -24,6 +24,7 @@
#include "srslte/common/bcd_helpers.h" #include "srslte/common/bcd_helpers.h"
#include "srslte/config.h" #include "srslte/config.h"
#include "srslte/srslte.h"
#include <string> #include <string>
/************************ /************************
@ -124,6 +125,7 @@ struct plmn_id_t {
struct s_tmsi_t { struct s_tmsi_t {
uint8_t mmec = 0; uint8_t mmec = 0;
uint32_t m_tmsi = 0; uint32_t m_tmsi = 0;
bool operator==(const s_tmsi_t& other) const { return mmec == other.mmec and m_tmsi == other.m_tmsi; }
}; };
/*************************** /***************************
@ -180,6 +182,18 @@ inline uint16_t to_number(const rlc_umd_sn_size_t& sn_size)
return enum_to_number(options, (uint32_t)rlc_mode_t::nulltype, (uint32_t)sn_size); return enum_to_number(options, (uint32_t)rlc_mode_t::nulltype, (uint32_t)sn_size);
} }
enum class rlc_um_nr_sn_size_t { size6bits, size12bits, nulltype };
inline std::string to_string(const rlc_um_nr_sn_size_t& sn_size)
{
constexpr static const char* options[] = {"6 bits", "12 bits"};
return enum_to_text(options, (uint32_t)rlc_mode_t::nulltype, (uint32_t)sn_size);
}
inline uint16_t to_number(const rlc_um_nr_sn_size_t& sn_size)
{
constexpr static uint16_t options[] = {6, 12};
return enum_to_number(options, (uint32_t)rlc_mode_t::nulltype, (uint32_t)sn_size);
}
struct rlc_am_config_t { struct rlc_am_config_t {
/**************************************************************************** /****************************************************************************
* Configurable parameters * Configurable parameters
@ -213,22 +227,49 @@ struct rlc_um_config_t {
bool is_mrb; // Whether this is a multicast bearer bool is_mrb; // Whether this is a multicast bearer
}; };
struct rlc_um_nr_config_t {
/****************************************************************************
* Configurable parameters
* Ref: 3GPP TS 38.322 v15.3.0 Section 7
***************************************************************************/
rlc_um_nr_sn_size_t sn_field_length; // Number of bits used for sequence number
uint32_t UM_Window_Size;
uint32_t mod; // Rx/Tx counter modulus
};
#define RLC_TX_QUEUE_LEN (128) #define RLC_TX_QUEUE_LEN (128)
enum class rlc_type_t { lte, nr, nulltype };
inline std::string to_string(const rlc_type_t& type)
{
constexpr static const char* options[] = {"LTE", "NR"};
return enum_to_text(options, (uint32_t)rlc_type_t::nulltype, (uint32_t)type);
}
class rlc_config_t class rlc_config_t
{ {
public: public:
rlc_type_t type;
rlc_mode_t rlc_mode; rlc_mode_t rlc_mode;
rlc_am_config_t am; rlc_am_config_t am;
rlc_um_config_t um; rlc_um_config_t um;
rlc_um_nr_config_t um_nr;
uint32_t tx_queue_length; uint32_t tx_queue_length;
rlc_config_t() : rlc_mode(rlc_mode_t::tm), am(), um(), tx_queue_length(RLC_TX_QUEUE_LEN){}; rlc_config_t() :
type(rlc_type_t::lte),
rlc_mode(rlc_mode_t::tm),
am(),
um(),
um_nr(),
tx_queue_length(RLC_TX_QUEUE_LEN){};
// Factory for MCH // Factory for MCH
static rlc_config_t mch_config() static rlc_config_t mch_config()
{ {
rlc_config_t cfg; rlc_config_t cfg = {};
cfg.type = rlc_type_t::lte;
cfg.rlc_mode = rlc_mode_t::um; cfg.rlc_mode = rlc_mode_t::um;
cfg.um.t_reordering = 45; cfg.um.t_reordering = 45;
cfg.um.rx_sn_field_length = rlc_umd_sn_size_t::size5bits; cfg.um.rx_sn_field_length = rlc_umd_sn_size_t::size5bits;
@ -246,7 +287,8 @@ public:
return {}; return {};
} }
// SRB1 and SRB2 are AM // SRB1 and SRB2 are AM
rlc_config_t rlc_cfg; rlc_config_t rlc_cfg = {};
rlc_cfg.type = rlc_type_t::lte;
rlc_cfg.rlc_mode = rlc_mode_t::am; rlc_cfg.rlc_mode = rlc_mode_t::am;
rlc_cfg.am.t_poll_retx = 45; rlc_cfg.am.t_poll_retx = 45;
rlc_cfg.am.poll_pdu = -1; rlc_cfg.am.poll_pdu = -1;
@ -258,7 +300,8 @@ public:
} }
static rlc_config_t default_rlc_um_config(uint32_t sn_size = 10) static rlc_config_t default_rlc_um_config(uint32_t sn_size = 10)
{ {
rlc_config_t cnfg; rlc_config_t cnfg = {};
cnfg.type = rlc_type_t::lte;
cnfg.rlc_mode = rlc_mode_t::um; cnfg.rlc_mode = rlc_mode_t::um;
cnfg.um.t_reordering = 5; cnfg.um.t_reordering = 5;
if (sn_size == 10) { if (sn_size == 10) {
@ -280,7 +323,8 @@ public:
} }
static rlc_config_t default_rlc_am_config() static rlc_config_t default_rlc_am_config()
{ {
rlc_config_t rlc_cnfg; rlc_config_t rlc_cnfg = {};
rlc_cnfg.type = rlc_type_t::lte;
rlc_cnfg.rlc_mode = rlc_mode_t::am; rlc_cnfg.rlc_mode = rlc_mode_t::am;
rlc_cnfg.am.t_reordering = 5; rlc_cnfg.am.t_reordering = 5;
rlc_cnfg.am.t_status_prohibit = 5; rlc_cnfg.am.t_status_prohibit = 5;
@ -290,7 +334,306 @@ public:
rlc_cnfg.am.t_poll_retx = 5; rlc_cnfg.am.t_poll_retx = 5;
return rlc_cnfg; return rlc_cnfg;
} }
static rlc_config_t default_rlc_um_nr_config(uint32_t sn_size = 6)
{
rlc_config_t cnfg = {};
cnfg.type = rlc_type_t::nr;
cnfg.rlc_mode = rlc_mode_t::um;
if (sn_size == 6) {
cnfg.um_nr.sn_field_length = rlc_um_nr_sn_size_t::size6bits;
cnfg.um_nr.UM_Window_Size = 32;
cnfg.um_nr.mod = 64;
} else if (sn_size == 12) {
cnfg.um_nr.sn_field_length = rlc_um_nr_sn_size_t::size12bits;
cnfg.um_nr.UM_Window_Size = 2048;
cnfg.um_nr.mod = 64;
} else {
return {};
}
return cnfg;
}
};
/***************************
* MAC Config
**************************/
struct bsr_cfg_t {
int periodic_timer;
int retx_timer;
bsr_cfg_t() { reset(); }
void reset()
{
periodic_timer = -1;
retx_timer = 2560;
}
};
struct phr_cfg_t {
bool enabled;
int periodic_timer;
int prohibit_timer;
int db_pathloss_change;
bool extended;
phr_cfg_t() { reset(); }
void reset()
{
enabled = false;
periodic_timer = -1;
prohibit_timer = -1;
db_pathloss_change = -1;
extended = false;
}
};
struct sr_cfg_t {
bool enabled;
int dsr_transmax;
sr_cfg_t() { reset(); }
void reset()
{
enabled = false;
dsr_transmax = 0;
}
};
struct ul_harq_cfg_t {
uint32_t max_harq_msg3_tx;
uint32_t max_harq_tx;
ul_harq_cfg_t() { reset(); }
void reset()
{
max_harq_msg3_tx = 5;
max_harq_tx = 5;
}
};
struct rach_cfg_t {
bool enabled;
uint32_t nof_preambles;
uint32_t nof_groupA_preambles;
int32_t messagePowerOffsetGroupB;
uint32_t messageSizeGroupA;
uint32_t responseWindowSize;
uint32_t powerRampingStep;
uint32_t preambleTransMax;
int32_t iniReceivedTargetPower;
uint32_t contentionResolutionTimer;
uint32_t new_ra_msg_len;
rach_cfg_t() { reset(); }
void reset()
{
enabled = false;
nof_preambles = 0;
nof_groupA_preambles = 0;
messagePowerOffsetGroupB = 0;
messageSizeGroupA = 0;
responseWindowSize = 0;
powerRampingStep = 0;
preambleTransMax = 0;
iniReceivedTargetPower = 0;
contentionResolutionTimer = 0;
new_ra_msg_len = 0;
}
};
struct mac_cfg_t {
// Default constructor with default values as in 36.331 9.2.2
mac_cfg_t() { set_defaults(); }
void set_defaults()
{
rach_cfg.reset();
set_mac_main_cfg_default();
}
void set_mac_main_cfg_default()
{
bsr_cfg.reset();
phr_cfg.reset();
sr_cfg.reset();
harq_cfg.reset();
time_alignment_timer = -1;
}
bsr_cfg_t bsr_cfg;
phr_cfg_t phr_cfg;
sr_cfg_t sr_cfg;
rach_cfg_t rach_cfg;
ul_harq_cfg_t harq_cfg;
int time_alignment_timer;
};
/***************************
* PHY Config
**************************/
struct phy_cfg_t {
phy_cfg_t() { set_defaults(); }
void set_defaults()
{
ZERO_OBJECT(ul_cfg);
ZERO_OBJECT(dl_cfg);
ZERO_OBJECT(prach_cfg);
// CommonConfig defaults for non-zero values
ul_cfg.pucch.delta_pucch_shift = 1;
ul_cfg.power_ctrl.delta_f_pucch[0] = 0;
ul_cfg.power_ctrl.delta_f_pucch[1] = 1;
ul_cfg.power_ctrl.delta_f_pucch[2] = 0;
ul_cfg.power_ctrl.delta_f_pucch[3] = 0;
ul_cfg.power_ctrl.delta_f_pucch[4] = 0;
set_defaults_dedicated();
}
// 36.331 9.2.4
void set_defaults_dedicated()
{
dl_cfg.tm = SRSLTE_TM1;
dl_cfg.pdsch.use_tbs_index_alt = false;
dl_cfg.pdsch.p_a = 0;
dl_cfg.cqi_report.periodic_configured = false;
dl_cfg.cqi_report.aperiodic_configured = false;
ul_cfg.pucch.tdd_ack_multiplex = false;
ul_cfg.pusch.uci_offset.I_offset_ack = 10;
ul_cfg.pusch.uci_offset.I_offset_ri = 12;
ul_cfg.pusch.uci_offset.I_offset_cqi = 15;
ul_cfg.power_ctrl.p0_nominal_pusch = 0;
ul_cfg.power_ctrl.delta_mcs_based = false;
ul_cfg.power_ctrl.acc_enabled = true;
ul_cfg.power_ctrl.p0_nominal_pucch = 0;
ul_cfg.power_ctrl.p_srs_offset = 7;
ul_cfg.srs.dedicated_enabled = false;
ul_cfg.pucch.sr_configured = false;
}
srslte_dl_cfg_t dl_cfg;
srslte_ul_cfg_t ul_cfg;
srslte_prach_cfg_t prach_cfg;
}; };
struct mbsfn_sf_cfg_t {
enum class alloc_period_t { n1, n2, n4, n8, n16, n32, nulltype };
alloc_period_t radioframe_alloc_period;
uint8_t radioframe_alloc_offset = 0;
enum class sf_alloc_type_t { one_frame, four_frames, nulltype };
sf_alloc_type_t nof_alloc_subfrs;
uint32_t sf_alloc;
};
inline uint16_t enum_to_number(const mbsfn_sf_cfg_t::alloc_period_t& radioframe_period)
{
constexpr static uint16_t options[] = {1, 2, 4, 8, 16, 32};
return enum_to_number(options, (uint32_t)mbsfn_sf_cfg_t::alloc_period_t::nulltype, (uint32_t)radioframe_period);
}
struct mbms_notif_cfg_t {
enum class coeff_t { n2, n4 };
coeff_t notif_repeat_coeff = coeff_t::n2;
uint8_t notif_offset = 0;
uint8_t notif_sf_idx = 1;
};
// MBSFN-AreaInfo-r9 ::= SEQUENCE
struct mbsfn_area_info_t {
uint8_t mbsfn_area_id = 0;
enum class region_len_t { s1, s2, nulltype } non_mbsfn_region_len;
uint8_t notif_ind = 0;
struct mcch_cfg_t {
enum class repeat_period_t { rf32, rf64, rf128, rf256, nulltype } mcch_repeat_period;
uint8_t mcch_offset = 0;
enum class mod_period_t { rf512, rf1024 } mcch_mod_period;
uint8_t sf_alloc_info = 0;
enum class sig_mcs_t { n2, n7, n13, n19, nulltype } sig_mcs;
} mcch_cfg;
};
inline uint16_t enum_to_number(const mbsfn_area_info_t::region_len_t& region_len)
{
constexpr static uint16_t options[] = {1, 2};
return enum_to_number(options, (uint32_t)mbsfn_area_info_t::region_len_t::nulltype, (uint32_t)region_len);
}
inline uint16_t enum_to_number(const mbsfn_area_info_t::mcch_cfg_t::repeat_period_t& repeat_period)
{
constexpr static uint16_t options[] = {32, 64, 128, 256};
return enum_to_number(
options, (uint32_t)mbsfn_area_info_t::mcch_cfg_t::repeat_period_t::nulltype, (uint32_t)repeat_period);
}
inline uint16_t enum_to_number(const mbsfn_area_info_t::mcch_cfg_t::sig_mcs_t& sig_mcs)
{
constexpr static uint16_t options[] = {2, 7, 13, 19};
return enum_to_number(options, (uint32_t)mbsfn_area_info_t::mcch_cfg_t::sig_mcs_t::nulltype, (uint32_t)sig_mcs);
}
// TMGI-r9
struct tmgi_t {
enum class plmn_id_type_t { plmn_idx, explicit_value } plmn_id_type;
union choice {
uint8_t plmn_idx;
plmn_id_t explicit_value;
choice() : plmn_idx(0) {}
} plmn_id;
uint8_t serviced_id[3];
tmgi_t() : plmn_id_type(plmn_id_type_t::plmn_idx) {}
};
struct pmch_info_t {
// pmch_cfg_t
uint16_t sf_alloc_end = 0;
uint8_t data_mcs = 0;
enum class mch_sched_period_t { rf8, rf16, rf32, rf64, rf128, rf256, rf512, rf1024, nulltype } mch_sched_period;
// mbms_session_info_list
struct mbms_session_info_t {
bool session_id_present = false;
tmgi_t tmgi;
uint8_t session_id;
uint8_t lc_ch_id = 0;
};
uint32_t nof_mbms_session_info;
static const uint32_t max_session_per_pmch = 29;
mbms_session_info_t mbms_session_info_list[max_session_per_pmch];
};
inline uint16_t enum_to_number(const pmch_info_t::mch_sched_period_t& mch_period)
{
constexpr static uint16_t options[] = {8, 16, 32, 64, 128, 256, 512, 1024};
return enum_to_number(options, (uint32_t)pmch_info_t::mch_sched_period_t::nulltype, (uint32_t)mch_period);
}
struct mcch_msg_t {
uint32_t nof_common_sf_alloc = 0;
mbsfn_sf_cfg_t common_sf_alloc[8];
enum class common_sf_alloc_period_t { rf4, rf8, rf16, rf32, rf64, rf128, rf256, nulltype } common_sf_alloc_period;
uint32_t nof_pmch_info;
pmch_info_t pmch_info_list[15];
// mbsfn_area_cfg_v930_ies non crit ext OPTIONAL
};
inline uint16_t enum_to_number(const mcch_msg_t::common_sf_alloc_period_t& alloc_period)
{
constexpr static uint16_t options[] = {4, 8, 16, 32, 64, 128, 256};
return enum_to_number(options, (uint32_t)mcch_msg_t::common_sf_alloc_period_t::nulltype, (uint32_t)alloc_period);
}
struct phy_cfg_mbsfn_t {
mbsfn_sf_cfg_t mbsfn_subfr_cnfg;
mbms_notif_cfg_t mbsfn_notification_cnfg;
mbsfn_area_info_t mbsfn_area_info;
mcch_msg_t mcch;
};
// SystemInformationBlockType13-r9
struct sib13_t {
static const uint32_t max_mbsfn_area = 8;
uint32_t nof_mbsfn_area_info = 0;
mbsfn_area_info_t mbsfn_area_info_list[max_mbsfn_area];
mbms_notif_cfg_t notif_cfg;
};
} // namespace srslte } // namespace srslte
#endif // SRSLTE_RRC_INTERFACE_TYPES_H #endif // SRSLTE_RRC_INTERFACE_TYPES_H

@ -32,10 +32,11 @@
#include "rrc_interface_types.h" #include "rrc_interface_types.h"
#include "srslte/asn1/liblte_mme.h" #include "srslte/asn1/liblte_mme.h"
#include "srslte/asn1/rrc_asn1.h"
#include "srslte/common/common.h" #include "srslte/common/common.h"
#include "srslte/common/interfaces_common.h" #include "srslte/common/interfaces_common.h"
#include "srslte/common/security.h" #include "srslte/common/security.h"
#include "srslte/common/stack_procedure.h"
#include "srslte/interfaces/rrc_interface_types.h"
#include "srslte/phy/channel/channel.h" #include "srslte/phy/channel/channel.h"
#include "srslte/phy/rf/rf.h" #include "srslte/phy/rf/rf.h"
@ -118,43 +119,6 @@ public:
virtual void write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t pdu) = 0; virtual void write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t pdu) = 0;
}; };
// NAS interface for RRC
class nas_interface_rrc
{
public:
typedef enum {
BARRING_NONE = 0,
BARRING_MO_DATA,
BARRING_MO_SIGNALLING,
BARRING_MT,
BARRING_ALL
} barring_t;
virtual void leave_connected() = 0;
virtual void set_barring(barring_t barring) = 0;
virtual void paging(srslte::s_tmsi_t* ue_identity) = 0;
virtual bool is_attached() = 0;
virtual void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t pdu) = 0;
virtual uint32_t get_k_enb_count() = 0;
virtual bool get_k_asme(uint8_t* k_asme_, uint32_t n) = 0;
virtual uint32_t get_ipv4_addr() = 0;
virtual bool get_ipv6_addr(uint8_t* ipv6_addr) = 0;
};
// NAS interface for UE
class nas_interface_ue
{
public:
virtual bool attach_request() = 0;
virtual bool detach_request() = 0;
};
// NAS interface for UE
class nas_interface_gw
{
public:
virtual bool attach_request() = 0;
};
// RRC interface for MAC // RRC interface for MAC
class rrc_interface_mac_common class rrc_interface_mac_common
{ {
@ -193,12 +157,13 @@ public:
virtual uint16_t get_mcc() = 0; virtual uint16_t get_mcc() = 0;
virtual uint16_t get_mnc() = 0; virtual uint16_t get_mnc() = 0;
virtual void enable_capabilities() = 0; virtual void enable_capabilities() = 0;
virtual int plmn_search(found_plmn_t found_plmns[MAX_FOUND_PLMNS]) = 0; virtual bool plmn_search() = 0;
virtual void plmn_select(srslte::plmn_id_t plmn_id) = 0; virtual void plmn_select(srslte::plmn_id_t plmn_id) = 0;
virtual bool connection_request(srslte::establishment_cause_t cause, virtual bool connection_request(srslte::establishment_cause_t cause,
srslte::unique_byte_buffer_t dedicatedInfoNAS) = 0; srslte::unique_byte_buffer_t dedicatedInfoNAS) = 0;
virtual void set_ue_identity(srslte::s_tmsi_t s_tmsi) = 0; virtual void set_ue_identity(srslte::s_tmsi_t s_tmsi) = 0;
virtual bool is_connected() = 0; virtual bool is_connected() = 0;
virtual void paging_completed(bool outcome) = 0;
virtual std::string get_rb_name(uint32_t lcid) = 0; virtual std::string get_rb_name(uint32_t lcid) = 0;
virtual uint32_t get_lcid_for_eps_bearer(const uint32_t& eps_bearer_id) = 0; virtual uint32_t get_lcid_for_eps_bearer(const uint32_t& eps_bearer_id) = 0;
}; };
@ -224,6 +189,33 @@ public:
virtual void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t pdu) = 0; virtual void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t pdu) = 0;
}; };
// NAS interface for RRC
class nas_interface_rrc
{
public:
typedef enum { BARRING_NONE = 0, BARRING_MO_DATA, BARRING_MO_SIGNALLING, BARRING_MT, BARRING_ALL } barring_t;
virtual void left_rrc_connected() = 0;
virtual void set_barring(barring_t barring) = 0;
virtual void paging(srslte::s_tmsi_t* ue_identity) = 0;
virtual bool is_attached() = 0;
virtual void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t pdu) = 0;
virtual uint32_t get_k_enb_count() = 0;
virtual bool get_k_asme(uint8_t* k_asme_, uint32_t n) = 0;
virtual uint32_t get_ipv4_addr() = 0;
virtual bool get_ipv6_addr(uint8_t* ipv6_addr) = 0;
virtual void plmn_search_completed(rrc_interface_nas::found_plmn_t found_plmns[rrc_interface_nas::MAX_FOUND_PLMNS],
int nof_plmns) = 0;
virtual bool connection_request_completed(bool outcome) = 0;
virtual void run_tti(uint32_t tti) = 0;
};
// NAS interface for UE
class nas_interface_ue
{
public:
virtual void start_attach_request(srslte::proc_state_t* proc_result) = 0;
virtual bool detach_request(const bool switch_off) = 0;
};
// PDCP interface for RRC // PDCP interface for RRC
class pdcp_interface_rrc class pdcp_interface_rrc
@ -233,7 +225,7 @@ public:
virtual void reestablish(uint32_t lcid) = 0; virtual void reestablish(uint32_t lcid) = 0;
virtual void reset() = 0; virtual void reset() = 0;
virtual void write_sdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu, bool blocking = true) = 0; virtual void write_sdu(uint32_t lcid, srslte::unique_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 add_bearer(uint32_t lcid, srslte::pdcp_config_t cnfg) = 0;
virtual void change_lcid(uint32_t old_lcid, uint32_t new_lcid) = 0; virtual void change_lcid(uint32_t old_lcid, uint32_t new_lcid) = 0;
virtual void config_security(uint32_t lcid, virtual void config_security(uint32_t lcid,
uint8_t* k_rrc_enc_, uint8_t* k_rrc_enc_,
@ -248,8 +240,6 @@ public:
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo_) = 0; srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo_) = 0;
virtual void enable_integrity(uint32_t lcid) = 0; virtual void enable_integrity(uint32_t lcid) = 0;
virtual void enable_encryption(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 // PDCP interface for RLC
@ -325,30 +315,6 @@ public:
virtual void write_pdu_mch(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes) = 0; virtual void write_pdu_mch(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes) = 0;
}; };
//BSR interface for MUX
class bsr_interface_mux
{
public:
typedef enum {
LONG_BSR,
SHORT_BSR,
TRUNC_BSR
} bsr_format_t;
typedef struct {
bsr_format_t format;
uint32_t buff_size[4];
} bsr_t;
/* MUX calls BSR to check if it can fit a BSR into PDU */
virtual bool need_to_send_bsr_on_ul_grant(uint32_t grant_size, bsr_t *bsr) = 0;
/* MUX calls BSR to let it generate a padding BSR if there is space in PDU */
virtual bool generate_padding_bsr(uint32_t nof_padding_bytes, bsr_t *bsr) = 0;
};
/** MAC interface /** MAC interface
* *
*/ */
@ -372,6 +338,7 @@ public:
uint32_t pid; uint32_t pid;
uint16_t rnti; uint16_t rnti;
bool is_sps_release; bool is_sps_release;
uint32_t tti;
} mac_grant_dl_t; } mac_grant_dl_t;
typedef struct { typedef struct {
@ -380,6 +347,7 @@ public:
uint16_t rnti; uint16_t rnti;
bool phich_available; bool phich_available;
bool hi_value; bool hi_value;
uint32_t tti_tx;
} mac_grant_ul_t; } mac_grant_ul_t;
typedef struct { typedef struct {
@ -449,196 +417,12 @@ public:
uint64_t contention_id; uint64_t contention_id;
} ue_rnti_t; } ue_rnti_t;
typedef struct ul_harq_cfg_t {
uint32_t max_harq_msg3_tx;
uint32_t max_harq_tx;
ul_harq_cfg_t() { reset(); }
void reset()
{
max_harq_msg3_tx = 5;
max_harq_tx = 5;
}
} ul_harq_cfg_t;
}; };
/* Interface RRC -> MAC */ /* Interface RRC -> MAC */
class mac_interface_rrc : public mac_interface_rrc_common class mac_interface_rrc : public mac_interface_rrc_common
{ {
public: public:
typedef struct bsr_cfg_t {
int periodic_timer;
int retx_timer;
bsr_cfg_t() { reset(); }
void reset()
{
periodic_timer = -1;
retx_timer = 2560;
}
} bsr_cfg_t;
typedef struct phr_cfg_t {
bool enabled;
int periodic_timer;
int prohibit_timer;
int db_pathloss_change;
bool extended;
phr_cfg_t() { reset(); }
void reset()
{
enabled = false;
periodic_timer = -1;
prohibit_timer = -1;
db_pathloss_change = -1;
extended = false;
}
} phr_cfg_t;
typedef struct sr_cfg_t {
bool enabled;
int dsr_transmax;
sr_cfg_t() { reset(); }
void reset()
{
enabled = false;
dsr_transmax = 0;
}
} sr_cfg_t;
typedef struct rach_cfg_t {
bool enabled;
uint32_t nof_preambles;
uint32_t nof_groupA_preambles;
int32_t messagePowerOffsetGroupB;
uint32_t messageSizeGroupA;
uint32_t responseWindowSize;
uint32_t powerRampingStep;
uint32_t preambleTransMax;
int32_t iniReceivedTargetPower;
uint32_t contentionResolutionTimer;
uint32_t new_ra_msg_len;
rach_cfg_t() { reset(); }
void reset()
{
enabled = false;
nof_preambles = 0;
nof_groupA_preambles = 0;
messagePowerOffsetGroupB = 0;
messageSizeGroupA = 0;
responseWindowSize = 0;
powerRampingStep = 0;
preambleTransMax = 0;
iniReceivedTargetPower = 0;
contentionResolutionTimer = 0;
new_ra_msg_len = 0;
}
} rach_cfg_t;
class mac_cfg_t
{
public:
// Default constructor with default values as in 36.331 9.2.2
mac_cfg_t() { set_defaults(); }
void set_defaults()
{
rach_cfg.reset();
set_mac_main_cfg_default();
}
void set_mac_main_cfg_default()
{
bsr_cfg.reset();
phr_cfg.reset();
sr_cfg.reset();
harq_cfg.reset();
time_alignment_timer = -1;
}
// Called only if section is present
void set_sched_request_cfg(asn1::rrc::sched_request_cfg_c& cfg)
{
sr_cfg.enabled = cfg.type() == asn1::rrc::setup_e::setup;
if (sr_cfg.enabled) {
sr_cfg.dsr_transmax = cfg.setup().dsr_trans_max.to_number();
}
}
// MAC-MainConfig section is always present
void set_mac_main_cfg(asn1::rrc::mac_main_cfg_s& cfg)
{
// Update values only if each section is present
if (cfg.phr_cfg_present) {
phr_cfg.enabled = cfg.phr_cfg.type() == asn1::rrc::setup_e::setup;
if (phr_cfg.enabled) {
phr_cfg.prohibit_timer = cfg.phr_cfg.setup().prohibit_phr_timer.to_number();
phr_cfg.periodic_timer = cfg.phr_cfg.setup().periodic_phr_timer.to_number();
phr_cfg.db_pathloss_change = cfg.phr_cfg.setup().dl_pathloss_change.to_number();
}
}
if (cfg.mac_main_cfg_v1020_present) {
typedef asn1::rrc::mac_main_cfg_s::mac_main_cfg_v1020_s_ mac_main_cfg_v1020_t;
mac_main_cfg_v1020_t* mac_main_cfg_v1020 = cfg.mac_main_cfg_v1020.get();
phr_cfg.extended = mac_main_cfg_v1020->extended_phr_r10_present;
}
if (cfg.ul_sch_cfg_present) {
bsr_cfg.periodic_timer = cfg.ul_sch_cfg.periodic_bsr_timer.to_number();
bsr_cfg.retx_timer = cfg.ul_sch_cfg.retx_bsr_timer.to_number();
if (cfg.ul_sch_cfg.max_harq_tx_present) {
harq_cfg.max_harq_tx = cfg.ul_sch_cfg.max_harq_tx.to_number();
}
}
// TimeAlignmentDedicated overwrites Common??
time_alignment_timer = cfg.time_align_timer_ded.to_number();
}
// RACH-Common section is always present
void set_rach_cfg_common(asn1::rrc::rach_cfg_common_s& cfg)
{
// Preamble info
rach_cfg.nof_preambles = cfg.preamb_info.nof_ra_preambs.to_number();
if (cfg.preamb_info.preambs_group_a_cfg_present) {
rach_cfg.nof_groupA_preambles = cfg.preamb_info.preambs_group_a_cfg.size_of_ra_preambs_group_a.to_number();
rach_cfg.messageSizeGroupA = cfg.preamb_info.preambs_group_a_cfg.msg_size_group_a.to_number();
rach_cfg.messagePowerOffsetGroupB = cfg.preamb_info.preambs_group_a_cfg.msg_pwr_offset_group_b.to_number();
} else {
rach_cfg.nof_groupA_preambles = 0;
}
// Power ramping
rach_cfg.powerRampingStep = cfg.pwr_ramp_params.pwr_ramp_step.to_number();
rach_cfg.iniReceivedTargetPower = cfg.pwr_ramp_params.preamb_init_rx_target_pwr.to_number();
// Supervision info
rach_cfg.preambleTransMax = cfg.ra_supervision_info.preamb_trans_max.to_number();
rach_cfg.responseWindowSize = cfg.ra_supervision_info.ra_resp_win_size.to_number();
rach_cfg.contentionResolutionTimer = cfg.ra_supervision_info.mac_contention_resolution_timer.to_number();
// HARQ Msg3
harq_cfg.max_harq_msg3_tx = cfg.max_harq_msg3_tx;
}
void set_time_alignment(asn1::rrc::time_align_timer_e time_alignment_timer)
{
this->time_alignment_timer = time_alignment_timer.to_number();
}
bsr_cfg_t& get_bsr_cfg() { return bsr_cfg; }
phr_cfg_t& get_phr_cfg() { return phr_cfg; }
rach_cfg_t& get_rach_cfg() { return rach_cfg; }
sr_cfg_t& get_sr_cfg() { return sr_cfg; }
ul_harq_cfg_t& get_harq_cfg() { return harq_cfg; }
int get_time_alignment_timer() { return time_alignment_timer; }
private:
bsr_cfg_t bsr_cfg;
phr_cfg_t phr_cfg;
sr_cfg_t sr_cfg;
rach_cfg_t rach_cfg;
ul_harq_cfg_t harq_cfg;
int time_alignment_timer;
};
virtual void clear_rntis() = 0; virtual void clear_rntis() = 0;
/* Instructs the MAC to start receiving BCCH */ /* Instructs the MAC to start receiving BCCH */
@ -656,7 +440,7 @@ public:
virtual uint32_t get_current_tti() = 0; virtual uint32_t get_current_tti() = 0;
virtual void set_config(mac_cfg_t& mac_cfg) = 0; virtual void set_config(srslte::mac_cfg_t& mac_cfg) = 0;
virtual void get_rntis(ue_rnti_t *rntis) = 0; virtual void get_rntis(ue_rnti_t *rntis) = 0;
virtual void set_contention_id(uint64_t uecri) = 0; virtual void set_contention_id(uint64_t uecri) = 0;
@ -791,42 +575,18 @@ public:
class phy_interface_rrc_lte class phy_interface_rrc_lte
{ {
public: public:
struct phy_cfg_common_t {
asn1::rrc::prach_cfg_sib_s prach_cnfg;
asn1::rrc::pdsch_cfg_common_s pdsch_cnfg;
asn1::rrc::pusch_cfg_common_s pusch_cnfg;
asn1::rrc::phich_cfg_s phich_cnfg;
asn1::rrc::pucch_cfg_common_s pucch_cnfg;
asn1::rrc::srs_ul_cfg_common_c srs_ul_cnfg;
asn1::rrc::ul_pwr_ctrl_common_s ul_pwr_ctrl;
asn1::rrc::tdd_cfg_s tdd_cnfg;
asn1::rrc::srs_ant_port_e ant_info;
bool rrc_enable_64qam;
};
struct phy_cfg_mbsfn_t {
asn1::rrc::mbsfn_sf_cfg_s mbsfn_subfr_cnfg;
asn1::rrc::mbms_notif_cfg_r9_s mbsfn_notification_cnfg;
asn1::rrc::mbsfn_area_info_r9_s mbsfn_area_info;
asn1::rrc::mcch_msg_s mcch;
};
typedef struct {
asn1::rrc::phys_cfg_ded_s dedicated;
phy_cfg_common_t common;
phy_cfg_mbsfn_t mbsfn;
} phy_cfg_t;
virtual void get_current_cell(srslte_cell_t* cell, uint32_t* current_earfcn = NULL) = 0; virtual void get_current_cell(srslte_cell_t* cell, uint32_t* current_earfcn = NULL) = 0;
virtual uint32_t get_current_earfcn() = 0; virtual uint32_t get_current_earfcn() = 0;
virtual uint32_t get_current_pci() = 0; virtual uint32_t get_current_pci() = 0;
virtual void set_config(phy_cfg_t* config) = 0; virtual void set_config(srslte::phy_cfg_t& config,
virtual void set_config_scell(asn1::rrc::scell_to_add_mod_r10_s* scell_config) = 0; uint32_t cc_idx = 0,
virtual void set_config_tdd(asn1::rrc::tdd_cfg_s* tdd) = 0; uint32_t earfcn = 0,
virtual void set_config_mbsfn_sib2(asn1::rrc::sib_type2_s* sib2) = 0; srslte_cell_t* cell_info = nullptr) = 0;
virtual void set_config_mbsfn_sib13(asn1::rrc::sib_type13_r9_s* sib13) = 0; virtual void set_config_tdd(srslte_tdd_config_t& tdd_config) = 0;
virtual void set_config_mbsfn_mcch(asn1::rrc::mcch_msg_s* mcch) = 0; virtual void set_config_mbsfn_sib2(srslte::mbsfn_sf_cfg_t* cfg_list, uint32_t nof_cfgs) = 0;
virtual void set_config_mbsfn_sib13(const srslte::sib13_t& sib13) = 0;
virtual void set_config_mbsfn_mcch(const srslte::mcch_msg_t& mcch) = 0;
/* Measurements interface */ /* Measurements interface */
virtual void meas_reset() = 0; virtual void meas_reset() = 0;
@ -864,6 +624,21 @@ class gw_interface_stack : public gw_interface_nas, public gw_interface_rrc, pub
{ {
}; };
// STACK interface for MAC
class stack_interface_mac
{
public:
virtual void process_pdus() = 0;
virtual void wait_ra_completion(uint16_t rnti) = 0;
};
// STACK interface for RRC
class stack_interface_rrc
{
public:
virtual void start_cell_search() = 0;
};
// Combined interface for PHY to access stack (MAC and RRC) // Combined interface for PHY to access stack (MAC and RRC)
class stack_interface_phy_lte : public mac_interface_phy_lte, public rrc_interface_phy_lte class stack_interface_phy_lte : public mac_interface_phy_lte, public rrc_interface_phy_lte
{ {

@ -64,6 +64,8 @@ typedef struct SRSLTE_API {
uint32_t I_srs; uint32_t I_srs;
uint32_t k_tc; uint32_t k_tc;
uint32_t n_rrc; uint32_t n_rrc;
bool dedicated_enabled;
bool common_enabled;
bool configured; bool configured;
} srslte_refsignal_srs_cfg_t; } srslte_refsignal_srs_cfg_t;

@ -24,10 +24,10 @@
#include "delay.h" #include "delay.h"
#include "fading.h" #include "fading.h"
#include "hst.h"
#include "rlf.h" #include "rlf.h"
#include <memory> #include <memory>
#include <srslte/config.h> #include <srslte/common/log_filter.h>
#include <srslte/srslte.h>
#include <string> #include <string>
namespace srslte { namespace srslte {
@ -43,11 +43,18 @@ public:
bool fading_enable = false; bool fading_enable = false;
std::string fading_model = "none"; std::string fading_model = "none";
// High Speed Train options
bool hst_enable = false;
float hst_fd_hz = 750.0f;
float hst_period_s = 7.2f;
float hst_init_time_s = 0.0f;
// Delay options // Delay options
bool delay_enable = false; bool delay_enable = false;
float delay_min_us = 10; float delay_min_us = 10;
float delay_max_us = 100; float delay_max_us = 100;
uint32_t delay_period_s = 3600; float delay_period_s = 3600;
float delay_init_time_s = 0;
// RLF options // RLF options
bool rlf_enable = false; bool rlf_enable = false;
@ -57,15 +64,18 @@ public:
channel(const args_t& channel_args, uint32_t _nof_ports); channel(const args_t& channel_args, uint32_t _nof_ports);
~channel(); ~channel();
void set_logger(log_filter* _log_h);
void set_srate(uint32_t srate); void set_srate(uint32_t srate);
void run(cf_t* in[SRSLTE_MAX_PORTS], cf_t* out[SRSLTE_MAX_PORTS], uint32_t len, const srslte_timestamp_t& t); void run(cf_t* in[SRSLTE_MAX_PORTS], cf_t* out[SRSLTE_MAX_PORTS], uint32_t len, const srslte_timestamp_t& t);
private: private:
srslte_channel_fading_t* fading[SRSLTE_MAX_PORTS] = {}; srslte_channel_fading_t* fading[SRSLTE_MAX_PORTS] = {};
srslte_channel_delay_t* delay[SRSLTE_MAX_PORTS] = {}; srslte_channel_delay_t* delay[SRSLTE_MAX_PORTS] = {};
srslte_channel_hst_t* hst = nullptr; // HST has no buffers / no multiple instance is required
srslte_channel_rlf_t* rlf = nullptr; // RLF has no buffers / no multiple instance is required srslte_channel_rlf_t* rlf = nullptr; // RLF has no buffers / no multiple instance is required
cf_t* buffer_in = nullptr; cf_t* buffer_in = nullptr;
cf_t* buffer_out = nullptr; cf_t* buffer_out = nullptr;
log_filter* log_h = nullptr;
uint32_t nof_ports = 0; uint32_t nof_ports = 0;
uint32_t current_srate = 0; uint32_t current_srate = 0;
args_t args = {}; args_t args = {};

@ -22,16 +22,17 @@
#ifndef SRSLTE_DELAY_H #ifndef SRSLTE_DELAY_H
#define SRSLTE_DELAY_H #define SRSLTE_DELAY_H
#include <srslte/config.h> #include <srslte/srslte.h>
#include <srslte/phy/common/timestamp.h>
#include <srslte/phy/utils/ringbuffer.h>
typedef struct { typedef struct {
float delay_min_us; float delay_min_us;
float delay_max_us; float delay_max_us;
uint32_t period_s; float period_s;
float init_time_s;
uint32_t srate_max_hz; uint32_t srate_max_hz;
uint32_t srate_hz; uint32_t srate_hz;
float delay_us;
float delay_nsamples;
srslte_ringbuffer_t rb; srslte_ringbuffer_t rb;
cf_t* zero_buffer; cf_t* zero_buffer;
@ -41,8 +42,12 @@ typedef struct {
extern "C" { extern "C" {
#endif #endif
SRSLTE_API int srslte_channel_delay_init( SRSLTE_API int srslte_channel_delay_init(srslte_channel_delay_t* q,
srslte_channel_delay_t* q, float delay_min_ns, float delay_max_ns, uint32_t period_s, uint32_t srate_max_hz); float delay_min_us,
float delay_max_us,
float period_s,
float init_time_s,
uint32_t srate_max_hz);
SRSLTE_API void srslte_channel_delay_update_srate(srslte_channel_delay_t* q, uint32_t srate_hz); SRSLTE_API void srslte_channel_delay_update_srate(srslte_channel_delay_t* q, uint32_t srate_hz);

@ -22,8 +22,8 @@
#ifndef SRSLTE_FADING_H #ifndef SRSLTE_FADING_H
#define SRSLTE_FADING_H #define SRSLTE_FADING_H
#include "srslte/phy/dft/dft.h"
#include <inttypes.h> #include <inttypes.h>
#include <srslte/srslte.h>
#define SRSLTE_CHANNEL_FADING_MAXTAPS 9 #define SRSLTE_CHANNEL_FADING_MAXTAPS 9

@ -0,0 +1,59 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* 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/.
*
*/
#ifndef SRSLTE_HST_H_
#define SRSLTE_HST_H_
#include <srslte/srslte.h>
typedef struct {
// System parameters
uint32_t srate_hz; // Sampling rate
// Model Parameters
float fd_hz; // Maximum Doppler Frequency
float ds_m; // eNb distance [m]
float dmin_m; // eNb Rail-track distance [m]
float period_s; // 2 * Ds / speed [s]
float init_time_s; // Time offset [s]
// State
float fs_hz; // Last doppler dispersion [Hz]
} srslte_channel_hst_t;
#ifdef __cplusplus
extern "C" {
#endif
SRSLTE_API int srslte_channel_hst_init(srslte_channel_hst_t* q, float fd_hz, float period_d, float init_time_s);
SRSLTE_API void srslte_channel_hst_update_srate(srslte_channel_hst_t* q, uint32_t srate);
SRSLTE_API void
srslte_channel_hst_execute(srslte_channel_hst_t* q, cf_t* in, cf_t* out, uint32_t len, const srslte_timestamp_t* ts);
SRSLTE_API void srslte_channel_hst_free(srslte_channel_hst_t* q);
#ifdef __cplusplus
}
#endif
#endif // SRSLTE_HST_H_

@ -22,8 +22,7 @@
#ifndef SRSLTE_RLF_H #ifndef SRSLTE_RLF_H
#define SRSLTE_RLF_H #define SRSLTE_RLF_H
#include <srslte/config.h> #include <srslte/srslte.h>
#include <srslte/phy/common/timestamp.h>
typedef struct { typedef struct {
uint32_t t_on_ms; uint32_t t_on_ms;

@ -258,6 +258,9 @@ typedef enum {
SRSLTE_DCI_FORMAT2B, SRSLTE_DCI_FORMAT2B,
// SRSLTE_DCI_FORMAT3, // SRSLTE_DCI_FORMAT3,
// SRSLTE_DCI_FORMAT3A, // SRSLTE_DCI_FORMAT3A,
SRSLTE_DCI_FORMATN0,
SRSLTE_DCI_FORMATN1,
SRSLTE_DCI_FORMATN2,
SRSLTE_DCI_NOF_FORMATS SRSLTE_DCI_NOF_FORMATS
} srslte_dci_format_t; } srslte_dci_format_t;
@ -283,6 +286,43 @@ enum band_geographical_area {
SRSLTE_BAND_GEO_AREA_NA SRSLTE_BAND_GEO_AREA_NA
}; };
// NB-IoT specific structs
typedef enum {
SRSLTE_NBIOT_MODE_INBAND_SAME_PCI = 0,
SRSLTE_NBIOT_MODE_INBAND_DIFFERENT_PCI,
SRSLTE_NBIOT_MODE_GUARDBAND,
SRSLTE_NBIOT_MODE_STANDALONE,
SRSLTE_NBIOT_MODE_N_ITEMS,
} srslte_nbiot_mode_t;
typedef struct SRSLTE_API {
srslte_cell_t base; // the umbrella or super cell
uint32_t nbiot_prb; // the index of the NB-IoT PRB within the cell
uint32_t n_id_ncell;
uint32_t nof_ports; // The number of antenna ports for NB-IoT
bool is_r14; // Whether the cell is a R14 cell
srslte_nbiot_mode_t mode;
} srslte_nbiot_cell_t;
#define SRSLTE_NBIOT_MAX_PORTS 2
#define SRSLTE_NBIOT_MAX_CODEWORDS SRSLTE_MAX_CODEWORDS
#define SRSLTE_SF_LEN_PRB_NBIOT (SRSLTE_SF_LEN_PRB(1))
#define SRSLTE_SF_LEN_RE_NBIOT (SRSLTE_SF_LEN_RE(1, SRSLTE_CP_NORM))
#define SRSLTE_NBIOT_FFT_SIZE 128
#define SRSLTE_NBIOT_FREQ_SHIFT_FACTOR ((float)-0.5)
#define SRSLTE_NBIOT_NUM_RX_ANTENNAS 1
#define SRSLTE_NBIOT_MAX_PRB 1
#define SRSLTE_NBIOT_DEFAULT_NUM_PRB_BASECELL 1
#define SRSLTE_NBIOT_DEFAULT_PRB_OFFSET 0
#define SRSLTE_DEFAULT_MAX_FRAMES_NPBCH 500
#define SRSLTE_DEFAULT_MAX_FRAMES_NPSS 20
#define SRSLTE_DEFAULT_NOF_VALID_NPSS_FRAMES 20
SRSLTE_API bool srslte_cell_isvalid(srslte_cell_t *cell); SRSLTE_API bool srslte_cell_isvalid(srslte_cell_t *cell);
SRSLTE_API void srslte_cell_fprint(FILE *stream, SRSLTE_API void srslte_cell_fprint(FILE *stream,
@ -386,4 +426,10 @@ SRSLTE_API uint32_t srslte_tti_interval(uint32_t tti1, uint32_t tti2);
SRSLTE_API uint32_t srslte_print_check(char* s, size_t max_len, uint32_t cur_len, const char* format, ...); SRSLTE_API uint32_t srslte_print_check(char* s, size_t max_len, uint32_t cur_len, const char* format, ...);
SRSLTE_API bool srslte_nbiot_cell_isvalid(srslte_nbiot_cell_t* cell);
SRSLTE_API bool srslte_nbiot_portid_isvalid(uint32_t port_id);
SRSLTE_API float srslte_band_fu_nbiot(uint32_t ul_earfcn, const float m_ul);
SRSLTE_API char* srslte_nbiot_mode_string(srslte_nbiot_mode_t mode);
#endif // SRSLTE_PHY_COMMON_H #endif // SRSLTE_PHY_COMMON_H

@ -33,6 +33,7 @@
#define SRSLTE_FILESINK_H #define SRSLTE_FILESINK_H
#include <stdint.h> #include <stdint.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include "srslte/config.h" #include "srslte/config.h"

@ -67,6 +67,8 @@ SRSLTE_API int srslte_netsource_read(srslte_netsource_t *q,
void *buffer, void *buffer,
int nof_bytes); int nof_bytes);
SRSLTE_API int srslte_netsource_write(srslte_netsource_t* q, void* buffer, int nbytes);
SRSLTE_API int srslte_netsource_set_timeout(srslte_netsource_t *q, SRSLTE_API int srslte_netsource_set_timeout(srslte_netsource_t *q,
uint32_t microseconds); uint32_t microseconds);

@ -52,6 +52,7 @@
typedef struct { typedef struct {
bool multiple_csi_request_enabled; bool multiple_csi_request_enabled;
bool cif_enabled; bool cif_enabled;
bool cif_present;
bool srs_request_enabled; bool srs_request_enabled;
bool ra_format_enabled; bool ra_format_enabled;
} srslte_dci_cfg_t; } srslte_dci_cfg_t;
@ -160,8 +161,9 @@ typedef struct SRSLTE_API {
// Release 10 // Release 10
uint32_t cif; uint32_t cif;
bool cif_present; bool cif_present;
uint8_t multiple_csi_request;
bool multiple_csi_request_present; bool multiple_csi_request_present;
uint32_t srs_request; bool srs_request;
bool srs_request_present; bool srs_request_present;
srslte_ra_type_t ra_type; srslte_ra_type_t ra_type;
bool ra_type_present; bool ra_type_present;

@ -60,6 +60,7 @@ typedef struct SRSLTE_API {
float rs_power; float rs_power;
bool power_scale; bool power_scale;
bool csi_enable; bool csi_enable;
bool use_tbs_index_alt;
union { union {
srslte_softbuffer_tx_t* tx[SRSLTE_MAX_CODEWORDS]; srslte_softbuffer_tx_t* tx[SRSLTE_MAX_CODEWORDS];

@ -62,9 +62,8 @@ typedef struct SRSLTE_API {
uint32_t n_pucch_2; uint32_t n_pucch_2;
uint32_t n_pucch_sr; uint32_t n_pucch_sr;
bool simul_cqi_ack; bool simul_cqi_ack;
bool tdd_ack_bundle; // if false, multiplex bool tdd_ack_multiplex; // if false, bundle
bool sps_enabled; bool sps_enabled;
uint32_t tpc_for_pucch;
// Release 10 CA specific // Release 10 CA specific
srslte_ack_nack_feedback_mode_t ack_nack_feedback_mode; srslte_ack_nack_feedback_mode_t ack_nack_feedback_mode;

@ -127,6 +127,10 @@ SRSLTE_API int srslte_uci_decode_ack_ri(srslte_pusch_cfg_t* cfg,
uint32_t nof_bits, uint32_t nof_bits,
bool is_ri); bool is_ri);
SRSLTE_API uint32_t srslte_uci_cfg_total_ack(srslte_uci_cfg_t* uci_cfg);
SRSLTE_API void srslte_uci_data_reset(srslte_uci_data_t* uci_data);
SRSLTE_API int srslte_uci_data_info(srslte_uci_cfg_t* uci_cfg, SRSLTE_API int srslte_uci_data_info(srslte_uci_cfg_t* uci_cfg,
srslte_uci_value_t* uci_data, srslte_uci_value_t* uci_data,
char* str, char* str,

@ -39,12 +39,13 @@ typedef struct SRSLTE_API {
uint32_t N_bundle; uint32_t N_bundle;
uint32_t tdd_ack_M; uint32_t tdd_ack_M;
uint32_t tdd_ack_m; uint32_t tdd_ack_m;
bool tdd_is_bundling; bool tdd_is_multiplex;
bool has_scell_ack; uint32_t tpc_for_pucch;
uint32_t grant_cc_idx;
} srslte_uci_cfg_ack_t; } srslte_uci_cfg_ack_t;
typedef struct SRSLTE_API { typedef struct SRSLTE_API {
srslte_uci_cfg_ack_t ack; srslte_uci_cfg_ack_t ack[SRSLTE_MAX_CARRIERS];
srslte_cqi_cfg_t cqi; srslte_cqi_cfg_t cqi;
bool is_scheduling_request_tti; bool is_scheduling_request_tti;
} srslte_uci_cfg_t; } srslte_uci_cfg_t;

@ -94,15 +94,7 @@ SRSLTE_API bool srslte_rf_has_rssi(srslte_rf_t *h);
SRSLTE_API float srslte_rf_get_rssi(srslte_rf_t* h); SRSLTE_API float srslte_rf_get_rssi(srslte_rf_t* h);
SRSLTE_API bool srslte_rf_rx_wait_lo_locked(srslte_rf_t *h); SRSLTE_API double srslte_rf_set_rx_srate(srslte_rf_t* h, double freq);
SRSLTE_API void srslte_rf_set_master_clock_rate(srslte_rf_t *h,
double rate);
SRSLTE_API bool srslte_rf_is_master_clock_dynamic(srslte_rf_t *h);
SRSLTE_API double srslte_rf_set_rx_srate(srslte_rf_t *h,
double freq);
SRSLTE_API double srslte_rf_set_rx_gain(srslte_rf_t *h, SRSLTE_API double srslte_rf_set_rx_gain(srslte_rf_t *h,
double gain); double gain);

@ -0,0 +1,123 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* 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: npss.h
*
* Description: Narrowband Primary synchronization signal (NPSS) generation and detection.
*
* The srslte_npss_synch_t object provides functions for fast
* computation of the crosscorrelation between the NPSS and received
* signal and CFO estimation. Also, the function srslte_npss_synch_tperiodic()
* is designed to be called periodically every subframe, taking
* care of the correct data alignment with respect to the NPSS sequence.
*
* The object is designed to work with signals sampled at ?.? Mhz
* centered at the carrier frequency. Thus, downsampling is required
* if the signal is sampled at higher frequencies.
*
* Reference: 3GPP TS 36.211 version 13.2.0 Release 13 Sec. 10.x.x
*****************************************************************************/
#ifndef SRSLTE_NPSS_H
#define SRSLTE_NPSS_H
#include <stdbool.h>
#include <stdint.h>
#include "srslte/config.h"
#include "srslte/phy/common/phy_common.h"
#include "srslte/phy/utils/convolution.h"
#define CONVOLUTION_FFT
#define SRSLTE_NPSS_RETURN_PSR
#define SRSLTE_NPSS_LEN 11
#define SRSLTE_NPSS_NUM_OFDM_SYMS 11
#define SRSLTE_NPSS_TOT_LEN (SRSLTE_NPSS_LEN * SRSLTE_NPSS_NUM_OFDM_SYMS)
#define SRSLTE_NPSS_CORR_FILTER_LEN \
((SRSLTE_NPSS_NUM_OFDM_SYMS * SRSLTE_NBIOT_FFT_SIZE) + \
(SRSLTE_NPSS_NUM_OFDM_SYMS - 1) * SRSLTE_CP_LEN_NORM(1, SRSLTE_NBIOT_FFT_SIZE) + \
SRSLTE_CP_LEN_NORM(0, SRSLTE_NBIOT_FFT_SIZE))
// The below value corresponds to the time-domain representation of the first
// three OFDM-symbols plus cyclic prefix that are not transmitted in the sub-frame
// carrying the NPSS
#define SRSLTE_NPSS_CORR_OFFSET (SRSLTE_SF_LEN(SRSLTE_NBIOT_FFT_SIZE) - SRSLTE_NPSS_CORR_FILTER_LEN)
// CFO estimation based on the NPSS is done using the second slot of the sub-frame
#define SRSLTE_NPSS_CFO_OFFSET (SRSLTE_SF_LEN(SRSLTE_NBIOT_FFT_SIZE) / 2 - SRSLTE_NPSS_CORR_OFFSET)
#define SRSLTE_NPSS_CFO_NUM_SYMS 6 // number of symbols for CFO estimation
#define SRSLTE_NPSS_CFO_NUM_SAMPS \
((SRSLTE_NPSS_CFO_NUM_SYMS * SRSLTE_NBIOT_FFT_SIZE) + \
(SRSLTE_NPSS_CFO_NUM_SYMS - 1) * SRSLTE_CP_LEN_NORM(1, SRSLTE_NBIOT_FFT_SIZE) + \
SRSLTE_CP_LEN_NORM(0, SRSLTE_NBIOT_FFT_SIZE)) // resulting number of samples
// NPSS processing options
#define SRSLTE_NPSS_ACCUMULATE_ABS // If enabled, accumulates the correlation absolute value on consecutive calls to
// srslte_pss_synch_find_pss
#define SRSLTE_NPSS_ABS_SQUARE // If enabled, compute abs square, otherwise computes absolute value only
#define SRSLTE_NPSS_RETURN_PSR // If enabled returns peak to side-lobe ratio, otherwise returns absolute peak value
/* Low-level API */
typedef struct SRSLTE_API {
#ifdef CONVOLUTION_FFT
srslte_conv_fft_cc_t conv_fft;
#endif
uint32_t frame_size, max_frame_size;
uint32_t fft_size, max_fft_size;
cf_t* npss_signal_time;
cf_t* tmp_input;
cf_t* conv_output;
float* conv_output_abs;
float ema_alpha;
float* conv_output_avg;
float peak_value;
} srslte_npss_synch_t;
// Basic functionality
SRSLTE_API int srslte_npss_synch_init(srslte_npss_synch_t* q, uint32_t frame_size, uint32_t fft_size);
SRSLTE_API void srslte_npss_synch_reset(srslte_npss_synch_t* q);
SRSLTE_API int srslte_npss_synch_resize(srslte_npss_synch_t* q, uint32_t frame_size, uint32_t fft_size);
SRSLTE_API void srslte_npss_synch_set_ema_alpha(srslte_npss_synch_t* q, float alpha);
SRSLTE_API void srslte_npss_synch_free(srslte_npss_synch_t* q);
SRSLTE_API int srslte_npss_sync_find(srslte_npss_synch_t* q, cf_t* input, float* corr_peak_value);
// Internal functions
SRSLTE_API int srslte_npss_corr_init(cf_t* npss_signal_time, uint32_t fft_size, uint32_t frame_size);
SRSLTE_API int srslte_npss_generate(cf_t* signal);
SRSLTE_API void srslte_npss_put_subframe(
srslte_npss_synch_t* q, cf_t* npss_signal, cf_t* sf, const uint32_t nof_prb, const uint32_t nbiot_prb_offset);
#endif // SRSLTE_NPSS_H

@ -0,0 +1,116 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* 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: nsss.h
*
* Description: Narrowband secondary synchronization signal (NSSS)
* generation and detection.
*
*
* Reference: 3GPP TS 36.211 version 13.2.0 Release 13 Sec. 10.2.7.2
*****************************************************************************/
#ifndef SRSLTE_NSSS_H
#define SRSLTE_NSSS_H
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "srslte/config.h"
#include "srslte/phy/common/phy_common.h"
#include "srslte/phy/dft/dft.h"
#include "srslte/phy/utils/convolution.h"
#define SRSLTE_NSSS_NSYMB 11
#define SRSLTE_NSSS_NSC 12
#define SRSLTE_NSSS_LEN (SRSLTE_NSSS_NSYMB * SRSLTE_NSSS_NSC)
#define SRSLTE_NSSS_NUM_SEQ 4
#define SRSLTE_NSSS_TOT_LEN (SRSLTE_NSSS_NUM_SEQ * SRSLTE_NSSS_LEN)
#define SRSLTE_NSSS_CORR_FILTER_LEN 1508
#define SRSLTE_NSSS_CORR_OFFSET 412
#define SRSLTE_NUM_PCI 504
#define SRSLTE_NSSS_PERIOD 2
#define SRSLTE_NSSS_NUM_SF_DETECT (SRSLTE_NSSS_PERIOD)
// b_q_m table from 3GPP TS 36.211 v13.2.0 table 10.2.7.2.1-1
static const int b_q_m[SRSLTE_NSSS_NUM_SEQ][128] = {
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1,
1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1,
1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1,
1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1},
{1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1,
-1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1,
-1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1,
-1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1,
1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1},
{1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1,
-1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1,
-1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1,
1, -1, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1,
-1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1}};
/* Low-level API */
typedef struct SRSLTE_API {
uint32_t input_size;
uint32_t subframe_sz;
uint32_t fft_size, max_fft_size;
srslte_conv_fft_cc_t conv_fft;
cf_t* nsss_signal_time[SRSLTE_NUM_PCI];
cf_t* tmp_input;
cf_t* conv_output;
float* conv_output_abs;
float peak_values[SRSLTE_NUM_PCI];
float corr_peak_threshold;
} srslte_nsss_synch_t;
SRSLTE_API int srslte_nsss_synch_init(srslte_nsss_synch_t* q, uint32_t input_size, uint32_t fft_size);
SRSLTE_API void srslte_nsss_synch_free(srslte_nsss_synch_t* q);
SRSLTE_API int srslte_nsss_synch_resize(srslte_nsss_synch_t* q, uint32_t fft_size);
SRSLTE_API int srslte_nsss_sync_find(
srslte_nsss_synch_t* q, cf_t* input, float* corr_peak_value, uint32_t* cell_id, uint32_t* sfn_partial);
void srslte_nsss_sync_find_pci(srslte_nsss_synch_t* q, cf_t* input, uint32_t cell_id);
SRSLTE_API int srslte_nsss_corr_init(srslte_nsss_synch_t* q);
SRSLTE_API void srslte_nsss_generate(cf_t* signal, uint32_t cell_id);
SRSLTE_API void srslte_nsss_put_subframe(srslte_nsss_synch_t* q,
cf_t* nsss,
cf_t* subframe,
const int nf,
const uint32_t nof_prb,
const uint32_t nbiot_prb_offset);
#endif // SRSLTE_NSSS_H

@ -0,0 +1,58 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* 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/.
*
*/
#ifndef SRSLTE_REFSIGNAL_DL_SYNC_H_
#define SRSLTE_REFSIGNAL_DL_SYNC_H_
#include <srslte/phy/ch_estimation/refsignal_dl.h>
#include <srslte/phy/dft/ofdm.h>
#include <srslte/phy/utils/convolution.h>
typedef struct {
srslte_refsignal_t refsignal;
srslte_ofdm_t ifft;
cf_t* ifft_buffer_in;
cf_t* ifft_buffer_out;
cf_t* sequences[SRSLTE_NOF_SF_X_FRAME];
cf_t* correlation;
srslte_conv_fft_cc_t conv_fft_cc;
// Results
bool found;
float rsrp_dBfs;
float rssi_dBfs;
float rsrq_dB;
float cfo_Hz;
uint32_t peak_index;
} srslte_refsignal_dl_sync_t;
SRSLTE_API int srslte_refsignal_dl_sync_init(srslte_refsignal_dl_sync_t* q);
SRSLTE_API int srslte_refsignal_dl_sync_set_cell(srslte_refsignal_dl_sync_t* q, srslte_cell_t cell);
SRSLTE_API void srslte_refsignal_dl_sync_free(srslte_refsignal_dl_sync_t* q);
SRSLTE_API void srslte_refsignal_dl_sync_run(srslte_refsignal_dl_sync_t* q, cf_t* buffer, uint32_t nsamples);
SRSLTE_API void srslte_refsignal_dl_sync_measure_sf(
srslte_refsignal_dl_sync_t* q, cf_t* buffer, uint32_t sf_idx, float* rsrp, float* rssi, float* cfo);
#endif // SRSLTE_REFSIGNAL_DL_SYNC_H_

@ -131,9 +131,7 @@ SRSLTE_API int srslte_sss_m0m1_diff(srslte_sss_t *q,
SRSLTE_API uint32_t srslte_sss_subframe(uint32_t m0, SRSLTE_API uint32_t srslte_sss_subframe(uint32_t m0,
uint32_t m1); uint32_t m1);
SRSLTE_API int srslte_sss_N_id_1(srslte_sss_t *q, SRSLTE_API int srslte_sss_N_id_1(srslte_sss_t* q, uint32_t m0, uint32_t m1, float corr);
uint32_t m0,
uint32_t m1);
SRSLTE_API int srslte_sss_frame(srslte_sss_t *q, SRSLTE_API int srslte_sss_frame(srslte_sss_t *q,
cf_t *input, cf_t *input,

@ -118,6 +118,7 @@ typedef struct SRSLTE_API {
bool sss_generated; bool sss_generated;
bool sss_detected; bool sss_detected;
bool sss_available; bool sss_available;
float sss_corr;
srslte_dft_plan_t idftp_sss; srslte_dft_plan_t idftp_sss;
cf_t sss_recv[SRSLTE_SYMBOL_SZ_MAX]; cf_t sss_recv[SRSLTE_SYMBOL_SZ_MAX];
cf_t sss_signal[2][SRSLTE_SYMBOL_SZ_MAX]; cf_t sss_signal[2][SRSLTE_SYMBOL_SZ_MAX];
@ -242,6 +243,8 @@ SRSLTE_API srslte_pss_t* srslte_sync_get_cur_pss_obj(srslte_sync_t *q);
SRSLTE_API bool srslte_sync_sss_detected(srslte_sync_t *q); SRSLTE_API bool srslte_sync_sss_detected(srslte_sync_t *q);
SRSLTE_API float srslte_sync_sss_correlation_peak(srslte_sync_t* q);
SRSLTE_API bool srslte_sync_sss_available(srslte_sync_t* q); SRSLTE_API bool srslte_sync_sss_available(srslte_sync_t* q);
/* Enables/Disables CP detection */ /* Enables/Disables CP detection */

@ -0,0 +1,125 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* 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: sync_nbiot.h
*
* Description: Time and frequency synchronization using the NPSS and NSSS signals.
*
* The object is designed to work with signals sampled at 1.92 Mhz
* centered at the carrier frequency. Thus, downsampling is required
* if the signal is sampled at higher frequencies.
*
* Correlation peak is detected comparing the maximum at the output
* of the correlator with a threshold.
*
* Reference: 3GPP TS 36.211 version 13.2.0 Release 13
*****************************************************************************/
#ifndef SRSLTE_SYNC_NBIOT_H
#define SRSLTE_SYNC_NBIOT_H
#include <math.h>
#include <stdbool.h>
#include "srslte/config.h"
#include "srslte/phy/sync/npss.h"
#include "srslte/phy/sync/nsss.h"
#include "srslte/phy/sync/sync.h"
#include "srslte/phy/ue/ue_sync.h"
#define MAX_NUM_CFO_CANDITATES 50
typedef struct SRSLTE_API {
srslte_npss_synch_t npss;
srslte_nsss_synch_t nsss;
srslte_cp_synch_t cp_synch;
uint32_t n_id_ncell;
float threshold;
float peak_value;
uint32_t fft_size;
uint32_t frame_size;
uint32_t max_frame_size;
uint32_t max_offset;
bool enable_cfo_estimation;
bool enable_cfo_cand_test;
float cfo_cand[MAX_NUM_CFO_CANDITATES];
int cfo_num_cand;
int cfo_cand_idx;
float mean_cfo;
float current_cfo_tol;
cf_t* shift_buffer;
cf_t* cfo_output;
int cfo_i;
bool find_cfo_i;
bool find_cfo_i_initiated;
float cfo_ema_alpha;
uint32_t nof_symbols;
uint32_t cp_len;
srslte_cfo_t cfocorr;
srslte_cp_t cp;
} srslte_sync_nbiot_t;
SRSLTE_API int
srslte_sync_nbiot_init(srslte_sync_nbiot_t* q, uint32_t frame_size, uint32_t max_offset, uint32_t fft_size);
SRSLTE_API void srslte_sync_nbiot_free(srslte_sync_nbiot_t* q);
SRSLTE_API int
srslte_sync_nbiot_resize(srslte_sync_nbiot_t* q, uint32_t frame_size, uint32_t max_offset, uint32_t fft_size);
SRSLTE_API srslte_sync_find_ret_t srslte_sync_nbiot_find(srslte_sync_nbiot_t* q,
cf_t* input,
uint32_t find_offset,
uint32_t* peak_position);
SRSLTE_API float cfo_estimate_nbiot(srslte_sync_nbiot_t* q, cf_t* input);
SRSLTE_API void srslte_sync_nbiot_set_threshold(srslte_sync_nbiot_t* q, float threshold);
SRSLTE_API void srslte_sync_nbiot_set_cfo_enable(srslte_sync_nbiot_t* q, bool enable);
SRSLTE_API void srslte_sync_nbiot_set_cfo_cand_test_enable(srslte_sync_nbiot_t* q, bool enable);
SRSLTE_API int srslte_sync_nbiot_set_cfo_cand(srslte_sync_nbiot_t* q, const float* cand, const int num);
SRSLTE_API void srslte_sync_nbiot_set_cfo_tol(srslte_sync_nbiot_t* q, float tol);
SRSLTE_API void srslte_sync_nbiot_set_cfo_ema_alpha(srslte_sync_nbiot_t* q, float alpha);
SRSLTE_API void srslte_sync_nbiot_set_npss_ema_alpha(srslte_sync_nbiot_t* q, float alpha);
SRSLTE_API int srslte_sync_nbiot_find_cell_id(srslte_sync_nbiot_t* q, cf_t* input);
SRSLTE_API int srslte_sync_nbiot_get_cell_id(srslte_sync_nbiot_t* q);
SRSLTE_API float srslte_sync_nbiot_get_cfo(srslte_sync_nbiot_t* q);
SRSLTE_API void srslte_sync_nbiot_set_cfo(srslte_sync_nbiot_t* q, float cfo);
SRSLTE_API bool srslte_sync_nbiot_nsss_detected(srslte_sync_nbiot_t* q);
SRSLTE_API float srslte_sync_nbiot_get_peak_value(srslte_sync_nbiot_t* q);
SRSLTE_API void srslte_sync_nbiot_reset(srslte_sync_nbiot_t* q);
#endif // SRSLTE_SYNC_NBIOT_H

@ -112,21 +112,22 @@ typedef struct SRSLTE_API {
typedef struct SRSLTE_API { typedef struct SRSLTE_API {
srslte_cqi_report_cfg_t cqi_report; srslte_cqi_report_cfg_t cqi_report;
srslte_pdsch_cfg_t pdsch; srslte_pdsch_cfg_t pdsch;
srslte_dci_cfg_t dci;
srslte_tm_t tm; srslte_tm_t tm;
} srslte_dl_cfg_t; } srslte_dl_cfg_t;
typedef struct SRSLTE_API { typedef struct SRSLTE_API {
srslte_dl_cfg_t cfg; srslte_dl_cfg_t cfg;
srslte_chest_dl_cfg_t chest_cfg; srslte_chest_dl_cfg_t chest_cfg;
srslte_dci_cfg_t dci_cfg;
uint32_t last_ri; uint32_t last_ri;
float snr_to_cqi_offset; float snr_to_cqi_offset;
bool pdsch_use_tbs_index_alt;
} srslte_ue_dl_cfg_t; } srslte_ue_dl_cfg_t;
typedef struct { typedef struct {
uint32_t v_dai_dl; uint32_t v_dai_dl;
uint32_t n_cce; uint32_t n_cce;
uint32_t grant_cc_idx;
uint32_t tpc_for_pucch;
} srslte_pdsch_ack_resource_t; } srslte_pdsch_ack_resource_t;
typedef struct { typedef struct {
@ -149,7 +150,7 @@ typedef struct {
srslte_ack_nack_feedback_mode_t ack_nack_feedback_mode; srslte_ack_nack_feedback_mode_t ack_nack_feedback_mode;
bool is_grant_available; bool is_grant_available;
bool is_pusch_available; bool is_pusch_available;
bool tdd_ack_bundle; bool tdd_ack_multiplex;
bool simul_cqi_ack; bool simul_cqi_ack;
} srslte_pdsch_ack_t; } srslte_pdsch_ack_t;
@ -182,13 +183,13 @@ SRSLTE_API int srslte_ue_dl_decode_fft_estimate_noguru(srslte_ue_dl_t* q,
/* Finds UL/DL DCI in the signal processed in a previous call to decode_fft_estimate() */ /* Finds UL/DL DCI in the signal processed in a previous call to decode_fft_estimate() */
SRSLTE_API int srslte_ue_dl_find_ul_dci(srslte_ue_dl_t* q, SRSLTE_API int srslte_ue_dl_find_ul_dci(srslte_ue_dl_t* q,
srslte_dl_sf_cfg_t* sf, srslte_dl_sf_cfg_t* sf,
srslte_ue_dl_cfg_t* cfg, srslte_ue_dl_cfg_t* dl_cfg,
uint16_t rnti, uint16_t rnti,
srslte_dci_ul_t dci_msg[SRSLTE_MAX_DCI_MSG]); srslte_dci_ul_t dci_msg[SRSLTE_MAX_DCI_MSG]);
SRSLTE_API int srslte_ue_dl_find_dl_dci(srslte_ue_dl_t* q, SRSLTE_API int srslte_ue_dl_find_dl_dci(srslte_ue_dl_t* q,
srslte_dl_sf_cfg_t* sf, srslte_dl_sf_cfg_t* sf,
srslte_ue_dl_cfg_t* cfg, srslte_ue_dl_cfg_t* dl_cfg,
uint16_t rnti, uint16_t rnti,
srslte_dci_dl_t dci_msg[SRSLTE_MAX_DCI_MSG]); srslte_dci_dl_t dci_msg[SRSLTE_MAX_DCI_MSG]);

@ -35,7 +35,8 @@ typedef struct {
int wpm; int wpm;
int rpm; int rpm;
pthread_mutex_t mutex; pthread_mutex_t mutex;
pthread_cond_t cvar; pthread_cond_t write_cvar;
pthread_cond_t read_cvar;
} srslte_ringbuffer_t; } srslte_ringbuffer_t;
#ifdef __cplusplus #ifdef __cplusplus
@ -54,6 +55,8 @@ SRSLTE_API int srslte_ringbuffer_space(srslte_ringbuffer_t *q);
SRSLTE_API int srslte_ringbuffer_write(srslte_ringbuffer_t* q, void* ptr, int nof_bytes); SRSLTE_API int srslte_ringbuffer_write(srslte_ringbuffer_t* q, void* ptr, int nof_bytes);
SRSLTE_API int srslte_ringbuffer_write_timed(srslte_ringbuffer_t* q, void* ptr, int nof_bytes, uint32_t timeout_ms);
SRSLTE_API int srslte_ringbuffer_read(srslte_ringbuffer_t* q, void* ptr, int nof_bytes); SRSLTE_API int srslte_ringbuffer_read(srslte_ringbuffer_t* q, void* ptr, int nof_bytes);
SRSLTE_API int srslte_ringbuffer_read_timed(srslte_ringbuffer_t* q, void* p, int nof_bytes, uint32_t timeout_ms); SRSLTE_API int srslte_ringbuffer_read_timed(srslte_ringbuffer_t* q, void* p, int nof_bytes, uint32_t timeout_ms);

@ -49,7 +49,6 @@ class radio {
burst_preamble_samples = 0; burst_preamble_samples = 0;
burst_preamble_time_rounded = 0; burst_preamble_time_rounded = 0;
master_clock_rate = 0;
cur_tx_srate = 0; cur_tx_srate = 0;
tx_adv_sec = 0; tx_adv_sec = 0;
tx_adv_nsamples = 0; tx_adv_nsamples = 0;
@ -92,6 +91,7 @@ class radio {
bool tx_single(cf_t* buffer, uint32_t nof_samples, srslte_timestamp_t tx_time); bool tx_single(cf_t* buffer, uint32_t nof_samples, srslte_timestamp_t tx_time);
bool tx(cf_t* buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t tx_time); bool tx(cf_t* buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t tx_time);
void tx_end(); void tx_end();
bool get_is_start_of_burst();
bool rx_now(cf_t* buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t* rxd_time); bool rx_now(cf_t* buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t* rxd_time);
bool rx_at(cf_t* buffer, uint32_t nof_samples, srslte_timestamp_t rx_time); bool rx_at(cf_t* buffer, uint32_t nof_samples, srslte_timestamp_t rx_time);
@ -99,7 +99,6 @@ class radio {
void set_rx_gain(float gain); void set_rx_gain(float gain);
void set_tx_rx_gain_offset(float offset); void set_tx_rx_gain_offset(float offset);
double set_rx_gain_th(float gain); double set_rx_gain_th(float gain);
void set_master_clock_rate(double rate);
void set_freq_offset(double freq); void set_freq_offset(double freq);
void set_tx_freq(uint32_t chan, double freq); void set_tx_freq(uint32_t chan, double freq);
@ -138,7 +137,6 @@ class radio {
uint32_t burst_preamble_samples; uint32_t burst_preamble_samples;
double burst_preamble_time_rounded; // preamble time rounded to sample time double burst_preamble_time_rounded; // preamble time rounded to sample time
cf_t* zeros; cf_t* zeros;
double master_clock_rate;
double cur_tx_srate; double cur_tx_srate;
double tx_adv_sec; // Transmission time advance to compensate for antenna->timestamp delay double tx_adv_sec; // Transmission time advance to compensate for antenna->timestamp delay

@ -57,6 +57,10 @@ public:
bool is_init() override { return radios.at(0)->is_init(); } bool is_init() override { return radios.at(0)->is_init(); }
void reset() override { return radios.at(0)->reset(); } void reset() override { return radios.at(0)->reset(); }
bool is_continuous_tx() override { return radios.at(0)->is_continuous_tx(); } bool is_continuous_tx() override { return radios.at(0)->is_continuous_tx(); }
bool get_is_start_of_burst(const uint32_t& radio_idx) override
{
return radios.at(radio_idx)->get_is_start_of_burst();
}
bool tx(const uint32_t& radio_idx, bool tx(const uint32_t& radio_idx,
cf_t* buffer[SRSLTE_MAX_PORTS], cf_t* buffer[SRSLTE_MAX_PORTS],
const uint32_t& nof_samples, const uint32_t& nof_samples,
@ -64,7 +68,13 @@ public:
{ {
return radios.at(radio_idx)->tx(buffer, nof_samples, tx_time); return radios.at(radio_idx)->tx(buffer, nof_samples, tx_time);
} }
void tx_end() override { return radios.at(0)->tx_end(); } void tx_end() override
{
// Send Tx exd to all radios
for (auto& r : radios) {
r->tx_end();
}
}
bool rx_now(const uint32_t& radio_idx, bool rx_now(const uint32_t& radio_idx,
cf_t* buffer[SRSLTE_MAX_PORTS], cf_t* buffer[SRSLTE_MAX_PORTS],

@ -114,12 +114,13 @@ extern "C" {
#include "srslte/phy/scrambling/scrambling.h" #include "srslte/phy/scrambling/scrambling.h"
#include "srslte/phy/sync/cfo.h"
#include "srslte/phy/sync/cp.h"
#include "srslte/phy/sync/pss.h" #include "srslte/phy/sync/pss.h"
#include "srslte/phy/sync/refsignal_dl_sync.h"
#include "srslte/phy/sync/sfo.h" #include "srslte/phy/sync/sfo.h"
#include "srslte/phy/sync/sss.h" #include "srslte/phy/sync/sss.h"
#include "srslte/phy/sync/sync.h" #include "srslte/phy/sync/sync.h"
#include "srslte/phy/sync/cfo.h"
#include "srslte/phy/sync/cp.h"
#ifdef __cplusplus #ifdef __cplusplus
} }

@ -22,17 +22,14 @@
#ifndef SRSLTE_PDCP_H #ifndef SRSLTE_PDCP_H
#define SRSLTE_PDCP_H #define SRSLTE_PDCP_H
#include "srslte/common/log.h"
#include "srslte/common/common.h" #include "srslte/common/common.h"
#include "srslte/common/log.h"
#include "srslte/interfaces/ue_interfaces.h" #include "srslte/interfaces/ue_interfaces.h"
#include "srslte/upper/pdcp_entity.h" #include "srslte/upper/pdcp_entity_lte.h"
namespace srslte { namespace srslte {
class pdcp class pdcp : public srsue::pdcp_interface_rlc, public srsue::pdcp_interface_rrc
:public srsue::pdcp_interface_gw
,public srsue::pdcp_interface_rlc
,public srsue::pdcp_interface_rrc
{ {
public: public:
pdcp(log* log_); pdcp(log* log_);
@ -49,8 +46,8 @@ public:
void reset(); void reset();
void write_sdu(uint32_t lcid, unique_byte_buffer_t sdu, bool blocking = true); void write_sdu(uint32_t lcid, unique_byte_buffer_t sdu, bool blocking = true);
void write_sdu_mch(uint32_t lcid, unique_byte_buffer_t sdu); void write_sdu_mch(uint32_t lcid, unique_byte_buffer_t sdu);
void add_bearer(uint32_t lcid, srslte_pdcp_config_t cnfg = srslte_pdcp_config_t()); void add_bearer(uint32_t lcid, pdcp_config_t cnfg);
void add_bearer_mrb(uint32_t lcid, srslte_pdcp_config_t cnfg = srslte_pdcp_config_t()); void add_bearer_mrb(uint32_t lcid, pdcp_config_t cnfg);
void del_bearer(uint32_t lcid); void del_bearer(uint32_t lcid);
void change_lcid(uint32_t old_lcid, uint32_t new_lcid); void change_lcid(uint32_t old_lcid, uint32_t new_lcid);
void config_security(uint32_t lcid, void config_security(uint32_t lcid,
@ -66,8 +63,6 @@ public:
INTEGRITY_ALGORITHM_ID_ENUM integ_algo); INTEGRITY_ALGORITHM_ID_ENUM integ_algo);
void enable_integrity(uint32_t lcid); void enable_integrity(uint32_t lcid);
void enable_encryption(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 // RLC interface
void write_pdu(uint32_t lcid, unique_byte_buffer_t sdu); void write_pdu(uint32_t lcid, unique_byte_buffer_t sdu);
@ -81,8 +76,8 @@ private:
srsue::rrc_interface_pdcp* rrc = nullptr; srsue::rrc_interface_pdcp* rrc = nullptr;
srsue::gw_interface_pdcp* gw = nullptr; srsue::gw_interface_pdcp* gw = nullptr;
typedef std::map<uint16_t, pdcp_entity_interface*> pdcp_map_t; typedef std::map<uint16_t, pdcp_entity_lte*> pdcp_map_t;
typedef std::pair<uint16_t, pdcp_entity_interface*> pdcp_map_pair_t; typedef std::pair<uint16_t, pdcp_entity_lte*> pdcp_map_pair_t;
log* pdcp_log = nullptr; log* pdcp_log = nullptr;
pdcp_map_t pdcp_array, pdcp_array_mrb; pdcp_map_t pdcp_array, pdcp_array_mrb;
@ -93,6 +88,4 @@ private:
}; };
} // namespace srslte } // namespace srslte
#endif // SRSLTE_PDCP_H #endif // SRSLTE_PDCP_H

@ -1,144 +0,0 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* 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/.
*
*/
#ifndef SRSLTE_PDCP_ENTITY_H
#define SRSLTE_PDCP_ENTITY_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"
#include "pdcp_interface.h"
namespace srslte {
/****************************************************************************
* Structs and Defines
* Ref: 3GPP TS 36.323 v10.1.0
***************************************************************************/
#define PDCP_CONTROL_MAC_I 0x00000000
#define PDCP_PDU_TYPE_PDCP_STATUS_REPORT 0x0
#define PDCP_PDU_TYPE_INTERSPERSED_ROHC_FEEDBACK_PACKET 0x1
typedef enum{
PDCP_D_C_CONTROL_PDU = 0,
PDCP_D_C_DATA_PDU,
PDCP_D_C_N_ITEMS,
}pdcp_d_c_t;
static const char pdcp_d_c_text[PDCP_D_C_N_ITEMS][20] = {"Control PDU",
"Data PDU"};
/****************************************************************************
* PDCP Entity interface
* Common interface for all PDCP entities
***************************************************************************/
class pdcp_entity : public pdcp_entity_interface
{
public:
pdcp_entity();
~pdcp_entity();
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_);
void reset();
void reestablish();
bool is_active();
// RRC interface
void write_sdu(unique_byte_buffer_t sdu, bool blocking);
void config_security(uint8_t *k_rrc_enc_,
uint8_t *k_rrc_int_,
uint8_t *k_up_enc_,
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(unique_byte_buffer_t pdu);
private:
byte_buffer_pool* pool = byte_buffer_pool::get_instance();
srslte::log* log = nullptr;
srsue::rlc_interface_pdcp* rlc = nullptr;
srsue::rrc_interface_pdcp* rrc = nullptr;
srsue::gw_interface_pdcp* gw = nullptr;
bool active = false;
uint32_t lcid = 0;
srslte_pdcp_config_t cfg = {};
uint8_t sn_len_bytes = 0;
bool do_integrity = false;
bool do_encryption = false;
uint32_t rx_count = 0;
uint32_t tx_count = 0;
uint8_t k_rrc_enc[32] = {};
uint8_t k_rrc_int[32] = {};
uint8_t k_up_enc[32] = {};
uint32_t rx_hfn = 0;
uint32_t next_pdcp_rx_sn = 0;
uint32_t reordering_window = 0;
uint32_t last_submitted_pdcp_rx_sn = 0;
uint32_t maximum_pdcp_sn = 0;
CIPHERING_ALGORITHM_ID_ENUM cipher_algo = CIPHERING_ALGORITHM_ID_EEA0;
INTEGRITY_ALGORITHM_ID_ENUM integ_algo = INTEGRITY_ALGORITHM_ID_EIA0;
pthread_mutex_t mutex;
void handle_um_drb_pdu(const srslte::unique_byte_buffer_t& pdu);
void handle_am_drb_pdu(const srslte::unique_byte_buffer_t& pdu);
void integrity_generate(uint8_t* msg, uint32_t msg_len, uint8_t* mac);
bool integrity_verify(uint8_t* msg, uint32_t count, uint32_t msg_len, uint8_t* mac);
void cipher_encrypt(uint8_t* msg, uint32_t msg_len, uint8_t* ct);
void cipher_decrypt(uint8_t* ct, uint32_t count, uint32_t ct_len, uint8_t* msg);
};
/****************************************************************************
* Pack/Unpack helper functions
* Ref: 3GPP TS 36.323 v10.1.0
***************************************************************************/
void pdcp_pack_control_pdu(uint32_t sn, byte_buffer_t *sdu);
void pdcp_unpack_control_pdu(byte_buffer_t *sdu, uint32_t *sn);
void pdcp_pack_data_pdu_short_sn(uint32_t sn, byte_buffer_t *sdu);
void pdcp_unpack_data_pdu_short_sn(byte_buffer_t *sdu, uint32_t *sn);
void pdcp_pack_data_pdu_long_sn(uint32_t sn, byte_buffer_t *sdu);
void pdcp_unpack_data_pdu_long_sn(byte_buffer_t *sdu, uint32_t *sn);
} // namespace srslte
#endif // SRSLTE_PDCP_ENTITY_H

@ -0,0 +1,133 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* 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/.
*
*/
#ifndef SRSLTE_PDCP_ENTITY_BASE_H
#define SRSLTE_PDCP_ENTITY_BASE_H
#include "srslte/common/buffer_pool.h"
#include "srslte/common/common.h"
#include "srslte/common/log.h"
#include "srslte/common/security.h"
#include "srslte/common/threads.h"
#include "srslte/interfaces/ue_interfaces.h"
#include <mutex>
namespace srslte {
/****************************************************************************
* Structs and Defines common to both LTE and NR
* Ref: 3GPP TS 36.323 v10.1.0 and TS 38.323 v15.2.0
***************************************************************************/
#define PDCP_PDU_TYPE_PDCP_STATUS_REPORT 0x0
#define PDCP_PDU_TYPE_INTERSPERSED_ROHC_FEEDBACK_PACKET 0x1
// Maximum supported PDCP SDU size is 9000 bytes.
// See TS 38.323 v15.2.0, section 4.3.1
#define PDCP_MAX_SDU_SIZE 9000
typedef enum {
PDCP_D_C_CONTROL_PDU = 0,
PDCP_D_C_DATA_PDU,
PDCP_D_C_N_ITEMS,
} pdcp_d_c_t;
static const char pdcp_d_c_text[PDCP_D_C_N_ITEMS][20] = {"Control PDU", "Data PDU"};
/****************************************************************************
* PDCP Entity interface
* Common interface for LTE and NR PDCP entities
***************************************************************************/
class pdcp_entity_base
{
public:
pdcp_entity_base();
virtual ~pdcp_entity_base();
virtual void reset() = 0;
virtual void reestablish() = 0;
bool is_active() { return active; }
bool is_srb() { return cfg.rb_type == PDCP_RB_IS_SRB; }
bool is_drb() { return cfg.rb_type == PDCP_RB_IS_DRB; }
// RRC interface
void enable_integrity() { do_integrity = true; }
void enable_encryption() { do_encryption = true; }
void config_security(uint8_t* k_rrc_enc_,
uint8_t* k_rrc_int_,
uint8_t* k_up_enc_,
uint8_t* k_up_int_, // NR Only, pass nullptr in LTE
CIPHERING_ALGORITHM_ID_ENUM cipher_algo_,
INTEGRITY_ALGORITHM_ID_ENUM integ_algo_);
// GW/SDAP/RRC interface
void write_sdu(unique_byte_buffer_t sdu, bool blocking);
// RLC interface
void write_pdu(unique_byte_buffer_t pdu);
// COUNT, HFN and SN helpers
uint32_t HFN(uint32_t count);
uint32_t SN(uint32_t count);
uint32_t COUNT(uint32_t hfn, uint32_t sn);
protected:
srslte::log* log = nullptr;
bool active = false;
uint32_t lcid = 0;
bool do_integrity = false;
bool do_encryption = false;
pdcp_config_t cfg = {1, PDCP_RB_IS_DRB, SECURITY_DIRECTION_DOWNLINK, SECURITY_DIRECTION_UPLINK, PDCP_SN_LEN_12};
std::mutex mutex;
uint8_t k_rrc_enc[32] = {};
uint8_t k_rrc_int[32] = {};
uint8_t k_up_enc[32] = {};
uint8_t k_up_int[32] = {};
CIPHERING_ALGORITHM_ID_ENUM cipher_algo = CIPHERING_ALGORITHM_ID_EEA0;
INTEGRITY_ALGORITHM_ID_ENUM integ_algo = INTEGRITY_ALGORITHM_ID_EIA0;
void integrity_generate(uint8_t* msg, uint32_t msg_len, uint32_t count, uint8_t* mac);
bool integrity_verify(uint8_t* msg, uint32_t msg_len, uint32_t count, uint8_t* mac);
void cipher_encrypt(uint8_t* msg, uint32_t msg_len, uint32_t count, uint8_t* ct);
void cipher_decrypt(uint8_t* ct, uint32_t ct_len, uint32_t count, uint8_t* msg);
};
inline uint32_t pdcp_entity_base::HFN(uint32_t count)
{
return (count >> cfg.sn_len);
}
inline uint32_t pdcp_entity_base::SN(uint32_t count)
{
return count & (0xFFFFFFFF >> (32 - cfg.sn_len));
}
inline uint32_t pdcp_entity_base::COUNT(uint32_t hfn, uint32_t sn)
{
return (hfn << cfg.sn_len) | sn;
}
} // namespace srslte
#endif // SRSLTE_PDCP_ENTITY_BASE_H

@ -0,0 +1,101 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* 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/.
*
*/
#ifndef SRSLTE_PDCP_ENTITY_LTE_H
#define SRSLTE_PDCP_ENTITY_LTE_H
#include "srslte/common/buffer_pool.h"
#include "srslte/common/common.h"
#include "srslte/common/log.h"
#include "srslte/common/security.h"
#include "srslte/common/threads.h"
#include "srslte/interfaces/ue_interfaces.h"
#include "srslte/upper/pdcp_entity_base.h"
namespace srslte {
/****************************************************************************
* Structs and Defines
* Ref: 3GPP TS 36.323 v10.1.0
***************************************************************************/
#define PDCP_CONTROL_MAC_I 0x00000000
/****************************************************************************
* LTE PDCP Entity
* Class for LTE PDCP entities
***************************************************************************/
class pdcp_entity_lte final : public pdcp_entity_base
{
public:
pdcp_entity_lte();
~pdcp_entity_lte();
void init(srsue::rlc_interface_pdcp* rlc_,
srsue::rrc_interface_pdcp* rrc_,
srsue::gw_interface_pdcp* gw_,
srslte::log* log_,
uint32_t lcid_,
pdcp_config_t cfg_);
void reset();
void reestablish();
// GW/RRC interface
void write_sdu(unique_byte_buffer_t sdu, bool blocking);
uint32_t get_dl_count();
uint32_t get_ul_count();
// RLC interface
void write_pdu(unique_byte_buffer_t pdu);
private:
srsue::rlc_interface_pdcp* rlc = nullptr;
srsue::rrc_interface_pdcp* rrc = nullptr;
srsue::gw_interface_pdcp* gw = nullptr;
uint32_t rx_count = 0;
uint32_t tx_count = 0;
uint32_t rx_hfn = 0;
uint32_t next_pdcp_rx_sn = 0;
uint32_t reordering_window = 0;
uint32_t last_submitted_pdcp_rx_sn = 0;
uint32_t maximum_pdcp_sn = 0;
void handle_um_drb_pdu(const srslte::unique_byte_buffer_t& pdu);
void handle_am_drb_pdu(const srslte::unique_byte_buffer_t& pdu);
};
/****************************************************************************
* Pack/Unpack helper functions
* Ref: 3GPP TS 36.323 v10.1.0
***************************************************************************/
void pdcp_pack_control_pdu(uint32_t sn, byte_buffer_t* sdu);
void pdcp_unpack_control_pdu(byte_buffer_t* sdu, uint32_t* sn);
void pdcp_pack_data_pdu_short_sn(uint32_t sn, byte_buffer_t* sdu);
void pdcp_unpack_data_pdu_short_sn(byte_buffer_t* sdu, uint32_t* sn);
void pdcp_pack_data_pdu_long_sn(uint32_t sn, byte_buffer_t* sdu);
void pdcp_unpack_data_pdu_long_sn(byte_buffer_t* sdu, uint32_t* sn);
} // namespace srslte
#endif // SRSLTE_PDCP_ENTITY_LTE_H

@ -0,0 +1,84 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* 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/.
*
*/
#ifndef SRSLTE_PDCP_ENTITY_NR_H
#define SRSLTE_PDCP_ENTITY_NR_H
#include "pdcp_entity_base.h"
#include "srslte/common/buffer_pool.h"
#include "srslte/common/common.h"
#include "srslte/common/interfaces_common.h"
#include "srslte/common/log.h"
#include "srslte/common/security.h"
#include "srslte/common/threads.h"
namespace srslte {
/****************************************************************************
* NR PDCP Entity
* PDCP entity for 5G NR
***************************************************************************/
class pdcp_entity_nr : public pdcp_entity_base
{
public:
pdcp_entity_nr();
~pdcp_entity_nr();
void init(srsue::rlc_interface_pdcp* rlc_,
srsue::rrc_interface_pdcp* rrc_,
srsue::gw_interface_pdcp* gw_,
srslte::log* log_,
uint32_t lcid_,
pdcp_config_t cfg_);
void reset();
void reestablish();
// RRC interface
void write_sdu(unique_byte_buffer_t sdu, bool blocking);
uint32_t get_dl_count();
uint32_t get_ul_count();
// RLC interface
void write_pdu(unique_byte_buffer_t pdu);
private:
srsue::rlc_interface_pdcp* rlc = nullptr;
srsue::rrc_interface_pdcp* rrc = nullptr;
srsue::gw_interface_pdcp* gw = nullptr;
// State variables: 3GPP TS 38.323 v15.2.0, section 7.1
uint32_t tx_next = 0; // COUNT value of next SDU to be transmitted.
uint32_t rx_next = 0; // COUNT value of next SDU expected to be received.
uint32_t rx_deliv = 0; // COUNT value of first SDU not delivered to upper layers, but still waited for.
uint32_t rx_reord = 0; // COUNT value following the COUNT value of PDCP Data PDU which triggered t-Reordering.
// Constants: 3GPP TS 38.323 v15.2.0, section 7.2
uint32_t window_size = 0;
// Packing/Unpacking Helper functions
uint32_t read_data_header(const unique_byte_buffer_t& sdu);
void write_data_header(const unique_byte_buffer_t& sdu, uint32_t sn);
void extract_mac(const unique_byte_buffer_t& sdu, uint8_t* mac);
void append_mac(const unique_byte_buffer_t& sdu, uint8_t* mac);
};
} // namespace srslte
#endif // SRSLTE_PDCP_ENTITY_NR_H

@ -1,71 +0,0 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* 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/.
*
*/
#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(unique_byte_buffer_t sdu, bool blocking) = 0;
virtual void config_security(uint8_t *k_rrc_enc_,
uint8_t *k_rrc_int_,
uint8_t *k_up_enc_,
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(unique_byte_buffer_t pdu) = 0;
};
} // namespace srslte
#endif // SRSLTE_PDCP_INTERFACE_H

@ -45,10 +45,7 @@ class rlc
public: public:
rlc(log* rlc_log_); rlc(log* rlc_log_);
virtual ~rlc(); virtual ~rlc();
void init(srsue::pdcp_interface_rlc* pdcp_, void init(srsue::pdcp_interface_rlc* pdcp_, srsue::rrc_interface_rlc* rrc_, srslte::timers* timers_, uint32_t lcid_);
srsue::rrc_interface_rlc* rrc_,
mac_interface_timers* mac_timers_,
uint32_t lcid_);
void stop(); void stop();
void get_metrics(rlc_metrics_t& m); void get_metrics(rlc_metrics_t& m);
@ -92,7 +89,7 @@ private:
srslte::log* rlc_log = nullptr; srslte::log* rlc_log = nullptr;
srsue::pdcp_interface_rlc* pdcp = nullptr; srsue::pdcp_interface_rlc* pdcp = nullptr;
srsue::rrc_interface_rlc* rrc = nullptr; srsue::rrc_interface_rlc* rrc = nullptr;
srslte::mac_interface_timers* mac_timers = nullptr; srslte::timers* timers = nullptr;
typedef std::map<uint16_t, rlc_common*> rlc_map_t; typedef std::map<uint16_t, rlc_common*> rlc_map_t;
typedef std::pair<uint16_t, rlc_common*> rlc_map_pair_t; typedef std::pair<uint16_t, rlc_common*> rlc_map_pair_t;
@ -109,7 +106,6 @@ private:
bool valid_lcid_mrb(uint32_t lcid); bool valid_lcid_mrb(uint32_t lcid);
}; };
} // namespace srsue } // namespace srslte
#endif // SRSLTE_RLC_H #endif // SRSLTE_RLC_H

@ -68,8 +68,7 @@ public:
uint32_t lcid_, uint32_t lcid_,
srsue::pdcp_interface_rlc* pdcp_, srsue::pdcp_interface_rlc* pdcp_,
srsue::rrc_interface_rlc* rrc_, srsue::rrc_interface_rlc* rrc_,
srslte::mac_interface_timers* mac_timers_); srslte::timers* timers_);
~rlc_am();
bool configure(rlc_config_t cfg_); bool configure(rlc_config_t cfg_);
void reestablish(); void reestablish();
void stop(); void stop();
@ -223,7 +222,7 @@ private:
void handle_data_pdu(uint8_t *payload, uint32_t nof_bytes, rlc_amd_pdu_header_t &header); void handle_data_pdu(uint8_t *payload, uint32_t nof_bytes, rlc_amd_pdu_header_t &header);
void handle_data_pdu_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_pdu_header_t &header); void handle_data_pdu_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_pdu_header_t &header);
void reassemble_rx_sdus(); void reassemble_rx_sdus();
bool inside_rx_window(uint16_t sn); bool inside_rx_window(const int16_t sn);
void debug_state(); void debug_state();
void print_rx_segments(); void print_rx_segments();
bool add_segment_and_check(rlc_amd_rx_pdu_segments_t *pdu, rlc_amd_rx_pdu_t *segment); bool add_segment_and_check(rlc_amd_rx_pdu_segments_t *pdu, rlc_amd_rx_pdu_t *segment);
@ -279,7 +278,7 @@ private:
srsue::rrc_interface_rlc* rrc = nullptr; srsue::rrc_interface_rlc* rrc = nullptr;
srslte::log* log = nullptr; srslte::log* log = nullptr;
srsue::pdcp_interface_rlc* pdcp = nullptr; srsue::pdcp_interface_rlc* pdcp = nullptr;
mac_interface_timers* mac_timers = nullptr; srslte::timers* timers = nullptr;
uint32_t lcid = 0; uint32_t lcid = 0;
rlc_config_t cfg = {}; rlc_config_t cfg = {};
std::string rb_name; std::string rb_name;
@ -307,6 +306,7 @@ int rlc_am_write_status_pdu(rlc_status_pdu_t *status, uint8_t *payload);
uint32_t rlc_am_packed_length(rlc_amd_pdu_header_t *header); uint32_t rlc_am_packed_length(rlc_amd_pdu_header_t *header);
uint32_t rlc_am_packed_length(rlc_status_pdu_t *status); uint32_t rlc_am_packed_length(rlc_status_pdu_t *status);
uint32_t rlc_am_packed_length(rlc_amd_retx_t retx); uint32_t rlc_am_packed_length(rlc_amd_retx_t retx);
bool rlc_am_is_valid_status_pdu(const rlc_status_pdu_t& status);
bool rlc_am_is_control_pdu(byte_buffer_t *pdu); bool rlc_am_is_control_pdu(byte_buffer_t *pdu);
bool rlc_am_is_control_pdu(uint8_t *payload); bool rlc_am_is_control_pdu(uint8_t *payload);
bool rlc_am_is_pdu_segment(uint8_t *payload); bool rlc_am_is_pdu_segment(uint8_t *payload);
@ -319,5 +319,4 @@ bool rlc_am_not_start_aligned(const uint8_t fi);
} // namespace srslte } // namespace srslte
#endif // SRSLTE_RLC_AM_H #endif // SRSLTE_RLC_AM_H

@ -48,6 +48,28 @@ static const char rlc_fi_field_text[RLC_FI_FIELD_N_ITEMS][32] = {"Start and end
"Not start aligned", "Not start aligned",
"Not start or end aligned"}; "Not start or end aligned"};
enum class rlc_nr_si_field_t : unsigned {
full_sdu = 0b00,
first_segment = 0b01,
last_segment = 0b10,
neither_first_nor_last_segment = 0b11,
nulltype
};
inline std::string to_string(const rlc_nr_si_field_t& si)
{
constexpr static const char* options[] = {"Data field contains full SDU",
"Data field contains first segment of SDU",
"Data field contains last segment of SDU",
"Data field contains neither first nor last segment of SDU"};
return enum_to_text(options, (uint32_t)rlc_nr_si_field_t::nulltype, (uint32_t)si);
}
static inline uint8_t operator&(rlc_nr_si_field_t lhs, int rhs)
{
return static_cast<uint8_t>(static_cast<std::underlying_type<rlc_nr_si_field_t>::type>(lhs) &
static_cast<std::underlying_type<rlc_nr_si_field_t>::type>(rhs));
}
typedef enum{ typedef enum{
RLC_DC_FIELD_CONTROL_PDU = 0, RLC_DC_FIELD_CONTROL_PDU = 0,
RLC_DC_FIELD_DATA_PDU, RLC_DC_FIELD_DATA_PDU,
@ -65,6 +87,13 @@ typedef struct{
uint16_t li[RLC_AM_WINDOW_SIZE]; // Array of length indicators uint16_t li[RLC_AM_WINDOW_SIZE]; // Array of length indicators
}rlc_umd_pdu_header_t; }rlc_umd_pdu_header_t;
typedef struct {
rlc_nr_si_field_t si; // Segmentation info
rlc_um_nr_sn_size_t sn_size; // Sequence number size (6 or 12 bits)
uint16_t sn; // Sequence number
uint16_t so; // Sequence offset
} rlc_um_nr_pdu_header_t;
// AMD PDU Header // AMD PDU Header
struct rlc_amd_pdu_header_t{ struct rlc_amd_pdu_header_t{
rlc_dc_field_t dc; // Data or control rlc_dc_field_t dc; // Data or control
@ -125,7 +154,7 @@ struct rlc_status_nack_t{
// STATUS PDU // STATUS PDU
struct rlc_status_pdu_t{ struct rlc_status_pdu_t{
uint16_t ack_sn; uint16_t ack_sn; // SN of the next not received RLC Data PDU
uint32_t N_nack; uint32_t N_nack;
rlc_status_nack_t nacks[RLC_AM_WINDOW_SIZE]; rlc_status_nack_t nacks[RLC_AM_WINDOW_SIZE];

@ -38,7 +38,7 @@ public:
uint32_t lcid_, uint32_t lcid_,
srsue::pdcp_interface_rlc* pdcp_, srsue::pdcp_interface_rlc* pdcp_,
srsue::rrc_interface_rlc* rrc_, srsue::rrc_interface_rlc* rrc_,
srslte::mac_interface_timers* mac_timers_, srslte::timers* timers_,
uint32_t queue_len = 16); uint32_t queue_len = 16);
~rlc_tm(); ~rlc_tm();
bool configure(rlc_config_t cnfg); bool configure(rlc_config_t cnfg);
@ -78,7 +78,6 @@ private:
rlc_tx_queue ul_queue; rlc_tx_queue ul_queue;
}; };
} // namespace srsue } // namespace srslte
#endif // SRSLTE_RLC_TM_H #endif // SRSLTE_RLC_TM_H

@ -23,13 +23,14 @@
#define SRSLTE_RLC_UM_H #define SRSLTE_RLC_UM_H
#include "srslte/common/buffer_pool.h" #include "srslte/common/buffer_pool.h"
#include "srslte/common/log.h"
#include "srslte/common/common.h" #include "srslte/common/common.h"
#include "srslte/common/log.h"
#include "srslte/interfaces/ue_interfaces.h" #include "srslte/interfaces/ue_interfaces.h"
#include "srslte/upper/rlc_tx_queue.h"
#include "srslte/upper/rlc_common.h" #include "srslte/upper/rlc_common.h"
#include <pthread.h> #include "srslte/upper/rlc_tx_queue.h"
#include <map> #include <map>
#include <mutex>
#include <pthread.h>
#include <queue> #include <queue>
namespace srslte { namespace srslte {
@ -39,6 +40,11 @@ struct rlc_umd_pdu_t{
unique_byte_buffer_t buf; unique_byte_buffer_t buf;
}; };
typedef struct {
rlc_um_nr_pdu_header_t header;
unique_byte_buffer_t buf;
} rlc_umd_pdu_nr_t;
class rlc_um class rlc_um
:public rlc_common :public rlc_common
{ {
@ -47,7 +53,7 @@ public:
uint32_t lcid_, uint32_t lcid_,
srsue::pdcp_interface_rlc* pdcp_, srsue::pdcp_interface_rlc* pdcp_,
srsue::rrc_interface_rlc* rrc_, srsue::rrc_interface_rlc* rrc_,
mac_interface_timers* mac_timers_); srslte::timers* timers_);
~rlc_um(); ~rlc_um();
bool configure(rlc_config_t cnfg); bool configure(rlc_config_t cnfg);
void reestablish(); void reestablish();
@ -73,14 +79,13 @@ public:
void reset_metrics(); void reset_metrics();
private: private:
// Transmitter sub-class base
// Transmitter sub-class class rlc_um_tx_base
class rlc_um_tx
{ {
public: public:
rlc_um_tx(srslte::log* log_); rlc_um_tx_base(srslte::log* log_);
~rlc_um_tx(); virtual ~rlc_um_tx_base();
bool configure(rlc_config_t cfg, std::string rb_name); virtual bool configure(rlc_config_t cfg, std::string rb_name) = 0;
int build_data_pdu(uint8_t *payload, uint32_t nof_bytes); int build_data_pdu(uint8_t *payload, uint32_t nof_bytes);
void stop(); void stop();
void reestablish(); void reestablish();
@ -92,7 +97,7 @@ private:
bool has_data(); bool has_data();
uint32_t get_buffer_state(); uint32_t get_buffer_state();
private: protected:
byte_buffer_pool* pool = nullptr; byte_buffer_pool* pool = nullptr;
srslte::log* log = nullptr; srslte::log* log = nullptr;
std::string rb_name; std::string rb_name;
@ -101,28 +106,58 @@ private:
* Configurable parameters * Configurable parameters
* Ref: 3GPP TS 36.322 v10.0.0 Section 7 * Ref: 3GPP TS 36.322 v10.0.0 Section 7
***************************************************************************/ ***************************************************************************/
rlc_um_config_t cfg = {}; rlc_config_t cfg = {};
// TX SDU buffers // TX SDU buffers
rlc_tx_queue tx_sdu_queue; rlc_tx_queue tx_sdu_queue;
unique_byte_buffer_t tx_sdu; unique_byte_buffer_t tx_sdu;
// Mutexes
std::mutex mutex;
bool tx_enabled = false;
uint32_t num_tx_bytes = 0;
virtual int build_data_pdu(unique_byte_buffer_t pdu, uint8_t* payload, uint32_t nof_bytes) = 0;
// helper functions
virtual void debug_state() = 0;
const char* get_rb_name();
};
// Transmitter sub-class for LTE
class rlc_um_tx : public rlc_um_tx_base
{
public:
rlc_um_tx(srslte::log* log_);
bool configure(rlc_config_t cfg, std::string rb_name);
int build_data_pdu(unique_byte_buffer_t pdu, uint8_t* payload, uint32_t nof_bytes);
private:
/**************************************************************************** /****************************************************************************
* State variables and counters * State variables and counters
* Ref: 3GPP TS 36.322 v10.0.0 Section 7 * Ref: 3GPP TS 36.322 v10.0.0 Section 7
***************************************************************************/ ***************************************************************************/
uint32_t vt_us = 0; // Send state. SN to be assigned for next PDU. uint32_t vt_us = 0; // Send state. SN to be assigned for next PDU.
// Mutexes void debug_state();
pthread_mutex_t mutex; };
bool tx_enabled = false; // Transmitter sub-class for NR
class rlc_um_tx_nr : public rlc_um_tx_base
{
public:
rlc_um_tx_nr(srslte::log* log_);
uint32_t num_tx_bytes = 0; bool configure(rlc_config_t cfg, std::string rb_name);
int build_data_pdu(unique_byte_buffer_t pdu, uint8_t* payload, uint32_t nof_bytes);
private:
uint32_t TX_Next = 0; // send state as defined in TS 38.322 v15.3 Section 7
// helper functions
void debug_state(); void debug_state();
const char* get_rb_name();
}; };
// Receiver sub-class // Receiver sub-class
@ -132,7 +167,7 @@ private:
uint32_t lcid_, uint32_t lcid_,
srsue::pdcp_interface_rlc* pdcp_, srsue::pdcp_interface_rlc* pdcp_,
srsue::rrc_interface_rlc* rrc_, srsue::rrc_interface_rlc* rrc_,
srslte::mac_interface_timers* mac_timers_); srslte::timers* timers_);
~rlc_um_rx(); ~rlc_um_rx();
void stop(); void stop();
void reestablish(); void reestablish();
@ -152,14 +187,14 @@ private:
byte_buffer_pool* pool = nullptr; byte_buffer_pool* pool = nullptr;
srslte::log* log = nullptr; srslte::log* log = nullptr;
mac_interface_timers* mac_timers = nullptr; srslte::timers* timers = nullptr;
std::string rb_name; std::string rb_name;
/**************************************************************************** /****************************************************************************
* Configurable parameters * Configurable parameters
* Ref: 3GPP TS 36.322 v10.0.0 Section 7 * Ref: 3GPP TS 36.322 v10.0.0 Section 7
***************************************************************************/ ***************************************************************************/
rlc_um_config_t cfg = {}; rlc_config_t cfg = {};
// Rx window // Rx window
std::map<uint32_t, rlc_umd_pdu_t> rx_window; std::map<uint32_t, rlc_umd_pdu_t> rx_window;
@ -182,7 +217,7 @@ private:
uint32_t lcid = 0; uint32_t lcid = 0;
// Mutexes // Mutexes
pthread_mutex_t mutex; std::mutex mutex;
bool rx_enabled = false; bool rx_enabled = false;
@ -209,7 +244,7 @@ private:
std::string get_rb_name(srsue::rrc_interface_rlc *rrc, uint32_t lcid, bool is_mrb); std::string get_rb_name(srsue::rrc_interface_rlc *rrc, uint32_t lcid, bool is_mrb);
// Rx and Tx objects // Rx and Tx objects
rlc_um_tx tx; std::unique_ptr<rlc_um_tx_base> tx;
rlc_um_rx rx; rlc_um_rx rx;
}; };
@ -225,7 +260,23 @@ uint32_t rlc_um_packed_length(rlc_umd_pdu_header_t *header);
bool rlc_um_start_aligned(uint8_t fi); bool rlc_um_start_aligned(uint8_t fi);
bool rlc_um_end_aligned(uint8_t fi); bool rlc_um_end_aligned(uint8_t fi);
} // namespace srsue /****************************************************************************
* Header pack/unpack helper functions for NR
* Ref: 3GPP TS 38.322 v15.3.0 Section 6.2.2.3
***************************************************************************/
uint32_t rlc_um_nr_read_data_pdu_header(const byte_buffer_t* pdu,
const rlc_um_nr_sn_size_t sn_size,
rlc_um_nr_pdu_header_t* header);
uint32_t rlc_um_nr_read_data_pdu_header(const uint8_t* payload,
const uint32_t nof_bytes,
const rlc_um_nr_sn_size_t sn_size,
rlc_um_nr_pdu_header_t* header);
uint32_t rlc_um_nr_write_data_pdu_header(const rlc_um_nr_pdu_header_t& header, byte_buffer_t* pdu);
uint32_t rlc_um_nr_packed_length(const rlc_um_nr_pdu_header_t& header);
} // namespace srslte
#endif // SRSLTE_RLC_UM_H #endif // SRSLTE_RLC_UM_H

@ -83,16 +83,6 @@ void log_error_code(SRSASN_CODE code, const char* filename, int line)
bit_ref bit_ref
*********************/ *********************/
bit_ref::bit_ref() : ptr(NULL), offset(0), start_ptr(NULL), max_ptr(NULL) {}
bit_ref::bit_ref(uint8_t* start_ptr_, uint32_t max_size_) :
ptr(start_ptr_),
offset(0),
start_ptr(start_ptr_),
max_ptr(max_size_ + start_ptr_)
{
}
int bit_ref::distance(const bit_ref& other) const int bit_ref::distance(const bit_ref& other) const
{ {
return ((int)offset - (int)other.offset) + 8 * ((int)(ptr - other.ptr)); return ((int)offset - (int)other.offset) + 8 * ((int)(ptr - other.ptr));
@ -116,6 +106,10 @@ int bit_ref::distance_bytes() const
SRSASN_CODE bit_ref::pack(uint32_t val, uint32_t n_bits) SRSASN_CODE bit_ref::pack(uint32_t val, uint32_t n_bits)
{ {
if (n_bits >= 32) {
srsasn_log_print(LOG_LEVEL_ERROR, "This method only supports packing up to 32 bits\n");
return SRSASN_ERROR_ENCODE_FAIL;
}
uint32_t mask; uint32_t mask;
while (n_bits > 0) { while (n_bits > 0) {
if (ptr >= max_ptr) { if (ptr >= max_ptr) {
@ -141,8 +135,33 @@ SRSASN_CODE bit_ref::pack(uint32_t val, uint32_t n_bits)
return SRSASN_SUCCESS; return SRSASN_SUCCESS;
} }
SRSASN_CODE bit_ref::pack_bytes(const uint8_t* buf, uint32_t n_bytes)
{
if (n_bytes == 0) {
return SRSASN_SUCCESS;
}
if (ptr + n_bytes >= max_ptr) {
srsasn_log_print(LOG_LEVEL_ERROR, "Buffer size limit was achieved\n");
return SRSASN_ERROR_ENCODE_FAIL;
}
if (offset == 0) {
// Aligned case
memcpy(ptr, buf, n_bytes);
ptr += n_bytes;
} else {
for (uint32_t i = 0; i < n_bytes; ++i) {
pack(buf[i], 8);
}
}
return SRSASN_SUCCESS;
}
ValOrError unpack_bits(uint8_t*& ptr, uint8_t& offset, uint8_t* max_ptr, uint32_t n_bits) ValOrError unpack_bits(uint8_t*& ptr, uint8_t& offset, uint8_t* max_ptr, uint32_t n_bits)
{ {
if (n_bits > 32) {
srsasn_log_print(LOG_LEVEL_ERROR, "This method only supports unpacking up to 32 bits\n");
return {0, SRSASN_ERROR_DECODE_FAIL};
}
uint32_t val = 0; uint32_t val = 0;
while (n_bits > 0) { while (n_bits > 0) {
if (ptr >= max_ptr) { if (ptr >= max_ptr) {
@ -165,6 +184,27 @@ ValOrError unpack_bits(uint8_t*& ptr, uint8_t& offset, uint8_t* max_ptr, uint32_
return ValOrError(val, SRSASN_SUCCESS); return ValOrError(val, SRSASN_SUCCESS);
} }
SRSASN_CODE bit_ref::unpack_bytes(uint8_t* buf, uint32_t n_bytes)
{
if (n_bytes == 0) {
return SRSASN_SUCCESS;
}
if (ptr + n_bytes >= max_ptr) {
srsasn_log_print(LOG_LEVEL_ERROR, "Buffer size limit was achieved\n");
return SRSASN_ERROR_DECODE_FAIL;
}
if (offset == 0) {
// Aligned case
memcpy(buf, ptr, n_bytes);
ptr += n_bytes;
} else {
for (uint32_t i = 0; i < n_bytes; ++i) {
unpack(buf[i], 8);
}
}
return SRSASN_SUCCESS;
}
SRSASN_CODE bit_ref::align_bytes() SRSASN_CODE bit_ref::align_bytes()
{ {
if (offset == 0) if (offset == 0)
@ -193,6 +233,21 @@ SRSASN_CODE bit_ref::align_bytes_zero()
return SRSASN_SUCCESS; return SRSASN_SUCCESS;
} }
SRSASN_CODE bit_ref::advance_bits(uint32_t n_bits)
{
uint32_t extra_bits = (offset + n_bits) % 8;
uint32_t bytes_required = ceilf((offset + n_bits) / 8.0f);
uint32_t bytes_offset = floorf((offset + n_bits) / 8.0f);
if (ptr + bytes_required >= max_ptr) {
srsasn_log_print(LOG_LEVEL_ERROR, "Buffer size limit was achieved\n");
return SRSASN_ERROR_DECODE_FAIL;
}
ptr += bytes_offset;
offset = extra_bits;
return SRSASN_SUCCESS;
}
void bit_ref::set(uint8_t* start_ptr_, uint32_t max_size_) void bit_ref::set(uint8_t* start_ptr_, uint32_t max_size_)
{ {
ptr = start_ptr_; ptr = start_ptr_;
@ -370,10 +425,6 @@ template SRSASN_CODE unpack_unalign_integer<uint16_t>(uint16_t& n, bit_ref& bref
template SRSASN_CODE unpack_unalign_integer<uint32_t>(uint32_t& n, bit_ref& bref, uint32_t lb, uint32_t ub); template SRSASN_CODE unpack_unalign_integer<uint32_t>(uint32_t& n, bit_ref& bref, uint32_t lb, uint32_t ub);
template SRSASN_CODE unpack_unalign_integer<uint64_t>(uint64_t& n, bit_ref& bref, uint64_t lb, uint64_t ub); template SRSASN_CODE unpack_unalign_integer<uint64_t>(uint64_t& n, bit_ref& bref, uint64_t lb, uint64_t ub);
template <class IntType>
UnalignedIntegerPacker<IntType>::UnalignedIntegerPacker(IntType lb_, IntType ub_) : lb(lb_), ub(ub_)
{
}
template <class IntType> template <class IntType>
SRSASN_CODE UnalignedIntegerPacker<IntType>::pack(bit_ref& bref, IntType n) const SRSASN_CODE UnalignedIntegerPacker<IntType>::pack(bit_ref& bref, IntType n) const
{ {
@ -921,86 +972,83 @@ void log_invalid_choice_id(uint32_t val, const char* choice_type)
ext group ext group
*********************/ *********************/
ext_groups_header::ext_groups_header(uint32_t max_nof_groups, uint32_t nof_nogroups_) : nof_nogroups(nof_nogroups_) bool& ext_groups_packer_guard::operator[](uint32_t idx)
{ {
if (max_nof_groups > 20) { if (idx >= groups.size()) {
srsasn_log_print(LOG_LEVEL_ERROR, "increase the size of ext group packer/unpacker\n"); uint32_t prev_size = groups.size();
} groups.resize(idx + 1);
groups.resize(max_nof_groups); std::fill(&groups[prev_size], &groups[groups.size()], false);
for (uint32_t i = 0; i < groups.size(); ++i) {
groups[i] = false;
} }
nof_groups = groups.size() + 1; // unset
}
bool& ext_groups_header::operator[](uint32_t idx)
{
return groups[idx]; return groups[idx];
} }
SRSASN_CODE ext_groups_header::pack_nof_groups(bit_ref& bref) const SRSASN_CODE ext_groups_packer_guard::pack(asn1::bit_ref& bref) const
{ {
nof_groups = 0; // pack number of groups
for (uint32_t i = 0; i < groups.size(); ++i) { int32_t i = groups.size() - 1;
for (; i >= 0; --i) {
if (groups[i]) { if (groups[i]) {
nof_groups = i + 1; break;
} }
} }
if (nof_groups > groups.size()) { uint32_t nof_groups = (uint32_t)i + 1u;
srsasn_log_print(LOG_LEVEL_ERROR, "Exceeded maximum number of groups (%d>%d)\n", nof_groups, groups.size()); HANDLE_CODE(pack_norm_small_integer(bref, nof_groups - 1));
return SRSASN_ERROR_ENCODE_FAIL;
// pack each group presence flag
for (uint32_t j = 0; j < nof_groups; ++j) {
HANDLE_CODE(bref.pack(groups[j], 1));
} }
HANDLE_CODE(pack_norm_small_integer(bref, nof_groups + nof_nogroups - 1));
return SRSASN_SUCCESS; return SRSASN_SUCCESS;
} }
SRSASN_CODE ext_groups_header::pack_group_flags(bit_ref& bref) const ext_groups_unpacker_guard::ext_groups_unpacker_guard(uint32_t nof_supported_groups_) :
nof_supported_groups(nof_supported_groups_)
{ {
if (nof_groups > groups.size()) { resize(nof_supported_groups);
srsasn_log_print(LOG_LEVEL_ERROR, "Exceeded maximum number of groups (%d>%d)\n", nof_groups, groups.size());
return SRSASN_ERROR_ENCODE_FAIL;
} }
for (uint32_t i = 0; i < nof_groups; ++i) {
HANDLE_CODE(bref.pack(groups[i], 1)); bool& ext_groups_unpacker_guard::operator[](uint32_t idx)
{
if (idx >= groups.size()) {
// only resizes for unknown extensions
resize(idx + 1);
} }
return SRSASN_SUCCESS; return groups[idx];
} }
SRSASN_CODE ext_groups_header::pack(bit_ref& bref) const void ext_groups_unpacker_guard::resize(uint32_t new_size)
{ {
HANDLE_CODE(pack_nof_groups(bref)); // always grows
return pack_group_flags(bref); uint32_t prev_size = groups.size();
groups.resize(std::max(new_size, nof_supported_groups));
std::fill(&groups[prev_size], &groups[groups.size()], false);
} }
SRSASN_CODE ext_groups_header::unpack_nof_groups(bit_ref& bref) ext_groups_unpacker_guard::~ext_groups_unpacker_guard()
{ {
HANDLE_CODE(unpack_norm_small_integer(nof_groups, bref)); // consume all the unknown extensions
nof_groups += 1 - nof_nogroups; for (uint32_t i = nof_supported_groups; i < nof_unpacked_groups; ++i) {
if (nof_groups > groups.size()) { if (groups[i]) {
srsasn_log_print(LOG_LEVEL_ERROR, "Exceeded maximum number of groups (%d>%d)\n", nof_groups, groups.size()); varlength_field_unpack_guard scope(*bref_tracker);
return SRSASN_ERROR_DECODE_FAIL; }
} }
return SRSASN_SUCCESS;
} }
SRSASN_CODE ext_groups_header::unpack_group_flags(bit_ref& bref) SRSASN_CODE ext_groups_unpacker_guard::unpack(bit_ref& bref)
{ {
if (nof_groups > groups.size()) { bref_tracker = &bref;
srsasn_log_print(LOG_LEVEL_ERROR, "Exceeded maximum number of groups (%d>%d)\n", nof_groups, groups.size()); // unpack nof of ext groups
return SRSASN_ERROR_DECODE_FAIL; HANDLE_CODE(unpack_norm_small_integer(nof_unpacked_groups, bref));
} nof_unpacked_groups += 1;
for (uint32_t i = 0; i < nof_groups; ++i) { resize(nof_unpacked_groups);
// unpack each group presence flag
for (uint32_t i = 0; i < nof_unpacked_groups; ++i) {
HANDLE_CODE(bref.unpack(groups[i], 1)); HANDLE_CODE(bref.unpack(groups[i], 1));
} }
return SRSASN_SUCCESS; return SRSASN_SUCCESS;
} }
SRSASN_CODE ext_groups_header::unpack(bit_ref& bref)
{
HANDLE_CODE(unpack_nof_groups(bref));
return unpack_group_flags(bref);
}
/********************* /*********************
Open Field Open Field
*********************/ *********************/

@ -6433,12 +6433,27 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_identity_request_msg(LIBLTE_BYTE_MSG_STRUCT*
Document Reference: 24.301 v10.2.0 Section 8.2.19 Document Reference: 24.301 v10.2.0 Section 8.2.19
*********************************************************************/ *********************************************************************/
LIBLTE_ERROR_ENUM liblte_mme_pack_identity_response_msg(LIBLTE_MME_ID_RESPONSE_MSG_STRUCT* id_resp, LIBLTE_ERROR_ENUM liblte_mme_pack_identity_response_msg(LIBLTE_MME_ID_RESPONSE_MSG_STRUCT* id_resp,
uint8 sec_hdr_type,
uint32 count,
LIBLTE_BYTE_MSG_STRUCT* msg) LIBLTE_BYTE_MSG_STRUCT* msg)
{ {
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
uint8* msg_ptr = msg->msg; uint8* msg_ptr = msg->msg;
if (id_resp != NULL && msg != NULL) { if (id_resp != NULL && msg != NULL) {
if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS != sec_hdr_type) {
// Protocol Discriminator and Security Header Type
*msg_ptr = (sec_hdr_type << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT);
msg_ptr++;
// MAC will be filled in later
msg_ptr += 4;
// Sequence Number
*msg_ptr = count & 0xFF;
msg_ptr++;
}
// Protocol Discriminator and Security Header Type // Protocol Discriminator and Security Header Type
*msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); *msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT);
msg_ptr++; msg_ptr++;

File diff suppressed because it is too large Load Diff

@ -26,8 +26,8 @@ using namespace asn1;
using namespace asn1::rrc; using namespace asn1::rrc;
/******************************************************************************* /*******************************************************************************
/* Helper Functions * Helper Functions
/******************************************************************************/ ******************************************************************************/
static void invalid_enum_number(int value, const char* name) static void invalid_enum_number(int value, const char* name)
{ {
@ -36,8 +36,8 @@ static void invalid_enum_number(int value, const char* name)
} }
/******************************************************************************* /*******************************************************************************
/* Struct Methods * Struct Methods
/******************************************************************************/ ******************************************************************************/
std::string phich_cfg_s::phich_dur_opts::to_string() const std::string phich_cfg_s::phich_dur_opts::to_string() const
{ {

@ -74,6 +74,32 @@ void to_asn1(asn1::rrc::s_tmsi_s* asn1_type, const s_tmsi_t& cfg)
asn1_type->m_tmsi.from_number(cfg.m_tmsi); asn1_type->m_tmsi.from_number(cfg.m_tmsi);
} }
/***************************
* CQI Report Aperiodic
**************************/
srslte_cqi_report_mode_t make_aperiodic_mode(const asn1::rrc::cqi_report_mode_aperiodic_e asn_mode)
{
switch (asn_mode) {
case asn1::rrc::cqi_report_mode_aperiodic_e::rm12:
return SRSLTE_CQI_MODE_12;
case asn1::rrc::cqi_report_mode_aperiodic_e::rm20:
return SRSLTE_CQI_MODE_20;
case asn1::rrc::cqi_report_mode_aperiodic_e::rm22:
return SRSLTE_CQI_MODE_22;
case asn1::rrc::cqi_report_mode_aperiodic_e::rm30:
return SRSLTE_CQI_MODE_30;
case asn1::rrc::cqi_report_mode_aperiodic_e::rm31:
return SRSLTE_CQI_MODE_31;
case asn1::rrc::cqi_report_mode_aperiodic_e::rm10_v1310:
case asn1::rrc::cqi_report_mode_aperiodic_e::rm11_v1310:
case asn1::rrc::cqi_report_mode_aperiodic_e::rm32_v1250:
fprintf(stderr, "Aperiodic mode %s not handled\n", asn_mode.to_string().c_str());
default:
return SRSLTE_CQI_MODE_NA;
}
}
/*************************** /***************************
* Establishment Cause * Establishment Cause
**************************/ **************************/
@ -155,4 +181,601 @@ void to_asn1(asn1::rrc::rlc_cfg_c* asn1_type, const srslte::rlc_config_t& cfg)
} }
/***************************
* MAC Config
**************************/
void set_mac_cfg_t_sched_request_cfg(mac_cfg_t* cfg, const asn1::rrc::sched_request_cfg_c& asn1_type)
{
cfg->sr_cfg.enabled = asn1_type.type() == asn1::rrc::setup_e::setup;
if (cfg->sr_cfg.enabled) {
cfg->sr_cfg.dsr_transmax = asn1_type.setup().dsr_trans_max.to_number();
}
}
// MAC-MainConfig section is always present
void set_mac_cfg_t_main_cfg(mac_cfg_t* cfg, const asn1::rrc::mac_main_cfg_s& asn1_type)
{
// Update values only if each section is present
if (asn1_type.phr_cfg_present) {
cfg->phr_cfg.enabled = asn1_type.phr_cfg.type() == asn1::rrc::setup_e::setup;
if (cfg->phr_cfg.enabled) {
cfg->phr_cfg.prohibit_timer = asn1_type.phr_cfg.setup().prohibit_phr_timer.to_number();
cfg->phr_cfg.periodic_timer = asn1_type.phr_cfg.setup().periodic_phr_timer.to_number();
cfg->phr_cfg.db_pathloss_change = asn1_type.phr_cfg.setup().dl_pathloss_change.to_number();
}
}
if (asn1_type.mac_main_cfg_v1020.is_present()) {
cfg->phr_cfg.extended = asn1_type.mac_main_cfg_v1020.get()->extended_phr_r10_present;
}
if (asn1_type.ul_sch_cfg_present) {
cfg->bsr_cfg.periodic_timer = asn1_type.ul_sch_cfg.periodic_bsr_timer.to_number();
cfg->bsr_cfg.retx_timer = asn1_type.ul_sch_cfg.retx_bsr_timer.to_number();
if (asn1_type.ul_sch_cfg.max_harq_tx_present) {
cfg->harq_cfg.max_harq_tx = asn1_type.ul_sch_cfg.max_harq_tx.to_number();
}
}
// TimeAlignmentDedicated overwrites Common??
cfg->time_alignment_timer = asn1_type.time_align_timer_ded.to_number();
}
// RACH-Common section is always present
void set_mac_cfg_t_rach_cfg_common(mac_cfg_t* cfg, const asn1::rrc::rach_cfg_common_s& asn1_type)
{
// Preamble info
cfg->rach_cfg.nof_preambles = asn1_type.preamb_info.nof_ra_preambs.to_number();
if (asn1_type.preamb_info.preambs_group_a_cfg_present) {
cfg->rach_cfg.nof_groupA_preambles =
asn1_type.preamb_info.preambs_group_a_cfg.size_of_ra_preambs_group_a.to_number();
cfg->rach_cfg.messageSizeGroupA = asn1_type.preamb_info.preambs_group_a_cfg.msg_size_group_a.to_number();
cfg->rach_cfg.messagePowerOffsetGroupB =
asn1_type.preamb_info.preambs_group_a_cfg.msg_pwr_offset_group_b.to_number();
} else {
cfg->rach_cfg.nof_groupA_preambles = 0;
}
// Power ramping
cfg->rach_cfg.powerRampingStep = asn1_type.pwr_ramp_params.pwr_ramp_step.to_number();
cfg->rach_cfg.iniReceivedTargetPower = asn1_type.pwr_ramp_params.preamb_init_rx_target_pwr.to_number();
// Supervision info
cfg->rach_cfg.preambleTransMax = asn1_type.ra_supervision_info.preamb_trans_max.to_number();
cfg->rach_cfg.responseWindowSize = asn1_type.ra_supervision_info.ra_resp_win_size.to_number();
cfg->rach_cfg.contentionResolutionTimer = asn1_type.ra_supervision_info.mac_contention_resolution_timer.to_number();
// HARQ Msg3
cfg->harq_cfg.max_harq_msg3_tx = asn1_type.max_harq_msg3_tx;
}
void set_mac_cfg_t_time_alignment(mac_cfg_t* cfg, const asn1::rrc::time_align_timer_opts asn1_type)
{
cfg->time_alignment_timer = asn1_type.to_number();
}
void set_phy_cfg_t_dedicated_cfg(phy_cfg_t* cfg, const asn1::rrc::phys_cfg_ded_s& asn1_type)
{
if (asn1_type.pucch_cfg_ded_present) {
if (asn1_type.pucch_cfg_ded.tdd_ack_nack_feedback_mode_present) {
cfg->ul_cfg.pucch.tdd_ack_multiplex = asn1_type.pucch_cfg_ded.tdd_ack_nack_feedback_mode ==
asn1::rrc::pucch_cfg_ded_s::tdd_ack_nack_feedback_mode_e_::mux;
} else {
cfg->ul_cfg.pucch.tdd_ack_multiplex = false;
}
}
if (asn1_type.pucch_cfg_ded_v1020.is_present()) {
auto* pucch_cfg_ded = asn1_type.pucch_cfg_ded_v1020.get();
if (pucch_cfg_ded->pucch_format_r10_present) {
typedef asn1::rrc::pucch_cfg_ded_v1020_s::pucch_format_r10_c_ pucch_format_r10_t;
auto* pucch_format_r10 = &pucch_cfg_ded->pucch_format_r10;
if (pucch_format_r10->type() == pucch_format_r10_t::types::format3_r10) {
// Select feedback mode
cfg->ul_cfg.pucch.ack_nack_feedback_mode = SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_PUCCH3;
auto* format3_r13 = &pucch_format_r10->format3_r10();
for (uint32_t n = 0; n < SRSLTE_MIN(format3_r13->n3_pucch_an_list_r13.size(), SRSLTE_PUCCH_SIZE_AN_CS); n++) {
cfg->ul_cfg.pucch.n3_pucch_an_list[n] = format3_r13->n3_pucch_an_list_r13[n];
}
if (format3_r13->two_ant_port_activ_pucch_format3_r13_present) {
if (format3_r13->two_ant_port_activ_pucch_format3_r13.type() == asn1::rrc::setup_e::setup) {
// TODO: UL MIMO Configure PUCCH two antenna port
} else {
// TODO: UL MIMO Disable two antenna port
}
}
} else if (pucch_format_r10->type() == asn1::rrc::pucch_cfg_ded_v1020_s::pucch_format_r10_c_::types::ch_sel_r10) {
typedef pucch_format_r10_t::ch_sel_r10_s_ ch_sel_r10_t;
auto* ch_sel_r10 = &pucch_format_r10->ch_sel_r10();
if (ch_sel_r10->n1_pucch_an_cs_r10_present) {
typedef ch_sel_r10_t::n1_pucch_an_cs_r10_c_ n1_pucch_an_cs_r10_t;
auto* n1_pucch_an_cs_r10 = &ch_sel_r10->n1_pucch_an_cs_r10;
if (n1_pucch_an_cs_r10->type() == asn1::rrc::setup_e::setup) {
// Select feedback mode
cfg->ul_cfg.pucch.ack_nack_feedback_mode = SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_CS;
typedef n1_pucch_an_cs_r10_t::setup_s_::n1_pucch_an_cs_list_r10_l_ n1_pucch_an_cs_list_r10_t;
n1_pucch_an_cs_list_r10_t n1_pucch_an_cs_list =
ch_sel_r10->n1_pucch_an_cs_r10.setup().n1_pucch_an_cs_list_r10;
for (uint32_t i = 0; i < SRSLTE_MIN(n1_pucch_an_cs_list.size(), SRSLTE_PUCCH_NOF_AN_CS); i++) {
asn1::rrc::n1_pucch_an_cs_r10_l n1_pucch_an_cs = n1_pucch_an_cs_list[i];
for (uint32_t j = 0; j < SRSLTE_PUCCH_SIZE_AN_CS; j++) {
cfg->ul_cfg.pucch.n1_pucch_an_cs[j][i] = n1_pucch_an_cs[j];
}
}
} else {
cfg->ul_cfg.pucch.ack_nack_feedback_mode = SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_NORMAL;
}
}
} else {
// Do nothing
}
}
}
if (asn1_type.pusch_cfg_ded_present) {
cfg->ul_cfg.pusch.uci_offset.I_offset_ack = asn1_type.pusch_cfg_ded.beta_offset_ack_idx;
cfg->ul_cfg.pusch.uci_offset.I_offset_cqi = asn1_type.pusch_cfg_ded.beta_offset_cqi_idx;
cfg->ul_cfg.pusch.uci_offset.I_offset_ri = asn1_type.pusch_cfg_ded.beta_offset_ri_idx;
}
if (asn1_type.ul_pwr_ctrl_ded_present) {
cfg->ul_cfg.power_ctrl.p0_ue_pusch = asn1_type.ul_pwr_ctrl_ded.p0_ue_pusch;
cfg->ul_cfg.power_ctrl.delta_mcs_based =
asn1_type.ul_pwr_ctrl_ded.delta_mcs_enabled == asn1::rrc::ul_pwr_ctrl_ded_s::delta_mcs_enabled_e_::en0;
cfg->ul_cfg.power_ctrl.acc_enabled = asn1_type.ul_pwr_ctrl_ded.accumulation_enabled;
cfg->ul_cfg.power_ctrl.p0_ue_pucch = asn1_type.ul_pwr_ctrl_ded.p0_ue_pucch;
cfg->ul_cfg.power_ctrl.p_srs_offset = asn1_type.ul_pwr_ctrl_ded.p_srs_offset;
}
if (asn1_type.ul_pwr_ctrl_ded.filt_coef_present) {
// TODO
}
if (asn1_type.tpc_pdcch_cfg_pucch_present) {
// TODO
}
if (asn1_type.tpc_pdcch_cfg_pusch_present) {
// TODO
}
if (asn1_type.cqi_report_cfg_present) {
if (asn1_type.cqi_report_cfg.cqi_report_periodic_present) {
cfg->dl_cfg.cqi_report.periodic_configured =
asn1_type.cqi_report_cfg.cqi_report_periodic.type() == asn1::rrc::setup_e::setup;
if (cfg->dl_cfg.cqi_report.periodic_configured) {
cfg->ul_cfg.pucch.n_pucch_2 = asn1_type.cqi_report_cfg.cqi_report_periodic.setup().cqi_pucch_res_idx;
cfg->ul_cfg.pucch.simul_cqi_ack = asn1_type.cqi_report_cfg.cqi_report_periodic.setup().simul_ack_nack_and_cqi;
cfg->dl_cfg.cqi_report.pmi_idx = asn1_type.cqi_report_cfg.cqi_report_periodic.setup().cqi_pmi_cfg_idx;
cfg->dl_cfg.cqi_report.format_is_subband =
asn1_type.cqi_report_cfg.cqi_report_periodic.setup().cqi_format_ind_periodic.type().value ==
asn1::rrc::cqi_report_periodic_c::setup_s_::cqi_format_ind_periodic_c_::types::subband_cqi;
if (cfg->dl_cfg.cqi_report.format_is_subband) {
cfg->dl_cfg.cqi_report.subband_size =
asn1_type.cqi_report_cfg.cqi_report_periodic.setup().cqi_format_ind_periodic.subband_cqi().k;
}
if (asn1_type.cqi_report_cfg.cqi_report_periodic.setup().ri_cfg_idx_present) {
cfg->dl_cfg.cqi_report.ri_idx = asn1_type.cqi_report_cfg.cqi_report_periodic.setup().ri_cfg_idx;
cfg->dl_cfg.cqi_report.ri_idx_present = true;
} else {
cfg->dl_cfg.cqi_report.ri_idx_present = false;
}
} else {
cfg->ul_cfg.pucch.n_pucch_2 = 0;
cfg->ul_cfg.pucch.simul_cqi_ack = false;
}
}
if (asn1_type.cqi_report_cfg.cqi_report_mode_aperiodic_present) {
cfg->dl_cfg.cqi_report.aperiodic_configured = true;
cfg->dl_cfg.cqi_report.aperiodic_mode = make_aperiodic_mode(asn1_type.cqi_report_cfg.cqi_report_mode_aperiodic);
}
}
if (asn1_type.cqi_report_cfg_pcell_v1250.is_present()) {
auto cqi_report_cfg_pcell_v1250 = asn1_type.cqi_report_cfg_pcell_v1250.get();
if (cqi_report_cfg_pcell_v1250->alt_cqi_table_r12_present) {
cfg->dl_cfg.pdsch.use_tbs_index_alt = true;
}
} else {
cfg->dl_cfg.pdsch.use_tbs_index_alt = false;
}
if (asn1_type.srs_ul_cfg_ded_present) {
cfg->ul_cfg.srs.dedicated_enabled = asn1_type.srs_ul_cfg_ded.type() == asn1::rrc::setup_e::setup;
if (cfg->ul_cfg.srs.dedicated_enabled) {
cfg->ul_cfg.srs.configured = cfg->ul_cfg.srs.dedicated_enabled and cfg->ul_cfg.srs.common_enabled;
cfg->ul_cfg.srs.I_srs = asn1_type.srs_ul_cfg_ded.setup().srs_cfg_idx;
cfg->ul_cfg.srs.B = asn1_type.srs_ul_cfg_ded.setup().srs_bw;
cfg->ul_cfg.srs.b_hop = asn1_type.srs_ul_cfg_ded.setup().srs_hop_bw;
cfg->ul_cfg.srs.n_rrc = asn1_type.srs_ul_cfg_ded.setup().freq_domain_position;
cfg->ul_cfg.srs.k_tc = asn1_type.srs_ul_cfg_ded.setup().tx_comb;
cfg->ul_cfg.srs.n_srs = asn1_type.srs_ul_cfg_ded.setup().cyclic_shift;
}
}
if (asn1_type.ant_info_r10.is_present() &&
asn1_type.ant_info_r10->type() == asn1::rrc::phys_cfg_ded_s::ant_info_r10_c_::types::explicit_value_r10) {
// Parse Release 10
asn1::rrc::ant_info_ded_r10_s::tx_mode_r10_e_::options tx_mode =
asn1_type.ant_info_r10->explicit_value_r10().tx_mode_r10.value;
if ((srslte_tm_t)tx_mode < SRSLTE_TMINV) {
cfg->dl_cfg.tm = (srslte_tm_t)tx_mode;
} else {
fprintf(stderr,
"Transmission mode (R10) %s is not supported\n",
asn1_type.ant_info_r10->explicit_value_r10().tx_mode_r10.to_string().c_str());
}
} else if (asn1_type.ant_info_present &&
asn1_type.ant_info.type() == asn1::rrc::phys_cfg_ded_s::ant_info_c_::types::explicit_value) {
// Parse Release 8
asn1::rrc::ant_info_ded_s::tx_mode_e_::options tx_mode = asn1_type.ant_info.explicit_value().tx_mode.value;
if ((srslte_tm_t)tx_mode < SRSLTE_TMINV) {
cfg->dl_cfg.tm = (srslte_tm_t)tx_mode;
} else {
fprintf(stderr,
"Transmission mode (R8) %s is not supported\n",
asn1_type.ant_info.explicit_value().tx_mode.to_string().c_str());
}
}
if (asn1_type.sched_request_cfg_present) {
if (asn1_type.sched_request_cfg_present and asn1_type.sched_request_cfg.type() == asn1::rrc::setup_e::setup) {
cfg->ul_cfg.pucch.I_sr = asn1_type.sched_request_cfg.setup().sr_cfg_idx;
cfg->ul_cfg.pucch.n_pucch_sr = asn1_type.sched_request_cfg.setup().sr_pucch_res_idx;
cfg->ul_cfg.pucch.sr_configured = true;
} else {
cfg->ul_cfg.pucch.I_sr = 0;
cfg->ul_cfg.pucch.n_pucch_sr = 0;
cfg->ul_cfg.pucch.sr_configured = false;
}
}
if (asn1_type.pdsch_cfg_ded_present) {
// Configure PDSCH
if (asn1_type.pdsch_cfg_ded_present && cfg->dl_cfg.pdsch.p_b < 4) {
cfg->dl_cfg.pdsch.p_a = asn1_type.pdsch_cfg_ded.p_a.to_number();
cfg->dl_cfg.pdsch.power_scale = true;
} else {
cfg->dl_cfg.pdsch.power_scale = false;
}
}
}
void set_phy_cfg_t_common_prach(phy_cfg_t* cfg, const asn1::rrc::prach_cfg_info_s* asn1_type, uint32_t root_seq_idx)
{
if (asn1_type) {
cfg->prach_cfg.config_idx = asn1_type->prach_cfg_idx;
cfg->prach_cfg.zero_corr_zone = asn1_type->zero_correlation_zone_cfg;
cfg->prach_cfg.freq_offset = asn1_type->prach_freq_offset;
cfg->prach_cfg.hs_flag = asn1_type->high_speed_flag;
}
cfg->prach_cfg.root_seq_idx = root_seq_idx;
}
void set_phy_cfg_t_common_pdsch(phy_cfg_t* cfg, const asn1::rrc::pdsch_cfg_common_s& asn1_type)
{
cfg->dl_cfg.pdsch.rs_power = (float)asn1_type.ref_sig_pwr;
cfg->dl_cfg.pdsch.p_b = asn1_type.p_b;
}
void set_phy_cfg_t_enable_64qam(phy_cfg_t* cfg, const bool enabled)
{
cfg->ul_cfg.pusch.enable_64qam = enabled;
}
void set_phy_cfg_t_common_pusch(phy_cfg_t* cfg, const asn1::rrc::pusch_cfg_common_s& asn1_type)
{
/* PUSCH DMRS signal configuration */
bzero(&cfg->ul_cfg.dmrs, sizeof(srslte_refsignal_dmrs_pusch_cfg_t));
cfg->ul_cfg.dmrs.group_hopping_en = asn1_type.ul_ref_sigs_pusch.group_hop_enabled;
cfg->ul_cfg.dmrs.sequence_hopping_en = asn1_type.ul_ref_sigs_pusch.seq_hop_enabled;
cfg->ul_cfg.dmrs.cyclic_shift = asn1_type.ul_ref_sigs_pusch.cyclic_shift;
cfg->ul_cfg.dmrs.delta_ss = asn1_type.ul_ref_sigs_pusch.group_assign_pusch;
/* PUSCH Hopping configuration */
bzero(&cfg->ul_cfg.hopping, sizeof(srslte_pusch_hopping_cfg_t));
cfg->ul_cfg.hopping.n_sb = asn1_type.pusch_cfg_basic.n_sb;
cfg->ul_cfg.hopping.hopping_offset = asn1_type.pusch_cfg_basic.pusch_hop_offset;
cfg->ul_cfg.hopping.hop_mode =
asn1_type.pusch_cfg_basic.hop_mode.value ==
asn1::rrc::pusch_cfg_common_s::pusch_cfg_basic_s_::hop_mode_e_::intra_and_inter_sub_frame
? cfg->ul_cfg.hopping.SRSLTE_PUSCH_HOP_MODE_INTRA_SF
: cfg->ul_cfg.hopping.SRSLTE_PUSCH_HOP_MODE_INTER_SF;
}
void set_phy_cfg_t_common_pucch(phy_cfg_t* cfg, const asn1::rrc::pucch_cfg_common_s& asn1_type)
{
/* PUCCH configuration */
cfg->ul_cfg.pucch.delta_pucch_shift = asn1_type.delta_pucch_shift.to_number();
cfg->ul_cfg.pucch.N_cs = asn1_type.n_cs_an;
cfg->ul_cfg.pucch.n_rb_2 = asn1_type.n_rb_cqi;
cfg->ul_cfg.pucch.N_pucch_1 = asn1_type.n1_pucch_an;
}
void set_phy_cfg_t_common_srs(phy_cfg_t* cfg, const asn1::rrc::srs_ul_cfg_common_c& asn1_type)
{
cfg->ul_cfg.srs.common_enabled = asn1_type.type() == asn1::rrc::setup_e::setup;
if (cfg->ul_cfg.srs.common_enabled) {
cfg->ul_cfg.srs.simul_ack = asn1_type.setup().ack_nack_srs_simul_tx;
cfg->ul_cfg.srs.bw_cfg = asn1_type.setup().srs_bw_cfg.to_number();
cfg->ul_cfg.srs.subframe_config = asn1_type.setup().srs_sf_cfg.to_number();
}
}
void set_phy_cfg_t_common_pwr_ctrl(phy_cfg_t* cfg, const asn1::rrc::ul_pwr_ctrl_common_s& asn1_type)
{
cfg->ul_cfg.power_ctrl.p0_nominal_pusch = asn1_type.p0_nominal_pusch;
cfg->ul_cfg.power_ctrl.alpha = asn1_type.alpha.to_number();
cfg->ul_cfg.power_ctrl.p0_nominal_pucch = asn1_type.p0_nominal_pucch;
cfg->ul_cfg.power_ctrl.delta_f_pucch[0] = asn1_type.delta_flist_pucch.delta_f_pucch_format1.to_number();
cfg->ul_cfg.power_ctrl.delta_f_pucch[1] = asn1_type.delta_flist_pucch.delta_f_pucch_format1b.to_number();
cfg->ul_cfg.power_ctrl.delta_f_pucch[2] = asn1_type.delta_flist_pucch.delta_f_pucch_format2.to_number();
cfg->ul_cfg.power_ctrl.delta_f_pucch[3] = asn1_type.delta_flist_pucch.delta_f_pucch_format2a.to_number();
cfg->ul_cfg.power_ctrl.delta_f_pucch[4] = asn1_type.delta_flist_pucch.delta_f_pucch_format2b.to_number();
cfg->ul_cfg.power_ctrl.delta_preamble_msg3 = asn1_type.delta_preamb_msg3;
}
void set_phy_cfg_t_scell_config(phy_cfg_t* cfg, const asn1::rrc::scell_to_add_mod_r10_s& asn1_type)
{
if (asn1_type.rr_cfg_common_scell_r10_present) {
// Enable always CSI request extra bit
cfg->dl_cfg.dci.multiple_csi_request_enabled = true;
auto* rr_cfg_common_scell_r10 = &asn1_type.rr_cfg_common_scell_r10;
if (rr_cfg_common_scell_r10->ul_cfg_r10_present) {
auto* ul_cfg_r10 = &rr_cfg_common_scell_r10->ul_cfg_r10;
// Parse Power control
auto* ul_pwr_ctrl_common_scell_r10 = &ul_cfg_r10->ul_pwr_ctrl_common_scell_r10;
bzero(&cfg->ul_cfg.power_ctrl, sizeof(srslte_ue_ul_powerctrl_t));
cfg->ul_cfg.power_ctrl.p0_nominal_pusch = ul_pwr_ctrl_common_scell_r10->p0_nominal_pusch_r10;
cfg->ul_cfg.power_ctrl.alpha = ul_pwr_ctrl_common_scell_r10->alpha_r10.to_number();
// Parse SRS
cfg->ul_cfg.srs.common_enabled = ul_cfg_r10->srs_ul_cfg_common_r10.type() == asn1::rrc::setup_e::setup;
if (cfg->ul_cfg.srs.common_enabled) {
auto* srs_ul_cfg_common = &ul_cfg_r10->srs_ul_cfg_common_r10.setup();
cfg->ul_cfg.srs.simul_ack = srs_ul_cfg_common->ack_nack_srs_simul_tx;
cfg->ul_cfg.srs.bw_cfg = srs_ul_cfg_common->srs_bw_cfg.to_number();
cfg->ul_cfg.srs.subframe_config = srs_ul_cfg_common->srs_sf_cfg.to_number();
}
// Parse PUSCH
auto* pusch_cfg_common = &ul_cfg_r10->pusch_cfg_common_r10;
bzero(&cfg->ul_cfg.hopping, sizeof(srslte_pusch_hopping_cfg_t));
cfg->ul_cfg.hopping.n_sb = pusch_cfg_common->pusch_cfg_basic.n_sb;
cfg->ul_cfg.hopping.hop_mode =
pusch_cfg_common->pusch_cfg_basic.hop_mode.value ==
asn1::rrc::pusch_cfg_common_s::pusch_cfg_basic_s_::hop_mode_e_::intra_and_inter_sub_frame
? cfg->ul_cfg.hopping.SRSLTE_PUSCH_HOP_MODE_INTRA_SF
: cfg->ul_cfg.hopping.SRSLTE_PUSCH_HOP_MODE_INTER_SF;
cfg->ul_cfg.hopping.hopping_offset = pusch_cfg_common->pusch_cfg_basic.pusch_hop_offset;
cfg->ul_cfg.pusch.enable_64qam = pusch_cfg_common->pusch_cfg_basic.enable64_qam;
}
}
if (asn1_type.rr_cfg_ded_scell_r10_present) {
auto* rr_cfg_ded_scell_r10 = &asn1_type.rr_cfg_ded_scell_r10;
if (rr_cfg_ded_scell_r10->phys_cfg_ded_scell_r10_present) {
auto* phys_cfg_ded_scell_r10 = &rr_cfg_ded_scell_r10->phys_cfg_ded_scell_r10;
// Parse nonUL Configuration
if (phys_cfg_ded_scell_r10->non_ul_cfg_r10_present) {
auto* non_ul_cfg = &phys_cfg_ded_scell_r10->non_ul_cfg_r10;
// Parse Transmission mode
if (non_ul_cfg->ant_info_r10_present) {
if (non_ul_cfg->ant_info_r10.tx_mode_r10.to_number() < (uint8_t)SRSLTE_TMINV) {
cfg->dl_cfg.tm = (srslte_tm_t)non_ul_cfg->ant_info_r10.tx_mode_r10.to_number();
} else {
fprintf(stderr,
"Transmission mode (R10) %s is not supported\n",
non_ul_cfg->ant_info_r10.tx_mode_r10.to_string().c_str());
}
}
// Parse Cross carrier scheduling
if (non_ul_cfg->cross_carrier_sched_cfg_r10_present) {
typedef asn1::rrc::cross_carrier_sched_cfg_r10_s::sched_cell_info_r10_c_ sched_info_t;
typedef sched_info_t::types cross_carrier_type_e;
auto* sched_info = &non_ul_cfg->cross_carrier_sched_cfg_r10.sched_cell_info_r10;
cross_carrier_type_e cross_carrier_type = sched_info->type();
if (cross_carrier_type == cross_carrier_type_e::own_r10) {
cfg->dl_cfg.dci.cif_present = sched_info->own_r10().cif_presence_r10;
} else {
cfg->dl_cfg.dci.cif_present = false; // This CC does not have Carrier Indicator Field
// ue_cfg->dl_cfg.blablabla = sched_info->other_r10().pdsch_start_r10;
// ue_cfg->dl_cfg.blablabla = sched_info->other_r10().sched_cell_id_r10;
}
}
// Parse pdsch config dedicated
if (non_ul_cfg->pdsch_cfg_ded_r10_present) {
cfg->dl_cfg.pdsch.p_b = asn1_type.rr_cfg_common_scell_r10.non_ul_cfg_r10.pdsch_cfg_common_r10.p_b;
cfg->dl_cfg.pdsch.p_a = non_ul_cfg->pdsch_cfg_ded_r10.p_a.to_number();
cfg->dl_cfg.pdsch.power_scale = true;
}
}
// Parse UL Configuration
if (phys_cfg_ded_scell_r10->ul_cfg_r10_present) {
auto* ul_cfg_r10 = &phys_cfg_ded_scell_r10->ul_cfg_r10;
// Parse CQI param
if (ul_cfg_r10->cqi_report_cfg_scell_r10_present) {
auto* cqi_report_cfg = &ul_cfg_r10->cqi_report_cfg_scell_r10;
// Aperiodic report
if (cqi_report_cfg->cqi_report_mode_aperiodic_r10_present) {
cfg->dl_cfg.cqi_report.aperiodic_configured = true;
cfg->dl_cfg.cqi_report.aperiodic_mode = make_aperiodic_mode(cqi_report_cfg->cqi_report_mode_aperiodic_r10);
}
// Periodic report
if (cqi_report_cfg->cqi_report_periodic_scell_r10_present) {
if (cqi_report_cfg->cqi_report_periodic_scell_r10.type() == asn1::rrc::setup_e::setup) {
typedef asn1::rrc::cqi_report_periodic_r10_c::setup_s_ cqi_cfg_t;
cqi_cfg_t cqi_cfg = cqi_report_cfg->cqi_report_periodic_scell_r10.setup();
cfg->dl_cfg.cqi_report.periodic_configured = true;
cfg->dl_cfg.cqi_report.pmi_idx = cqi_cfg.cqi_pmi_cfg_idx;
cfg->dl_cfg.cqi_report.format_is_subband =
cqi_cfg.cqi_format_ind_periodic_r10.type().value ==
cqi_cfg_t::cqi_format_ind_periodic_r10_c_::types::subband_cqi_r10;
if (cfg->dl_cfg.cqi_report.format_is_subband) {
cfg->dl_cfg.cqi_report.subband_size = cqi_cfg.cqi_format_ind_periodic_r10.subband_cqi_r10().k;
}
if (cqi_cfg.ri_cfg_idx_present) {
cfg->dl_cfg.cqi_report.ri_idx = cqi_cfg.ri_cfg_idx;
cfg->dl_cfg.cqi_report.ri_idx_present = true;
} else {
cfg->dl_cfg.cqi_report.ri_idx_present = false;
}
} else {
// Release, disable periodic reporting
cfg->dl_cfg.cqi_report.periodic_configured = false;
}
}
}
// Sounding reference signals Dedicated
if (ul_cfg_r10->srs_ul_cfg_ded_r10_present) {
cfg->ul_cfg.srs.dedicated_enabled = ul_cfg_r10->srs_ul_cfg_ded_r10.type() == asn1::rrc::setup_e::setup;
if (cfg->ul_cfg.srs.dedicated_enabled) {
auto* srs_ul_cfg_ded_r10 = &ul_cfg_r10->srs_ul_cfg_ded_r10.setup();
cfg->ul_cfg.srs.configured = cfg->ul_cfg.srs.dedicated_enabled and cfg->ul_cfg.srs.common_enabled;
cfg->ul_cfg.srs.I_srs = srs_ul_cfg_ded_r10->srs_cfg_idx;
cfg->ul_cfg.srs.B = srs_ul_cfg_ded_r10->srs_bw;
cfg->ul_cfg.srs.b_hop = srs_ul_cfg_ded_r10->srs_hop_bw;
cfg->ul_cfg.srs.n_rrc = srs_ul_cfg_ded_r10->freq_domain_position;
cfg->ul_cfg.srs.k_tc = srs_ul_cfg_ded_r10->tx_comb;
cfg->ul_cfg.srs.n_srs = srs_ul_cfg_ded_r10->cyclic_shift;
}
}
}
if (phys_cfg_ded_scell_r10->cqi_report_cfg_scell_v1250.is_present()) {
// Enable/disable PDSCH 256QAM
auto cqi_report_cfg_scell = phys_cfg_ded_scell_r10->cqi_report_cfg_scell_v1250.get();
cfg->dl_cfg.pdsch.use_tbs_index_alt = cqi_report_cfg_scell->alt_cqi_table_r12_present;
} else {
// Assume there is no PDSCH 256QAM
cfg->dl_cfg.pdsch.use_tbs_index_alt = false;
}
}
}
}
// MBMS
mbms_notif_cfg_t make_mbms_notif_cfg(const asn1::rrc::mbms_notif_cfg_r9_s& asn1_type)
{
mbms_notif_cfg_t ret{};
ret.notif_repeat_coeff = (mbms_notif_cfg_t::coeff_t)asn1_type.notif_repeat_coeff_r9.value;
ret.notif_offset = asn1_type.notif_offset_r9;
ret.notif_sf_idx = asn1_type.notif_sf_idx_r9;
return ret;
}
mbsfn_area_info_t make_mbsfn_area_info(const asn1::rrc::mbsfn_area_info_r9_s& asn1_type)
{
mbsfn_area_info_t ret{};
ret.mbsfn_area_id = asn1_type.mbsfn_area_id_r9;
ret.non_mbsfn_region_len = (mbsfn_area_info_t::region_len_t)asn1_type.non_mbsfn_region_len.value;
ret.notif_ind = asn1_type.notif_ind_r9;
ret.mcch_cfg.mcch_repeat_period =
(mbsfn_area_info_t::mcch_cfg_t::repeat_period_t)asn1_type.mcch_cfg_r9.mcch_repeat_period_r9.value;
ret.mcch_cfg.mcch_offset = asn1_type.mcch_cfg_r9.mcch_offset_r9;
ret.mcch_cfg.mcch_mod_period =
(mbsfn_area_info_t::mcch_cfg_t::mod_period_t)asn1_type.mcch_cfg_r9.mcch_mod_period_r9.value;
ret.mcch_cfg.sf_alloc_info = asn1_type.mcch_cfg_r9.sf_alloc_info_r9.to_number();
ret.mcch_cfg.sig_mcs = (mbsfn_area_info_t::mcch_cfg_t::sig_mcs_t)asn1_type.mcch_cfg_r9.sig_mcs_r9.value;
return ret;
}
mbsfn_sf_cfg_t make_mbsfn_sf_cfg(const asn1::rrc::mbsfn_sf_cfg_s& sf_cfg)
{
mbsfn_sf_cfg_t cfg{};
cfg.radioframe_alloc_period = (mbsfn_sf_cfg_t::alloc_period_t)sf_cfg.radioframe_alloc_period.value;
cfg.radioframe_alloc_offset = sf_cfg.radioframe_alloc_offset;
cfg.nof_alloc_subfrs = (mbsfn_sf_cfg_t::sf_alloc_type_t)sf_cfg.sf_alloc.type().value;
if (sf_cfg.sf_alloc.type().value == asn1::rrc::mbsfn_sf_cfg_s::sf_alloc_c_::types_opts::one_frame) {
cfg.sf_alloc = sf_cfg.sf_alloc.one_frame().to_number();
} else {
cfg.sf_alloc = sf_cfg.sf_alloc.four_frames().to_number();
}
return cfg;
}
pmch_info_t make_pmch_info(const asn1::rrc::pmch_info_r9_s& asn1_type)
{
pmch_info_t ret{};
ret.sf_alloc_end = asn1_type.pmch_cfg_r9.sf_alloc_end_r9;
ret.data_mcs = asn1_type.pmch_cfg_r9.data_mcs_r9;
ret.mch_sched_period = (pmch_info_t::mch_sched_period_t)asn1_type.pmch_cfg_r9.mch_sched_period_r9.value;
ret.nof_mbms_session_info = asn1_type.mbms_session_info_list_r9.size();
for (uint32_t i = 0; i < ret.nof_mbms_session_info; ++i) {
auto& asn1item = asn1_type.mbms_session_info_list_r9[i];
auto& item = ret.mbms_session_info_list[i];
item.session_id_present = asn1item.session_id_r9_present;
item.lc_ch_id = asn1item.lc_ch_id_r9;
item.session_id = asn1item.session_id_r9[0];
item.tmgi.plmn_id_type = (tmgi_t::plmn_id_type_t)asn1item.tmgi_r9.plmn_id_r9.type().value;
if (item.tmgi.plmn_id_type == tmgi_t::plmn_id_type_t::plmn_idx) {
item.tmgi.plmn_id.plmn_idx = asn1item.tmgi_r9.plmn_id_r9.plmn_idx_r9();
} else {
item.tmgi.plmn_id.explicit_value = make_plmn_id_t(asn1item.tmgi_r9.plmn_id_r9.explicit_value_r9());
}
memcpy(item.tmgi.serviced_id, &asn1item.tmgi_r9.service_id_r9[0], 3);
}
return ret;
}
mcch_msg_t make_mcch_msg(const asn1::rrc::mcch_msg_s& asn1_type)
{
mcch_msg_t msg{};
auto& r9 = asn1_type.msg.c1().mbsfn_area_cfg_r9();
msg.nof_common_sf_alloc = r9.common_sf_alloc_r9.size();
for (uint32_t i = 0; i < msg.nof_common_sf_alloc; ++i) {
msg.common_sf_alloc[i] = make_mbsfn_sf_cfg(r9.common_sf_alloc_r9[i]);
}
msg.common_sf_alloc_period = (mcch_msg_t::common_sf_alloc_period_t)r9.common_sf_alloc_period_r9.value;
msg.nof_pmch_info = r9.pmch_info_list_r9.size();
for (uint32_t i = 0; i < msg.nof_pmch_info; ++i) {
msg.pmch_info_list[i] = make_pmch_info(r9.pmch_info_list_r9[i]);
}
return msg;
}
static_assert(ASN1_RRC_MAX_SESSION_PER_PMCH == pmch_info_t::max_session_per_pmch, "ASN1 to srsLTE interface mismatch");
sib13_t make_sib13(const asn1::rrc::sib_type13_r9_s& asn1_type)
{
sib13_t sib13{};
sib13.nof_mbsfn_area_info = asn1_type.mbsfn_area_info_list_r9.size();
for (uint32_t i = 0; i < asn1_type.mbsfn_area_info_list_r9.size(); ++i) {
sib13.mbsfn_area_info_list[i] = make_mbsfn_area_info(asn1_type.mbsfn_area_info_list_r9[i]);
}
sib13.notif_cfg = make_mbms_notif_cfg(asn1_type.notif_cfg_r9);
return sib13;
}
} // namespace srslte } // namespace srslte

@ -21,6 +21,9 @@
file(GLOB CXX_SOURCES "*.cc") file(GLOB CXX_SOURCES "*.cc")
file(GLOB C_SOURCES "*.c") file(GLOB C_SOURCES "*.c")
# Avoid warnings caused by libmbedtls about deprecated functions
set_source_files_properties(security.cc PROPERTIES COMPILE_FLAGS -Wno-deprecated-declarations)
add_library(srslte_common STATIC ${C_SOURCES} ${CXX_SOURCES}) add_library(srslte_common STATIC ${C_SOURCES} ${CXX_SOURCES})
add_custom_target(gen_build_info COMMAND cmake -P ${CMAKE_BINARY_DIR}/SRSLTEbuildinfo.cmake) add_custom_target(gen_build_info COMMAND cmake -P ${CMAKE_BINARY_DIR}/SRSLTEbuildinfo.cmake)
add_dependencies(srslte_common gen_build_info) add_dependencies(srslte_common gen_build_info)

@ -50,4 +50,4 @@ void byte_buffer_pool::cleanup(void)
pthread_mutex_unlock(&instance_mutex); pthread_mutex_unlock(&instance_mutex);
} }
} // namespace srsue } // namespace srslte

@ -37,6 +37,7 @@
#include "srslte/common/liblte_security.h" #include "srslte/common/liblte_security.h"
#include "math.h" #include "math.h"
#include "srslte/common/liblte_ssl.h" #include "srslte/common/liblte_ssl.h"
#include "srslte/common/zuc.h"
/******************************************************************************* /*******************************************************************************
DEFINES DEFINES
@ -807,6 +808,88 @@ LIBLTE_ERROR_ENUM liblte_security_128_eia2(
return (err); return (err);
} }
u32 GET_WORD(u32* DATA, u32 i)
{
u32 WORD, ti;
ti = i % 32;
if (ti == 0)
WORD = DATA[i / 32];
else
WORD = (DATA[i / 32] << ti) | (DATA[i / 32 + 1] >> (32 - ti));
return WORD;
}
u8 GET_BIT(uint8_t* DATA, u32 i)
{
return (DATA[i / 8] & (1 << (7 - (i % 8)))) ? 1 : 0;
}
LIBLTE_ERROR_ENUM liblte_security_128_eia3(
uint8* key, uint32 count, uint8 bearer, uint8 direction, uint8* msg, uint32 msg_len, uint8* mac)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
uint8_t iv[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
uint32* ks;
uint32 msg_len_block_8, msg_len_block_32, m;
if (key != NULL && msg != NULL && mac != NULL) {
msg_len_block_8 = (msg_len + 7) / 8;
msg_len_block_32 = (msg_len + 31) / 32;
// Construct iv
iv[0] = (count >> 24) & 0xFF;
iv[1] = (count >> 16) & 0xFF;
iv[2] = (count >> 8) & 0xFF;
iv[3] = count & 0xFF;
iv[4] = (bearer << 3) & 0xF8;
iv[5] = iv[6] = iv[7] = 0;
iv[8] = ((count >> 24) & 0xFF) ^ ((direction & 1) << 7);
iv[9] = (count >> 16) & 0xFF;
iv[10] = (count >> 8) & 0xFF;
iv[11] = count & 0xFF;
iv[12] = iv[4];
iv[13] = iv[5];
iv[14] = iv[6] ^ ((direction & 1) << 7);
iv[15] = iv[7];
zuc_state_t zuc_state;
// Initialize keystream
zuc_initialize(&zuc_state, key, iv);
// Generate keystream
int N = msg_len + 64;
int L = (N + 31) / 32;
ks = (uint32*)calloc(L, sizeof(uint32));
zuc_generate_keystream(&zuc_state, L, ks);
uint32_t T = 0;
for (uint32_t i = 0; i < msg_len; i++) {
if (GET_BIT(msg, i)) {
T ^= GET_WORD(ks, i);
}
}
T ^= GET_WORD(ks, msg_len);
uint32_t mac_tmp = T ^ ks[L - 1];
mac[0] = (mac_tmp >> 24) & 0xFF;
mac[1] = (mac_tmp >> 16) & 0xFF;
mac[2] = (mac_tmp >> 8) & 0xFF;
mac[3] = mac_tmp & 0xFF;
free(ks);
}
return (err);
}
/********************************************************************* /*********************************************************************
Name: liblte_security_encryption_eea1 Name: liblte_security_encryption_eea1
@ -951,6 +1034,89 @@ LIBLTE_ERROR_ENUM liblte_security_decryption_eea2(
return liblte_security_encryption_eea2(key, count, bearer, direction, ct, ct_len, out); return liblte_security_encryption_eea2(key, count, bearer, direction, ct, ct_len, out);
} }
/*********************************************************************
Name: liblte_security_encryption_eea1
Description: 128-bit encryption algorithm EEA1.
Document Reference: 33.401 v13.1.0 Annex B.1.2
35.215 v13.0.0 References
Specification of the 3GPP Confidentiality and
Integrity Algorithms UEA2 & UIA2 D1 v2.1
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_security_encryption_eea3(
uint8* key, uint32 count, uint8 bearer, uint8 direction, uint8* msg, uint32 msg_len, uint8* out)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
uint8_t iv[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
uint32* ks;
int32 i;
uint32 msg_len_block_8, msg_len_block_32, m;
if (key != NULL && msg != NULL && out != NULL) {
msg_len_block_8 = (msg_len + 7) / 8;
msg_len_block_32 = (msg_len + 31) / 32;
// Construct iv
iv[0] = (count >> 24) & 0xFF;
iv[1] = (count >> 16) & 0xFF;
iv[2] = (count >> 8) & 0xFF;
iv[3] = (count)&0xFF;
iv[4] = ((bearer & 0x1F) << 3) | ((direction & 0x01) << 2);
iv[5] = 0;
iv[6] = 0;
iv[7] = 0;
iv[8] = iv[0];
iv[9] = iv[1];
iv[10] = iv[2];
iv[11] = iv[3];
iv[12] = iv[4];
iv[13] = iv[5];
iv[14] = iv[6];
iv[15] = iv[7];
zuc_state_t zuc_state;
// Initialize keystream
zuc_initialize(&zuc_state, key, iv);
// Generate keystream
ks = (uint32*)calloc(msg_len_block_32, sizeof(uint32));
zuc_generate_keystream(&zuc_state, msg_len_block_32, ks);
// Generate output except last block
for (i = 0; i < (int32_t)msg_len_block_32 - 1; i++) {
out[4 * i + 0] = msg[4 * i + 0] ^ ((ks[i] >> 24) & 0xFF);
out[4 * i + 1] = msg[4 * i + 1] ^ ((ks[i] >> 16) & 0xFF);
out[4 * i + 2] = msg[4 * i + 2] ^ ((ks[i] >> 8) & 0xFF);
out[4 * i + 3] = msg[4 * i + 3] ^ ((ks[i] & 0xFF));
}
// Process last bytes
for (i = (msg_len_block_32 - 1) * 4; i < (int32_t)msg_len_block_8; i++) {
out[i] = msg[i] ^ ((ks[i / 4] >> ((3 - (i % 4)) * 8)) & 0xFF);
}
// Zero tailing bits
zero_tailing_bits(out, msg_len);
// Clean up
free(ks);
// zuc_deinitialize(state_ptr);
err = LIBLTE_SUCCESS;
}
return (err);
}
LIBLTE_ERROR_ENUM liblte_security_decryption_eea3(
uint8* key, uint32 count, uint8 bearer, uint8 direction, uint8* msg, uint32 msg_len, uint8* out)
{
return liblte_security_encryption_eea3(key, count, bearer, direction, msg, msg_len, out);
}
/********************************************************************* /*********************************************************************
Name: liblte_security_milenage_f1 Name: liblte_security_milenage_f1

@ -65,216 +65,173 @@ void log_filter::init(std::string layer, logger *logger_, bool tti)
do_tti = tti; do_tti = tti;
} }
void log_filter::all_log(srslte::LOG_LEVEL_ENUM level, void log_filter::all_log(
uint32_t tti, srslte::LOG_LEVEL_ENUM level, uint32_t tti, const char* msg, const uint8_t* hex, int size, bool long_msg)
const char *msg)
{ {
if(logger_h) { char buffer_tti[16] = {};
std::stringstream ss; char buffer_time[64] = {};
ss << now_time() << " ";
if (show_layer_en) {
ss << "[" <<get_service_name() << "] ";
}
if (level_text_short) {
ss << log_level_text_short[level] << " ";
} else {
ss << log_level_text[level] << " ";
}
if(do_tti) {
ss << "[" << std::setfill('0') << std::setw(5) << tti << "] ";
}
if (add_string_en) {
ss << add_string_val << " ";
}
ss << msg;
str_ptr s_ptr(new std::string(ss.str()));
logger_h->log(s_ptr);
}
}
void log_filter::all_log(srslte::LOG_LEVEL_ENUM level,
uint32_t tti,
const char *msg,
const uint8_t *hex,
int size)
{
if (logger_h) { if (logger_h) {
std::stringstream ss; logger::unique_log_str_t log_str = nullptr;
ss << now_time() << " "; if (long_msg) {
if (show_layer_en) { // For long messages, dynamically allocate a new log_str with enough size outside the pool.
ss << "[" <<get_service_name() << "] "; uint32_t log_str_msg_len = sizeof(buffer_tti) + sizeof(buffer_time) + 20 + size;
} log_str = logger::unique_log_str_t(new logger::log_str(nullptr, log_str_msg_len), logger::log_str_deleter());
if (level_text_short) {
ss << log_level_text_short[level] << " ";
} else { } else {
ss << log_level_text[level] << " "; log_str = logger_h->allocate_unique_log_str();
} }
if (log_str) {
now_time(buffer_time, sizeof(buffer_time));
if (do_tti) { if (do_tti) {
ss << "[" << std::setfill('0') << std::setw(5) << tti << "] "; get_tti_str(tti, buffer_tti, sizeof(buffer_tti));
} }
if (add_string_en) { snprintf(log_str->str(),
ss << add_string_val << " "; log_str->get_buffer_size(),
} "%s [%s] %s %s%s%s%s%s",
ss << msg; buffer_time,
get_service_name().c_str(),
log_level_text_short[level],
do_tti ? buffer_tti : "",
add_string_en ? add_string_val.c_str() : "",
msg,
msg[strlen(msg) - 1] != '\n' ? "\n" : "",
(hex_limit > 0 && hex && size > 0) ? hex_string(hex, size).c_str() : "");
if (msg[strlen(msg)-1] != '\n') { logger_h->log(std::move(log_str));
ss << std::endl; } else {
} logger_h->log_char("Error in Log: Not enough buffers in pool\n");
if (hex_limit > 0 && hex && size > 0) {
ss << hex_string(hex, size);
} }
str_ptr s_ptr(new std::string(ss.str()));
logger_h->log(s_ptr);
} }
} }
void log_filter::console(const char * message, ...) { void log_filter::console(const char * message, ...) {
char *args_msg = NULL; char args_msg[char_buff_size];
va_list args; va_list args;
va_start(args, message); va_start(args, message);
if(vasprintf(&args_msg, message, args) > 0) if (vsnprintf(args_msg, char_buff_size, message, args) > 0)
printf("%s",args_msg); // Print directly to stdout printf("%s",args_msg); // Print directly to stdout
fflush(stdout); fflush(stdout);
va_end(args); va_end(args);
free(args_msg);
} }
#define all_log_expand(log_level) \
do { \
if (level >= log_level) { \
char args_msg[char_buff_size]; \
va_list args; \
va_start(args, message); \
if (vsnprintf(args_msg, char_buff_size, message, args) > 0) \
all_log(log_level, tti, args_msg); \
va_end(args); \
} \
} while (0)
#define all_log_hex_expand(log_level) \
do { \
if (level >= log_level) { \
char args_msg[char_buff_size]; \
va_list args; \
va_start(args, message); \
if (vsnprintf(args_msg, char_buff_size, message, args) > 0) \
all_log(log_level, tti, args_msg, hex, size); \
va_end(args); \
} \
} while (0)
void log_filter::error(const char * message, ...) { void log_filter::error(const char * message, ...) {
if (level >= LOG_LEVEL_ERROR) { all_log_expand(LOG_LEVEL_ERROR);
char *args_msg = NULL;
va_list args;
va_start(args, message);
if(vasprintf(&args_msg, message, args) > 0)
all_log(LOG_LEVEL_ERROR, tti, args_msg);
va_end(args);
free(args_msg);
}
} }
void log_filter::warning(const char * message, ...) { void log_filter::warning(const char * message, ...) {
if (level >= LOG_LEVEL_WARNING) { all_log_expand(LOG_LEVEL_WARNING);
char *args_msg = NULL;
va_list args;
va_start(args, message);
if(vasprintf(&args_msg, message, args) > 0)
all_log(LOG_LEVEL_WARNING, tti, args_msg);
va_end(args);
free(args_msg);
}
} }
void log_filter::info(const char * message, ...) { void log_filter::info(const char * message, ...) {
if (level >= LOG_LEVEL_INFO) { all_log_expand(LOG_LEVEL_INFO);
char *args_msg = NULL;
va_list args;
va_start(args, message);
if(vasprintf(&args_msg, message, args) > 0)
all_log(LOG_LEVEL_INFO, tti, args_msg);
va_end(args);
free(args_msg);
}
} }
void log_filter::debug(const char * message, ...) { void log_filter::debug(const char * message, ...) {
all_log_expand(LOG_LEVEL_DEBUG);
}
void log_filter::debug_long(const char* message, ...)
{
if (level >= LOG_LEVEL_DEBUG) { if (level >= LOG_LEVEL_DEBUG) {
char* args_msg = NULL; char* args_msg = NULL;
va_list args; va_list args;
va_start(args, message); va_start(args, message);
if (vasprintf(&args_msg, message, args) > 0) if (vasprintf(&args_msg, message, args) > 0)
all_log(LOG_LEVEL_DEBUG, tti, args_msg); all_log(LOG_LEVEL_DEBUG, tti, args_msg, nullptr, strlen(args_msg), true);
va_end(args); va_end(args);
free(args_msg); free(args_msg);
} }
} }
void log_filter::error_hex(const uint8_t *hex, int size, const char * message, ...) { void log_filter::error_hex(const uint8_t *hex, int size, const char * message, ...) {
if (level >= LOG_LEVEL_ERROR) { all_log_hex_expand(LOG_LEVEL_ERROR);
char *args_msg = NULL;
va_list args;
va_start(args, message);
if(vasprintf(&args_msg, message, args) > 0)
all_log(LOG_LEVEL_ERROR, tti, args_msg, hex, size);
va_end(args);
free(args_msg);
}
} }
void log_filter::warning_hex(const uint8_t *hex, int size, const char * message, ...) { void log_filter::warning_hex(const uint8_t *hex, int size, const char * message, ...) {
if (level >= LOG_LEVEL_WARNING) { all_log_hex_expand(LOG_LEVEL_WARNING);
char *args_msg = NULL;
va_list args;
va_start(args, message);
if(vasprintf(&args_msg, message, args) > 0)
all_log(LOG_LEVEL_WARNING, tti, args_msg, hex, size);
va_end(args);
free(args_msg);
}
} }
void log_filter::info_hex(const uint8_t *hex, int size, const char * message, ...) { void log_filter::info_hex(const uint8_t *hex, int size, const char * message, ...) {
if (level >= LOG_LEVEL_INFO) { all_log_hex_expand(LOG_LEVEL_INFO);
char *args_msg = NULL;
va_list args;
va_start(args, message);
if(vasprintf(&args_msg, message, args) > 0)
all_log(LOG_LEVEL_INFO, tti, args_msg, hex, size);
va_end(args);
free(args_msg);
}
} }
void log_filter::debug_hex(const uint8_t *hex, int size, const char * message, ...) { void log_filter::debug_hex(const uint8_t *hex, int size, const char * message, ...) {
if (level >= LOG_LEVEL_DEBUG) { all_log_hex_expand(LOG_LEVEL_DEBUG);
char *args_msg = NULL;
va_list args;
va_start(args, message);
if(vasprintf(&args_msg, message, args) > 0)
all_log(LOG_LEVEL_DEBUG, tti, args_msg, hex, size);
va_end(args);
free(args_msg);
}
} }
void log_filter::set_time_src(time_itf *source, time_format_t format) { void log_filter::set_time_src(time_itf *source, time_format_t format) {
this->time_src = source; this->time_src = source;
this->time_format = format; this->time_format = format;
} }
void log_filter::get_tti_str(const uint32_t tti_, char* buffer, const uint32_t buffer_len)
{
snprintf(buffer, buffer_len, "[%5d] ", tti_);
}
std::string log_filter::now_time() void log_filter::now_time(char* buffer, const uint32_t buffer_len)
{ {
struct timeval rawtime; struct timeval rawtime;
struct tm * timeinfo; struct tm * timeinfo;
char buffer[64];
char us[16]; char us[16];
srslte_timestamp_t now; srslte_timestamp_t now;
uint64_t usec_epoch; uint64_t usec_epoch;
if (buffer_len < 16) {
fprintf(stderr, "Error buffer provided for time too small\n");
return;
}
if (!time_src) { if (!time_src) {
gettimeofday(&rawtime, NULL); gettimeofday(&rawtime, NULL);
timeinfo = localtime(&rawtime.tv_sec); timeinfo = localtime(&rawtime.tv_sec);
if (time_format == TIME) { if (time_format == TIME) {
strftime(buffer, 64, "%H:%M:%S", timeinfo); strftime(buffer, buffer_len, "%H:%M:%S.", timeinfo);
strcat(buffer, ".");
snprintf(us, 16, "%06ld", rawtime.tv_usec); snprintf(us, 16, "%06ld", rawtime.tv_usec);
strcat(buffer, us); uint32_t dest_len = strlen(buffer);
strncat(buffer, us, buffer_len - dest_len - 1);
} else { } else {
usec_epoch = rawtime.tv_sec * 1000000 + rawtime.tv_usec; usec_epoch = rawtime.tv_sec * 1000000 + rawtime.tv_usec;
snprintf(buffer, 64, "%ld", usec_epoch); snprintf(buffer, buffer_len, "%ld", usec_epoch);
} }
} else { } else {
now = time_src->get_time(); now = time_src->get_time();
if (time_format == TIME) { if (time_format == TIME) {
snprintf(buffer, 64, "%ld:%06u", now.full_secs, (uint32_t) (now.frac_secs * 1e6)); snprintf(buffer, buffer_len, "%ld:%06u", now.full_secs, (uint32_t)(now.frac_secs * 1e6));
} else { } else {
usec_epoch = now.full_secs * 1000000 + (uint32_t) (now.frac_secs * 1e6); usec_epoch = now.full_secs * 1000000 + (uint32_t) (now.frac_secs * 1e6);
snprintf(buffer, 64, "%ld", usec_epoch); snprintf(buffer, buffer_len, "%ld", usec_epoch);
} }
} }
return std::string(buffer);
} }
std::string log_filter::hex_string(const uint8_t *hex, int size) std::string log_filter::hex_string(const uint8_t *hex, int size)
@ -297,4 +254,4 @@ std::string log_filter::hex_string(const uint8_t *hex, int size)
return ss.str(); return ss.str();
} }
} // namespace srsue } // namespace srslte

@ -33,26 +33,19 @@ logger_file::logger_file() : logfile(NULL), is_running(false), cur_length(0), ma
pthread_cond_init(&not_empty, NULL); pthread_cond_init(&not_empty, NULL);
} }
logger_file::~logger_file() { logger_file::~logger_file()
if(is_running) { {
log(new std::string("Closing log\n")); stop();
pthread_mutex_lock(&mutex);
is_running = false;
pthread_cond_signal(&not_empty); // wakeup thread and let it terminate
pthread_mutex_unlock(&mutex);
wait_thread_finish();
flush();
if (logfile) {
fclose(logfile);
}
}
pthread_mutex_destroy(&mutex); pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&not_empty); pthread_cond_destroy(&not_empty);
} }
void logger_file::init(std::string file, int max_length_) { void logger_file::init(std::string file, int max_length_) {
pthread_mutex_init(&mutex, NULL); if (is_running) {
pthread_cond_init(&not_empty, NULL); fprintf(stderr, "Error: logger thread is already running.\n");
return;
}
pthread_mutex_lock(&mutex);
max_length = (int64_t)max_length_*1024; max_length = (int64_t)max_length_*1024;
name_idx = 0; name_idx = 0;
filename = file; filename = file;
@ -62,15 +55,36 @@ void logger_file::init(std::string file, int max_length_) {
} }
is_running = true; is_running = true;
start(-2); start(-2);
pthread_mutex_unlock(&mutex);
} }
void logger_file::log(const char *msg) { void logger_file::stop()
log(new std::string(msg)); {
if (is_running) {
logger::log_char("Closing log\n");
pthread_mutex_lock(&mutex);
is_running = false;
pthread_cond_signal(&not_empty); // wakeup thread and let it terminate
pthread_mutex_unlock(&mutex);
wait_thread_finish();
pthread_mutex_lock(&mutex);
flush();
if (logfile) {
fclose(logfile);
logfile = NULL;
}
pthread_mutex_unlock(&mutex);
} else {
pthread_mutex_lock(&mutex);
flush(); // flush even if thread isn't running anymore
pthread_mutex_unlock(&mutex);
}
} }
void logger_file::log(str_ptr msg) { void logger_file::log(unique_log_str_t msg)
{
pthread_mutex_lock(&mutex); pthread_mutex_lock(&mutex);
buffer.push_back(msg); buffer.push_back(std::move(msg));
pthread_cond_signal(&not_empty); pthread_cond_signal(&not_empty);
pthread_mutex_unlock(&mutex); pthread_mutex_unlock(&mutex);
} }
@ -85,13 +99,14 @@ void logger_file::run_thread() {
return; // Thread done. Messages in buffer will be handled in flush. return; // Thread done. Messages in buffer will be handled in flush.
} }
} }
str_ptr s = buffer.front(); unique_log_str_t s = std::move(buffer.front());
int n = 0; int n = 0;
if(logfile) if (logfile) {
n = fprintf(logfile, "%s", s->c_str()); n = fprintf(logfile, "%s", s->str());
delete s; }
buffer.pop_front(); buffer.pop_front();
pthread_mutex_unlock(&mutex);
if (n > 0) { if (n > 0) {
cur_length += (int64_t) n; cur_length += (int64_t) n;
if (cur_length >= max_length && max_length > 0) { if (cur_length >= max_length && max_length > 0) {
@ -107,18 +122,20 @@ void logger_file::run_thread() {
cur_length = 0; cur_length = 0;
} }
} }
pthread_mutex_unlock(&mutex);
} }
} }
void logger_file::flush() { void logger_file::flush()
std::deque<str_ptr>::iterator it;
for(it=buffer.begin();it!=buffer.end();it++)
{ {
str_ptr s = *it; std::deque<unique_log_str_t>::iterator it;
if(logfile) for (it = buffer.begin(); it != buffer.end(); it++) {
fprintf(logfile, "%s", s->c_str()); unique_log_str_t s = std::move(*it);
delete s; if (logfile) {
fprintf(logfile, "%s", s->str());
}
} }
buffer.clear();
} }
} // namespace srsue } // namespace srslte

@ -0,0 +1,117 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* 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 "srslte/common/mac_nr_pcap.h"
#include "srslte/srslte.h"
#include <stdint.h>
namespace srslte {
mac_nr_pcap::mac_nr_pcap() {}
mac_nr_pcap::~mac_nr_pcap()
{
if (pcap_file) {
close();
}
}
void mac_nr_pcap::enable(const bool& enable_)
{
enable_write = enable_;
}
void mac_nr_pcap::open(const std::string& filename_, const uint16_t& ue_id_)
{
fprintf(stdout, "Opening MAC-NR PCAP with DLT=%d\n", UDP_DLT);
filename = filename_;
pcap_file = LTE_PCAP_Open(UDP_DLT, filename.c_str());
ue_id = ue_id_;
enable_write = true;
}
void mac_nr_pcap::close()
{
enable_write = false;
fprintf(stdout, "Saving MAC-NR PCAP to %s\n", filename.c_str());
LTE_PCAP_Close(pcap_file);
pcap_file = nullptr;
}
void mac_nr_pcap::set_ue_id(const uint16_t& ue_id_)
{
ue_id = ue_id_;
}
void mac_nr_pcap::pack_and_write(uint8_t* pdu,
uint32_t pdu_len_bytes,
uint32_t tti,
uint16_t crnti,
uint8_t harqid,
uint8_t direction,
uint8_t rnti_type)
{
if (enable_write) {
mac_nr_context_info_t context = {};
context.radioType = FDD_RADIO;
context.direction = direction;
context.rntiType = rnti_type;
context.rnti = crnti;
context.ueid = ue_id;
context.harqid = harqid;
context.system_frame_number = tti / 10;
context.sub_frame_number = tti % 10;
if (pdu) {
NR_PCAP_MAC_WritePDU(pcap_file, &context, pdu, pdu_len_bytes);
}
}
}
void mac_nr_pcap::write_dl_crnti(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti)
{
pack_and_write(pdu, pdu_len_bytes, tti, rnti, harqid, DIRECTION_DOWNLINK, C_RNTI);
}
void mac_nr_pcap::write_ul_crnti(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti)
{
pack_and_write(pdu, pdu_len_bytes, tti, rnti, harqid, DIRECTION_UPLINK, C_RNTI);
}
void mac_nr_pcap::write_dl_ra_rnti(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti)
{
pack_and_write(pdu, pdu_len_bytes, tti, rnti, harqid, DIRECTION_DOWNLINK, RA_RNTI);
}
void mac_nr_pcap::write_dl_bch(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti)
{
pack_and_write(pdu, pdu_len_bytes, tti, rnti, harqid, DIRECTION_DOWNLINK, NO_RNTI);
}
void mac_nr_pcap::write_dl_pch(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti)
{
pack_and_write(pdu, pdu_len_bytes, tti, rnti, harqid, DIRECTION_DOWNLINK, P_RNTI);
}
void mac_nr_pcap::write_dl_si_rnti(uint8_t* pdu, uint32_t pdu_len_bytes, uint16_t rnti, uint8_t harqid, uint32_t tti)
{
pack_and_write(pdu, pdu_len_bytes, tti, rnti, harqid, DIRECTION_DOWNLINK, SI_RNTI);
}
} // namespace srslte

@ -0,0 +1,275 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* 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 "srslte/common/mac_nr_pdu.h"
namespace srslte {
mac_nr_sch_subpdu::mac_nr_sch_subpdu(mac_nr_sch_pdu* parent_) : parent(parent_) {}
mac_nr_sch_subpdu::nr_lcid_sch_t mac_nr_sch_subpdu::get_type()
{
if (lcid >= 32) {
return (nr_lcid_sch_t)lcid;
}
return CCCH;
}
bool mac_nr_sch_subpdu::is_sdu()
{
return get_type() == CCCH;
}
bool mac_nr_sch_subpdu::is_var_len_ce()
{
return false;
}
// return length of PDU
uint32_t mac_nr_sch_subpdu::read_subheader(const uint8_t* ptr)
{
// Skip R, read F bit and LCID
F_bit = (bool)(*ptr & 0x40) ? true : false;
lcid = (uint8_t)*ptr & 0x3f;
ptr++;
header_length = 1;
if (is_sdu() || is_var_len_ce()) {
// Read first length byte
sdu_length = (uint32_t)*ptr;
ptr++;
header_length++;
if (F_bit) {
// add second length byte
sdu_length = sdu_length << 8 | ((uint32_t)*ptr & 0xff);
ptr++;
header_length++;
}
} else {
sdu_length = sizeof_ce(lcid, parent->is_ulsch());
}
sdu = (uint8_t*)ptr;
return header_length;
}
void mac_nr_sch_subpdu::set_sdu(const uint32_t lcid_, const uint8_t* payload_, const uint32_t len_)
{
lcid = lcid_;
sdu = const_cast<uint8_t*>(payload_);
sdu_length = len_;
header_length = 2;
if (sdu_length >= 256) {
F_bit = true;
header_length += 1;
}
}
void mac_nr_sch_subpdu::set_padding(const uint32_t len_)
{
lcid = PADDING;
// 1 Byte R/LCID MAC subheader
sdu_length = len_ - 1;
header_length = 1;
}
// Section 6.1.2
uint32_t mac_nr_sch_subpdu::write_subpdu(const uint8_t* start_)
{
uint8_t* ptr = const_cast<uint8_t*>(start_);
*ptr = (uint8_t)((F_bit ? 1 : 0) << 6) | ((uint8_t)lcid & 0x3f);
ptr += 1;
if (header_length == 3) {
// 3 Byte R/F/LCID/L MAC subheader with 16-bit L field
*ptr = ((sdu_length & 0xff00) >> 8);
ptr += 1;
*ptr = static_cast<uint8_t>(sdu_length);
ptr += 1;
} else if (header_length == 2) {
// 2 Byte R/F/LCID/L MAC subheader with 8-bit L field
*ptr = static_cast<uint8_t>(sdu_length);
ptr += 1;
} else if (header_length == 1) {
// do nothing
} else {
fprintf(stderr, "Error while packing PDU. Unsupported header length (%d)\n", header_length);
}
// copy SDU payload
if (sdu) {
memcpy(ptr, sdu, sdu_length);
} else {
// clear memory
memset(ptr, 0, sdu_length);
}
ptr += sdu_length;
// return total length of subpdu
return ptr - start_;
}
uint32_t mac_nr_sch_subpdu::get_total_length()
{
return (header_length + sdu_length);
}
uint32_t mac_nr_sch_subpdu::get_sdu_length()
{
return sdu_length;
}
uint32_t mac_nr_sch_subpdu::get_lcid()
{
return lcid;
}
uint8_t* mac_nr_sch_subpdu::get_sdu()
{
return sdu;
}
uint32_t mac_nr_sch_subpdu::sizeof_ce(uint32_t lcid, bool is_ul)
{
if (is_ul) {
switch (lcid) {
case CRNTI:
return 2;
case SHORT_TRUNC_BSR:
return 1;
case SHORT_BSR:
return 1;
case PADDING:
return 0;
}
} else {
switch (lcid) {
case CON_RES_ID:
return 6;
case TA_CMD:
return 1;
case DRX_CMD:
return 0;
case PADDING:
return 0;
}
}
return 0;
}
void mac_nr_sch_pdu::pack()
{
// SDUs are written in place, only add padding if needed
if (remaining_len) {
mac_nr_sch_subpdu padding_subpdu(this);
padding_subpdu.set_padding(remaining_len);
padding_subpdu.write_subpdu(buffer->msg + buffer->N_bytes);
// update length
buffer->N_bytes += padding_subpdu.get_total_length();
remaining_len -= padding_subpdu.get_total_length();
subpdus.push_back(padding_subpdu);
}
}
void mac_nr_sch_pdu::unpack(const uint8_t* payload, const uint32_t& len)
{
uint32_t offset = 0;
while (offset < len) {
mac_nr_sch_subpdu sch_pdu(this);
sch_pdu.read_subheader(payload + offset);
offset += sch_pdu.get_total_length();
subpdus.push_back(sch_pdu);
}
if (offset != len) {
fprintf(stderr, "Error parsing NR MAC PDU (len=%d, offset=%d)\n", len, offset);
}
}
uint32_t mac_nr_sch_pdu::get_num_subpdus()
{
return subpdus.size();
}
const mac_nr_sch_subpdu& mac_nr_sch_pdu::get_subpdu(const uint32_t& index)
{
return subpdus.at(index);
}
bool mac_nr_sch_pdu::is_ulsch()
{
return ulsch;
}
void mac_nr_sch_pdu::init_tx(byte_buffer_t* buffer_, uint32_t pdu_len_, bool ulsch_)
{
buffer = buffer_;
pdu_len = pdu_len_;
remaining_len = pdu_len_;
ulsch = ulsch_;
}
uint32_t mac_nr_sch_pdu::size_header_sdu(const uint32_t nbytes)
{
if (nbytes < 256) {
return 2;
} else {
return 3;
}
}
uint32_t mac_nr_sch_pdu::get_remaing_len()
{
return remaining_len;
}
uint32_t mac_nr_sch_pdu::add_sdu(const uint32_t lcid_, const uint8_t* payload_, const uint32_t len_)
{
int header_size = size_header_sdu(len_);
if (header_size + len_ > remaining_len) {
printf("Header and SDU exceed space in PDU (%d > %d).\n", header_size + len_, remaining_len);
return SRSLTE_ERROR;
}
mac_nr_sch_subpdu sch_pdu(this);
sch_pdu.set_sdu(lcid_, payload_, len_);
uint32_t length = sch_pdu.write_subpdu(buffer->msg + buffer->N_bytes);
if (length != sch_pdu.get_total_length()) {
fprintf(stderr, "Error writing subPDU (Length error: %d != %d)\n", length, sch_pdu.get_total_length());
return SRSLTE_ERROR;
}
// update length and advance payload pointer
buffer->N_bytes += length;
remaining_len -= length;
subpdus.push_back(sch_pdu);
return SRSLTE_SUCCESS;
}
} // namespace srslte

@ -177,7 +177,7 @@ uint8_t* sch_pdu::write_packet(srslte::log* log_h)
// Print warning if we have padding only // Print warning if we have padding only
if (nof_subheaders <= 0 && nof_subheaders < (int)max_subheaders) { if (nof_subheaders <= 0 && nof_subheaders < (int)max_subheaders) {
log_h->warning("Writing MAC PDU with padding only (%d B)\n", pdu_len); log_h->debug("Writing MAC PDU with padding only (%d B)\n", pdu_len);
} }
/* Sanity check and print if error */ /* Sanity check and print if error */
@ -556,9 +556,9 @@ bool sch_subh::set_bsr(uint32_t buff_size[4], sch_subh::cetype format)
uint32_t ce_size = format == LONG_BSR ? 3 : 1; uint32_t ce_size = format == LONG_BSR ? 3 : 1;
if (((sch_pdu*)parent)->has_space_ce(ce_size)) { if (((sch_pdu*)parent)->has_space_ce(ce_size)) {
if (format == LONG_BSR) { if (format == LONG_BSR) {
w_payload_ce[0] = (buff_size_table(buff_size[0]) & 0x3f) << 2 | (buff_size_table(buff_size[1]) & 0xc0) >> 6; w_payload_ce[0] = ((buff_size_table(buff_size[0]) & 0x3f) << 2) | ((buff_size_table(buff_size[1]) & 0x30) >> 4);
w_payload_ce[1] = (buff_size_table(buff_size[1]) & 0xf) << 4 | (buff_size_table(buff_size[2]) & 0xf0) >> 4; w_payload_ce[1] = ((buff_size_table(buff_size[1]) & 0xf) << 4) | ((buff_size_table(buff_size[2]) & 0x3c) >> 2);
w_payload_ce[2] = (buff_size_table(buff_size[2]) & 0x3) << 6 | (buff_size_table(buff_size[3]) & 0x3f); w_payload_ce[2] = ((buff_size_table(buff_size[2]) & 0x3) << 6) | ((buff_size_table(buff_size[3]) & 0x3f));
} else { } else {
w_payload_ce[0] = (nonzero_lcg & 0x3) << 6 | (buff_size_table(buff_size[nonzero_lcg]) & 0x3f); w_payload_ce[0] = (nonzero_lcg & 0x3) << 6 | (buff_size_table(buff_size[nonzero_lcg]) & 0x3f);
} }

@ -32,8 +32,8 @@ void rlc_pcap::enable(bool en)
} }
void rlc_pcap::open(const char* filename, uint32_t ue_id) void rlc_pcap::open(const char* filename, uint32_t ue_id)
{ {
fprintf(stdout, "Opening RLC PCAP with DLT=%d\n", RLC_LTE_DLT); fprintf(stdout, "Opening RLC PCAP with DLT=%d\n", UDP_DLT);
pcap_file = LTE_PCAP_Open(RLC_LTE_DLT, filename); pcap_file = LTE_PCAP_Open(UDP_DLT, filename);
this->ue_id = ue_id; this->ue_id = ue_id;
enable_write = true; enable_write = true;
} }

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save