Merge branch 'next' into epc_sigpipe

master
Pedro Alvarez 7 years ago
commit 11b51e7cb4

@ -1,6 +1,10 @@
Change Log for Releases Change Log for Releases
============================== ==============================
## 18.03.1
* Fixed compilation for NEON
* Fixed logging and RLC AM issue
## 18.03 ## 18.03
* Many bug-fixes and improved stability and performance in all parts * Many bug-fixes and improved stability and performance in all parts

@ -131,6 +131,16 @@ else(POLARSSL_FOUND)
endif (MBEDTLS_FOUND) endif (MBEDTLS_FOUND)
endif(POLARSSL_FOUND) endif(POLARSSL_FOUND)
# Hard-SIM support
find_package(PCSCLite)
if (PCSCLITE_FOUND)
message(STATUS "Building with PCSC support.")
add_definitions(-DHAVE_PCSC)
set(HAVE_PCSC TRUE)
include_directories(${PCSCLITE_INCLUDE_DIR})
#link_directories(${PCSCLITE_LIBRARIES})
endif (PCSCLITE_FOUND)
# UHD # UHD
find_package(UHD) find_package(UHD)
if(UHD_FOUND) if(UHD_FOUND)
@ -214,6 +224,13 @@ set(INCLUDE_DIR include)
set(DOC_DIR "share/doc/${CPACK_PACKAGE_NAME}") set(DOC_DIR "share/doc/${CPACK_PACKAGE_NAME}")
set(DATA_DIR share/${CPACK_PACKAGE_NAME}) set(DATA_DIR share/${CPACK_PACKAGE_NAME})
# Auto-generate config install helper and mark for installation
configure_file(
${CMAKE_SOURCE_DIR}/cmake/modules/SRSLTE_install_configs.sh.in
${CMAKE_BINARY_DIR}/srslte_install_configs.sh
)
install(PROGRAMS ${CMAKE_BINARY_DIR}/srslte_install_configs.sh DESTINATION ${RUNTIME_DIR})
######################################################################## ########################################################################
# Compiler specific setup # Compiler specific setup
######################################################################## ########################################################################
@ -226,7 +243,7 @@ macro(ADD_CXX_COMPILER_FLAG_IF_AVAILABLE flag have)
endmacro(ADD_CXX_COMPILER_FLAG_IF_AVAILABLE) endmacro(ADD_CXX_COMPILER_FLAG_IF_AVAILABLE)
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=${GCC_ARCH} -Wall -Wno-comment -Wno-reorder -Wno-unused-but-set-variable -Wno-unused-variable -Wformat -std=c++03") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=${GCC_ARCH} -Wall -Wno-comment -Wno-reorder -Wno-unused-but-set-variable -Wno-unused-variable -Wformat -Wmissing-field-initializers -Wtype-limits -std=c++03")
find_package(SSE) find_package(SSE)
if (HAVE_AVX2) if (HAVE_AVX2)
@ -243,7 +260,7 @@ endif(CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clan
ADD_CXX_COMPILER_FLAG_IF_AVAILABLE("-Werror=incompatible-pointer-types" HAVE_ERROR_INCOMPATIBLE) ADD_CXX_COMPILER_FLAG_IF_AVAILABLE("-Werror=incompatible-pointer-types" HAVE_ERROR_INCOMPATIBLE)
if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang") if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=${GCC_ARCH} -Wall -Wno-comment -Wno-write-strings -Wno-format-extra-args -Winline -Wno-unused-result -Wno-format -std=c99 -D_GNU_SOURCE") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=${GCC_ARCH} -Wall -Wno-comment -Wno-write-strings -Winline -Wno-unused-result -Wformat -Wmissing-field-initializers -Wtype-limits -std=c99 -D_GNU_SOURCE")
if(${CMAKE_BUILD_TYPE} STREQUAL "Debug") if(${CMAKE_BUILD_TYPE} STREQUAL "Debug")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ggdb -O0 -DDEBUG_MODE -DBUILD_TYPE_DEBUG") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ggdb -O0 -DDEBUG_MODE -DBUILD_TYPE_DEBUG")
@ -274,6 +291,10 @@ if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang")
endif(HAVE_AVX) endif(HAVE_AVX)
endif (HAVE_AVX2) endif (HAVE_AVX2)
if (HAVE_FMA)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfma -DLV_HAVE_FMA")
endif (HAVE_FMA)
if (HAVE_AVX512) if (HAVE_AVX512)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mavx512f -mavx512cd -DLV_HAVE_AVX512") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mavx512f -mavx512cd -DLV_HAVE_AVX512")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mavx512f -mavx512cd -DLV_HAVE_AVX512") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mavx512f -mavx512cd -DLV_HAVE_AVX512")

@ -658,4 +658,40 @@ specific requirements.
You should also get your employer (if you work as a programmer) or school, You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary. if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see For more information on this, and how to apply and follow the GNU AGPL, see
<http://www.gnu.org/licenses/>. <http://www.gnu.org/licenses/>.
The license terms used for the scard class (in pcsc_usim) derived from wpa_supplicant
-------------------------------------------------------------------------------------
Modified BSD license (no advertisement clause):
Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name(s) of the above-listed copyright holder(s) nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

@ -108,6 +108,7 @@ Note that depending on your flavor and version of Linux, the actual package name
* Optional requirements: * Optional requirements:
* srsgui: https://github.com/srslte/srsgui - for real-time plotting. * srsgui: https://github.com/srslte/srsgui - for real-time plotting.
* libpcsclite-dev https://pcsclite.apdu.fr/ - for accessing smart card readers
* RF front-end driver: * RF front-end driver:
* UHD: https://github.com/EttusResearch/uhd * UHD: https://github.com/EttusResearch/uhd

@ -0,0 +1,48 @@
# - Find PCSC-Lite
# Find the native PCSC-Lite includes and library
#
# PCSCLITE_INCLUDE_DIR - where to find winscard.h, wintypes.h, etc.
# PCSCLITE_LIBRARIES - List of libraries when using PCSC-Lite.
# PCSCLITE_FOUND - True if PCSC-Lite found.
FIND_PACKAGE(PkgConfig)
PKG_CHECK_MODULES(PC_PCSCLITE libpcsclite)
IF(NOT PCSCLITE_FOUND)
FIND_PATH(PCSCLITE_INCLUDE_DIR
NAMES winscard.h
HINTS /usr/include/PCSC
/usr/local/include/PCSC
${PC_PCSCLITE_INCLUDEDIR}
${PC_PCSCLITE_INCLUDE_DIRS}
${PC_PCSCLITE_INCLUDE_DIRS}/PCSC
${CMAKE_INSTALL_PREFIX}/include
)
FIND_LIBRARY(PCSCLITE_LIBRARY NAMES pcsclite libpcsclite PCSC
HINTS ${PC_PCSCLITE_LIBDIR}
${PC_PCSCLITE_LIBRARY_DIRS}
${CMAKE_INSTALL_PREFIX}/lib
${CMAKE_INSTALL_PREFIX}/lib64
PATHS /usr/local/lib
/usr/local/lib64
/usr/lib
/usr/lib64
)
# handle the QUIETLY and REQUIRED arguments and set PCSCLITE_FOUND to TRUE if
# all listed variables are TRUE
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(PCSCLITE DEFAULT_MSG PCSCLITE_LIBRARY PCSCLITE_INCLUDE_DIR)
IF(PCSCLITE_FOUND)
SET(PCSCLITE_LIBRARIES ${PCSCLITE_LIBRARY})
ELSE(PCSCLITE_FOUND)
SET(PCSCLITE_LIBRARIES )
ENDIF(PCSCLITE_FOUND)
message(STATUS "PCSC LIBRARIES: " ${PCSCLITE_LIBRARY})
message(STATUS "PCSC INCLUDE DIRS: " ${PCSCLITE_INCLUDE_DIR})
MARK_AS_ADVANCED( PCSCLITE_LIBRARY PCSCLITE_INCLUDE_DIR )
ENDIF(NOT PCSCLITE_FOUND)

@ -20,5 +20,5 @@
SET(SRSLTE_VERSION_MAJOR 18) SET(SRSLTE_VERSION_MAJOR 18)
SET(SRSLTE_VERSION_MINOR 3) SET(SRSLTE_VERSION_MINOR 3)
SET(SRSLTE_VERSION_PATCH 0) SET(SRSLTE_VERSION_PATCH 1)
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}")

@ -0,0 +1,55 @@
#!/bin/bash
# Auto-updated by CMake with actual install path
SRSLTE_INSTALL_DIR="${CMAKE_INSTALL_PREFIX}/${DATA_DIR}"
# Default folder where configs go
dest_folder="$HOME/.srs"
install_file(){
source_path="$SRSLTE_INSTALL_DIR/$1"
dest_path=$(echo "$dest_folder/$1" | sed 's/\.[^.]*$//') # Strip .example from filename
# Check if config file already exists in location
if [ -f $dest_path ]; then
echo " - $dest_path already exists. Skipping it."
return
fi
# Check if config file exists in source location
if [ -f $source_path ]; then
echo " - Installing $1 in $dest_path"
cp $source_path $dest_path
# Set file ownership to user calling sudo
if [ $SUDO_USER ]; then
user=$SUDO_USER
chown $user:$user $dest_path
fi
else
echo " - $source_path doesn't exists. Skipping it."
fi
return
}
# Install all srsLTE config files
echo "Installing srsLTE configuration files:"
# Make sure the target directory exists
if [ ! -d "$dest_folder" ]; then
echo " - Creating srsLTE config folder $dest_folder"
mkdir $dest_folder
fi
install_file "ue.conf.example"
install_file "enb.conf.example"
install_file "sib.conf.example"
install_file "rr.conf.example"
install_file "drb.conf.example"
install_file "epc.conf.example"
install_file "mbms.conf.example"
install_file "user_db.csv.example"
echo "Done."

11
debian/changelog vendored

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

1
debian/compat vendored

@ -0,0 +1 @@
9

14
debian/control vendored

@ -0,0 +1,14 @@
Source: srslte
Section: misc
Priority: optional
Maintainer: Andre Puschmann <andre@softwareradiosystems.com>
Build-Depends: debhelper (>= 9), dh-exec, cmake, build-essential, libfftw3-dev, libmbedtls-dev, libboost-program-options-dev, libconfig++-dev, libsctp-dev, libuhd-dev, uhd-host
Standards-Version: 4.1.1
Homepage: https://github.com/srsLTE/srsLTE/
Package: srslte
Architecture: any
Depends: libfftw3-3 (>= 3.3.3-1), libboost-program-options1.62.0 (>= 1.62.0), libmbedcrypto1 (>= 2.8.0-1), libconfig++9v5 (>= 1.5-0.2), libsctp1 (>= 1.0.16+dfsg-3), uhd-host (>= 3.9.2-1), libuhd003.010.003 (>= 3.10.3.0-2)
Description: This is srsLTE, a free and open-source LTE software suite.
This software allows you to run a full end-to-end, open-source LTE system.
It contains a UE, eNB and EPC implementation.

516
debian/copyright vendored

@ -0,0 +1,516 @@
Copyright (C) 2013-2016 Software Radio Systems Limited. All rights reserved.
The following copyright notices are for libraries used within srsLTE:
-----------------------------------------------------------
FEC Library - Version 3.0.1 - August 7th, 2007
-----------------------------------------------------------
COPYRIGHT
This package is copyright 2006 by Phil Karn, KA9Q. It may be used
under the terms of the GNU Lesser General Public License (LGPL).
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

15
debian/rules vendored

@ -0,0 +1,15 @@
#!/usr/bin/make -f
# Uncomment this to turn on verbose mode.
export DH_VERBOSE=1
# This has to be exported to make some magic below work.
export DH_OPTIONS
%:
dh $@ --parallel
override_dh_auto_configure:
dh_auto_configure --buildsystem=cmake -- $(extraopts) $(CEPH_EXTRA_CMAKE_ARGS) -DCMAKE_BUILD_TYPE=Release
override_dh_auto_test:
# skip executing tests

@ -0,0 +1 @@
3.0 (quilt)

@ -0,0 +1,9 @@
#!/usr/bin/dh-exec
srsue/ue.conf.example => usr/share/srslte/config/ue.conf
srsenb/enb.conf.example => usr/share/srslte/config/enb.conf
srsenb/rr.conf.example => usr/share/srslte/config/rr.conf
srsenb/drb.conf.example => usr/share/srslte/config/drb.conf
srsenb/sib.conf.example => usr/share/srslte/config/sib.conf
srsepc/epc.conf.example => usr/share/srslte/config/epc.conf
srsepc/mbms.conf.example => usr/share/srslte/config/mbms.conf
srsepc/user_db.csv.example => usr/share/srslte/config/user_db.csv

@ -32,18 +32,18 @@ target_link_libraries(synch_file srslte_phy)
if(RF_FOUND) if(RF_FOUND)
add_executable(pdsch_ue pdsch_ue.c) add_executable(pdsch_ue pdsch_ue.c)
target_link_libraries(pdsch_ue srslte_phy srslte_rf pthread) target_link_libraries(pdsch_ue srslte_phy srslte_common srslte_rf pthread)
add_executable(pdsch_enodeb pdsch_enodeb.c) add_executable(pdsch_enodeb pdsch_enodeb.c)
target_link_libraries(pdsch_enodeb srslte_phy srslte_rf pthread) target_link_libraries(pdsch_enodeb srslte_phy srslte_common srslte_rf pthread)
else(RF_FOUND) else(RF_FOUND)
add_definitions(-DDISABLE_RF) add_definitions(-DDISABLE_RF)
add_executable(pdsch_ue pdsch_ue.c) add_executable(pdsch_ue pdsch_ue.c)
target_link_libraries(pdsch_ue srslte_phy pthread) target_link_libraries(pdsch_ue srslte_common srslte_phy pthread)
add_executable(pdsch_enodeb pdsch_enodeb.c) add_executable(pdsch_enodeb pdsch_enodeb.c)
target_link_libraries(pdsch_enodeb srslte_phy pthread) target_link_libraries(pdsch_enodeb srslte_common srslte_phy pthread)
endif(RF_FOUND) endif(RF_FOUND)
find_package(SRSGUI) find_package(SRSGUI)

@ -199,7 +199,12 @@ int main(int argc, char **argv) {
srslte_ue_cellsearch_set_nof_valid_frames(&cs, cell_detect_config.nof_valid_pss_frames); srslte_ue_cellsearch_set_nof_valid_frames(&cs, cell_detect_config.nof_valid_pss_frames);
} }
if (cell_detect_config.init_agc) { if (cell_detect_config.init_agc) {
srslte_ue_sync_start_agc(&cs.ue_sync, srslte_rf_set_rx_gain_wrapper, cell_detect_config.init_agc); srslte_rf_info_t *rf_info = srslte_rf_get_info(&rf);
srslte_ue_sync_start_agc(&cs.ue_sync,
srslte_rf_set_rx_gain_wrapper,
rf_info->min_rx_gain,
rf_info->max_rx_gain,
cell_detect_config.init_agc);
} }
for (freq=0;freq<nof_freqs && !go_exit;freq++) { for (freq=0;freq<nof_freqs && !go_exit;freq++) {

@ -35,7 +35,7 @@
#include <signal.h> #include <signal.h>
#include <srslte/phy/common/phy_common.h> #include <srslte/phy/common/phy_common.h>
#include <srslte/phy/phch/pdsch_cfg.h> #include <srslte/phy/phch/pdsch_cfg.h>
#include "srslte/common/gen_mch_tables.h"
#include "srslte/srslte.h" #include "srslte/srslte.h"
@ -79,10 +79,10 @@ char mimo_type_str[32] = "single";
uint32_t nof_tb = 1; uint32_t nof_tb = 1;
uint32_t multiplex_pmi = 0; uint32_t multiplex_pmi = 0;
uint32_t multiplex_nof_layers = 1; uint32_t multiplex_nof_layers = 1;
uint8_t mbsfn_sf_mask = 32;
int mbsfn_area_id = -1; int mbsfn_area_id = -1;
char *rf_args = ""; char *rf_args = "";
float rf_amp = 0.8, rf_gain = 70.0, rf_freq = 2400000000; float rf_amp = 0.8, rf_gain = 60.0, rf_freq = 2400000000;
float output_file_snr = +INFINITY; float output_file_snr = +INFINITY;
@ -123,7 +123,7 @@ int prbset_orig = 0;
#define DATA_BUFF_SZ 1024*1024 #define DATA_BUFF_SZ 1024*1024
uint8_t *data[2], data2[DATA_BUFF_SZ]; uint8_t *data_mbms, *data[2], data2[DATA_BUFF_SZ];
uint8_t data_tmp[DATA_BUFF_SZ]; uint8_t data_tmp[DATA_BUFF_SZ];
void usage(char *prog) { void usage(char *prog) {
@ -145,7 +145,7 @@ void usage(char *prog) {
printf("\t-x Transmission mode[single|diversity|cdd|multiplex] [Default %s]\n", mimo_type_str); printf("\t-x Transmission mode[single|diversity|cdd|multiplex] [Default %s]\n", mimo_type_str);
printf("\t-b Precoding Matrix Index (multiplex mode only)* [Default %d]\n", multiplex_pmi); printf("\t-b Precoding Matrix Index (multiplex mode only)* [Default %d]\n", multiplex_pmi);
printf("\t-w Number of codewords/layers (multiplex mode only)* [Default %d]\n", multiplex_nof_layers); printf("\t-w Number of codewords/layers (multiplex mode only)* [Default %d]\n", multiplex_nof_layers);
printf("\t-u listen TCP port for input data (-1 is random) [Default %d]\n", net_port); printf("\t-u listen TCP/UDP port for input data (if mbsfn is active then the stream is over mbsfn only) (-1 is random) [Default %d]\n", net_port);
printf("\t-v [set srslte_verbose to debug, default none]\n"); printf("\t-v [set srslte_verbose to debug, default none]\n");
printf("\t-s output file SNR [Default %f]\n", output_file_snr); printf("\t-s output file SNR [Default %f]\n", output_file_snr);
printf("\n"); printf("\n");
@ -154,7 +154,7 @@ void usage(char *prog) {
void parse_args(int argc, char **argv) { void parse_args(int argc, char **argv) {
int opt; int opt;
while ((opt = getopt(argc, argv, "aglfmoncpvutxbwMs")) != -1) { while ((opt = getopt(argc, argv, "aglfmoncpvutxbwMsB")) != -1) {
switch (opt) { switch (opt) {
case 'a': case 'a':
@ -206,6 +206,9 @@ void parse_args(int argc, char **argv) {
case 's': case 's':
output_file_snr = atof(argv[optind]); output_file_snr = atof(argv[optind]);
break; break;
case 'B':
mbsfn_sf_mask = atoi(argv[optind]);
break;
default: default:
usage(argv[0]); usage(argv[0]);
exit(-1); exit(-1);
@ -256,6 +259,8 @@ void base_init() {
} }
bzero(data[i], sizeof(uint8_t) * SOFTBUFFER_SIZE); bzero(data[i], sizeof(uint8_t) * SOFTBUFFER_SIZE);
} }
data_mbms = srslte_vec_malloc(sizeof(uint8_t) * SOFTBUFFER_SIZE);
/* init memory */ /* init memory */
for (i = 0; i < SRSLTE_MAX_PORTS; i++) { for (i = 0; i < SRSLTE_MAX_PORTS; i++) {
@ -301,7 +306,7 @@ void base_init() {
} }
if (net_port > 0) { if (net_port > 0) {
if (srslte_netsource_init(&net_source, "0.0.0.0", net_port, SRSLTE_NETSOURCE_TCP)) { if (srslte_netsource_init(&net_source, "127.0.0.1", net_port, SRSLTE_NETSOURCE_UDP)) {
fprintf(stderr, "Error creating input UDP socket at port %d\n", net_port); fprintf(stderr, "Error creating input UDP socket at port %d\n", net_port);
exit(-1); exit(-1);
} }
@ -659,15 +664,21 @@ void *net_thread_fnc(void *arg) {
n = srslte_netsource_read(&net_source, &data2[rpm], DATA_BUFF_SZ-rpm); n = srslte_netsource_read(&net_source, &data2[rpm], DATA_BUFF_SZ-rpm);
if (n > 0) { if (n > 0) {
// FIXME: I assume that both transport blocks have same size in case of 2 tb are active // FIXME: I assume that both transport blocks have same size in case of 2 tb are active
int nbytes = 1 + (pdsch_cfg.grant.mcs[0].tbs + pdsch_cfg.grant.mcs[1].tbs - 1) / 8;
int nbytes = 1 + (((mbsfn_area_id > -1)?(pmch_cfg.grant.mcs[0].tbs):(pdsch_cfg.grant.mcs[0].tbs + pdsch_cfg.grant.mcs[1].tbs)) - 1) / 8;
rpm += n; rpm += n;
INFO("received %d bytes. rpm=%d/%d\n",n,rpm,nbytes); INFO("received %d bytes. rpm=%d/%d\n",n,rpm,nbytes);
wpm = 0; wpm = 0;
while (rpm >= nbytes) { while (rpm >= nbytes) {
// wait for packet to be transmitted // wait for packet to be transmitted
sem_wait(&net_sem); sem_wait(&net_sem);
memcpy(data[0], &data2[wpm], nbytes / (size_t) 2); if(mbsfn_area_id > -1){
memcpy(data[1], &data2[wpm], nbytes / (size_t) 2); memcpy(data_mbms, &data2[wpm], nbytes);
}
else{
memcpy(data[0], &data2[wpm], nbytes / (size_t) 2);
memcpy(data[1], &data2[wpm], nbytes / (size_t) 2);
}
INFO("Sent %d/%d bytes ready\n", nbytes, rpm); INFO("Sent %d/%d bytes ready\n", nbytes, rpm);
rpm -= nbytes; rpm -= nbytes;
wpm += nbytes; wpm += nbytes;
@ -714,6 +725,11 @@ int main(int argc, char **argv) {
parse_args(argc, argv); parse_args(argc, argv);
uint8_t mch_table[10];
bzero(&mch_table[0], sizeof(uint8_t)*10);
if(mbsfn_area_id < -1) {
generate_mcch_table(mch_table, mbsfn_sf_mask);
}
N_id_2 = cell.id % 3; N_id_2 = cell.id % 3;
sf_n_re = 2 * SRSLTE_CP_NORM_NSYMB * cell.nof_prb * SRSLTE_NRE; sf_n_re = 2 * SRSLTE_CP_NORM_NSYMB * cell.nof_prb * SRSLTE_NRE;
sf_n_samples = 2 * SRSLTE_SLOT_LEN(srslte_symbol_sz(cell.nof_prb)); sf_n_samples = 2 * SRSLTE_SLOT_LEN(srslte_symbol_sz(cell.nof_prb));
@ -739,10 +755,15 @@ int main(int argc, char **argv) {
exit(-1); exit(-1);
} }
if(mbsfn_area_id > -1) { if(mbsfn_area_id > -1) {
if(srslte_refsignal_mbsfn_init(&mbsfn_refs, cell, mbsfn_area_id)) { if(srslte_refsignal_mbsfn_init(&mbsfn_refs, cell.nof_prb)) {
fprintf(stderr, "Error initializing equalizer\n"); fprintf(stderr, "Error initializing equalizer\n");
exit(-1); exit(-1);
} }
if (srslte_refsignal_mbsfn_set_cell(&mbsfn_refs, cell, mbsfn_area_id)) {
fprintf(stderr, "Error initializing MBSFNR signal\n");
exit(-1);
}
} }
if(srslte_refsignal_cs_set_cell(&csr_refs, cell)){ if(srslte_refsignal_cs_set_cell(&csr_refs, cell)){
@ -801,7 +822,7 @@ int main(int argc, char **argv) {
exit(-1); exit(-1);
} }
} }
pmch_cfg.grant.mcs[0].tbs = 1096;
/* Initiate valid DCI locations */ /* Initiate valid DCI locations */
for (i=0;i<SRSLTE_NSUBFRAMES_X_FRAME;i++) { for (i=0;i<SRSLTE_NSUBFRAMES_X_FRAME;i++) {
srslte_pdcch_ue_locations(&pdcch, locations[i], 30, i, cfi, UE_CRNTI); srslte_pdcch_ue_locations(&pdcch, locations[i], 30, i, cfi, UE_CRNTI);
@ -830,13 +851,13 @@ int main(int argc, char **argv) {
srslte_sss_put_slot(sf_idx ? sss_signal5 : sss_signal0, sf_symbols[0], cell.nof_prb, srslte_sss_put_slot(sf_idx ? sss_signal5 : sss_signal0, sf_symbols[0], cell.nof_prb,
SRSLTE_CP_NORM); SRSLTE_CP_NORM);
} }
/* Copy zeros, SSS, PSS into the rest of antenna ports */ /* Copy zeros, SSS, PSS into the rest of antenna ports */
for (i = 1; i < cell.nof_ports; i++) { for (i = 1; i < cell.nof_ports; i++) {
memcpy(sf_symbols[i], sf_symbols[0], sizeof(cf_t) * sf_n_re); memcpy(sf_symbols[i], sf_symbols[0], sizeof(cf_t) * sf_n_re);
} }
if(sf_idx == 1 && mbsfn_area_id > -1){ if(mch_table[sf_idx] == 1 && mbsfn_area_id > -1){
srslte_refsignal_mbsfn_put_sf(cell, 0,csr_refs.pilots[0][sf_idx], mbsfn_refs.pilots[0][sf_idx], sf_symbols[0]); srslte_refsignal_mbsfn_put_sf(cell, 0,csr_refs.pilots[0][sf_idx], mbsfn_refs.pilots[0][sf_idx], sf_symbols[0]);
} else { } else {
for (i = 0; i < cell.nof_ports; i++) { for (i = 0; i < cell.nof_ports; i++) {
@ -857,10 +878,10 @@ int main(int argc, char **argv) {
} }
/* Transmit PDCCH + PDSCH only when there is data to send */ /* Transmit PDCCH + PDSCH only when there is data to send */
if (net_port > 0) { if ((net_port > 0) && (mch_table[sf_idx] == 1 && mbsfn_area_id > -1)) {
send_data = net_packet_ready; send_data = net_packet_ready;
if (net_packet_ready) { if (net_packet_ready) {
INFO("Transmitting packet\n"); INFO("Transmitting packet from port\n");
} }
} else { } else {
INFO("SF: %d, Generating %d random bits\n", sf_idx, pdsch_cfg.grant.mcs[0].tbs + pdsch_cfg.grant.mcs[1].tbs); INFO("SF: %d, Generating %d random bits\n", sf_idx, pdsch_cfg.grant.mcs[0].tbs + pdsch_cfg.grant.mcs[1].tbs);
@ -878,9 +899,8 @@ int main(int argc, char **argv) {
send_data = false; send_data = false;
} }
} }
if (send_data) { if (send_data) {
if(sf_idx != 1 || mbsfn_area_id < 0) { // PDCCH + PDSCH if(mch_table[sf_idx] == 0 || mbsfn_area_id < 0) { // PDCCH + PDSCH
srslte_dci_format_t dci_format; srslte_dci_format_t dci_format;
switch(pdsch_cfg.mimo_type) { switch(pdsch_cfg.mimo_type) {
case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA:
@ -932,41 +952,46 @@ int main(int argc, char **argv) {
} }
} }
} }
net_packet_ready = false; if(mbsfn_area_id < 0){
sem_post(&net_sem); net_packet_ready = false;
sem_post(&net_sem);
}
} }
}else{ // We're sending MCH on subframe 1 - PDCCH + PMCH }else{ // We're sending MCH on subframe 1 - PDCCH + PMCH
/* Encode PDCCH */ /* Encode PDCCH */
INFO("Putting DCI to location: n=%d, L=%d\n", locations[sf_idx][0].ncce, locations[sf_idx][0].L); //INFO("Putting DCI to location: n=%d, L=%d\n", locations[sf_idx][0].ncce, locations[sf_idx][0].L);
srslte_dci_msg_pack_pdsch(&ra_dl, SRSLTE_DCI_FORMAT1, &dci_msg, cell.nof_prb, cell.nof_ports, false); //srslte_dci_msg_pack_pdsch(&ra_dl, SRSLTE_DCI_FORMAT1, &dci_msg, cell.nof_prb, cell.nof_ports, false);
if (srslte_pdcch_encode(&pdcch, &dci_msg, locations[sf_idx][0], M_CRNTI, sf_symbols, sf_idx, cfi)) { //if (srslte_pdcch_encode(&pdcch, &dci_msg, locations[sf_idx][0], M_CRNTI, sf_symbols, sf_idx, cfi)) {
fprintf(stderr, "Error encoding DCI message\n"); // fprintf(stderr, "Error encoding DCI message\n");
exit(-1); // exit(-1);
} // }
/* Configure pmch_cfg parameters */ /* Configure pmch_cfg parameters */
srslte_ra_dl_grant_t grant; srslte_ra_dl_grant_t grant;
grant.tb_en[0] = true; grant.tb_en[0] = true;
grant.tb_en[1] = false; grant.tb_en[1] = false;
grant.mcs[0].idx = 2; grant.mcs[0].idx = 2;
grant.mcs[0].mod = SRSLTE_MOD_QPSK;
grant.nof_prb = cell.nof_prb; grant.nof_prb = cell.nof_prb;
grant.sf_type = SRSLTE_SF_MBSFN; grant.sf_type = SRSLTE_SF_MBSFN;
grant.Qm[0] = srslte_mod_bits_x_symbol(grant.mcs[0].mod);
srslte_dl_fill_ra_mcs(&grant.mcs[0], cell.nof_prb); srslte_dl_fill_ra_mcs(&grant.mcs[0], cell.nof_prb);
grant.Qm[0] = srslte_mod_bits_x_symbol(grant.mcs[0].mod);
for(int i = 0; i < 2; i++){ for(int i = 0; i < 2; i++){
for(int j = 0; j < grant.nof_prb; j++){ for(int j = 0; j < grant.nof_prb; j++){
grant.prb_idx[i][j] = true; grant.prb_idx[i][j] = true;
} }
} }
for(int i = 0; i < grant.mcs[0].tbs/8;i++)
{
data_mbms[i] = i%255;
}
if (srslte_pmch_cfg(&pmch_cfg, cell, &grant, cfi, sf_idx)) { if (srslte_pmch_cfg(&pmch_cfg, cell, &grant, cfi, sf_idx)) {
fprintf(stderr, "Error configuring PMCH\n"); fprintf(stderr, "Error configuring PMCH\n");
exit(-1); exit(-1);
} }
/* Encode PMCH */ /* Encode PMCH */
if (srslte_pmch_encode(&pmch, &pmch_cfg, softbuffers[0], data[0], mbsfn_area_id, sf_symbols)) { if (srslte_pmch_encode(&pmch, &pmch_cfg, softbuffers[0], data_mbms, mbsfn_area_id, sf_symbols)) {
fprintf(stderr, "Error encoding PDSCH\n"); fprintf(stderr, "Error encoding PDSCH\n");
exit(-1); exit(-1);
} }
@ -984,13 +1009,14 @@ int main(int argc, char **argv) {
} }
/* Transform to OFDM symbols */ /* Transform to OFDM symbols */
if(sf_idx != 1 || mbsfn_area_id < 0){ if(mch_table[sf_idx] == 0 || mbsfn_area_id < 0){
for (i = 0; i < cell.nof_ports; i++) { for (i = 0; i < cell.nof_ports; i++) {
srslte_ofdm_tx_sf(&ifft[i]); srslte_ofdm_tx_sf(&ifft[i]);
} }
}else{ }else{
srslte_ofdm_tx_sf(&ifft_mbsfn); srslte_ofdm_tx_sf(&ifft_mbsfn);
} }
/* send to file or usrp */ /* send to file or usrp */
if (output_file_name) { if (output_file_name) {
@ -1006,7 +1032,7 @@ int main(int argc, char **argv) {
} }
usleep(1000); usleep(1000);
} else { } else {
#ifndef DISABLE_RF #ifndef DISABLE_RF
float norm_factor = (float) cell.nof_prb/15/sqrtf(pdsch_cfg.grant.nof_prb); float norm_factor = (float) cell.nof_prb/15/sqrtf(pdsch_cfg.grant.nof_prb);
for (i = 0; i < cell.nof_ports; i++) { for (i = 0; i < cell.nof_ports; i++) {
srslte_vec_sc_prod_cfc(output_buffer[i], rf_amp * norm_factor, output_buffer[i], SRSLTE_SF_LEN_PRB(cell.nof_prb)); srslte_vec_sc_prod_cfc(output_buffer[i], rf_amp * norm_factor, output_buffer[i], SRSLTE_SF_LEN_PRB(cell.nof_prb));

@ -36,6 +36,7 @@
#include <signal.h> #include <signal.h>
#include <pthread.h> #include <pthread.h>
#include <semaphore.h> #include <semaphore.h>
#include "srslte/common/gen_mch_tables.h"
#include <srslte/phy/common/phy_common.h> #include <srslte/phy/common/phy_common.h>
#include "srslte/phy/io/filesink.h" #include "srslte/phy/io/filesink.h"
#include "srslte/srslte.h" #include "srslte/srslte.h"
@ -103,6 +104,7 @@ typedef struct {
int decimate; int decimate;
int32_t mbsfn_area_id; int32_t mbsfn_area_id;
uint8_t non_mbsfn_region; uint8_t non_mbsfn_region;
uint8_t mbsfn_sf_mask;
int verbose; int verbose;
}prog_args_t; }prog_args_t;
@ -138,6 +140,7 @@ void args_default(prog_args_t *args) {
args->cpu_affinity = -1; args->cpu_affinity = -1;
args->mbsfn_area_id = -1; args->mbsfn_area_id = -1;
args->non_mbsfn_region = 2; args->non_mbsfn_region = 2;
args->mbsfn_sf_mask = 32;
} }
void usage(prog_args_t *args, char *prog) { void usage(prog_args_t *args, char *prog) {
@ -185,7 +188,7 @@ void usage(prog_args_t *args, char *prog) {
void parse_args(prog_args_t *args, int argc, char **argv) { void parse_args(prog_args_t *args, int argc, char **argv) {
int opt; int opt;
args_default(args); args_default(args);
while ((opt = getopt(argc, argv, "aAoglipPcOCtdDFRnvrfuUsSZyWMN")) != -1) { while ((opt = getopt(argc, argv, "aAoglipPcOCtdDFRnvrfuUsSZyWMNB")) != -1) {
switch (opt) { switch (opt) {
case 'i': case 'i':
args->input_file_name = argv[optind]; args->input_file_name = argv[optind];
@ -275,6 +278,9 @@ void parse_args(prog_args_t *args, int argc, char **argv) {
case 'N': case 'N':
args->non_mbsfn_region = atoi(argv[optind]); args->non_mbsfn_region = atoi(argv[optind]);
break; break;
case 'B':
args->mbsfn_sf_mask = atoi(argv[optind]);
break;
default: default:
usage(args, argv[0]); usage(args, argv[0]);
exit(-1); exit(-1);
@ -364,8 +370,11 @@ int main(int argc, char **argv) {
go_exit = true; go_exit = true;
} }
} }
uint8_t mch_table[10];
bzero(&mch_table[0], sizeof(uint8_t)*10);
if(prog_args.mbsfn_area_id < -1) {
generate_mcch_table(mch_table, prog_args.mbsfn_sf_mask);
}
if(prog_args.cpu_affinity > -1) { if(prog_args.cpu_affinity > -1) {
cpu_set_t cpuset; cpu_set_t cpuset;
@ -385,7 +394,7 @@ int main(int argc, char **argv) {
} }
if (prog_args.net_port > 0) { if (prog_args.net_port > 0) {
if (srslte_netsink_init(&net_sink, prog_args.net_address, prog_args.net_port, SRSLTE_NETSINK_TCP)) { if (srslte_netsink_init(&net_sink, prog_args.net_address, prog_args.net_port, SRSLTE_NETSINK_UDP)) {
fprintf(stderr, "Error initiating UDP socket to %s:%d\n", prog_args.net_address, prog_args.net_port); fprintf(stderr, "Error initiating UDP socket to %s:%d\n", prog_args.net_address, prog_args.net_port);
exit(-1); exit(-1);
} }
@ -591,7 +600,12 @@ int main(int argc, char **argv) {
#ifndef DISABLE_RF #ifndef DISABLE_RF
if (prog_args.rf_gain < 0) { if (prog_args.rf_gain < 0) {
srslte_ue_sync_start_agc(&ue_sync, srslte_rf_set_rx_gain_th_wrapper_, cell_detect_config.init_agc); srslte_rf_info_t *rf_info = srslte_rf_get_info(&rf);
srslte_ue_sync_start_agc(&ue_sync,
srslte_rf_set_rx_gain_th_wrapper_,
rf_info->min_rx_gain,
rf_info->max_rx_gain,
cell_detect_config.init_agc);
} }
#endif #endif
#ifdef PRINT_CHANGE_SCHEDULIGN #ifdef PRINT_CHANGE_SCHEDULIGN
@ -668,7 +682,7 @@ int main(int argc, char **argv) {
decode_pdsch = true; decode_pdsch = true;
} else { } else {
/* We are looking for SIB1 Blocks, search only in appropiate places */ /* We are looking for SIB1 Blocks, search only in appropiate places */
if ((sfidx == 5 && (sfn%2)==0) || sfidx == 1) { if ((sfidx == 5 && (sfn%2)==0) ||mch_table[sfidx] == 1) {
decode_pdsch = true; decode_pdsch = true;
} else { } else {
decode_pdsch = false; decode_pdsch = false;
@ -677,7 +691,7 @@ int main(int argc, char **argv) {
gettimeofday(&t[1], NULL); gettimeofday(&t[1], NULL);
if (decode_pdsch) { if (decode_pdsch) {
if(sfidx != 1 || prog_args.mbsfn_area_id < 0){ // Not an MBSFN subframe if(mch_table[sfidx] == 0 || prog_args.mbsfn_area_id < 0){ // Not an MBSFN subframe
if (cell.nof_ports == 1) { if (cell.nof_ports == 1) {
/* Transmission mode 1 */ /* Transmission mode 1 */
n = srslte_ue_dl_decode(&ue_dl, data, 0, sfn*10+srslte_ue_sync_get_sfidx(&ue_sync), acks); n = srslte_ue_dl_decode(&ue_dl, data, 0, sfn*10+srslte_ue_sync_get_sfidx(&ue_sync), acks);
@ -864,6 +878,8 @@ int main(int argc, char **argv) {
PRINT_LINE_ADVANCE_CURSOR(); PRINT_LINE_ADVANCE_CURSOR();
ue_dl.pdsch_pkt_errors = 0; ue_dl.pdsch_pkt_errors = 0;
ue_dl.pdsch_pkts_total = 0; ue_dl.pdsch_pkts_total = 0;
ue_dl.pmch_pkt_errors = 0;
ue_dl.pmch_pkts_total = 0;
/* /*
ue_dl.pkt_errors = 0; ue_dl.pkt_errors = 0;
ue_dl.pkts_total = 0; ue_dl.pkts_total = 0;
@ -944,7 +960,7 @@ int main(int argc, char **argv) {
plot_real_t p_sync, pce; plot_real_t p_sync, pce;
plot_scatter_t pscatequal, pscatequal_pdcch; plot_scatter_t pscatequal, pscatequal_pdcch, pscatequal_pmch;
float tmp_plot[110*15*2048]; float tmp_plot[110*15*2048];
float tmp_plot2[110*15*2048]; float tmp_plot2[110*15*2048];
@ -963,6 +979,15 @@ void *plot_thread_run(void *arg) {
plot_scatter_setYAxisScale(&pscatequal, -4, 4); plot_scatter_setYAxisScale(&pscatequal, -4, 4);
plot_scatter_addToWindowGrid(&pscatequal, (char*)"pdsch_ue", 0, 0); plot_scatter_addToWindowGrid(&pscatequal, (char*)"pdsch_ue", 0, 0);
plot_scatter_init(&pscatequal_pmch);
plot_scatter_setTitle(&pscatequal_pmch, "PMCH - Equalized Symbols");
plot_scatter_setXAxisScale(&pscatequal_pmch, -4, 4);
plot_scatter_setYAxisScale(&pscatequal_pmch, -4, 4);
plot_scatter_addToWindowGrid(&pscatequal_pmch, (char*)"pdsch_ue", 0, 1);
if (!prog_args.disable_plots_except_constellation) { if (!prog_args.disable_plots_except_constellation) {
plot_real_init(&pce); plot_real_init(&pce);
@ -979,7 +1004,7 @@ void *plot_thread_run(void *arg) {
plot_scatter_setXAxisScale(&pscatequal_pdcch, -4, 4); plot_scatter_setXAxisScale(&pscatequal_pdcch, -4, 4);
plot_scatter_setYAxisScale(&pscatequal_pdcch, -4, 4); plot_scatter_setYAxisScale(&pscatequal_pdcch, -4, 4);
plot_real_addToWindowGrid(&pce, (char*)"pdsch_ue", 0, 1); plot_real_addToWindowGrid(&pce, (char*)"pdsch_ue", 0, 2);
plot_real_addToWindowGrid(&pscatequal_pdcch, (char*)"pdsch_ue", 1, 0); plot_real_addToWindowGrid(&pscatequal_pdcch, (char*)"pdsch_ue", 1, 0);
plot_real_addToWindowGrid(&p_sync, (char*)"pdsch_ue", 1, 1); plot_real_addToWindowGrid(&p_sync, (char*)"pdsch_ue", 1, 1);
} }
@ -988,6 +1013,7 @@ void *plot_thread_run(void *arg) {
sem_wait(&plot_sem); sem_wait(&plot_sem);
uint32_t nof_symbols = ue_dl.pdsch_cfg.nbits[0].nof_re; uint32_t nof_symbols = ue_dl.pdsch_cfg.nbits[0].nof_re;
uint32_t nof_symbols_pmch = ue_dl.pmch_cfg.nbits[0].nof_re;
if (!prog_args.disable_plots_except_constellation) { if (!prog_args.disable_plots_except_constellation) {
for (i = 0; i < nof_re; i++) { for (i = 0; i < nof_re; i++) {
tmp_plot[i] = 20 * log10f(cabsf(ue_dl.sf_symbols[i])); tmp_plot[i] = 20 * log10f(cabsf(ue_dl.sf_symbols[i]));
@ -1031,6 +1057,7 @@ void *plot_thread_run(void *arg) {
plot_scatter_setNewData(&pscatequal, ue_dl.pdsch.d[0], nof_symbols); plot_scatter_setNewData(&pscatequal, ue_dl.pdsch.d[0], nof_symbols);
plot_scatter_setNewData(&pscatequal_pmch, ue_dl.pmch.d, nof_symbols_pmch);
if (plot_sf_idx == 1) { if (plot_sf_idx == 1) {
if (prog_args.net_port_signal > 0) { if (prog_args.net_port_signal > 0) {
srslte_netsink_write(&net_sink_signal, &sf_buffer[srslte_ue_sync_sf_len(&ue_sync)/7], srslte_netsink_write(&net_sink_signal, &sf_buffer[srslte_ue_sync_sf_len(&ue_sync)/7],

@ -113,7 +113,7 @@ int main(int argc, char **argv) {
uint32_t m0, m1; uint32_t m0, m1;
float m0_value, m1_value; float m0_value, m1_value;
uint32_t N_id_2; uint32_t N_id_2;
uint32_t sss_idx; int sss_idx;
struct timeval tdata[3]; struct timeval tdata[3];
int *exec_time; int *exec_time;

@ -51,9 +51,11 @@
// FIXME: This was chosen arbitrarily // FIXME: This was chosen arbitrarily
#define LIBLTE_ASN1_OID_MAXSUBIDS 128 #define LIBLTE_ASN1_OID_MAXSUBIDS 128
// Caution these values must match SRSLTE_ ones in common.h
#define LIBLTE_MAX_MSG_SIZE_BITS 102048 #define LIBLTE_MAX_MSG_SIZE_BITS 102048
#define LIBLTE_MAX_MSG_SIZE_BYTES 12756 #define LIBLTE_MAX_MSG_SIZE_BYTES 12756
#define LIBLTE_MSG_HEADER_OFFSET 1024 #define LIBLTE_MSG_HEADER_OFFSET 1020
/******************************************************************************* /*******************************************************************************
TYPEDEFS TYPEDEFS
@ -82,6 +84,8 @@ static const char liblte_error_text[LIBLTE_ERROR_N_ITEMS][64] = {
"Decode failure", "Decode failure",
}; };
#define LIBLTE_STRING_LEN 128
typedef void* LIBLTE_ASN1_OPEN_TYPE_STRUCT; typedef void* LIBLTE_ASN1_OPEN_TYPE_STRUCT;
typedef struct { typedef struct {
@ -96,86 +100,15 @@ typedef struct{
typedef struct{ typedef struct{
uint32 N_bits; uint32 N_bits;
uint8 header[LIBLTE_MSG_HEADER_OFFSET];
uint8 msg[LIBLTE_MAX_MSG_SIZE_BITS]; uint8 msg[LIBLTE_MAX_MSG_SIZE_BITS];
}LIBLTE_SIMPLE_BIT_MSG_STRUCT; }LIBLTE_BIT_MSG_STRUCT;
typedef struct{ typedef struct{
uint32 N_bytes; uint32 N_bytes;
uint8 header[LIBLTE_MSG_HEADER_OFFSET];
uint8 msg[LIBLTE_MAX_MSG_SIZE_BYTES]; uint8 msg[LIBLTE_MAX_MSG_SIZE_BYTES];
}LIBLTE_SIMPLE_BYTE_MSG_STRUCT; }LIBLTE_BYTE_MSG_STRUCT;
struct LIBLTE_BYTE_MSG_STRUCT{
uint32 N_bytes;
uint8 buffer[LIBLTE_MAX_MSG_SIZE_BYTES];
uint8 *msg;
LIBLTE_BYTE_MSG_STRUCT():N_bytes(0)
{
msg = &buffer[LIBLTE_MSG_HEADER_OFFSET];
}
LIBLTE_BYTE_MSG_STRUCT(const LIBLTE_BYTE_MSG_STRUCT& buf)
{
N_bytes = buf.N_bytes;
memcpy(msg, buf.msg, N_bytes);
}
LIBLTE_BYTE_MSG_STRUCT & operator= (const LIBLTE_BYTE_MSG_STRUCT & buf)
{
// avoid self assignment
if (&buf == this)
return *this;
N_bytes = buf.N_bytes;
memcpy(msg, buf.msg, N_bytes);
return *this;
}
uint32 get_headroom()
{
return msg-buffer;
}
void reset()
{
N_bytes = 0;
msg = &buffer[LIBLTE_MSG_HEADER_OFFSET];
}
};
struct LIBLTE_BIT_MSG_STRUCT{
uint32 N_bits;
uint8 buffer[LIBLTE_MAX_MSG_SIZE_BITS];
uint8 *msg;
LIBLTE_BIT_MSG_STRUCT():N_bits(0)
{
msg = &buffer[LIBLTE_MSG_HEADER_OFFSET];
while( (uint64_t)(msg) % 8 > 0) {
msg++;
}
}
LIBLTE_BIT_MSG_STRUCT(const LIBLTE_BIT_MSG_STRUCT& buf){
N_bits = buf.N_bits;
memcpy(msg, buf.msg, N_bits);
}
LIBLTE_BIT_MSG_STRUCT & operator= (const LIBLTE_BIT_MSG_STRUCT & buf){
// avoid self assignment
if (&buf == this)
return *this;
N_bits = buf.N_bits;
memcpy(msg, buf.msg, N_bits);
return *this;
}
uint32 get_headroom()
{
return msg-buffer;
}
void reset()
{
N_bits = 0;
msg = &buffer[LIBLTE_MSG_HEADER_OFFSET];
while( (uint64_t)(msg) % 8 > 0) {
msg++;
}
}
};
/******************************************************************************* /*******************************************************************************

@ -1209,7 +1209,7 @@ static const char liblte_mme_add_ci_text[LIBLTE_MME_ADD_CI_N_ITEMS][20] = {"Don'
"Add"}; "Add"};
// Structs // Structs
typedef struct{ typedef struct{
std::string name; char name[LIBLTE_STRING_LEN];
LIBLTE_MME_ADD_CI_ENUM add_ci; LIBLTE_MME_ADD_CI_ENUM add_ci;
}LIBLTE_MME_NETWORK_NAME_STRUCT; }LIBLTE_MME_NETWORK_NAME_STRUCT;
// Functions // Functions
@ -1752,7 +1752,7 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_guti_type_ie(uint8 **ie_
// Enums // Enums
// Structs // Structs
typedef struct{ typedef struct{
std::string apn; char apn[LIBLTE_STRING_LEN];
}LIBLTE_MME_ACCESS_POINT_NAME_STRUCT; }LIBLTE_MME_ACCESS_POINT_NAME_STRUCT;
// Functions // Functions
LIBLTE_ERROR_ENUM liblte_mme_pack_access_point_name_ie(LIBLTE_MME_ACCESS_POINT_NAME_STRUCT *apn, LIBLTE_ERROR_ENUM liblte_mme_pack_access_point_name_ie(LIBLTE_MME_ACCESS_POINT_NAME_STRUCT *apn,
@ -2810,6 +2810,7 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_authentication_request_msg(LIBLTE_BYTE_MSG_S
// Structs // Structs
typedef struct{ typedef struct{
uint8 res[16]; uint8 res[16];
int res_len;
}LIBLTE_MME_AUTHENTICATION_RESPONSE_MSG_STRUCT; }LIBLTE_MME_AUTHENTICATION_RESPONSE_MSG_STRUCT;
// Functions // Functions
LIBLTE_ERROR_ENUM liblte_mme_pack_authentication_response_msg(LIBLTE_MME_AUTHENTICATION_RESPONSE_MSG_STRUCT *auth_resp, LIBLTE_ERROR_ENUM liblte_mme_pack_authentication_response_msg(LIBLTE_MME_AUTHENTICATION_RESPONSE_MSG_STRUCT *auth_resp,
@ -3791,6 +3792,8 @@ typedef struct{
}LIBLTE_MME_ESM_INFORMATION_RESPONSE_MSG_STRUCT; }LIBLTE_MME_ESM_INFORMATION_RESPONSE_MSG_STRUCT;
// Functions // Functions
LIBLTE_ERROR_ENUM liblte_mme_pack_esm_information_response_msg(LIBLTE_MME_ESM_INFORMATION_RESPONSE_MSG_STRUCT *esm_info_resp, LIBLTE_ERROR_ENUM liblte_mme_pack_esm_information_response_msg(LIBLTE_MME_ESM_INFORMATION_RESPONSE_MSG_STRUCT *esm_info_resp,
uint8 sec_hdr_type,
uint32 count,
LIBLTE_BYTE_MSG_STRUCT *msg); LIBLTE_BYTE_MSG_STRUCT *msg);
LIBLTE_ERROR_ENUM liblte_mme_unpack_esm_information_response_msg(LIBLTE_BYTE_MSG_STRUCT *msg, LIBLTE_ERROR_ENUM liblte_mme_unpack_esm_information_response_msg(LIBLTE_BYTE_MSG_STRUCT *msg,
LIBLTE_MME_ESM_INFORMATION_RESPONSE_MSG_STRUCT *esm_info_resp); LIBLTE_MME_ESM_INFORMATION_RESPONSE_MSG_STRUCT *esm_info_resp);

@ -213,17 +213,111 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_mbsfn_subframe_config_ie(uint8
LIBLTE_RRC_MBSFN_SUBFRAME_CONFIG_STRUCT *mbsfn_subfr_cnfg); LIBLTE_RRC_MBSFN_SUBFRAME_CONFIG_STRUCT *mbsfn_subfr_cnfg);
/********************************************************************* /*********************************************************************
IE Name: PMCH Info List IE Name: TMGI
Description: Specifies configuration of all PMCHs of an MBSFN area Description: Temporary Mobile Group Identity (PLMN + MBMS service ID)
Document Reference: 36.331 v10.0.0 Section 6.3.7 Document Reference: 36.331 v10.0.0 Section 6.3.7
*********************************************************************/ *********************************************************************/
// Defines // Defines
// Enums // Enums
// Structs // Structs
typedef struct{
uint16 mcc;
uint16 mnc;
}LIBLTE_RRC_PLMN_IDENTITY_STRUCT;
typedef struct{
LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id_r9;
uint8 plmn_index_r9;
bool plmn_id_explicit;
uint32 serviceid_r9;
}LIBLTE_RRC_TMGI_R9_STRUCT;
// Functions // Functions
// FIXME LIBLTE_ERROR_ENUM liblte_rrc_pack_tmgi_r9_ie(LIBLTE_RRC_TMGI_R9_STRUCT *tmgi,
uint8 **ie_ptr);
LIBLTE_ERROR_ENUM liblte_rrc_unpack_tmgi_r9_ie(uint8 **ie_ptr,
LIBLTE_RRC_TMGI_R9_STRUCT *tmgi);
/*********************************************************************
IE Name: MBMS Session Info
Description: Information about an individual MBMS session
Document Reference: 36.331 v10.0.0 Section 6.3.7
*********************************************************************/
// Defines
// Enums
// Structs
typedef struct{
LIBLTE_RRC_TMGI_R9_STRUCT tmgi_r9;
uint8 sessionid_r9;
bool sessionid_r9_present;
uint8 logicalchannelid_r9;
}LIBLTE_RRC_MBMS_SESSION_INFO_R9_STRUCT;
// Functions
LIBLTE_ERROR_ENUM liblte_rrc_pack_mbms_session_info_r9_ie(LIBLTE_RRC_MBMS_SESSION_INFO_R9_STRUCT *mbms_session_info,
uint8 **ie_ptr);
LIBLTE_ERROR_ENUM liblte_rrc_unpack_mbms_session_info_r9_ie(uint8 **ie_ptr,
LIBLTE_RRC_MBMS_SESSION_INFO_R9_STRUCT *mbms_session_info);
/*********************************************************************
IE Name: PMCH Config
Description: Contains configuration parameters of the sessions
carried by a PMCH
Document Reference: 36.331 v10.0.0 Section 6.3.7
*********************************************************************/
// Defines
// Enums
typedef enum{
LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_RF8 = 0,
LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_RF16,
LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_RF32,
LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_RF64,
LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_RF128,
LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_RF256,
LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_RF512,
LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_RF1024,
LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_N_ITEMS,
}LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_ENUM;
static const char liblte_rrc_mch_scheduling_period_r9_text[LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_N_ITEMS][20] = {"8", "16", "32", "64", "128", "256", "512", "1024"};
static const uint16 liblte_rrc_mch_scheduling_period_r9_num[LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_N_ITEMS] = {8, 16, 32, 64, 128, 256, 512, 1024};
// Structs
typedef struct{
uint16 sf_alloc_end_r9;
uint8 datamcs_r9;
LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_ENUM mch_schedulingperiod_r9;
}LIBLTE_RRC_PMCH_CONFIG_R9_STRUCT;
// Functions
LIBLTE_ERROR_ENUM liblte_rrc_pack_pmch_config_r9_ie(LIBLTE_RRC_PMCH_CONFIG_R9_STRUCT *pmch_cnfg,
uint8 **ie_ptr);
LIBLTE_ERROR_ENUM liblte_rrc_unpack_pmch_config_r9_ie(uint8 **ie_ptr,
LIBLTE_RRC_PMCH_CONFIG_R9_STRUCT *pmch_cnfg);
/*********************************************************************
IE Name: PMCH Info
Description: Specifies configuration of PMCH of an MBSFN area
Document Reference: 36.331 v10.0.0 Section 6.3.7
*********************************************************************/
// Defines
#define LIBLTE_RRC_MAX_SESSION_PER_PMCH 29
// Enums
// Structs
typedef struct{
LIBLTE_RRC_PMCH_CONFIG_R9_STRUCT pmch_config_r9;
LIBLTE_RRC_MBMS_SESSION_INFO_R9_STRUCT mbms_sessioninfolist_r9[LIBLTE_RRC_MAX_SESSION_PER_PMCH];
uint8 mbms_sessioninfolist_r9_size;
}LIBLTE_RRC_PMCH_INFO_R9_STRUCT;
// Functions
LIBLTE_ERROR_ENUM liblte_rrc_pack_pmch_info_r9_ie(LIBLTE_RRC_PMCH_INFO_R9_STRUCT *pmch_info,
uint8 **ie_ptr);
LIBLTE_ERROR_ENUM liblte_rrc_unpack_pmch_info_r9_ie(uint8 **ie_ptr,
LIBLTE_RRC_PMCH_INFO_R9_STRUCT *pmch_info);
/********************************************************************* /*********************************************************************
IE Name: C-RNTI IE Name: C-RNTI
@ -2227,10 +2321,6 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_csfb_registration_param_1xrtt_v920_ie(uint8
// Defines // Defines
// Enums // Enums
// Structs // Structs
typedef struct{
uint16 mcc;
uint16 mnc;
}LIBLTE_RRC_PLMN_IDENTITY_STRUCT;
typedef struct{ typedef struct{
LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id; LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id;
uint32 cell_id; uint32 cell_id;
@ -5135,7 +5225,7 @@ typedef struct{
LIBLTE_RRC_UE_TIMERS_AND_CONSTANTS_STRUCT ue_timers_and_constants; LIBLTE_RRC_UE_TIMERS_AND_CONSTANTS_STRUCT ue_timers_and_constants;
LIBLTE_RRC_ARFCN_VALUE_EUTRA_STRUCT arfcn_value_eutra; LIBLTE_RRC_ARFCN_VALUE_EUTRA_STRUCT arfcn_value_eutra;
LIBLTE_RRC_UL_BW_STRUCT ul_bw; LIBLTE_RRC_UL_BW_STRUCT ul_bw;
LIBLTE_RRC_MBSFN_SUBFRAME_CONFIG_STRUCT mbsfn_subfr_cnfg[LIBLTE_RRC_MAX_MBSFN_ALLOCATIONS]; LIBLTE_RRC_MBSFN_SUBFRAME_CONFIG_STRUCT mbsfn_subfr_cnfg_list[LIBLTE_RRC_MAX_MBSFN_ALLOCATIONS];
LIBLTE_RRC_TIME_ALIGNMENT_TIMER_ENUM time_alignment_timer; LIBLTE_RRC_TIME_ALIGNMENT_TIMER_ENUM time_alignment_timer;
uint32 mbsfn_subfr_cnfg_list_size; uint32 mbsfn_subfr_cnfg_list_size;
uint8 additional_spectrum_emission; uint8 additional_spectrum_emission;
@ -5545,7 +5635,7 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_sys_info_block_type_9_ie(uint8
// Structs // Structs
typedef struct{ typedef struct{
LIBLTE_RRC_MBSFN_AREA_INFO_STRUCT mbsfn_area_info_list_r9[LIBLTE_RRC_MAX_MBSFN_AREAS]; LIBLTE_RRC_MBSFN_AREA_INFO_STRUCT mbsfn_area_info_list_r9[LIBLTE_RRC_MAX_MBSFN_AREAS];
LIBLTE_RRC_MBSFN_NOTIFICATION_CONFIG_STRUCT mbms_notification_config; LIBLTE_RRC_MBSFN_NOTIFICATION_CONFIG_STRUCT mbsfn_notification_config;
uint8 mbsfn_area_info_list_r9_size; uint8 mbsfn_area_info_list_r9_size;
}LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT; }LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT;
// Functions // Functions
@ -5579,7 +5669,7 @@ static const char liblte_rrc_ul_information_transfer_type_text[LIBLTE_RRC_UL_INF
"CDMA2000-HRPD"}; "CDMA2000-HRPD"};
// Structs // Structs
typedef struct{ typedef struct{
LIBLTE_SIMPLE_BYTE_MSG_STRUCT dedicated_info; LIBLTE_BYTE_MSG_STRUCT dedicated_info;
LIBLTE_RRC_UL_INFORMATION_TRANSFER_TYPE_ENUM dedicated_info_type; LIBLTE_RRC_UL_INFORMATION_TRANSFER_TYPE_ENUM dedicated_info_type;
}LIBLTE_RRC_UL_INFORMATION_TRANSFER_STRUCT; }LIBLTE_RRC_UL_INFORMATION_TRANSFER_STRUCT;
// Functions // Functions
@ -5771,18 +5861,18 @@ typedef enum{
LIBLTE_RRC_SIB_TYPE_11, LIBLTE_RRC_SIB_TYPE_11,
LIBLTE_RRC_SIB_TYPE_12_v920, LIBLTE_RRC_SIB_TYPE_12_v920,
LIBLTE_RRC_SIB_TYPE_13_v920, LIBLTE_RRC_SIB_TYPE_13_v920,
LIBLTE_RRC_SIB_TYPE_SPARE_5, LIBLTE_RRC_SIB_TYPE_14_v1130,
LIBLTE_RRC_SIB_TYPE_SPARE_4, LIBLTE_RRC_SIB_TYPE_15_v1130,
LIBLTE_RRC_SIB_TYPE_SPARE_3, LIBLTE_RRC_SIB_TYPE_16_v1130,
LIBLTE_RRC_SIB_TYPE_SPARE_2, LIBLTE_RRC_SIB_TYPE_17_v1250,
LIBLTE_RRC_SIB_TYPE_SPARE_1, LIBLTE_RRC_SIB_TYPE_18_v1250,
LIBLTE_RRC_SIB_TYPE_N_ITEMS, LIBLTE_RRC_SIB_TYPE_N_ITEMS,
}LIBLTE_RRC_SIB_TYPE_ENUM; }LIBLTE_RRC_SIB_TYPE_ENUM;
static const char liblte_rrc_sib_type_text[LIBLTE_RRC_SIB_TYPE_N_ITEMS][20] = { "3", "4", "5", "6", static const char liblte_rrc_sib_type_text[LIBLTE_RRC_SIB_TYPE_N_ITEMS][20] = { "3", "4", "5", "6",
"7", "8", "9", "10", "7", "8", "9", "10",
"11", "12", "13", "SPARE", "11", "12_v920", "13_v920", "14_v1130",
"SPARE", "SPARE", "SPARE", "SPARE"}; "15_v1130", "16_v1130", "17_v1250", "18_v1250"};
static const uint8 liblte_rrc_sib_type_num[LIBLTE_RRC_SIB_TYPE_N_ITEMS] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0, 0, 0, 0, 0}; static const uint8 liblte_rrc_sib_type_num[LIBLTE_RRC_SIB_TYPE_N_ITEMS] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18};
// Structs // Structs
typedef struct{ typedef struct{
LIBLTE_RRC_PLMN_IDENTITY_STRUCT id; LIBLTE_RRC_PLMN_IDENTITY_STRUCT id;
@ -5846,14 +5936,20 @@ typedef enum{
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_11, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_11,
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_12, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_12,
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13,
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_14,
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_15,
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_16,
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_17,
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_18,
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1, // Intentionally not first LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1, // Intentionally not first
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_N_ITEMS, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_N_ITEMS,
}LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_ENUM; }LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_ENUM;
static const char liblte_rrc_sys_info_block_type_text[LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_N_ITEMS][20] = { "2", "3", "4", "5", static const char liblte_rrc_sys_info_block_type_text[LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_N_ITEMS][20] = { "2", "3", "4", "5",
"6", "7", "8", "9", "6", "7", "8", "9",
"10", "11", "12", "13", "10", "11", "12", "13",
"1"}; "14", "15", "16", "17",
static const uint8 liblte_rrc_sys_info_block_type_num[LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_N_ITEMS] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1}; "18", "1"};
static const uint8 liblte_rrc_sys_info_block_type_num[LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_N_ITEMS] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 1};
// Structs // Structs
typedef union{ typedef union{
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT sib1; LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT sib1;
@ -5960,7 +6056,7 @@ typedef struct{
}LIBLTE_RRC_REGISTERED_MME_STRUCT; }LIBLTE_RRC_REGISTERED_MME_STRUCT;
typedef struct{ typedef struct{
LIBLTE_RRC_REGISTERED_MME_STRUCT registered_mme; LIBLTE_RRC_REGISTERED_MME_STRUCT registered_mme;
LIBLTE_SIMPLE_BYTE_MSG_STRUCT dedicated_info_nas; LIBLTE_BYTE_MSG_STRUCT dedicated_info_nas;
uint8 rrc_transaction_id; uint8 rrc_transaction_id;
uint8 selected_plmn_id; uint8 selected_plmn_id;
bool registered_mme_present; bool registered_mme_present;
@ -6245,7 +6341,7 @@ typedef struct{
typedef struct{ typedef struct{
LIBLTE_RRC_MEAS_CONFIG_STRUCT meas_cnfg; LIBLTE_RRC_MEAS_CONFIG_STRUCT meas_cnfg;
LIBLTE_RRC_MOBILITY_CONTROL_INFO_STRUCT mob_ctrl_info; LIBLTE_RRC_MOBILITY_CONTROL_INFO_STRUCT mob_ctrl_info;
LIBLTE_SIMPLE_BYTE_MSG_STRUCT ded_info_nas_list[LIBLTE_RRC_MAX_DRB]; LIBLTE_BYTE_MSG_STRUCT ded_info_nas_list[LIBLTE_RRC_MAX_DRB];
LIBLTE_RRC_RR_CONFIG_DEDICATED_STRUCT rr_cnfg_ded; LIBLTE_RRC_RR_CONFIG_DEDICATED_STRUCT rr_cnfg_ded;
LIBLTE_RRC_SECURITY_CONFIG_HO_STRUCT sec_cnfg_ho; LIBLTE_RRC_SECURITY_CONFIG_HO_STRUCT sec_cnfg_ho;
uint32 N_ded_info_nas; uint32 N_ded_info_nas;
@ -6551,10 +6647,37 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_measurement_report_msg(LIBLTE_BIT_MSG_STRUCT
Document Reference: 36.331 v10.0.0 Section 6.2.2 Document Reference: 36.331 v10.0.0 Section 6.2.2
*********************************************************************/ *********************************************************************/
// Defines // Defines
#define LIBLTE_RRC_MAX_PMCH_PER_MBSFN 15
// Enums // Enums
typedef enum{
LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_RF4 = 0,
LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_RF8,
LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_RF16,
LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_RF32,
LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_RF64,
LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_RF128,
LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_RF256,
LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_N_ITEMS,
}LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_ENUM;
static const char liblte_rrc_mbsfn_common_sf_alloc_period_r9_text[LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_N_ITEMS][20] = {"4", "8", "16", "32",
"64", "128", "256"};
static const uint32 liblte_rrc_mbsfn_common_sf_alloc_period_r9_num[LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_N_ITEMS] = {4, 8, 16, 32,
64, 128, 256};
// Structs // Structs
typedef struct{
LIBLTE_RRC_MBSFN_SUBFRAME_CONFIG_STRUCT commonsf_allocpatternlist_r9[LIBLTE_RRC_MAX_MBSFN_ALLOCATIONS];
uint8 commonsf_allocpatternlist_r9_size;
LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_ENUM commonsf_allocperiod_r9;
LIBLTE_RRC_PMCH_INFO_R9_STRUCT pmch_infolist_r9[LIBLTE_RRC_MAX_PMCH_PER_MBSFN];
uint8 pmch_infolist_r9_size;
}LIBLTE_RRC_MBSFN_AREA_CONFIGURATION_R9_STRUCT;
// Functions // Functions
// FIXME LIBLTE_ERROR_ENUM liblte_rrc_pack_mbsfn_area_configuration_r9_msg(LIBLTE_RRC_MBSFN_AREA_CONFIGURATION_R9_STRUCT *mbsfn_area_cnfg,
LIBLTE_BIT_MSG_STRUCT *msg);
LIBLTE_ERROR_ENUM liblte_rrc_unpack_mbsfn_area_configuration_r9_msg(LIBLTE_RRC_MBSFN_AREA_CONFIGURATION_R9_STRUCT *msg,
LIBLTE_RRC_PAGING_STRUCT *mbsfn_area_cnfg);
/********************************************************************* /*********************************************************************
Message Name: Master Information Block Message Name: Master Information Block
@ -6626,7 +6749,7 @@ static const char liblte_rrc_dl_information_transfer_type_text[LIBLTE_RRC_DL_INF
"CDMA2000-HRPD"}; "CDMA2000-HRPD"};
// Structs // Structs
typedef struct{ typedef struct{
LIBLTE_SIMPLE_BYTE_MSG_STRUCT dedicated_info; LIBLTE_BYTE_MSG_STRUCT dedicated_info;
LIBLTE_RRC_DL_INFORMATION_TRANSFER_TYPE_ENUM dedicated_info_type; LIBLTE_RRC_DL_INFORMATION_TRANSFER_TYPE_ENUM dedicated_info_type;
uint8 rrc_transaction_id; uint8 rrc_transaction_id;
}LIBLTE_RRC_DL_INFORMATION_TRANSFER_STRUCT; }LIBLTE_RRC_DL_INFORMATION_TRANSFER_STRUCT;
@ -6783,8 +6906,12 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_bcch_dlsch_msg(LIBLTE_BIT_MSG_STRUCT
// Defines // Defines
// Enums // Enums
// Structs // Structs
typedef LIBLTE_RRC_MBSFN_AREA_CONFIGURATION_R9_STRUCT LIBLTE_RRC_MCCH_MSG_STRUCT;
// Functions // Functions
// FIXME LIBLTE_ERROR_ENUM liblte_rrc_pack_mcch_msg(LIBLTE_RRC_MCCH_MSG_STRUCT *mcch_msg,
LIBLTE_BIT_MSG_STRUCT *msg);
LIBLTE_ERROR_ENUM liblte_rrc_unpack_mcch_msg(LIBLTE_BIT_MSG_STRUCT *msg,
LIBLTE_RRC_MCCH_MSG_STRUCT *mcch_msg);
/********************************************************************* /*********************************************************************
Message Name: PCCH Message Message Name: PCCH Message

@ -24,6 +24,15 @@
* *
*/ */
/******************************************************************************
* File: block_queue.h
* Description: General-purpose blocking queue. It can behave as a bounded or
* unbounded blocking queue and allows blocking and non-blocking
* operations in both push and pop
*****************************************************************************/
#ifndef SRSLTE_BLOCK_QUEUE_H #ifndef SRSLTE_BLOCK_QUEUE_H
#define SRSLTE_BLOCK_QUEUE_H #define SRSLTE_BLOCK_QUEUE_H
@ -32,21 +41,62 @@
#include <utility> #include <utility>
#include <pthread.h> #include <pthread.h>
#include <stdio.h> #include <stdio.h>
#include <stdint.h>
namespace srslte { namespace srslte {
template<typename myobj> template<typename myobj>
class block_queue { class block_queue {
public: public:
block_queue<myobj>() {
// Callback functions for mutexed operations inside pop/push methods
class call_mutexed_itf {
public:
virtual void popping(myobj obj) = 0;
virtual void pushing(myobj obj) = 0;
};
block_queue<myobj>(int capacity = -1) {
pthread_mutex_init(&mutex, NULL); pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cvar, NULL); pthread_cond_init(&cv_empty, NULL);
pthread_cond_init(&cv_full, NULL);
this->capacity = capacity;
mutexed_callback = NULL;
} }
void push(const myobj& value) { void set_mutexed_itf(call_mutexed_itf *itf) {
mutexed_callback = itf;
}
void resize(int new_capacity) {
capacity = new_capacity;
}
bool push_(const myobj& value, bool block) {
pthread_mutex_lock(&mutex); pthread_mutex_lock(&mutex);
if (capacity > 0) {
if (block) {
while(q.size() > (uint32_t) capacity) {
pthread_cond_wait(&cv_full, &mutex);
}
} else {
pthread_mutex_unlock(&mutex);
return false;
}
}
q.push(value); q.push(value);
pthread_cond_signal(&cvar); if (mutexed_callback) {
mutexed_callback->pushing(value);
}
pthread_cond_signal(&cv_empty);
pthread_mutex_unlock(&mutex); pthread_mutex_unlock(&mutex);
return true;
}
void push(const myobj& value) {
push_(value, true);
}
bool try_push(const myobj& value) {
return push_(value, false);
} }
bool try_pop(myobj *value) { bool try_pop(myobj *value) {
@ -59,6 +109,10 @@ public:
*value = q.front(); *value = q.front();
q.pop(); q.pop();
} }
if (mutexed_callback) {
mutexed_callback->popping(*value);
}
pthread_cond_signal(&cv_full);
pthread_mutex_unlock(&mutex); pthread_mutex_unlock(&mutex);
return true; return true;
} }
@ -66,15 +120,19 @@ public:
myobj wait_pop() { // blocking pop myobj wait_pop() { // blocking pop
pthread_mutex_lock(&mutex); pthread_mutex_lock(&mutex);
while(q.empty()) { while(q.empty()) {
pthread_cond_wait(&cvar, &mutex); pthread_cond_wait(&cv_empty, &mutex);
} }
myobj value = q.front(); myobj value = q.front();
q.pop(); q.pop();
if (mutexed_callback) {
mutexed_callback->popping(value);
}
pthread_cond_signal(&cv_full);
pthread_mutex_unlock(&mutex); pthread_mutex_unlock(&mutex);
return value; return value;
} }
bool empty() const { // queue is empty? bool empty() { // queue is empty?
pthread_mutex_lock(&mutex); pthread_mutex_lock(&mutex);
bool ret = q.empty(); bool ret = q.empty();
pthread_mutex_unlock(&mutex); pthread_mutex_unlock(&mutex);
@ -86,10 +144,21 @@ public:
while (try_pop(item)); while (try_pop(item));
} }
myobj front() {
return q.front();
}
size_t size() {
return q.size();
}
private: private:
std::queue<myobj> q; std::queue<myobj> q;
pthread_mutex_t mutex; pthread_mutex_t mutex;
pthread_cond_t cvar; pthread_cond_t cv_empty;
pthread_cond_t cv_full;
call_mutexed_itf *mutexed_callback;
int capacity;
}; };
} }

@ -93,6 +93,10 @@ public:
#endif #endif
} }
uint32_t nof_available_pdus() {
return available.size();
}
bool is_almost_empty() { bool is_almost_empty() {
return available.size() < capacity/20; return available.size() < capacity/20;
} }

@ -44,6 +44,8 @@
#define SRSLTE_N_DRB 8 #define SRSLTE_N_DRB 8
#define SRSLTE_N_RADIO_BEARERS 11 #define SRSLTE_N_RADIO_BEARERS 11
#define SRSLTE_N_MCH_LCIDS 32
#define HARQ_DELAY_MS 4 #define HARQ_DELAY_MS 4
#define MSG3_DELAY_MS 2 // Delay added to HARQ_DELAY_MS #define MSG3_DELAY_MS 2 // Delay added to HARQ_DELAY_MS
#define TTI_RX(tti) (tti>HARQ_DELAY_MS?((tti-HARQ_DELAY_MS)%10240):(10240+tti-HARQ_DELAY_MS)) #define TTI_RX(tti) (tti>HARQ_DELAY_MS?((tti-HARQ_DELAY_MS)%10240):(10240+tti-HARQ_DELAY_MS))
@ -61,17 +63,19 @@
// 3GPP 36.306 Table 4.1.1 // 3GPP 36.306 Table 4.1.1
#define SRSLTE_MAX_BUFFER_SIZE_BITS 102048 #define SRSLTE_MAX_BUFFER_SIZE_BITS 102048
#define SRSLTE_MAX_BUFFER_SIZE_BYTES 12756 #define SRSLTE_MAX_BUFFER_SIZE_BYTES 12756
#define SRSLTE_BUFFER_HEADER_OFFSET 1024 #define SRSLTE_BUFFER_HEADER_OFFSET 1020
#define SRSLTE_BUFFER_POOL_LOG_ENABLED #define SRSLTE_BUFFER_POOL_LOG_ENABLED
#ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED #ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED
#define pool_allocate (pool->allocate(__FUNCTION__)) #define pool_allocate (pool->allocate(__PRETTY_FUNCTION__))
#define SRSLTE_BUFFER_POOL_LOG_NAME_LEN 128 #define SRSLTE_BUFFER_POOL_LOG_NAME_LEN 128
#else #else
#define pool_allocate (pool->allocate()) #define pool_allocate (pool->allocate())
#endif #endif
#define ZERO_OBJECT(x) memset(&(x), 0x0, sizeof((x)))
#include "srslte/srslte.h" #include "srslte/srslte.h"
/******************************************************************************* /*******************************************************************************
@ -116,15 +120,17 @@ public:
byte_buffer_t():N_bytes(0) byte_buffer_t():N_bytes(0)
{ {
timestamp_is_set = false; bzero(buffer, SRSLTE_MAX_BUFFER_SIZE_BYTES);
timestamp_is_set = false;
msg = &buffer[SRSLTE_BUFFER_HEADER_OFFSET]; msg = &buffer[SRSLTE_BUFFER_HEADER_OFFSET];
next = NULL; next = NULL;
#ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED #ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED
debug_name[0] = 0; bzero(debug_name, SRSLTE_BUFFER_POOL_LOG_NAME_LEN);
#endif #endif
} }
byte_buffer_t(const byte_buffer_t& buf) byte_buffer_t(const byte_buffer_t& buf)
{ {
bzero(buffer, SRSLTE_MAX_BUFFER_SIZE_BYTES);
N_bytes = buf.N_bytes; N_bytes = buf.N_bytes;
memcpy(msg, buf.msg, N_bytes); memcpy(msg, buf.msg, N_bytes);
} }
@ -133,6 +139,7 @@ public:
// avoid self assignment // avoid self assignment
if (&buf == this) if (&buf == this)
return *this; return *this;
bzero(buffer, SRSLTE_MAX_BUFFER_SIZE_BYTES);
N_bytes = buf.N_bytes; N_bytes = buf.N_bytes;
memcpy(msg, buf.msg, N_bytes); memcpy(msg, buf.msg, N_bytes);
return *this; return *this;

@ -0,0 +1,59 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsUE library.
*
* srsUE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsUE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef SRSLTE_CONFIG_FILE_H
#define SRSLTE_CONFIG_FILE_H
#include <fstream>
#include <pwd.h>
#include "common.h"
bool config_exists(std::string &filename, std::string default_name)
{
std::ifstream conf(filename.c_str(), std::ios::in);
if(conf.fail()) {
const char *homedir = NULL;
char full_path[256];
ZERO_OBJECT(full_path);
if ((homedir = getenv("HOME")) == NULL) {
homedir = getpwuid(getuid())->pw_dir;
}
if (!homedir) {
homedir = ".";
}
snprintf(full_path, sizeof(full_path), "%s/.srs/%s", homedir, default_name.c_str());
filename = std::string(full_path);
// try to open again
conf.open(filename.c_str());
if (conf.fail()) {
return false;
}
}
return true;
}
#endif // SRSLTE_CONFIG_FILE_H

@ -0,0 +1,52 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsUE library.
*
* srsUE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsUE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef GEN_MCH_TALBES_H
#define GEN_MCH_TALBES_H
/******************************************************************************
* Common mch table generation - used in phch_common of UE and ENB for MBMS
*****************************************************************************/
#include <pthread.h>
#include <string.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
void generate_frame_mch_table(uint8_t *table, uint8_t alloc);
void generate_mch_table(uint8_t *table, uint32_t sf_alloc, uint8_t num_frames);
void generate_mcch_table(uint8_t *table, uint32_t sf_alloc);
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // SECURITY_H

@ -38,13 +38,19 @@ namespace srslte {
class srslte_nas_config_t class srslte_nas_config_t
{ {
public: public:
srslte_nas_config_t(uint32_t lcid_ = 0, std::string apn_ = "") srslte_nas_config_t(uint32_t lcid_ = 0, std::string apn_ = "", std::string user_ = "", std::string pass_ = "", bool force_imsi_attach_ = false)
:lcid(lcid_), :lcid(lcid_),
apn(apn_) apn(apn_),
user(user_),
pass(pass_),
force_imsi_attach(force_imsi_attach_)
{} {}
uint32_t lcid; uint32_t lcid;
std::string apn; std::string apn;
std::string user;
std::string pass;
bool force_imsi_attach;
}; };

@ -129,13 +129,13 @@ public:
virtual void debug(const char * message, ...) __attribute__ ((format (printf, 2, 3))) = 0; virtual void debug(const char * message, ...) __attribute__ ((format (printf, 2, 3))) = 0;
// Same with hex dump // Same with hex dump
virtual void error_hex(const uint8_t *hex, int size, const char *, ...) __attribute__((format (printf, 4, 5))) virtual void error_hex(const uint8_t *, int, const char *, ...) __attribute__((format (printf, 4, 5)))
{error("error_hex not implemented.\n");} {error("error_hex not implemented.\n");}
virtual void warning_hex(const uint8_t *hex, int size, const char *, ...) __attribute__((format (printf, 4, 5))) virtual void warning_hex(const uint8_t *, int, const char *, ...) __attribute__((format (printf, 4, 5)))
{error("warning_hex not implemented.\n");} {error("warning_hex not implemented.\n");}
virtual void info_hex(const uint8_t *hex, int size, const char *, ...) __attribute__((format (printf, 4, 5))) virtual void info_hex(const uint8_t *, int, const char *, ...) __attribute__((format (printf, 4, 5)))
{error("info_hex not implemented.\n");} {error("info_hex not implemented.\n");}
virtual void debug_hex(const uint8_t *hex, int size, const char *, ...) __attribute__((format (printf, 4, 5))) virtual void debug_hex(const uint8_t *, int, const char *, ...) __attribute__((format (printf, 4, 5)))
{error("debug_hex not implemented.\n");} {error("debug_hex not implemented.\n");}
protected: protected:

@ -50,6 +50,7 @@ public:
void write_dl_sirnti(uint8_t *pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti); void write_dl_sirnti(uint8_t *pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti);
void write_dl_bch(uint8_t *pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti); void write_dl_bch(uint8_t *pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti);
void write_dl_pch(uint8_t *pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti); void write_dl_pch(uint8_t *pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti);
void write_dl_mch(uint8_t *pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti);
private: private:
bool enable_write; bool enable_write;

@ -63,7 +63,7 @@ private:
get_time_interval(sleep_period_start); get_time_interval(sleep_period_start);
uint32_t period = sleep_period_start[0].tv_sec*1e6 + sleep_period_start[0].tv_usec; uint32_t period = sleep_period_start[0].tv_sec*1e6 + sleep_period_start[0].tv_usec;
if (m) { if (m) {
metrics_t metric = {}; metrics_t metric;
m->get_metrics(metric); m->get_metrics(metric);
for (uint32_t i=0;i<listeners.size();i++) { for (uint32_t i=0;i<listeners.size();i++) {
listeners[i]->set_metrics(metric, period); listeners[i]->set_metrics(metric, period);

@ -1,155 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsUE library.
*
* srsUE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsUE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
/******************************************************************************
* File: msg_queue.h
* Description: Thread-safe bounded circular buffer of srsue_byte_buffer pointers.
* Reference:
*****************************************************************************/
#ifndef SRSLTE_MSG_QUEUE_H
#define SRSLTE_MSG_QUEUE_H
#include "srslte/common/common.h"
#include <pthread.h>
namespace srslte {
class msg_queue
{
public:
msg_queue(uint32_t capacity_ = 128)
:head(0)
,tail(0)
,unread(0)
,unread_bytes(0)
,capacity(capacity_)
{
buf = new byte_buffer_t*[capacity];
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&not_empty, NULL);
pthread_cond_init(&not_full, NULL);
}
~msg_queue()
{
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&not_empty);
pthread_cond_destroy(&not_full);
delete [] buf;
}
void write(byte_buffer_t *msg)
{
pthread_mutex_lock(&mutex);
while(is_full()) {
pthread_cond_wait(&not_full, &mutex);
}
buf[head] = msg;
head = (head+1)%capacity;
unread++;
unread_bytes += msg->N_bytes;
pthread_cond_signal(&not_empty);
pthread_mutex_unlock(&mutex);
}
void read(byte_buffer_t **msg)
{
pthread_mutex_lock(&mutex);
while(is_empty()) {
pthread_cond_wait(&not_empty, &mutex);
}
*msg = buf[tail];
tail = (tail+1)%capacity;
unread--;
unread_bytes -= (*msg)->N_bytes;
pthread_cond_signal(&not_full);
pthread_mutex_unlock(&mutex);
}
bool try_read(byte_buffer_t **msg)
{
pthread_mutex_lock(&mutex);
if(is_empty())
{
pthread_mutex_unlock(&mutex);
return false;
}else{
*msg = buf[tail];
tail = (tail+1)%capacity;
unread--;
unread_bytes -= (*msg)->N_bytes;
pthread_cond_signal(&not_full);
pthread_mutex_unlock(&mutex);
return true;
}
}
uint32_t size()
{
pthread_mutex_lock(&mutex);
uint32_t r = unread;
pthread_mutex_unlock(&mutex);
return r;
}
uint32_t size_bytes()
{
pthread_mutex_lock(&mutex);
uint32_t r = unread_bytes;
pthread_mutex_unlock(&mutex);
return r;
}
uint32_t size_tail_bytes()
{
pthread_mutex_lock(&mutex);
uint32_t r = buf[tail]->N_bytes;
pthread_mutex_unlock(&mutex);
return r;
}
private:
bool is_empty() const { return unread == 0; }
bool is_full() const { return unread == capacity; }
pthread_cond_t not_empty;
pthread_cond_t not_full;
pthread_mutex_t mutex;
byte_buffer_t **buf;
uint32_t capacity;
uint32_t unread;
uint32_t unread_bytes;
uint32_t head;
uint32_t tail;
};
} // namespace srslte
#endif // SRSLTE_MSG_QUEUE_H

@ -34,6 +34,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
/* This structure gets written to the start of the file */ /* This structure gets written to the start of the file */
@ -104,6 +105,67 @@ typedef struct NAS_Context_Info_s {
} NAS_Context_Info_t; } NAS_Context_Info_t;
/* RLC-LTE disector */
/* rlcMode */
#define RLC_TM_MODE 1
#define RLC_UM_MODE 2
#define RLC_AM_MODE 4
#define RLC_PREDEF 8
/* priority ? */
/* channelType */
#define CHANNEL_TYPE_CCCH 1
#define CHANNEL_TYPE_BCCH_BCH 2
#define CHANNEL_TYPE_PCCH 3
#define CHANNEL_TYPE_SRB 4
#define CHANNEL_TYPE_DRB 5
#define CHANNEL_TYPE_BCCH_DL_SCH 6
#define CHANNEL_TYPE_MCCH 7
#define CHANNEL_TYPE_MTCH 8
/* sequenceNumberLength */
#define UM_SN_LENGTH_5_BITS 5
#define UM_SN_LENGTH_10_BITS 10
#define AM_SN_LENGTH_10_BITS 10
#define AM_SN_LENGTH_16_BITS 16
/* Narrow band mode */
typedef enum {
rlc_no_nb_mode = 0,
rlc_nb_mode = 1
} rlc_lte_nb_mode;
/* Context information for every RLC PDU that will be logged */
typedef struct {
unsigned char rlcMode;
unsigned char direction;
unsigned char priority;
unsigned char sequenceNumberLength;
unsigned short ueid;
unsigned short channelType;
unsigned short channelId; /* for SRB: 1=SRB1, 2=SRB2, 3=SRB1bis; for DRB: DRB ID */
unsigned short pduLength;
bool extendedLiField;
rlc_lte_nb_mode nbMode;
} RLC_Context_Info_t;
// See Wireshark's packet-rlc-lte.h for details
#define RLC_LTE_START_STRING "rlc-lte"
#define RLC_LTE_SN_LENGTH_TAG 0x02
#define RLC_LTE_DIRECTION_TAG 0x03
#define RLC_LTE_PRIORITY_TAG 0x04
#define RLC_LTE_UEID_TAG 0x05
#define RLC_LTE_CHANNEL_TYPE_TAG 0x06
#define RLC_LTE_CHANNEL_ID_TAG 0x07
#define RLC_LTE_EXT_LI_FIELD_TAG 0x08
#define RLC_LTE_NB_MODE_TAG 0x09
#define RLC_LTE_PAYLOAD_TAG 0x01
/************************************************************************** /**************************************************************************
* API functions for opening/closing LTE PCAP files * * API functions for opening/closing LTE PCAP files *
**************************************************************************/ **************************************************************************/
@ -247,4 +309,93 @@ inline int LTE_PCAP_NAS_WritePDU(FILE *fd, NAS_Context_Info_t *context,
return 1; return 1;
} }
/**************************************************************************
* API functions for writing RLC-LTE PCAP files *
**************************************************************************/
/* Write an individual RLC PDU (PCAP packet header + UDP header + rlc-context + rlc-pdu) */
inline int LTE_PCAP_RLC_WritePDU(FILE *fd, RLC_Context_Info_t *context,
const unsigned char *PDU, unsigned int length)
{
pcaprec_hdr_t packet_header;
char context_header[256];
int offset = 0;
uint16_t tmp16;
/* 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
tmp16 = length + 12;
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], RLC_LTE_START_STRING, strlen(RLC_LTE_START_STRING));
offset += strlen(RLC_LTE_START_STRING);
// Fixed field RLC mode
context_header[offset++] = context->rlcMode;
// Conditional fields
if (context->rlcMode == RLC_UM_MODE) {
context_header[offset++] = RLC_LTE_SN_LENGTH_TAG;
context_header[offset++] = context->sequenceNumberLength;
}
// Optional fields
context_header[offset++] = RLC_LTE_DIRECTION_TAG;
context_header[offset++] = context->direction;
context_header[offset++] = RLC_LTE_PRIORITY_TAG;
context_header[offset++] = context->priority;
context_header[offset++] = RLC_LTE_UEID_TAG;
tmp16 = htons(context->ueid);
memcpy(context_header+offset, &tmp16, 2);
offset += 2;
context_header[offset++] = RLC_LTE_CHANNEL_TYPE_TAG;
tmp16 = htons(context->channelType);
memcpy(context_header+offset, &tmp16, 2);
offset += 2;
context_header[offset++] = RLC_LTE_CHANNEL_ID_TAG;
tmp16 = htons(context->channelId);
memcpy(context_header+offset, &tmp16, 2);
offset += 2;
// Now the actual PDU
context_header[offset++] = RLC_LTE_PAYLOAD_TAG;
// PCAP header
struct timeval t;
gettimeofday(&t, NULL);
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;
// Write everything to 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

@ -34,10 +34,10 @@
#include <stdio.h> #include <stdio.h>
/* MAC PDU Packing/Unpacking functions. Section 6 of 36.321 */ /* MAC PDU Packing/Unpacking functions. Section 6 of 36.321 */
class subh;
namespace srslte { namespace srslte {
template<class SubH> template<class SubH>
class pdu class pdu
{ {
@ -147,10 +147,11 @@ public:
} }
} }
protected: protected:
std::vector<SubH> subheaders; std::vector<SubH> subheaders;
uint32_t pdu_len; uint32_t pdu_len;
uint32_t rem_len; uint32_t rem_len;
int cur_idx; int cur_idx;
int nof_subheaders; int nof_subheaders;
uint32_t max_subheaders; uint32_t max_subheaders;
@ -159,11 +160,10 @@ protected:
uint32_t total_sdu_len; uint32_t total_sdu_len;
uint32_t sdu_offset_start; uint32_t sdu_offset_start;
int last_sdu_idx; int last_sdu_idx;
private:
/* Prepares the PDU for parsing or writing by setting the number of subheaders to 0 and the pdu length */ /* Prepares the PDU for parsing or writing by setting the number of subheaders to 0 and the pdu length */
void init_(uint8_t *buffer_tx_ptr, uint32_t pdu_len_bytes, bool is_ulsch) { virtual void init_(uint8_t *buffer_tx_ptr, uint32_t pdu_len_bytes, bool is_ulsch) {
nof_subheaders = 0; nof_subheaders = 0;
pdu_len = pdu_len_bytes; pdu_len = pdu_len_bytes;
rem_len = pdu_len; rem_len = pdu_len;
@ -180,55 +180,80 @@ private:
} }
}; };
typedef enum {
SCH_SUBH_TYPE = 0,
MCH_SUBH_TYPE = 1,
RAR_SUBH_TYPE = 2
} subh_type;
template<class SubH> template<class SubH>
class subh class subh
{ {
public: public:
subh(){}
virtual ~subh(){}
virtual bool read_subheader(uint8_t** ptr) = 0; virtual bool read_subheader(uint8_t** ptr) = 0;
virtual void read_payload(uint8_t **ptr) = 0; virtual void read_payload(uint8_t **ptr) = 0;
virtual void write_subheader(uint8_t** ptr, bool is_last) = 0; virtual void write_subheader(uint8_t** ptr, bool is_last) = 0;
virtual void write_payload(uint8_t **ptr) = 0; virtual void write_payload(uint8_t **ptr) = 0;
virtual void fprint(FILE *stream) = 0; virtual void fprint(FILE *stream) = 0;
pdu<SubH>* parent; pdu<SubH>* parent;
private: private:
virtual void init() = 0; virtual void init() = 0;
}; };
class sch_subh : public subh<sch_subh> class sch_subh : public subh<sch_subh>
{ {
public:
sch_subh(subh_type type_ = SCH_SUBH_TYPE) {
lcid = 0;
nof_bytes = 0;
payload = NULL;
nof_mch_sched_ce = 0;
cur_mch_sched_ce = 0;
F_bit = false;
type = type_;
parent = NULL;
bzero(&w_payload_ce, sizeof(w_payload_ce));
}
public: virtual ~sch_subh(){}
typedef enum { typedef enum {
PHR_REPORT = 26, PHR_REPORT = 26,
CRNTI = 27, CRNTI = 27,
CON_RES_ID = 28, CON_RES_ID = 28,
TRUNC_BSR = 28, MTCH_MAX_LCID = 28,
TA_CMD = 29, TRUNC_BSR = 28,
SHORT_BSR = 29, TA_CMD = 29,
DRX_CMD = 30, SHORT_BSR = 29,
LONG_BSR = 30, DRX_CMD = 30,
PADDING = 31, LONG_BSR = 30,
SDU = 0 MCH_SCHED_INFO = 30,
} cetype; PADDING = 31,
SDU = 0
} cetype;
// Size of MAC CEs // Size of MAC CEs
const static int MAC_CE_CONTRES_LEN = 6; const static int MAC_CE_CONTRES_LEN = 6;
// Reading functions // Reading functions
bool is_sdu(); bool is_sdu();
cetype ce_type(); bool is_var_len_ce();
cetype ce_type();
uint32_t size_plus_header(); uint32_t size_plus_header();
void set_payload_size(uint32_t size); void set_payload_size(uint32_t size);
bool read_subheader(uint8_t** ptr); bool read_subheader(uint8_t** ptr);
void read_payload(uint8_t **ptr); void read_payload(uint8_t **ptr);
uint32_t get_sdu_lcid(); uint32_t get_sdu_lcid();
int get_payload_size(); uint32_t get_payload_size();
uint32_t get_header_size(bool is_last); uint32_t get_header_size(bool is_last);
uint8_t* get_sdu_ptr(); uint8_t* get_sdu_ptr();
@ -237,10 +262,13 @@ public:
uint8_t get_ta_cmd(); uint8_t get_ta_cmd();
float get_phr(); float get_phr();
int get_bsr(uint32_t buff_size[4]); int get_bsr(uint32_t buff_size[4]);
bool get_next_mch_sched_info(uint8_t *lcid, uint16_t *mtch_stop);
// Writing functions // Writing functions
void write_subheader(uint8_t** ptr, bool is_last); void write_subheader(uint8_t** ptr, bool is_last);
void write_payload(uint8_t **ptr); void write_payload(uint8_t **ptr);
int set_sdu(uint32_t lcid, uint32_t nof_bytes, uint8_t *payload); int set_sdu(uint32_t lcid, uint32_t nof_bytes, uint8_t *payload);
int set_sdu(uint32_t lcid, uint32_t requested_bytes, read_pdu_interface *sdu_itf); int set_sdu(uint32_t lcid, uint32_t requested_bytes, read_pdu_interface *sdu_itf);
bool set_c_rnti(uint16_t crnti); bool set_c_rnti(uint16_t crnti);
@ -251,46 +279,62 @@ public:
void set_padding(); void set_padding();
void set_padding(uint32_t padding_len); void set_padding(uint32_t padding_len);
void init(); void init();
void fprint(FILE *stream); void fprint(FILE *stream);
bool set_next_mch_sched_info(uint8_t lcid, uint16_t mtch_stop);
protected:
static const int MAX_CE_PAYLOAD_LEN = 8;
uint32_t lcid;
int nof_bytes;
uint8_t* payload;
uint8_t w_payload_ce[64];
uint8_t nof_mch_sched_ce;
uint8_t cur_mch_sched_ce;
bool F_bit;
subh_type type;
private: private:
static const int MAX_CE_PAYLOAD_LEN = 8;
uint32_t lcid;
int nof_bytes;
uint8_t* payload;
uint8_t w_payload_ce[8];
bool F_bit;
uint32_t sizeof_ce(uint32_t lcid, bool is_ul); uint32_t sizeof_ce(uint32_t lcid, bool is_ul);
static uint8_t buff_size_table(uint32_t buffer_size); static uint8_t buff_size_table(uint32_t buffer_size);
static uint8_t phr_report_table(float phr_value); static uint8_t phr_report_table(float phr_value);
}; };
class sch_pdu : public pdu<sch_subh> class sch_pdu : public pdu<sch_subh>
{ {
public: public:
sch_pdu(uint32_t max_subh): pdu(max_subh) {}
sch_pdu(uint32_t max_subh) : pdu(max_subh) {}
void parse_packet(uint8_t *ptr); void parse_packet(uint8_t *ptr);
uint8_t* write_packet(); uint8_t* write_packet();
uint8_t* write_packet(srslte::log *log_h); uint8_t* write_packet(srslte::log *log_h);
bool has_space_ce(uint32_t nbytes); bool has_space_ce(uint32_t nbytes, bool var_len=false);
bool has_space_sdu(uint32_t nbytes); bool has_space_sdu(uint32_t nbytes);
int get_pdu_len(); int get_pdu_len();
int rem_size(); int rem_size();
int get_sdu_space(); int get_sdu_space();
static uint32_t size_header_sdu(uint32_t nbytes); static uint32_t size_header_sdu(uint32_t nbytes);
bool update_space_ce(uint32_t nbytes); bool update_space_ce(uint32_t nbytes, bool var_len=false);
bool update_space_sdu(uint32_t nbytes); bool update_space_sdu(uint32_t nbytes);
void fprint(FILE *stream); void fprint(FILE *stream);
}; };
class rar_subh : public subh<rar_subh> class rar_subh : public subh<rar_subh>
{ {
public: public:
rar_subh() {
bzero(&grant, sizeof(grant));
ta = 0;
temp_rnti = 0;
preamble = 0;
parent = NULL;
}
static const uint32_t RAR_GRANT_LEN = 20; static const uint32_t RAR_GRANT_LEN = 20;
@ -333,11 +377,50 @@ public:
bool write_packet(uint8_t* ptr); bool write_packet(uint8_t* ptr);
void fprint(FILE *stream); void fprint(FILE *stream);
private: private:
bool has_backoff_indicator; bool has_backoff_indicator;
uint8_t backoff_indicator; uint8_t backoff_indicator;
};
class mch_subh : public sch_subh
{
public:
mch_subh():sch_subh(MCH_SUBH_TYPE){}
// Size of MAC CEs
const static int MAC_CE_CONTRES_LEN = 6;
}; };
} // namespace srslte class mch_pdu : public sch_pdu
{
public:
mch_pdu(uint32_t max_subh) : sch_pdu(max_subh) {}
private:
/* Prepares the PDU for parsing or writing by setting the number of subheaders to 0 and the pdu length */
virtual void init_(uint8_t *buffer_tx_ptr, uint32_t pdu_len_bytes, bool is_ulsch) {
nof_subheaders = 0;
pdu_len = pdu_len_bytes;
rem_len = pdu_len;
pdu_is_ul = is_ulsch;
buffer_tx = buffer_tx_ptr;
sdu_offset_start = max_subheaders*2 + 13; // Assuming worst-case 2 bytes per sdu subheader + all possible CE
total_sdu_len = 0;
last_sdu_idx = -1;
reset();
for (uint32_t i=0;i<max_subheaders;i++) {
mch_subh mch_subh1;
subheaders[i] = mch_subh1;
subheaders[i].parent = this;
subheaders[i].init();
}
}
};
} // namespace srsue
#endif // MACPDU_H
#endif // SRSLTE_PDU_H

@ -41,29 +41,35 @@ namespace srslte {
class pdu_queue class pdu_queue
{ {
public: public:
typedef enum {
DCH,
BCH,
MCH
} channel_t;
class process_callback class process_callback
{ {
public: public:
virtual void process_pdu(uint8_t *buff, uint32_t len, uint32_t tstamp) = 0; virtual void process_pdu(uint8_t *buff, uint32_t len, channel_t channel, uint32_t tstamp) = 0;
}; };
pdu_queue(uint32_t pool_size = DEFAULT_POOL_SIZE) : pool(pool_size), callback(NULL), log_h(NULL) {} pdu_queue(uint32_t pool_size = DEFAULT_POOL_SIZE) : pool(pool_size), callback(NULL), log_h(NULL) {}
void init(process_callback *callback, log* log_h_); void init(process_callback *callback, log* log_h_);
uint8_t* request(uint32_t len); uint8_t* request(uint32_t len);
void deallocate(uint8_t* pdu); void deallocate(uint8_t* pdu);
void push(uint8_t *ptr, uint32_t len, uint32_t tstamp = 0); void push(uint8_t *ptr, uint32_t len, channel_t channel = DCH, uint32_t tstamp = 0);
bool process_pdus(); bool process_pdus();
private: private:
const static int DEFAULT_POOL_SIZE = 64; // Number of PDU buffers in total const static int DEFAULT_POOL_SIZE = 64; // Number of PDU buffers in total
const static int MAX_PDU_LEN = 150*1024/8; // ~ 150 Mbps const static int MAX_PDU_LEN = 150*1024/8; // ~ 150 Mbps
typedef struct { typedef struct {
uint8_t ptr[MAX_PDU_LEN]; uint8_t ptr[MAX_PDU_LEN];
uint32_t len; uint32_t len;
uint32_t tstamp; uint32_t tstamp;
channel_t channel;
#ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED #ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED
char debug_name[128]; char debug_name[128];
#endif #endif

@ -0,0 +1,65 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsUE library.
*
* srsUE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsUE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef RLCPCAP_H
#define RLCPCAP_H
#include <stdint.h>
#include "srslte/common/pcap.h"
namespace srslte {
class rlc_pcap
{
public:
rlc_pcap() {enable_write=false; ue_id=0; pcap_file = NULL; };
void enable(bool en);
void open(const char *filename, uint32_t ue_id = 0);
void close();
void set_ue_id(uint16_t ue_id);
void write_dl_am_ccch(uint8_t* pdu, uint32_t pdu_len_bytes);
void write_ul_am_ccch(uint8_t* pdu, uint32_t pdu_len_bytes);
private:
bool enable_write;
FILE *pcap_file;
uint32_t ue_id;
void pack_and_write(uint8_t* pdu,
uint32_t pdu_len_bytes,
uint8_t mode,
uint8_t direction,
uint8_t priority,
uint8_t seqnumberlength,
uint16_t ueid,
uint16_t channel_type,
uint16_t channel_id);
};
} // namespace srsue
#endif // RLCPCAP_H

@ -109,7 +109,7 @@ uint8_t security_generate_k_up( uint8_t *k_enb,
uint8_t security_128_eia1( uint8_t *key, uint8_t security_128_eia1( uint8_t *key,
uint32_t count, uint32_t count,
uint8_t bearer, uint32_t bearer,
uint8_t direction, uint8_t direction,
uint8_t *msg, uint8_t *msg,
uint32_t msg_len, uint32_t msg_len,
@ -117,12 +117,17 @@ uint8_t security_128_eia1( uint8_t *key,
uint8_t security_128_eia2( uint8_t *key, uint8_t security_128_eia2( uint8_t *key,
uint32_t count, uint32_t count,
uint8_t bearer, uint32_t bearer,
uint8_t direction, uint8_t direction,
uint8_t *msg, uint8_t *msg,
uint32_t msg_len, uint32_t msg_len,
uint8_t *mac); uint8_t *mac);
uint8_t security_md5(const uint8_t *input,
size_t len,
uint8_t *output);
/****************************************************************************** /******************************************************************************
* Encryption / Decryption * Encryption / Decryption
*****************************************************************************/ *****************************************************************************/

@ -89,7 +89,7 @@ public:
period_us = period_us_; period_us = period_us_;
start(priority); start(priority);
} }
void stop() { void stop_thread() {
run_enable = false; run_enable = false;
wait_thread_finish(); wait_thread_finish();
} }

@ -64,7 +64,7 @@ public:
return (counter < timeout) && running; return (counter < timeout) && running;
} }
bool is_expired() { bool is_expired() {
return (timeout > 0) && (counter >= timeout || !running); return (timeout > 0) && (counter >= timeout);
} }
uint32_t get_timeout() { uint32_t get_timeout() {
return timeout; return timeout;
@ -143,7 +143,7 @@ public:
used_timers[i] = false; used_timers[i] = false;
nof_used_timers--; nof_used_timers--;
} else { } else {
fprintf(stderr, "Error releasing timer: nof_used_timers=%d, nof_timers=%d\n", nof_used_timers, nof_timers); fprintf(stderr, "Error releasing timer id=%d: nof_used_timers=%d, nof_timers=%d\n", i, nof_used_timers, nof_timers);
} }
} }
uint32_t get_unique_id() { uint32_t get_unique_id() {

@ -72,6 +72,7 @@ public:
virtual int crc_info(uint32_t tti, uint16_t rnti, uint32_t nof_bytes, bool crc_res) = 0; virtual int crc_info(uint32_t tti, uint16_t rnti, uint32_t nof_bytes, bool crc_res) = 0;
virtual int get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res) = 0; virtual int get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res) = 0;
virtual int get_mch_sched(bool is_mcch, dl_sched_t *dl_sched_res) = 0;
virtual int get_ul_sched(uint32_t tti, ul_sched_t *ul_sched_res) = 0; virtual int get_ul_sched(uint32_t tti, ul_sched_t *ul_sched_res) = 0;
// Radio-Link status // Radio-Link status
@ -95,6 +96,20 @@ public:
class phy_interface_rrc class phy_interface_rrc
{ {
public: public:
typedef struct {
LIBLTE_RRC_MBSFN_SUBFRAME_CONFIG_STRUCT mbsfn_subfr_cnfg;
LIBLTE_RRC_MBSFN_NOTIFICATION_CONFIG_STRUCT mbsfn_notification_cnfg;
LIBLTE_RRC_MBSFN_AREA_INFO_STRUCT mbsfn_area_info;
LIBLTE_RRC_MCCH_MSG_STRUCT mcch;
} phy_cfg_mbsfn_t;
typedef struct {
phy_cfg_mbsfn_t mbsfn;
} phy_rrc_cfg_t;
virtual void configure_mbsfn(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT *sib13, LIBLTE_RRC_MCCH_MSG_STRUCT mcch) = 0;
virtual void set_conf_dedicated_ack(uint16_t rnti, bool rrc_completed) = 0; virtual void set_conf_dedicated_ack(uint16_t rnti, bool rrc_completed) = 0;
virtual void set_config_dedicated(uint16_t rnti, LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT* dedicated) = 0; virtual void set_config_dedicated(uint16_t rnti, LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT* dedicated) = 0;
@ -116,7 +131,7 @@ public:
virtual int bearer_ue_rem(uint16_t rnti, uint32_t lc_id) = 0; virtual int bearer_ue_rem(uint16_t rnti, uint32_t lc_id) = 0;
virtual int set_dl_ant_info(uint16_t rnti, LIBLTE_RRC_ANTENNA_INFO_DEDICATED_STRUCT *dl_ant_info) = 0; virtual int set_dl_ant_info(uint16_t rnti, LIBLTE_RRC_ANTENNA_INFO_DEDICATED_STRUCT *dl_ant_info) = 0;
virtual void phy_config_enabled(uint16_t rnti, bool enabled) = 0; virtual void phy_config_enabled(uint16_t rnti, bool enabled) = 0;
virtual void write_mcch(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT *sib13, LIBLTE_RRC_MCCH_MSG_STRUCT *mcch) = 0;
}; };
class mac_interface_rlc class mac_interface_rlc
@ -164,6 +179,7 @@ public:
virtual void rem_user(uint16_t rnti) = 0; virtual void rem_user(uint16_t rnti) = 0;
virtual void add_bearer(uint16_t rnti, uint32_t lcid) = 0; virtual void add_bearer(uint16_t rnti, uint32_t lcid) = 0;
virtual void add_bearer(uint16_t rnti, uint32_t lcid, srslte::srslte_rlc_config_t cnfg) = 0; virtual void add_bearer(uint16_t rnti, uint32_t lcid, srslte::srslte_rlc_config_t cnfg) = 0;
virtual void add_bearer_mrb(uint16_t rnti, uint32_t lcid) = 0;
}; };
// PDCP interface for GTPU // PDCP interface for GTPU
@ -262,9 +278,7 @@ public:
virtual void initial_ue(uint16_t rnti, srslte::byte_buffer_t *pdu, uint32_t m_tmsi, uint8_t mmec) = 0; virtual void initial_ue(uint16_t rnti, srslte::byte_buffer_t *pdu, uint32_t m_tmsi, uint8_t mmec) = 0;
virtual void write_pdu(uint16_t rnti, srslte::byte_buffer_t *pdu) = 0; virtual void write_pdu(uint16_t rnti, srslte::byte_buffer_t *pdu) = 0;
virtual bool user_exists(uint16_t rnti) = 0; virtual bool user_exists(uint16_t rnti) = 0;
virtual void user_inactivity(uint16_t rnti) = 0; virtual bool user_release(uint16_t rnti, LIBLTE_S1AP_CAUSERADIONETWORK_ENUM cause_radio) = 0;
virtual void release_eutran(uint16_t rnti) = 0;
virtual bool user_link_lost(uint16_t rnti) = 0;
virtual void ue_ctxt_setup_complete(uint16_t rnti, LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPRESPONSE_STRUCT *res) = 0; virtual void ue_ctxt_setup_complete(uint16_t rnti, LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPRESPONSE_STRUCT *res) = 0;
virtual void ue_erab_setup_complete(uint16_t rnti, LIBLTE_S1AP_MESSAGE_E_RABSETUPRESPONSE_STRUCT *res) = 0; virtual void ue_erab_setup_complete(uint16_t rnti, LIBLTE_S1AP_MESSAGE_E_RABSETUPRESPONSE_STRUCT *res) = 0;
// virtual void ue_capabilities(uint16_t rnti, LIBLTE_RRC_UE_EUTRA_CAPABILITY_STRUCT *caps) = 0; // virtual void ue_capabilities(uint16_t rnti, LIBLTE_RRC_UE_EUTRA_CAPABILITY_STRUCT *caps) = 0;

@ -129,6 +129,22 @@ public:
uint32_t nbytes; uint32_t nbytes;
} dl_sched_pdu_t; } dl_sched_pdu_t;
typedef struct {
uint32_t lcid;
uint32_t lcid_buffer_size;
uint32_t stop;
uint8_t *mtch_payload;
} dl_mtch_sched_t;
typedef struct {
dl_sched_pdu_t pdu[20];
dl_mtch_sched_t mtch_sched[8];
uint32_t num_mtch_sched;
uint8_t *mcch_payload;
uint32_t current_sf_allocation_num;
} dl_pdu_mch_t;
typedef struct { typedef struct {
uint32_t rnti; uint32_t rnti;
srslte_dci_format_t dci_format; srslte_dci_format_t dci_format;

@ -43,6 +43,12 @@
namespace srsue { namespace srsue {
typedef enum {
AUTH_OK,
AUTH_FAILED,
AUTH_SYNCH_FAILURE
} auth_result_t;
// UE interface // UE interface
class ue_interface class ue_interface
{ {
@ -57,12 +63,12 @@ public:
virtual bool get_imsi_vec(uint8_t* imsi_, uint32_t n) = 0; virtual bool get_imsi_vec(uint8_t* imsi_, uint32_t n) = 0;
virtual bool get_imei_vec(uint8_t* imei_, uint32_t n) = 0; virtual bool get_imei_vec(uint8_t* imei_, uint32_t n) = 0;
virtual bool get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id) = 0; virtual bool get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id) = 0;
virtual void generate_authentication_response(uint8_t *rand, virtual auth_result_t generate_authentication_response(uint8_t *rand,
uint8_t *autn_enb, uint8_t *autn_enb,
uint16_t mcc, uint16_t mcc,
uint16_t mnc, uint16_t mnc,
bool *net_valid,
uint8_t *res, uint8_t *res,
int *res_len,
uint8_t *k_asme) = 0; uint8_t *k_asme) = 0;
virtual void generate_nas_keys(uint8_t *k_asme, virtual void generate_nas_keys(uint8_t *k_asme,
uint8_t *k_nas_enc, uint8_t *k_nas_enc,
@ -101,41 +107,53 @@ public:
virtual srslte::error_t setup_if_addr(uint32_t ip_addr, char *err_str) = 0; virtual srslte::error_t setup_if_addr(uint32_t ip_addr, char *err_str) = 0;
}; };
// GW interface for RRC
class gw_interface_rrc
{
public:
virtual void add_mch_port(uint32_t lcid, uint32_t port) = 0;
};
// GW interface for PDCP // GW interface for PDCP
class gw_interface_pdcp class gw_interface_pdcp
{ {
public: public:
virtual void write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu) = 0; virtual void write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu) = 0;
virtual void write_pdu_mch(uint32_t lcid, srslte::byte_buffer_t *pdu) = 0;
}; };
// NAS interface for RRC // NAS interface for RRC
class nas_interface_rrc class nas_interface_rrc
{ {
public: public:
typedef enum {
BARRING_NONE = 0,
BARRING_MO_DATA,
BARRING_MO_SIGNALLING,
BARRING_MT,
BARRING_ALL
} barring_t;
virtual void set_barring(barring_t barring) = 0;
virtual void paging(LIBLTE_RRC_S_TMSI_STRUCT *ue_identiy) = 0;
virtual bool is_attached() = 0; virtual bool is_attached() = 0;
virtual bool is_attaching() = 0;
virtual void notify_connection_setup() = 0;
virtual void write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu) = 0; virtual void write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu) = 0;
virtual uint32_t get_ul_count() = 0; virtual uint32_t get_ul_count() = 0;
virtual bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) = 0;
virtual bool get_k_asme(uint8_t *k_asme_, uint32_t n) = 0; virtual bool get_k_asme(uint8_t *k_asme_, uint32_t n) = 0;
virtual bool plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code) = 0;
virtual void plmn_search_end() = 0;
}; };
// NAS interface for UE // NAS interface for UE
class nas_interface_ue class nas_interface_ue
{ {
public: public:
virtual void attach_request() = 0; virtual bool attach_request() = 0;
virtual void deattach_request() = 0; virtual bool deattach_request() = 0;
}; };
// NAS interface for UE // NAS interface for UE
class nas_interface_gw class nas_interface_gw
{ {
public: public:
virtual void attach_request() = 0; virtual bool attach_request() = 0;
}; };
// RRC interface for MAC // RRC interface for MAC
@ -159,8 +177,6 @@ class rrc_interface_phy
public: public:
virtual void in_sync() = 0; virtual void in_sync() = 0;
virtual void out_of_sync() = 0; virtual void out_of_sync() = 0;
virtual void earfcn_end() = 0;
virtual void cell_camping(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp = NAN) = 0;
virtual void new_phy_meas(float rsrp, float rsrq, uint32_t tti, int earfcn = -1, int pci = -1) = 0; virtual void new_phy_meas(float rsrp, float rsrq, uint32_t tti, int earfcn = -1, int pci = -1) = 0;
}; };
@ -168,12 +184,23 @@ public:
class rrc_interface_nas class rrc_interface_nas
{ {
public: public:
typedef struct {
LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id;
uint16_t tac;
} found_plmn_t;
const static int MAX_FOUND_PLMNS = 16;
virtual void write_sdu(uint32_t lcid, srslte::byte_buffer_t *sdu) = 0; virtual void write_sdu(uint32_t lcid, srslte::byte_buffer_t *sdu) = 0;
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 void plmn_search() = 0; virtual int plmn_search(found_plmn_t found_plmns[MAX_FOUND_PLMNS]) = 0;
virtual void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, bool connect_request = false) = 0; virtual void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) = 0;
virtual bool connection_request(LIBLTE_RRC_CON_REQ_EST_CAUSE_ENUM cause,
srslte::byte_buffer_t *dedicatedInfoNAS) = 0;
virtual void set_ue_idenity(LIBLTE_RRC_S_TMSI_STRUCT s_tmsi) = 0;
virtual bool is_connected() = 0;
virtual std::string get_rb_name(uint32_t lcid) = 0; virtual std::string get_rb_name(uint32_t lcid) = 0;
}; };
@ -185,6 +212,7 @@ public:
virtual void write_pdu_bcch_bch(srslte::byte_buffer_t *pdu) = 0; virtual void write_pdu_bcch_bch(srslte::byte_buffer_t *pdu) = 0;
virtual void write_pdu_bcch_dlsch(srslte::byte_buffer_t *pdu) = 0; virtual void write_pdu_bcch_dlsch(srslte::byte_buffer_t *pdu) = 0;
virtual void write_pdu_pcch(srslte::byte_buffer_t *pdu) = 0; virtual void write_pdu_pcch(srslte::byte_buffer_t *pdu) = 0;
virtual void write_pdu_mch(uint32_t lcid, srslte::byte_buffer_t *pdu) = 0;
virtual std::string get_rb_name(uint32_t lcid) = 0; virtual std::string get_rb_name(uint32_t lcid) = 0;
}; };
@ -234,6 +262,7 @@ public:
virtual void write_pdu_bcch_bch(srslte::byte_buffer_t *sdu) = 0; virtual void write_pdu_bcch_bch(srslte::byte_buffer_t *sdu) = 0;
virtual void write_pdu_bcch_dlsch(srslte::byte_buffer_t *sdu) = 0; virtual void write_pdu_bcch_dlsch(srslte::byte_buffer_t *sdu) = 0;
virtual void write_pdu_pcch(srslte::byte_buffer_t *sdu) = 0; virtual void write_pdu_pcch(srslte::byte_buffer_t *sdu) = 0;
virtual void write_pdu_mch(uint32_t lcid, srslte::byte_buffer_t *sdu) = 0;
}; };
// RLC interface for RRC // RLC interface for RRC
@ -244,6 +273,7 @@ public:
virtual void reestablish() = 0; virtual void reestablish() = 0;
virtual void add_bearer(uint32_t lcid) = 0; virtual void add_bearer(uint32_t lcid) = 0;
virtual void add_bearer(uint32_t lcid, srslte::srslte_rlc_config_t cnfg) = 0; virtual void add_bearer(uint32_t lcid, srslte::srslte_rlc_config_t cnfg) = 0;
virtual void add_bearer_mrb(uint32_t lcid) = 0;
}; };
// RLC interface for PDCP // RLC interface for PDCP
@ -278,6 +308,7 @@ public:
virtual void write_pdu_bcch_bch(uint8_t *payload, uint32_t nof_bytes) = 0; virtual void write_pdu_bcch_bch(uint8_t *payload, uint32_t nof_bytes) = 0;
virtual void write_pdu_bcch_dlsch(uint8_t *payload, uint32_t nof_bytes) = 0; virtual void write_pdu_bcch_dlsch(uint8_t *payload, uint32_t nof_bytes) = 0;
virtual void write_pdu_pcch(uint8_t *payload, uint32_t nof_bytes) = 0; virtual void write_pdu_pcch(uint8_t *payload, uint32_t nof_bytes) = 0;
virtual void write_pdu_mch(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes) = 0;
}; };
@ -314,6 +345,11 @@ public:
class mac_interface_phy class mac_interface_phy
{ {
public: public:
typedef struct {
uint32_t nof_mbsfn_services;
} mac_phy_cfg_mbsfn_t;
typedef struct { typedef struct {
uint32_t pid; uint32_t pid;
@ -366,26 +402,35 @@ public:
/* Indicate reception of UL grant + HARQ information throught PHICH in the same TTI. */ /* Indicate reception of UL grant + HARQ information throught PHICH in the same TTI. */
virtual void new_grant_ul_ack(mac_grant_t grant, bool ack, tb_action_ul_t *action) = 0; virtual void new_grant_ul_ack(mac_grant_t grant, bool ack, tb_action_ul_t *action) = 0;
/* Obtain action for a new MCH subframe. */
virtual void new_mch_dl(srslte_ra_dl_grant_t phy_grant, tb_action_dl_t *action) = 0;
/* Indicate reception of HARQ information only through PHICH. */ /* Indicate reception of HARQ information only through PHICH. */
virtual void harq_recv(uint32_t tti, bool ack, tb_action_ul_t *action) = 0; virtual void harq_recv(uint32_t tti, bool ack, tb_action_ul_t *action) = 0;
/* Indicate reception of DL grant. */ /* Indicate reception of DL grant. */
virtual void new_grant_dl(mac_grant_t grant, tb_action_dl_t *action) = 0; virtual void new_grant_dl(mac_grant_t grant, tb_action_dl_t *action) = 0;
/* Indicate successfull decoding of PDSCH TB. */ /* Indicate successful decoding of PDSCH TB. */
virtual void tb_decoded(bool ack, uint32_t tb_idx, srslte_rnti_type_t rnti_type, uint32_t harq_pid) = 0; virtual void tb_decoded(bool ack, uint32_t tb_idx, srslte_rnti_type_t rnti_type, uint32_t harq_pid) = 0;
/* Indicate successfull decoding of BCH TB through PBCH */ /* Indicate successful decoding of BCH TB through PBCH */
virtual void bch_decoded_ok(uint8_t *payload, uint32_t len) = 0; virtual void bch_decoded_ok(uint8_t *payload, uint32_t len) = 0;
/* Indicate successfull decoding of PCH TB through PDSCH */ /* Indicate successful decoding of PCH TB through PDSCH */
virtual void pch_decoded_ok(uint32_t len) = 0; virtual void pch_decoded_ok(uint32_t len) = 0;
/* Indicate successful decoding of MCH TB through PMCH */
virtual void mch_decoded_ok(uint32_t len) = 0;
/* Communicate the number of mbsfn services available */
virtual void set_mbsfn_config(uint32_t nof_mbsfn_services) = 0;
/* Function called every start of a subframe (TTI). Warning, this function is called /* Function called every start of a subframe (TTI). Warning, this function is called
* from a high priority thread and should terminate asap * from a high priority thread and should terminate asap
*/ */
virtual void tti_clock(uint32_t tti) = 0;
}; };
/* Interface RRC -> MAC shared between different RATs */ /* Interface RRC -> MAC shared between different RATs */
@ -420,18 +465,20 @@ public:
uint32_t prach_config_index; uint32_t prach_config_index;
} mac_cfg_t; } mac_cfg_t;
virtual void clear_rntis() = 0;
/* Instructs the MAC to start receiving BCCH */ /* Instructs the MAC to start receiving BCCH */
virtual void bcch_start_rx() = 0;
virtual void bcch_stop_rx() = 0;
virtual void bcch_start_rx(int si_window_start, int si_window_length) = 0; virtual void bcch_start_rx(int si_window_start, int si_window_length) = 0;
/* Instructs the MAC to start receiving PCCH */ /* Instructs the MAC to start receiving PCCH */
virtual void pcch_start_rx() = 0; virtual void pcch_start_rx() = 0;
virtual void pcch_stop_rx() = 0;
/* RRC configures a logical channel */ /* RRC configures a logical channel */
virtual void setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD) = 0; virtual void setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD) = 0;
/* Instructs the MAC to start receiving an MCH */
virtual void mch_start_rx(uint32_t lcid) = 0;
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(mac_cfg_t *mac_cfg) = 0;
@ -453,8 +500,6 @@ public:
}; };
/** PHY interface /** PHY interface
* *
*/ */
@ -484,12 +529,15 @@ typedef struct {
float cfo_loop_bw_ref; float cfo_loop_bw_ref;
float cfo_loop_ref_min; float cfo_loop_ref_min;
float cfo_loop_pss_tol; float cfo_loop_pss_tol;
float sfo_ema;
uint32_t sfo_correct_period;
uint32_t cfo_loop_pss_conv; uint32_t cfo_loop_pss_conv;
uint32_t cfo_ref_mask; uint32_t cfo_ref_mask;
bool average_subframe_enabled; bool average_subframe_enabled;
int time_correct_period; bool estimator_fil_auto;
float estimator_fil_stddev;
uint32_t estimator_fil_order;
std::string sss_algorithm; std::string sss_algorithm;
float estimator_fil_w;
bool rssi_sensor_enabled; bool rssi_sensor_enabled;
bool sic_pss_enabled; bool sic_pss_enabled;
float rx_gain_offset; float rx_gain_offset;
@ -503,9 +551,7 @@ typedef struct {
class phy_interface_mac_common class phy_interface_mac_common
{ {
public: public:
/* Start synchronization with strongest cell in the current carrier frequency */
virtual bool sync_status() = 0;
/* Sets a C-RNTI allowing the PHY to pregenerate signals if necessary */ /* Sets a C-RNTI allowing the PHY to pregenerate signals if necessary */
virtual void set_crnti(uint16_t rnti) = 0; virtual void set_crnti(uint16_t rnti) = 0;
@ -526,12 +572,12 @@ public:
class phy_interface_mac : public phy_interface_mac_common class phy_interface_mac : public phy_interface_mac_common
{ {
public: public:
/* Configure PRACH using parameters written by RRC */ /* Configure PRACH using parameters written by RRC */
virtual void configure_prach_params() = 0; virtual void configure_prach_params() = 0;
virtual void prach_send(uint32_t preamble_idx, int allowed_subframe, float target_power_dbm) = 0; virtual void prach_send(uint32_t preamble_idx, int allowed_subframe, float target_power_dbm) = 0;
virtual int prach_tx_tti() = 0; virtual int prach_tx_tti() = 0;
/* Indicates the transmission of a SR signal in the next opportunity */ /* Indicates the transmission of a SR signal in the next opportunity */
virtual void sr_send() = 0; virtual void sr_send() = 0;
virtual int sr_last_tx_tti() = 0; virtual int sr_last_tx_tti() = 0;
@ -541,6 +587,9 @@ public:
virtual void pdcch_dl_search(srslte_rnti_type_t rnti_type, uint16_t rnti, int tti_start = -1, int tti_end = -1) = 0; virtual void pdcch_dl_search(srslte_rnti_type_t rnti_type, uint16_t rnti, int tti_start = -1, int tti_end = -1) = 0;
virtual void pdcch_ul_search_reset() = 0; virtual void pdcch_ul_search_reset() = 0;
virtual void pdcch_dl_search_reset() = 0; virtual void pdcch_dl_search_reset() = 0;
virtual void set_mch_period_stop(uint32_t stop) = 0;
}; };
class phy_interface_rrc class phy_interface_rrc
@ -558,10 +607,19 @@ public:
LIBLTE_RRC_TDD_CONFIG_STRUCT tdd_cnfg; LIBLTE_RRC_TDD_CONFIG_STRUCT tdd_cnfg;
LIBLTE_RRC_ANTENNA_PORTS_COUNT_ENUM ant_info; LIBLTE_RRC_ANTENNA_PORTS_COUNT_ENUM ant_info;
} phy_cfg_common_t; } phy_cfg_common_t;
typedef struct {
LIBLTE_RRC_MBSFN_SUBFRAME_CONFIG_STRUCT mbsfn_subfr_cnfg;
LIBLTE_RRC_MBSFN_NOTIFICATION_CONFIG_STRUCT mbsfn_notification_cnfg;
LIBLTE_RRC_MBSFN_AREA_INFO_STRUCT mbsfn_area_info;
LIBLTE_RRC_MCCH_MSG_STRUCT mcch;
} phy_cfg_mbsfn_t;
typedef struct { typedef struct {
LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT dedicated; LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT dedicated;
phy_cfg_common_t common; phy_cfg_common_t common;
phy_cfg_mbsfn_t mbsfn;
bool enable_64qam; bool enable_64qam;
} phy_cfg_t; } phy_cfg_t;
@ -575,21 +633,29 @@ public:
virtual void set_config_common(phy_cfg_common_t *common) = 0; virtual void set_config_common(phy_cfg_common_t *common) = 0;
virtual void set_config_tdd(LIBLTE_RRC_TDD_CONFIG_STRUCT *tdd) = 0; virtual void set_config_tdd(LIBLTE_RRC_TDD_CONFIG_STRUCT *tdd) = 0;
virtual void set_config_64qam_en(bool enable) = 0; virtual void set_config_64qam_en(bool enable) = 0;
virtual void set_config_mbsfn_sib2(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2) = 0;
virtual void set_config_mbsfn_sib13(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT *sib13) = 0;
virtual void set_config_mbsfn_mcch(LIBLTE_RRC_MCCH_MSG_STRUCT *mcch) = 0;
/* Measurements interface */ /* Measurements interface */
virtual void meas_reset() = 0; virtual void meas_reset() = 0;
virtual int meas_start(uint32_t earfcn, int pci = -1) = 0; virtual int meas_start(uint32_t earfcn, int pci = -1) = 0;
virtual int meas_stop(uint32_t earfcn, int pci = -1) = 0; virtual int meas_stop(uint32_t earfcn, int pci = -1) = 0;
typedef struct {
enum {CELL_FOUND = 0, CELL_NOT_FOUND, ERROR} found;
enum {MORE_FREQS = 0, NO_MORE_FREQS} last_freq;
} cell_search_ret_t;
typedef struct {
srslte_cell_t cell;
uint32_t earfcn;
} phy_cell_t;
/* Cell search and selection procedures */ /* Cell search and selection procedures */
virtual void cell_search_start() = 0; virtual cell_search_ret_t cell_search(phy_cell_t *cell) = 0;
virtual void cell_search_next() = 0; virtual bool cell_select(phy_cell_t *cell = NULL) = 0;
virtual void cell_select(uint32_t earfcn, srslte_cell_t cell) = 0; virtual bool cell_is_camping() = 0;
virtual bool cell_handover(srslte_cell_t cell) = 0;
/* Is the PHY downlink synchronized? */
virtual bool sync_status() = 0;
virtual void sync_reset() = 0;
/* Configure UL using parameters written with set_param() */ /* Configure UL using parameters written with set_param() */
virtual void configure_ul_params(bool pregen_disabled = false) = 0; virtual void configure_ul_params(bool pregen_disabled = false) = 0;

@ -53,6 +53,8 @@ typedef enum SRSLTE_API {
typedef struct SRSLTE_API{ typedef struct SRSLTE_API{
float bandwidth; float bandwidth;
double gain; double gain;
double min_gain;
double max_gain;
float y_out; float y_out;
bool lock; bool lock;
bool isfirst; bool isfirst;
@ -79,6 +81,8 @@ SRSLTE_API void srslte_agc_free(srslte_agc_t *q);
SRSLTE_API void srslte_agc_reset(srslte_agc_t *q); SRSLTE_API void srslte_agc_reset(srslte_agc_t *q);
SRSLTE_API void srslte_agc_set_gain_range(srslte_agc_t *q, double min_gain, double max_gain);
SRSLTE_API void srslte_agc_set_bandwidth(srslte_agc_t *q, SRSLTE_API void srslte_agc_set_bandwidth(srslte_agc_t *q,
float bandwidth); float bandwidth);

@ -74,6 +74,7 @@ typedef struct {
float snr_vector[12000]; float snr_vector[12000];
float pilot_power[12000]; float pilot_power[12000];
#endif #endif
bool smooth_filter_auto;
uint32_t smooth_filter_len; uint32_t smooth_filter_len;
float smooth_filter[SRSLTE_CHEST_MAX_SMOOTH_FIL_LEN]; float smooth_filter[SRSLTE_CHEST_MAX_SMOOTH_FIL_LEN];
@ -112,10 +113,10 @@ SRSLTE_API void srslte_chest_dl_free(srslte_chest_dl_t *q);
SRSLTE_API int srslte_chest_dl_set_mbsfn_area_id(srslte_chest_dl_t *q, SRSLTE_API int srslte_chest_dl_set_mbsfn_area_id(srslte_chest_dl_t *q,
uint16_t mbsfn_area_id); uint16_t mbsfn_area_id);
SRSLTE_API int srslte_chest_dl_set_cell(srslte_chest_dl_t *q, SRSLTE_API int srslte_chest_dl_set_cell(srslte_chest_dl_t *q,
srslte_cell_t cell); srslte_cell_t cell);
SRSLTE_API void srslte_chest_dl_set_smooth_filter(srslte_chest_dl_t *q, SRSLTE_API void srslte_chest_dl_set_smooth_filter(srslte_chest_dl_t *q,
float *filter, float *filter,
uint32_t filter_len); uint32_t filter_len);
@ -123,6 +124,13 @@ SRSLTE_API void srslte_chest_dl_set_smooth_filter(srslte_chest_dl_t *q,
SRSLTE_API void srslte_chest_dl_set_smooth_filter3_coeff(srslte_chest_dl_t* q, SRSLTE_API void srslte_chest_dl_set_smooth_filter3_coeff(srslte_chest_dl_t* q,
float w); float w);
SRSLTE_API void srslte_chest_dl_set_smooth_filter_gauss(srslte_chest_dl_t* q,
uint32_t order,
float std_dev);
SRSLTE_API void srslte_chest_dl_set_smooth_filter_auto(srslte_chest_dl_t* q,
bool enable);
SRSLTE_API void srslte_chest_dl_set_noise_alg(srslte_chest_dl_t *q, SRSLTE_API void srslte_chest_dl_set_noise_alg(srslte_chest_dl_t *q,
srslte_chest_dl_noise_alg_t noise_estimation_alg); srslte_chest_dl_noise_alg_t noise_estimation_alg);

@ -93,8 +93,10 @@ SRSLTE_API uint32_t srslte_refsignal_cs_v(uint32_t port_id,
SRSLTE_API uint32_t srslte_refsignal_cs_nof_symbols(uint32_t port_id); SRSLTE_API uint32_t srslte_refsignal_cs_nof_symbols(uint32_t port_id);
SRSLTE_API int srslte_refsignal_mbsfn_init(srslte_refsignal_t *q, srslte_cell_t cell, SRSLTE_API int srslte_refsignal_mbsfn_init(srslte_refsignal_t *q, uint32_t max_prb);
uint16_t mbsfn_area_id);
SRSLTE_API int srslte_refsignal_mbsfn_set_cell(srslte_refsignal_t * q,
srslte_cell_t cell, uint16_t mbsfn_area_id);
SRSLTE_API int srslte_refsignal_mbsfn_get_sf(srslte_cell_t cell, SRSLTE_API int srslte_refsignal_mbsfn_get_sf(srslte_cell_t cell,
uint32_t port_id, uint32_t port_id,

@ -92,7 +92,7 @@ SRSLTE_API int srslte_ofdm_rx_init_mbsfn(srslte_ofdm_t *q,
srslte_cp_t cp_type, srslte_cp_t cp_type,
cf_t *in_buffer, cf_t *in_buffer,
cf_t *out_buffer, cf_t *out_buffer,
uint32_t nof_prb); uint32_t max_prb);
SRSLTE_API int srslte_ofdm_rx_init(srslte_ofdm_t *q, SRSLTE_API int srslte_ofdm_rx_init(srslte_ofdm_t *q,
srslte_cp_t cp_type, srslte_cp_t cp_type,

@ -69,15 +69,20 @@ typedef struct SRSLTE_API {
cf_t *slot1_symbols[SRSLTE_MAX_PORTS]; cf_t *slot1_symbols[SRSLTE_MAX_PORTS];
srslte_ofdm_t ifft[SRSLTE_MAX_PORTS]; srslte_ofdm_t ifft[SRSLTE_MAX_PORTS];
srslte_ofdm_t ifft_mbsfn;
srslte_pbch_t pbch; srslte_pbch_t pbch;
srslte_pcfich_t pcfich; srslte_pcfich_t pcfich;
srslte_regs_t regs; srslte_regs_t regs;
srslte_pdcch_t pdcch; srslte_pdcch_t pdcch;
srslte_pdsch_t pdsch; srslte_pdsch_t pdsch;
srslte_pmch_t pmch;
srslte_phich_t phich; srslte_phich_t phich;
srslte_refsignal_t csr_signal; srslte_refsignal_t csr_signal;
srslte_pdsch_cfg_t pdsch_cfg; srslte_refsignal_t mbsfnr_signal;
srslte_pdsch_cfg_t pdsch_cfg;
srslte_pdsch_cfg_t pmch_cfg;
srslte_ra_dl_dci_t dl_dci; srslte_ra_dl_dci_t dl_dci;
srslte_dci_format_t dci_format; srslte_dci_format_t dci_format;
@ -134,6 +139,8 @@ SRSLTE_API void srslte_enb_dl_prepare_power_allocation(srslte_enb_dl_t *q);
SRSLTE_API void srslte_enb_dl_set_amp(srslte_enb_dl_t *q, SRSLTE_API void srslte_enb_dl_set_amp(srslte_enb_dl_t *q,
float amp); float amp);
SRSLTE_API void srslte_enb_dl_set_non_mbsfn_region(srslte_enb_dl_t *q, uint8_t non_mbsfn_region);
SRSLTE_API void srslte_enb_dl_clear_sf(srslte_enb_dl_t *q); SRSLTE_API void srslte_enb_dl_clear_sf(srslte_enb_dl_t *q);
SRSLTE_API void srslte_enb_dl_put_sync(srslte_enb_dl_t *q, SRSLTE_API void srslte_enb_dl_put_sync(srslte_enb_dl_t *q,
@ -157,8 +164,13 @@ SRSLTE_API void srslte_enb_dl_put_phich(srslte_enb_dl_t *q,
SRSLTE_API void srslte_enb_dl_put_base(srslte_enb_dl_t *q, SRSLTE_API void srslte_enb_dl_put_base(srslte_enb_dl_t *q,
uint32_t tti); uint32_t tti);
SRSLTE_API void srslte_enb_dl_put_mbsfn_base(srslte_enb_dl_t *q,
uint32_t tti);
SRSLTE_API void srslte_enb_dl_gen_signal(srslte_enb_dl_t *q); SRSLTE_API void srslte_enb_dl_gen_signal(srslte_enb_dl_t *q);
SRSLTE_API void srslte_enb_dl_gen_signal_mbsfn(srslte_enb_dl_t *q);
SRSLTE_API int srslte_enb_dl_add_rnti(srslte_enb_dl_t *q, SRSLTE_API int srslte_enb_dl_add_rnti(srslte_enb_dl_t *q,
uint16_t rnti); uint16_t rnti);
@ -174,6 +186,12 @@ SRSLTE_API int srslte_enb_dl_put_pdsch(srslte_enb_dl_t *q,
uint8_t *data[SRSLTE_MAX_CODEWORDS], uint8_t *data[SRSLTE_MAX_CODEWORDS],
srslte_mimo_type_t mimo_type); srslte_mimo_type_t mimo_type);
SRSLTE_API int srslte_enb_dl_put_pmch(srslte_enb_dl_t *q,
srslte_ra_dl_grant_t *grant,
srslte_softbuffer_tx_t *softbuffer,
uint32_t sf_idx,
uint8_t *data_mbms);
SRSLTE_API int srslte_enb_dl_put_pdcch_dl(srslte_enb_dl_t *q, SRSLTE_API int srslte_enb_dl_put_pdcch_dl(srslte_enb_dl_t *q,
srslte_ra_dl_dci_t *grant, srslte_ra_dl_dci_t *grant,
srslte_dci_format_t format, srslte_dci_format_t format,

@ -87,7 +87,7 @@ SRSLTE_API int srslte_predecoding_single(cf_t *y,
SRSLTE_API int srslte_predecoding_single_multi(cf_t *y[SRSLTE_MAX_PORTS], SRSLTE_API int srslte_predecoding_single_multi(cf_t *y[SRSLTE_MAX_PORTS],
cf_t *h[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS],
cf_t *x, cf_t *x,
float *csi, float *csi[SRSLTE_MAX_CODEWORDS],
int nof_rxant, int nof_rxant,
int nof_symbols, int nof_symbols,
float scaling, float scaling,
@ -102,7 +102,8 @@ SRSLTE_API int srslte_predecoding_diversity(cf_t *y,
SRSLTE_API int srslte_predecoding_diversity_multi(cf_t *y[SRSLTE_MAX_PORTS], SRSLTE_API int srslte_predecoding_diversity_multi(cf_t *y[SRSLTE_MAX_PORTS],
cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], cf_t *x[SRSLTE_MAX_LAYERS],
float *csi[SRSLTE_MAX_LAYERS],
int nof_rxant, int nof_rxant,
int nof_ports, int nof_ports,
int nof_symbols, int nof_symbols,
@ -113,7 +114,7 @@ SRSLTE_API void srslte_predecoding_set_mimo_decoder (srslte_mimo_decoder_t _mimo
SRSLTE_API int srslte_predecoding_type(cf_t *y[SRSLTE_MAX_PORTS], SRSLTE_API int srslte_predecoding_type(cf_t *y[SRSLTE_MAX_PORTS],
cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], cf_t *x[SRSLTE_MAX_LAYERS],
float *csi, float *csi[SRSLTE_MAX_CODEWORDS],
int nof_rxant, int nof_rxant,
int nof_ports, int nof_ports,
int nof_layers, int nof_layers,

@ -89,6 +89,8 @@ typedef struct SRSLTE_API {
srslte_sch_t dl_sch; srslte_sch_t dl_sch;
void *coworker_ptr;
} srslte_pdsch_t; } srslte_pdsch_t;
@ -167,6 +169,8 @@ SRSLTE_API void srslte_pdsch_set_max_noi(srslte_pdsch_t *q,
SRSLTE_API float srslte_pdsch_last_noi(srslte_pdsch_t *q); SRSLTE_API float srslte_pdsch_last_noi(srslte_pdsch_t *q);
SRSLTE_API int srslte_pdsch_enable_coworker(srslte_pdsch_t *q);
SRSLTE_API uint32_t srslte_pdsch_last_noi_cw(srslte_pdsch_t *q, SRSLTE_API uint32_t srslte_pdsch_last_noi_cw(srslte_pdsch_t *q,
uint32_t cw_idx); uint32_t cw_idx);

@ -94,7 +94,7 @@ SRSLTE_API int srslte_pmch_init_multi(srslte_pmch_t *q,
SRSLTE_API void srslte_pmch_free(srslte_pmch_t *q); SRSLTE_API void srslte_pmch_free(srslte_pmch_t *q);
SRSLTE_API int srslte_pmch_set_cell(srslte_pmch_t *q, srslte_cell_t cell);
SRSLTE_API int srslte_pmch_set_area_id(srslte_pmch_t *q, uint16_t area_id); SRSLTE_API int srslte_pmch_set_area_id(srslte_pmch_t *q, uint16_t area_id);

@ -64,7 +64,7 @@ typedef struct SRSLTE_API {
uint8_t *parity_bits; uint8_t *parity_bits;
void *e; void *e;
uint8_t *temp_g_bits; uint8_t *temp_g_bits;
uint16_t *ul_interleaver; uint32_t *ul_interleaver;
srslte_uci_bit_t ack_ri_bits[12*288]; srslte_uci_bit_t ack_ri_bits[12*288];
uint32_t nof_ri_ack_bits; uint32_t nof_ri_ack_bits;

@ -55,6 +55,14 @@ typedef struct {
float iq_q; float iq_q;
} srslte_rf_cal_t; } srslte_rf_cal_t;
typedef struct {
double min_tx_gain;
double max_tx_gain;
double min_rx_gain;
double max_rx_gain;
} srslte_rf_info_t;
typedef struct { typedef struct {
enum { enum {
SRSLTE_RF_ERROR_LATE, SRSLTE_RF_ERROR_LATE,
@ -125,6 +133,8 @@ SRSLTE_API double srslte_rf_get_rx_gain(srslte_rf_t *h);
SRSLTE_API double srslte_rf_get_tx_gain(srslte_rf_t *h); SRSLTE_API double srslte_rf_get_tx_gain(srslte_rf_t *h);
SRSLTE_API srslte_rf_info_t *srslte_rf_get_info(srslte_rf_t *h);
SRSLTE_API void srslte_rf_suppress_stdout(srslte_rf_t *h); SRSLTE_API void srslte_rf_suppress_stdout(srslte_rf_t *h);
SRSLTE_API void srslte_rf_register_error_handler(srslte_rf_t *h, SRSLTE_API void srslte_rf_register_error_handler(srslte_rf_t *h,

@ -61,6 +61,8 @@
#include "srslte/phy/common/timestamp.h" #include "srslte/phy/common/timestamp.h"
#include "srslte/phy/io/filesource.h" #include "srslte/phy/io/filesource.h"
#define DEFAULT_SAMPLE_OFFSET_CORRECT_PERIOD 10
#define DEFAULT_SFO_EMA_COEFF 0.1
#define DEFAULT_CFO_BW_PSS 0.05 #define DEFAULT_CFO_BW_PSS 0.05
#define DEFAULT_CFO_PSS_MIN 400 // typical bias of PSS estimation. #define DEFAULT_CFO_PSS_MIN 400 // typical bias of PSS estimation.
@ -140,8 +142,7 @@ typedef struct SRSLTE_API {
int next_rf_sample_offset; int next_rf_sample_offset;
int last_sample_offset; int last_sample_offset;
float mean_sample_offset; float mean_sample_offset;
float mean_sfo; uint32_t sample_offset_correct_period;
uint32_t sample_offset_correct_period;
float sfo_ema; float sfo_ema;
@ -198,7 +199,9 @@ SRSLTE_API void srslte_ue_sync_reset(srslte_ue_sync_t *q);
SRSLTE_API int srslte_ue_sync_start_agc(srslte_ue_sync_t *q, SRSLTE_API int srslte_ue_sync_start_agc(srslte_ue_sync_t *q,
double (set_gain_callback)(void*, double), double (set_gain_callback)(void*, double),
float init_gain_value); double min_gain,
double max_gain,
double init_gain_value);
SRSLTE_API uint32_t srslte_ue_sync_sf_len(srslte_ue_sync_t *q); SRSLTE_API uint32_t srslte_ue_sync_sf_len(srslte_ue_sync_t *q);
@ -248,8 +251,11 @@ SRSLTE_API float srslte_ue_sync_get_sfo(srslte_ue_sync_t *q);
SRSLTE_API int srslte_ue_sync_get_last_sample_offset(srslte_ue_sync_t *q); SRSLTE_API int srslte_ue_sync_get_last_sample_offset(srslte_ue_sync_t *q);
SRSLTE_API void srslte_ue_sync_set_sample_offset_correct_period(srslte_ue_sync_t *q, SRSLTE_API void srslte_ue_sync_set_sfo_correct_period(srslte_ue_sync_t *q,
uint32_t nof_subframes); uint32_t nof_subframes);
SRSLTE_API void srslte_ue_sync_set_sfo_ema(srslte_ue_sync_t *q,
float ema_coefficient);
SRSLTE_API void srslte_ue_sync_get_last_timestamp(srslte_ue_sync_t *q, SRSLTE_API void srslte_ue_sync_get_last_timestamp(srslte_ue_sync_t *q,
srslte_timestamp_t *timestamp); srslte_timestamp_t *timestamp);

@ -70,6 +70,17 @@ SRSLTE_API void srslte_bit_copy(uint8_t *dst,
uint32_t src_offset, uint32_t src_offset,
uint32_t nof_bits); uint32_t nof_bits);
SRSLTE_API void srslte_bit_interleave_i(uint8_t *input,
uint8_t *output,
uint32_t *interleaver,
uint32_t nof_bits);
SRSLTE_API void srslte_bit_interleave_i_w_offset(uint8_t *input,
uint8_t *output,
uint32_t *interleaver,
uint32_t nof_bits,
uint32_t w_offset);
SRSLTE_API void srslte_bit_interleave_w_offset(uint8_t *input, SRSLTE_API void srslte_bit_interleave_w_offset(uint8_t *input,
uint8_t *output, uint8_t *output,
uint16_t *interleaver, uint16_t *interleaver,

@ -53,12 +53,17 @@ SRSLTE_API void srslte_mat_2x2_mmse_gen(cf_t y0, cf_t y1,
float noise_estimate, float noise_estimate,
float norm); float norm);
SRSLTE_API void srslte_mat_2x2_mmse_csi_gen(cf_t y0, cf_t y1,
cf_t h00, cf_t h01, cf_t h10, cf_t h11,
cf_t *x0, cf_t *x1, float *csi0, float *csi1,
float noise_estimate,
float norm);
SRSLTE_API float srslte_mat_2x2_cn(cf_t h00, SRSLTE_API float srslte_mat_2x2_cn(cf_t h00,
cf_t h01, cf_t h01,
cf_t h10, cf_t h10,
cf_t h11); cf_t h11);
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
/* SSE implementation for complex reciprocal */ /* SSE implementation for complex reciprocal */
@ -103,4 +108,114 @@ SRSLTE_API void srslte_mat_2x2_mmse_avx(__m256 y0, __m256 y1,
#endif /* LV_HAVE_AVX */ #endif /* LV_HAVE_AVX */
#endif // SRSLTE_MAT_H #if SRSLTE_SIMD_CF_SIZE != 0
/* Generic SIMD implementation for 2x2 determinant */
static inline simd_cf_t srslte_mat_2x2_det_simd(simd_cf_t a00, simd_cf_t a01, simd_cf_t a10, simd_cf_t a11) {
return srslte_simd_cf_sub(srslte_simd_cf_prod(a00, a11), srslte_simd_cf_prod(a01, a10));
}
/* Generic SIMD implementation for Zero Forcing (ZF) solver */
static inline void srslte_mat_2x2_zf_csi_simd(simd_cf_t y0,
simd_cf_t y1,
simd_cf_t h00,
simd_cf_t h01,
simd_cf_t h10,
simd_cf_t h11,
simd_cf_t *x0,
simd_cf_t *x1,
simd_f_t *csi0,
simd_f_t *csi1,
float norm) {
simd_cf_t det = srslte_mat_2x2_det_simd(h00, h01, h10, h11);
simd_cf_t detrec = srslte_simd_cf_mul(srslte_simd_cf_rcp(det), srslte_simd_f_set1(norm));
*x0 = srslte_simd_cf_prod(srslte_simd_cf_sub(srslte_simd_cf_prod(h11, y0), srslte_simd_cf_prod(h01, y1)), detrec);
*x1 = srslte_simd_cf_prod(srslte_simd_cf_sub(srslte_simd_cf_prod(h00, y1), srslte_simd_cf_prod(h10, y0)), detrec);
*csi0 = srslte_simd_f_set1(1.0f);
*csi1 = srslte_simd_f_set1(1.0f);
}
static inline void srslte_mat_2x2_zf_simd(simd_cf_t y0,
simd_cf_t y1,
simd_cf_t h00,
simd_cf_t h01,
simd_cf_t h10,
simd_cf_t h11,
simd_cf_t *x0,
simd_cf_t *x1,
float norm) {
simd_f_t csi1, csi2;
srslte_mat_2x2_zf_csi_simd(y0, y1, h00, h01, h10, h11, x0, x1, &csi1, &csi2, norm);
}
/* Generic SIMD implementation for Minimum Mean Squared Error (MMSE) solver */
static inline void srslte_mat_2x2_mmse_csi_simd(simd_cf_t y0,
simd_cf_t y1,
simd_cf_t h00,
simd_cf_t h01,
simd_cf_t h10,
simd_cf_t h11,
simd_cf_t *x0,
simd_cf_t *x1,
simd_f_t *csi0,
simd_f_t *csi1,
float noise_estimate,
float norm) {
simd_cf_t _noise_estimate;
simd_f_t _norm = srslte_simd_f_set1(norm);
_noise_estimate.re = srslte_simd_f_set1(noise_estimate);
_noise_estimate.im = srslte_simd_f_zero();
/* 1. A = H' x H + No*/
simd_cf_t a00 =
srslte_simd_cf_add(srslte_simd_cf_add(srslte_simd_cf_conjprod(h00, h00), srslte_simd_cf_conjprod(h10, h10)),
_noise_estimate);
simd_cf_t a01 = srslte_simd_cf_add(srslte_simd_cf_conjprod(h01, h00), srslte_simd_cf_conjprod(h11, h10));
simd_cf_t a10 = srslte_simd_cf_add(srslte_simd_cf_conjprod(h00, h01), srslte_simd_cf_conjprod(h10, h11));
simd_cf_t a11 =
srslte_simd_cf_add(srslte_simd_cf_add(srslte_simd_cf_conjprod(h01, h01), srslte_simd_cf_conjprod(h11, h11)),
_noise_estimate);
simd_cf_t a_det_rcp = srslte_simd_cf_rcp(srslte_mat_2x2_det_simd(a00, a01, a10, a11));
/* 2. B = inv(H' x H + No) = inv(A) */
simd_cf_t _norm2 = srslte_simd_cf_mul(a_det_rcp, _norm);
simd_cf_t b00 = srslte_simd_cf_prod(a11, _norm2);
simd_cf_t b01 = srslte_simd_cf_prod(srslte_simd_cf_neg(a01), _norm2);
simd_cf_t b10 = srslte_simd_cf_prod(srslte_simd_cf_neg(a10), _norm2);
simd_cf_t b11 = srslte_simd_cf_prod(a00, _norm2);
/* 3. W = inv(H' x H + No) x H' = B x H' */
simd_cf_t w00 = srslte_simd_cf_add(srslte_simd_cf_conjprod(b00, h00), srslte_simd_cf_conjprod(b01, h01));
simd_cf_t w01 = srslte_simd_cf_add(srslte_simd_cf_conjprod(b00, h10), srslte_simd_cf_conjprod(b01, h11));
simd_cf_t w10 = srslte_simd_cf_add(srslte_simd_cf_conjprod(b10, h00), srslte_simd_cf_conjprod(b11, h01));
simd_cf_t w11 = srslte_simd_cf_add(srslte_simd_cf_conjprod(b10, h10), srslte_simd_cf_conjprod(b11, h11));
/* 4. X = W x Y */
*x0 = srslte_simd_cf_add(srslte_simd_cf_prod(y0, w00), srslte_simd_cf_prod(y1, w01));
*x1 = srslte_simd_cf_add(srslte_simd_cf_prod(y0, w10), srslte_simd_cf_prod(y1, w11));
/* 5. Extract CSI */
*csi0 = srslte_simd_f_rcp(srslte_simd_cf_re(b00));
*csi1 = srslte_simd_f_rcp(srslte_simd_cf_re(b11));
}
static inline void srslte_mat_2x2_mmse_simd(simd_cf_t y0,
simd_cf_t y1,
simd_cf_t h00,
simd_cf_t h01,
simd_cf_t h10,
simd_cf_t h11,
simd_cf_t *x0,
simd_cf_t *x1,
float noise_estimate,
float norm) {
simd_f_t csi0, csi1;
srslte_mat_2x2_mmse_csi_simd(y0, y1, h00, h01, h10, h11, x0, x1, &csi0, &csi1, noise_estimate, norm);
}
#endif /* SRSLTE_SIMD_CF_SIZE != 0 */
#endif /* SRSLTE_MAT_H */

@ -197,7 +197,7 @@ static inline simd_f_t srslte_simd_f_loadu(const float *ptr) {
#ifdef LV_HAVE_AVX512 #ifdef LV_HAVE_AVX512
return _mm512_loadu_ps(ptr); return _mm512_loadu_ps(ptr);
#else /* LV_HAVE_AVX512 */ #else /* LV_HAVE_AVX512 */
#ifdef LV_HAVE_AVX2 #ifdef LV_HAVE_AVX2
return _mm256_loadu_ps(ptr); return _mm256_loadu_ps(ptr);
#else /* LV_HAVE_AVX2 */ #else /* LV_HAVE_AVX2 */
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
@ -233,7 +233,7 @@ static inline void srslte_simd_f_storeu(float *ptr, simd_f_t simdreg) {
#ifdef LV_HAVE_AVX512 #ifdef LV_HAVE_AVX512
_mm512_storeu_ps(ptr, simdreg); _mm512_storeu_ps(ptr, simdreg);
#else /* LV_HAVE_AVX512 */ #else /* LV_HAVE_AVX512 */
#ifdef LV_HAVE_AVX2 #ifdef LV_HAVE_AVX2
_mm256_storeu_ps(ptr, simdreg); _mm256_storeu_ps(ptr, simdreg);
#else /* LV_HAVE_AVX2 */ #else /* LV_HAVE_AVX2 */
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
@ -360,7 +360,7 @@ static inline simd_f_t srslte_simd_f_add(simd_f_t a, simd_f_t b) {
#ifdef LV_HAVE_AVX2 #ifdef LV_HAVE_AVX2
return _mm256_add_ps(a, b); return _mm256_add_ps(a, b);
#else /* LV_HAVE_AVX2 */ #else /* LV_HAVE_AVX2 */
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
return _mm_add_ps(a, b); return _mm_add_ps(a, b);
#else /* LV_HAVE_SSE */ #else /* LV_HAVE_SSE */
#ifdef HAVE_NEON #ifdef HAVE_NEON
@ -376,9 +376,9 @@ static inline simd_f_t srslte_simd_f_zero (void) {
return _mm512_setzero_ps(); return _mm512_setzero_ps();
#else /* LV_HAVE_AVX512 */ #else /* LV_HAVE_AVX512 */
#ifdef LV_HAVE_AVX2 #ifdef LV_HAVE_AVX2
return _mm256_setzero_ps(); return _mm256_setzero_ps();
#else /* LV_HAVE_AVX2 */ #else /* LV_HAVE_AVX2 */
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
return _mm_setzero_ps(); return _mm_setzero_ps();
#else /* LV_HAVE_SSE */ #else /* LV_HAVE_SSE */
#ifdef HAVE_NEON #ifdef HAVE_NEON
@ -401,7 +401,7 @@ static inline simd_f_t srslte_simd_f_swap(simd_f_t a) {
#else /* LV_HAVE_SSE */ #else /* LV_HAVE_SSE */
#ifdef HAVE_NEON #ifdef HAVE_NEON
return vcombine_f32(vrev64_f32(vget_low_f32(a)), vrev64_f32(vget_high_f32(a))); return vcombine_f32(vrev64_f32(vget_low_f32(a)), vrev64_f32(vget_high_f32(a)));
#endif /* HAVE_NEON */ #endif /* HAVE_NEON */
#endif /* LV_HAVE_SSE */ #endif /* LV_HAVE_SSE */
#endif /* LV_HAVE_AVX2 */ #endif /* LV_HAVE_AVX2 */
#endif /* LV_HAVE_AVX512 */ #endif /* LV_HAVE_AVX512 */
@ -443,7 +443,7 @@ static inline simd_f_t srslte_simd_f_sqrt(simd_f_t a) {
#ifdef LV_HAVE_AVX512 #ifdef LV_HAVE_AVX512
return _mm512_sqrt_ps(a); return _mm512_sqrt_ps(a);
#else /* LV_HAVE_AVX512 */ #else /* LV_HAVE_AVX512 */
#ifdef LV_HAVE_AVX2 #ifdef LV_HAVE_AVX2
return _mm256_sqrt_ps(a); return _mm256_sqrt_ps(a);
#else /* LV_HAVE_AVX2 */ #else /* LV_HAVE_AVX2 */
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
@ -458,7 +458,43 @@ static inline simd_f_t srslte_simd_f_sqrt(simd_f_t a) {
float32x4_t zeros = vmovq_n_f32(0); /* Zero vector */ float32x4_t zeros = vmovq_n_f32(0); /* Zero vector */
uint32x4_t mask = vceqq_f32(a, zeros); /* Zero vector mask */ uint32x4_t mask = vceqq_f32(a, zeros); /* Zero vector mask */
return vbslq_f32(mask, zeros, result); /* Force zero results and return */ return vbslq_f32(mask, zeros, result); /* Force zero results and return */
#endif /* HAVE_NEON */ #endif /* HAVE_NEON */
#endif /* LV_HAVE_SSE */
#endif /* LV_HAVE_AVX2 */
#endif /* LV_HAVE_AVX512 */
}
static inline simd_f_t srslte_simd_f_neg(simd_f_t a) {
#ifdef LV_HAVE_AVX512
return _mm512_xor_ps(_mm512_set1_ps(-0.0f), a);
#else /* LV_HAVE_AVX512 */
#ifdef LV_HAVE_AVX2
return _mm256_xor_ps(_mm256_set1_ps(-0.0f), a);
#else /* LV_HAVE_AVX2 */
#ifdef LV_HAVE_SSE
return _mm_xor_ps(_mm_set1_ps(-0.0f), a);
#else /* LV_HAVE_SSE */
#ifdef HAVE_NEON
return vnegq_f32(a);
#endif /* HAVE_NEON */
#endif /* LV_HAVE_SSE */
#endif /* LV_HAVE_AVX2 */
#endif /* LV_HAVE_AVX512 */
}
static inline simd_f_t srslte_simd_f_neg_mask(simd_f_t a, simd_f_t mask) {
#ifdef LV_HAVE_AVX512
return _mm512_xor_ps(mask, a);
#else /* LV_HAVE_AVX512 */
#ifdef LV_HAVE_AVX2
return _mm256_xor_ps(mask, a);
#else /* LV_HAVE_AVX2 */
#ifdef LV_HAVE_SSE
return _mm_xor_ps(mask, a);
#else /* LV_HAVE_SSE */
#ifdef HAVE_NEON
return (float32x4_t) veorq_s32((int32x4_t) a, (int32x4_t) mask);
#endif /* HAVE_NEON */
#endif /* LV_HAVE_SSE */ #endif /* LV_HAVE_SSE */
#endif /* LV_HAVE_AVX2 */ #endif /* LV_HAVE_AVX2 */
#endif /* LV_HAVE_AVX512 */ #endif /* LV_HAVE_AVX512 */
@ -470,12 +506,11 @@ static inline simd_f_t srslte_simd_f_sqrt(simd_f_t a) {
#if SRSLTE_SIMD_CF_SIZE #if SRSLTE_SIMD_CF_SIZE
#ifdef HAVE_NEON #ifdef HAVE_NEON
typedef float32x4x2_t simd_cf_t; typedef float32x4x2_t simd_cf_t;
#else #else
typedef struct { typedef struct {
simd_f_t re; simd_f_t re;
simd_f_t im; simd_f_t im;
} simd_cf_t; } simd_cf_t;
#endif #endif
@ -667,8 +702,8 @@ static inline void srslte_simd_cf_store(float *re, float *im, simd_cf_t simdreg)
_mm512_store_ps(im, simdreg.im); _mm512_store_ps(im, simdreg.im);
#else /* LV_HAVE_AVX512 */ #else /* LV_HAVE_AVX512 */
#ifdef LV_HAVE_AVX2 #ifdef LV_HAVE_AVX2
_mm256_store_ps((float *) re, simdreg.re); _mm256_store_ps(re, simdreg.re);
_mm256_store_ps((float *) im, simdreg.im); _mm256_store_ps(im, simdreg.im);
#else /* LV_HAVE_AVX512 */ #else /* LV_HAVE_AVX512 */
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
_mm_store_ps((float *) re, simdreg.re); _mm_store_ps((float *) re, simdreg.re);
@ -689,8 +724,8 @@ static inline void srslte_simd_cf_storeu(float *re, float *im, simd_cf_t simdreg
_mm512_storeu_ps(im, simdreg.im); _mm512_storeu_ps(im, simdreg.im);
#else /* LV_HAVE_AVX512 */ #else /* LV_HAVE_AVX512 */
#ifdef LV_HAVE_AVX2 #ifdef LV_HAVE_AVX2
_mm256_storeu_ps((float *) re, simdreg.re); _mm256_storeu_ps(re, simdreg.re);
_mm256_storeu_ps((float *) im, simdreg.im); _mm256_storeu_ps(im, simdreg.im);
#else /* LV_HAVE_AVX512 */ #else /* LV_HAVE_AVX512 */
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
_mm_storeu_ps((float *) re, simdreg.re); _mm_storeu_ps((float *) re, simdreg.re);
@ -754,10 +789,15 @@ static inline simd_cf_t srslte_simd_cf_prod (simd_cf_t a, simd_cf_t b) {
_mm512_mul_ps(a.im, b.re)); _mm512_mul_ps(a.im, b.re));
#else /* LV_HAVE_AVX512 */ #else /* LV_HAVE_AVX512 */
#ifdef LV_HAVE_AVX2 #ifdef LV_HAVE_AVX2
#ifdef LV_HAVE_FMA
ret.re = _mm256_fmsub_ps(a.re, b.re, _mm256_mul_ps(a.im, b.im));
ret.im = _mm256_fmadd_ps(a.re, b.im, _mm256_mul_ps(a.im, b.re));
#else /* LV_HAVE_FMA */
ret.re = _mm256_sub_ps(_mm256_mul_ps(a.re, b.re), ret.re = _mm256_sub_ps(_mm256_mul_ps(a.re, b.re),
_mm256_mul_ps(a.im, b.im)); _mm256_mul_ps(a.im, b.im));
ret.im = _mm256_add_ps(_mm256_mul_ps(a.re, b.im), ret.im = _mm256_add_ps(_mm256_mul_ps(a.re, b.im),
_mm256_mul_ps(a.im, b.re)); _mm256_mul_ps(a.im, b.re));
#endif /* LV_HAVE_FMA */
#else #else
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
ret.re = _mm_sub_ps(_mm_mul_ps(a.re, b.re), ret.re = _mm_sub_ps(_mm_mul_ps(a.re, b.re),
@ -833,8 +873,32 @@ static inline simd_cf_t srslte_simd_cf_add (simd_cf_t a, simd_cf_t b) {
return ret; return ret;
} }
static inline simd_cf_t srslte_simd_cf_sub (simd_cf_t a, simd_cf_t b) {
simd_cf_t ret;
#ifdef LV_HAVE_AVX512
ret.re = _mm512_sub_ps(a.re, b.re);
ret.im = _mm512_sub_ps(a.im, b.im);
#else /* LV_HAVE_AVX512 */
#ifdef LV_HAVE_AVX2
ret.re = _mm256_sub_ps(a.re, b.re);
ret.im = _mm256_sub_ps(a.im, b.im);
#else /* LV_HAVE_AVX2 */
#ifdef LV_HAVE_SSE
ret.re = _mm_sub_ps(a.re, b.re);
ret.im = _mm_sub_ps(a.im, b.im);
#else /* LV_HAVE_SSE */
#ifdef HAVE_NEON
ret.val[0] = vsubq_f32(a.val[0],b.val[0]);
ret.val[1] = vsubq_f32(a.val[1],b.val[1]);
#endif /* HAVE_NEON */
#endif /* LV_HAVE_SSE */
#endif /* LV_HAVE_AVX2 */
#endif /* LV_HAVE_AVX512 */
return ret;
}
static inline simd_cf_t srslte_simd_cf_mul (simd_cf_t a, simd_f_t b) { static inline simd_cf_t srslte_simd_cf_mul (simd_cf_t a, simd_f_t b) {
simd_cf_t ret; simd_cf_t ret;
#ifdef LV_HAVE_AVX512 #ifdef LV_HAVE_AVX512
ret.re = _mm512_mul_ps(a.re, b); ret.re = _mm512_mul_ps(a.re, b);
ret.im = _mm512_mul_ps(a.im, b); ret.im = _mm512_mul_ps(a.im, b);
@ -855,7 +919,7 @@ static inline simd_cf_t srslte_simd_cf_mul (simd_cf_t a, simd_f_t b) {
#endif /* LV_HAVE_SSE */ #endif /* LV_HAVE_SSE */
#endif /* LV_HAVE_AVX2 */ #endif /* LV_HAVE_AVX2 */
#endif /* LV_HAVE_AVX512 */ #endif /* LV_HAVE_AVX512 */
return ret; return ret;
} }
static inline simd_cf_t srslte_simd_cf_rcp (simd_cf_t a) { static inline simd_cf_t srslte_simd_cf_rcp (simd_cf_t a) {
@ -902,6 +966,59 @@ static inline simd_cf_t srslte_simd_cf_rcp (simd_cf_t a) {
return ret; return ret;
} }
static inline simd_cf_t srslte_simd_cf_neg (simd_cf_t a) {
simd_cf_t ret;
#if LV_HAVE_NEON
ret.val[0] = srslte_simd_f_neg(a.val[0]);
ret.val[1] = srslte_simd_f_neg(a.val[1]);
#else /* LV_HAVE_NEON */
ret.re = srslte_simd_f_neg(a.re);
ret.im = srslte_simd_f_neg(a.im);
#endif /* LV_HAVE_NEON */
return ret;
}
static inline simd_cf_t srslte_simd_cf_neg_mask (simd_cf_t a, simd_f_t mask) {
simd_cf_t ret;
#ifndef LV_HAVE_AVX512
#ifdef LV_HAVE_AVX2
mask = _mm256_permutevar8x32_ps(mask, _mm256_setr_epi32(0,4,1,5,2,6,3,7));
#endif /* LV_HAVE_AVX2 */
#endif /* LV_HAVE_AVX512 */
#if LV_HAVE_NEON
ret.val[0] = srslte_simd_f_neg_mask(a.val[0], mask);
ret.val[1] = srslte_simd_f_neg_mask(a.val[1], mask);
#else /* LV_HAVE_NEON */
ret.re = srslte_simd_f_neg_mask(a.re, mask);
ret.im = srslte_simd_f_neg_mask(a.im, mask);
#endif /* LV_HAVE_NEON */
return ret;
}
static inline simd_cf_t srslte_simd_cf_conj (simd_cf_t a) {
simd_cf_t ret;
#if LV_HAVE_NEON
ret.val[0] = a.val[0];
ret.val[1] = srslte_simd_f_neg(a.val[1]);
#else /* LV_HAVE_NEON */
ret.re = a.re;
ret.im = srslte_simd_f_neg(a.im);
#endif /* LV_HAVE_NEON */
return ret;
}
static inline simd_cf_t srslte_simd_cf_mulj (simd_cf_t a) {
simd_cf_t ret;
#if LV_HAVE_NEON
ret.val[0] = srslte_simd_f_neg(a.val[1]);
ret.val[1] = a.val[0];
#else /* LV_HAVE_NEON */
ret.re = srslte_simd_f_neg(a.im);
ret.im = a.re;
#endif /* LV_HAVE_NEON */
return ret;
}
static inline simd_cf_t srslte_simd_cf_zero (void) { static inline simd_cf_t srslte_simd_cf_zero (void) {
simd_cf_t ret; simd_cf_t ret;
#ifdef LV_HAVE_AVX512 #ifdef LV_HAVE_AVX512
@ -1057,7 +1174,7 @@ static inline simd_i_t srslte_simd_i_select(simd_i_t a, simd_i_t b, simd_sel_t s
int* sel = (int*) &selector; int* sel = (int*) &selector;
int* c_ptr = (int*) &ret; int* c_ptr = (int*) &ret;
for(int i = 0;i<4;i++) for(int i = 0;i<4;i++)
{ {
if(sel[i] == -1){ if(sel[i] == -1){
c_ptr[i] = b_ptr[i]; c_ptr[i] = b_ptr[i];
}else{ }else{
@ -1115,7 +1232,7 @@ static inline simd_s_t srslte_simd_s_loadu(const int16_t *ptr) {
#ifdef LV_HAVE_AVX512 #ifdef LV_HAVE_AVX512
return _mm512_loadu_si512(ptr); return _mm512_loadu_si512(ptr);
#else /* LV_HAVE_AVX512 */ #else /* LV_HAVE_AVX512 */
#ifdef LV_HAVE_AVX2 #ifdef LV_HAVE_AVX2
return _mm256_loadu_si256((__m256i*) ptr); return _mm256_loadu_si256((__m256i*) ptr);
#else /* LV_HAVE_AVX2 */ #else /* LV_HAVE_AVX2 */
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE

@ -99,6 +99,7 @@ SRSLTE_API void srslte_vec_convert_fi(const float *x, const float scale, int16_t
SRSLTE_API void srslte_vec_convert_if(const int16_t *x, const float scale, float *z, const uint32_t len); SRSLTE_API void srslte_vec_convert_if(const int16_t *x, const float scale, float *z, const uint32_t len);
SRSLTE_API void srslte_vec_lut_sss(const short *x, const unsigned short *lut, short *y, const uint32_t len); SRSLTE_API void srslte_vec_lut_sss(const short *x, const unsigned short *lut, short *y, const uint32_t len);
SRSLTE_API void srslte_vec_lut_sis(const short *x, const unsigned int *lut, short *y, const uint32_t len);
/* vector product (element-wise) */ /* vector product (element-wise) */
SRSLTE_API void srslte_vec_prod_ccc(const cf_t *x, const cf_t *y, cf_t *z, const uint32_t len); SRSLTE_API void srslte_vec_prod_ccc(const cf_t *x, const cf_t *y, cf_t *z, const uint32_t len);
@ -155,6 +156,9 @@ SRSLTE_API void srslte_vec_interleave(const cf_t *x, const cf_t *y, cf_t *z, con
SRSLTE_API void srslte_vec_interleave_add(const cf_t *x, const cf_t *y, cf_t *z, const int len); SRSLTE_API void srslte_vec_interleave_add(const cf_t *x, const cf_t *y, cf_t *z, const int len);
SRSLTE_API void srslte_vec_apply_cfo(const cf_t *x, float cfo, cf_t *z, int len);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

@ -130,6 +130,9 @@ SRSLTE_API void srslte_vec_interleave_simd(const cf_t *x, const cf_t *y, cf_t *z
SRSLTE_API void srslte_vec_interleave_add_simd(const cf_t *x, const cf_t *y, cf_t *z, const int len); SRSLTE_API void srslte_vec_interleave_add_simd(const cf_t *x, const cf_t *y, cf_t *z, const int len);
SRSLTE_API void srslte_vec_apply_cfo_simd(const cf_t *x, float cfo, cf_t *z, int len);
/* SIMD Find Max functions */ /* SIMD Find Max functions */
SRSLTE_API uint32_t srslte_vec_max_fi_simd(const float *x, const int len); SRSLTE_API uint32_t srslte_vec_max_fi_simd(const float *x, const int len);

@ -34,150 +34,153 @@
#define SRSLTE_RADIO_H #define SRSLTE_RADIO_H
typedef struct { typedef struct {
float tx_corr_dc_gain; float tx_corr_dc_gain;
float tx_corr_dc_phase; float tx_corr_dc_phase;
float tx_corr_iq_i; float tx_corr_iq_i;
float tx_corr_iq_q; float tx_corr_iq_q;
float rx_corr_dc_gain; float rx_corr_dc_gain;
float rx_corr_dc_phase; float rx_corr_dc_phase;
float rx_corr_iq_i; float rx_corr_iq_i;
float rx_corr_iq_q; float rx_corr_iq_q;
}rf_cal_t; } rf_cal_t;
namespace srslte { namespace srslte {
/* Interface to the RF frontend. /* Interface to the RF frontend.
*/ */
class radio class radio {
{ public:
public: radio() : tr_local_time(1024 * 10), tr_usrp_time(1024 * 10), tr_tx_time(1024 * 10), tr_is_eob(1024 * 10) {
radio() : tr_local_time(1024*10), tr_usrp_time(1024*10), tr_tx_time(1024*10), tr_is_eob(1024*10) { bzero(&rf_device, sizeof(srslte_rf_t));
bzero(&rf_device, sizeof(srslte_rf_t)); bzero(&end_of_burst_time, sizeof(srslte_timestamp_t));
bzero(&end_of_burst_time, sizeof(srslte_timestamp_t)); bzero(zeros, burst_preamble_max_samples * sizeof(cf_t));
bzero(zeros, burst_preamble_max_samples*sizeof(cf_t));
burst_preamble_sec = 0;
burst_preamble_sec = 0; is_start_of_burst = false;
is_start_of_burst = false; burst_preamble_samples = 0;
burst_preamble_samples = 0; burst_preamble_time_rounded = 0;
burst_preamble_time_rounded = 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; tx_adv_auto = false;
tx_adv_auto = false; tx_adv_negative = false;
tx_adv_negative = false; tx_freq = 0;
tx_freq = 0; rx_freq = 0;
rx_freq = 0; trace_enabled = false;
trace_enabled = false; tti = 0;
tti = 0; agc_enabled = false;
agc_enabled = false; radio_is_streaming = false;
radio_is_streaming = false; is_initialized = false;
is_initialized = false; continuous_tx = false;
}; };
bool init(char *args = NULL, char *devname = NULL, uint32_t nof_channels = 1); bool init(char *args = NULL, char *devname = NULL, uint32_t nof_channels = 1);
void stop(); void stop();
void reset(); void reset();
bool start_agc(bool tx_gain_same_rx); bool start_agc(bool tx_gain_same_rx);
void set_burst_preamble(double preamble_us); void set_burst_preamble(double preamble_us);
void set_tx_adv(int nsamples); void set_tx_adv(int nsamples);
void set_tx_adv_neg(bool tx_adv_is_neg); void set_tx_adv_neg(bool tx_adv_is_neg);
void set_manual_calibration(rf_cal_t *calibration); void set_manual_calibration(rf_cal_t *calibration);
void get_time(srslte_timestamp_t *now); bool is_continuous_tx();
bool tx_single(void *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time); void set_continuous_tx(bool enable);
bool tx(void *buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t tx_time);
void tx_end(); void get_time(srslte_timestamp_t *now);
bool rx_now(void *buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t *rxd_time); bool tx_single(void *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time);
bool rx_at(void *buffer, uint32_t nof_samples, srslte_timestamp_t rx_time); bool tx(void *buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t tx_time);
void tx_end();
void set_tx_gain(float gain); bool rx_now(void *buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t *rxd_time);
void set_rx_gain(float gain); bool rx_at(void *buffer, uint32_t nof_samples, srslte_timestamp_t rx_time);
void set_tx_rx_gain_offset(float offset);
double set_rx_gain_th(float gain); void set_tx_gain(float gain);
void set_rx_gain(float gain);
void set_freq_offset(double freq); void set_tx_rx_gain_offset(float offset);
void set_tx_freq(double freq); double set_rx_gain_th(float gain);
void set_rx_freq(double freq);
void set_freq_offset(double freq);
double get_freq_offset(); void set_tx_freq(double freq);
double get_tx_freq(); void set_rx_freq(double freq);
double get_rx_freq();
double get_freq_offset();
void set_master_clock_rate(double rate); double get_tx_freq();
void set_tx_srate(double srate); double get_rx_freq();
void set_rx_srate(double srate);
void set_master_clock_rate(double rate);
float get_tx_gain(); void set_tx_srate(double srate);
float get_rx_gain(); void set_rx_srate(double srate);
float get_max_tx_power(); float get_tx_gain();
float set_tx_power(float power); float get_rx_gain();
float get_rssi(); srslte_rf_info_t *get_info();
bool has_rssi();
float get_max_tx_power();
void start_trace(); float set_tx_power(float power);
void write_trace(std::string filename); float get_rssi();
bool has_rssi();
void set_tti(uint32_t tti);
void start_trace();
bool is_first_of_burst(); void write_trace(std::string filename);
bool is_init(); void set_tti(uint32_t tti);
void register_error_handler(srslte_rf_error_handler_t h); bool is_first_of_burst();
protected: bool is_init();
void save_trace(uint32_t is_eob, srslte_timestamp_t *usrp_time); void register_error_handler(srslte_rf_error_handler_t h);
srslte_rf_t rf_device; protected:
void save_trace(uint32_t is_eob, srslte_timestamp_t *usrp_time);
const static uint32_t burst_preamble_max_samples = 30720000; // 30.72 MHz is maximum frequency
double burst_preamble_sec;// Start of burst preamble time (off->on RF transition time) srslte_rf_t rf_device;
srslte_timestamp_t end_of_burst_time;
bool is_start_of_burst; const static uint32_t burst_preamble_max_samples = 30720000; // 30.72 MHz is maximum frequency
uint32_t burst_preamble_samples; double burst_preamble_sec;// Start of burst preamble time (off->on RF transition time)
double burst_preamble_time_rounded; // preamble time rounded to sample time srslte_timestamp_t end_of_burst_time;
cf_t zeros[burst_preamble_max_samples]; bool is_start_of_burst;
double cur_tx_srate; uint32_t burst_preamble_samples;
double burst_preamble_time_rounded; // preamble time rounded to sample time
double tx_adv_sec; // Transmission time advance to compensate for antenna->timestamp delay cf_t zeros[burst_preamble_max_samples];
int tx_adv_nsamples; // Transmision time advance in number of samples double cur_tx_srate;
// Define default values for known radios double tx_adv_sec; // Transmission time advance to compensate for antenna->timestamp delay
bool tx_adv_auto; int tx_adv_nsamples; // Transmision time advance in number of samples
bool tx_adv_negative;
const static double uhd_default_burst_preamble_sec = 600*1e-6; // Define default values for known radios
const static double uhd_default_tx_adv_samples = 98; bool tx_adv_auto;
const static double uhd_default_tx_adv_offset_sec = 4*1e-6; bool tx_adv_negative;
const static double uhd_default_burst_preamble_sec = 600 * 1e-6;
const static double blade_default_burst_preamble_sec = 0.0; const static double uhd_default_tx_adv_samples = 98;
const static double blade_default_tx_adv_samples = 27; const static double uhd_default_tx_adv_offset_sec = 4 * 1e-6;
const static double blade_default_tx_adv_offset_sec = 1e-6;
const static double blade_default_burst_preamble_sec = 0.0;
double tx_freq, rx_freq, freq_offset; const static double blade_default_tx_adv_samples = 27;
const static double blade_default_tx_adv_offset_sec = 1e-6;
trace<uint32_t> tr_local_time;
trace<uint32_t> tr_usrp_time; double tx_freq, rx_freq, freq_offset;
trace<uint32_t> tr_tx_time;
trace<uint32_t> tr_is_eob; trace<uint32_t> tr_local_time;
bool trace_enabled; trace<uint32_t> tr_usrp_time;
uint32_t tti; trace<uint32_t> tr_tx_time;
bool agc_enabled; trace<uint32_t> tr_is_eob;
bool trace_enabled;
bool is_initialized = true;; uint32_t tti;
bool radio_is_streaming; bool agc_enabled;
uint32_t saved_nof_channels; bool continuous_tx;
char saved_args[128]; bool is_initialized;
char saved_devname[128]; bool radio_is_streaming;
}; uint32_t saved_nof_channels;
char saved_args[128];
char saved_devname[128];
};
} }
#endif // SRSLTE_RADIO_H #endif // SRSLTE_RADIO_H

@ -45,7 +45,8 @@ namespace srslte {
class radio_multi : public radio class radio_multi : public radio
{ {
public: public:
radio_multi() {}
~radio_multi() {}
bool init_multi(uint32_t nof_rx_antennas, char *args = NULL, char *devname = NULL); bool init_multi(uint32_t nof_rx_antennas, char *args = NULL, char *devname = NULL);
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);
}; };

@ -57,7 +57,9 @@ public:
void reestablish(); void reestablish();
void reset(); void reset();
void write_sdu(uint32_t lcid, byte_buffer_t *sdu); void write_sdu(uint32_t lcid, byte_buffer_t *sdu);
void write_sdu_mch(uint32_t lcid, byte_buffer_t *sdu);
void add_bearer(uint32_t lcid, srslte_pdcp_config_t cnfg = srslte_pdcp_config_t()); void add_bearer(uint32_t lcid, srslte_pdcp_config_t cnfg = srslte_pdcp_config_t());
void add_bearer_mrb(uint32_t lcid, srslte_pdcp_config_t cnfg = srslte_pdcp_config_t());
void config_security(uint32_t lcid, void config_security(uint32_t lcid,
uint8_t *k_enc, uint8_t *k_enc,
uint8_t *k_int, uint8_t *k_int,
@ -72,9 +74,11 @@ public:
// RLC interface // RLC interface
void write_pdu(uint32_t lcid, byte_buffer_t *sdu); void write_pdu(uint32_t lcid, byte_buffer_t *sdu);
void write_pdu_mch(uint32_t lcid, byte_buffer_t *sdu);
void write_pdu_bcch_bch(byte_buffer_t *sdu); void write_pdu_bcch_bch(byte_buffer_t *sdu);
void write_pdu_bcch_dlsch(byte_buffer_t *sdu); void write_pdu_bcch_dlsch(byte_buffer_t *sdu);
void write_pdu_pcch(byte_buffer_t *sdu); void write_pdu_pcch(byte_buffer_t *sdu);
private: private:
srsue::rlc_interface_pdcp *rlc; srsue::rlc_interface_pdcp *rlc;
@ -83,10 +87,12 @@ private:
log *pdcp_log; log *pdcp_log;
pdcp_entity pdcp_array[SRSLTE_N_RADIO_BEARERS]; pdcp_entity pdcp_array[SRSLTE_N_RADIO_BEARERS];
pdcp_entity pdcp_array_mrb[SRSLTE_N_MCH_LCIDS];
uint32_t lcid; // default LCID that is maintained active by PDCP instance uint32_t lcid; // default LCID that is maintained active by PDCP instance
uint8_t direction; uint8_t direction;
bool valid_lcid(uint32_t lcid); bool valid_lcid(uint32_t lcid);
bool valid_mch_lcid(uint32_t lcid);
}; };
} // namespace srslte } // namespace srslte

@ -32,7 +32,6 @@
#include "srslte/common/common.h" #include "srslte/common/common.h"
#include "srslte/interfaces/ue_interfaces.h" #include "srslte/interfaces/ue_interfaces.h"
#include "srslte/common/security.h" #include "srslte/common/security.h"
#include "srslte/common/msg_queue.h"
#include "srslte/common/threads.h" #include "srslte/common/threads.h"

@ -31,7 +31,6 @@
#include "srslte/common/log.h" #include "srslte/common/log.h"
#include "srslte/common/common.h" #include "srslte/common/common.h"
#include "srslte/interfaces/ue_interfaces.h" #include "srslte/interfaces/ue_interfaces.h"
#include "srslte/common/msg_queue.h"
#include "srslte/upper/rlc_entity.h" #include "srslte/upper/rlc_entity.h"
#include "srslte/upper/rlc_metrics.h" #include "srslte/upper/rlc_metrics.h"
#include "srslte/upper/rlc_common.h" #include "srslte/upper/rlc_common.h"
@ -64,17 +63,21 @@ public:
// PDCP interface // PDCP interface
void write_sdu(uint32_t lcid, byte_buffer_t *sdu); void write_sdu(uint32_t lcid, byte_buffer_t *sdu);
void write_sdu_mch(uint32_t lcid, byte_buffer_t *sdu);
bool rb_is_um(uint32_t lcid); bool rb_is_um(uint32_t lcid);
// MAC interface // MAC interface
uint32_t get_buffer_state(uint32_t lcid); uint32_t get_buffer_state(uint32_t lcid);
uint32_t get_total_buffer_state(uint32_t lcid); uint32_t get_total_buffer_state(uint32_t lcid);
uint32_t get_total_mch_buffer_state(uint32_t lcid);
int read_pdu(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes); int read_pdu(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes);
int read_pdu_mch(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes);
int get_increment_sequence_num();
void write_pdu(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes); void write_pdu(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes);
void write_pdu_bcch_bch(uint8_t *payload, uint32_t nof_bytes); void write_pdu_bcch_bch(uint8_t *payload, uint32_t nof_bytes);
void write_pdu_bcch_dlsch(uint8_t *payload, uint32_t nof_bytes); void write_pdu_bcch_dlsch(uint8_t *payload, uint32_t nof_bytes);
void write_pdu_pcch(uint8_t *payload, uint32_t nof_bytes); void write_pdu_pcch(uint8_t *payload, uint32_t nof_bytes);
void write_pdu_mch(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes);
// RRC interface // RRC interface
void reestablish(); void reestablish();
@ -82,7 +85,8 @@ public:
void empty_queue(); void empty_queue();
void add_bearer(uint32_t lcid); void add_bearer(uint32_t lcid);
void add_bearer(uint32_t lcid, srslte_rlc_config_t cnfg); void add_bearer(uint32_t lcid, srslte_rlc_config_t cnfg);
void add_bearer_mrb(uint32_t lcid);
void add_bearer_mrb_enb(uint32_t lcid);
private: private:
void reset_metrics(); void reset_metrics();
@ -93,13 +97,16 @@ private:
srslte::mac_interface_timers *mac_timers; srslte::mac_interface_timers *mac_timers;
srsue::ue_interface *ue; srsue::ue_interface *ue;
srslte::rlc_entity rlc_array[SRSLTE_N_RADIO_BEARERS]; srslte::rlc_entity rlc_array[SRSLTE_N_RADIO_BEARERS];
srslte::rlc_um rlc_array_mrb[SRSLTE_N_MCH_LCIDS];
uint32_t default_lcid; uint32_t default_lcid;
long ul_tput_bytes[SRSLTE_N_RADIO_BEARERS]; long ul_tput_bytes[SRSLTE_N_RADIO_BEARERS];
long dl_tput_bytes[SRSLTE_N_RADIO_BEARERS]; long dl_tput_bytes[SRSLTE_N_RADIO_BEARERS];
long dl_tput_bytes_mrb[SRSLTE_N_MCH_LCIDS];
struct timeval metrics_time[3]; struct timeval metrics_time[3];
bool valid_lcid(uint32_t lcid); bool valid_lcid(uint32_t lcid);
bool valid_lcid_mrb(uint32_t lcid);
}; };
} // namespace srsue } // namespace srsue

@ -31,7 +31,7 @@
#include "srslte/common/log.h" #include "srslte/common/log.h"
#include "srslte/common/common.h" #include "srslte/common/common.h"
#include "srslte/interfaces/ue_interfaces.h" #include "srslte/interfaces/ue_interfaces.h"
#include "srslte/common/msg_queue.h" #include "srslte/upper/rlc_tx_queue.h"
#include "srslte/common/timeout.h" #include "srslte/common/timeout.h"
#include "srslte/upper/rlc_common.h" #include "srslte/upper/rlc_common.h"
#include <map> #include <map>
@ -104,7 +104,7 @@ private:
srsue::rrc_interface_rlc *rrc; srsue::rrc_interface_rlc *rrc;
// TX SDU buffers // TX SDU buffers
msg_queue tx_sdu_queue; rlc_tx_queue tx_sdu_queue;
byte_buffer_t *tx_sdu; byte_buffer_t *tx_sdu;
// PDU being resegmented // PDU being resegmented
@ -217,8 +217,10 @@ 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);
std::string rlc_am_to_string(rlc_status_pdu_t *status); std::string rlc_am_to_string(rlc_status_pdu_t *status);
bool rlc_am_start_aligned(uint8_t fi); bool rlc_am_start_aligned(const uint8_t fi);
bool rlc_am_end_aligned(uint8_t fi); bool rlc_am_end_aligned(const uint8_t fi);
bool rlc_am_is_unaligned(const uint8_t fi);
bool rlc_am_not_start_aligned(const uint8_t fi);
} // namespace srslte } // namespace srslte

@ -47,12 +47,12 @@ class rlc_entity
{ {
public: public:
rlc_entity(); rlc_entity();
void init(rlc_mode_t mode, void init(rlc_mode_t mode,
log *rlc_entity_log_, log *rlc_entity_log_,
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_); mac_interface_timers *mac_timers_);
void configure(srslte_rlc_config_t cnfg); void configure(srslte_rlc_config_t cnfg);
void reset(); void reset();

@ -73,6 +73,7 @@ typedef struct {
uint32_t rx_window_size; uint32_t rx_window_size;
uint32_t rx_mod; // Rx counter modulus uint32_t rx_mod; // Rx counter modulus
uint32_t tx_mod; // Tx counter modulus uint32_t tx_mod; // Tx counter modulus
bool is_mrb; // Whether this is a multicast bearer
} srslte_rlc_um_config_t; } srslte_rlc_um_config_t;
@ -83,6 +84,9 @@ public:
srslte_rlc_am_config_t am; srslte_rlc_am_config_t am;
srslte_rlc_um_config_t um; srslte_rlc_um_config_t um;
// Default ctor
srslte_rlc_config_t(): rlc_mode(LIBLTE_RRC_RLC_MODE_AM), am(), um() {};
// Constructor based on liblte's RLC config // Constructor based on liblte's RLC config
srslte_rlc_config_t(LIBLTE_RRC_RLC_CONFIG_STRUCT *cnfg) : rlc_mode(cnfg->rlc_mode), am(), um() srslte_rlc_config_t(LIBLTE_RRC_RLC_CONFIG_STRUCT *cnfg) : rlc_mode(cnfg->rlc_mode), am(), um()
{ {
@ -119,6 +123,21 @@ public:
break; break;
} }
} }
// Factory for MCH
static srslte_rlc_config_t mch_config()
{
srslte_rlc_config_t cfg;
cfg.rlc_mode = LIBLTE_RRC_RLC_MODE_UM_UNI_DL;
cfg.um.t_reordering = 0;
cfg.um.rx_sn_field_length = RLC_UMD_SN_SIZE_5_BITS;
cfg.um.rx_window_size = 0;
cfg.um.rx_mod = 1;
cfg.um.tx_sn_field_length = RLC_UMD_SN_SIZE_5_BITS;
cfg.um.tx_mod = 1;
cfg.um.is_mrb = true;
return cfg;
}
}; };
} // namespace srslte } // namespace srslte

@ -31,7 +31,7 @@
#include "srslte/common/log.h" #include "srslte/common/log.h"
#include "srslte/common/common.h" #include "srslte/common/common.h"
#include "srslte/interfaces/ue_interfaces.h" #include "srslte/interfaces/ue_interfaces.h"
#include "srslte/common/msg_queue.h" #include "srslte/upper/rlc_tx_queue.h"
#include "srslte/upper/rlc_common.h" #include "srslte/upper/rlc_common.h"
namespace srslte { namespace srslte {
@ -41,11 +41,11 @@ class rlc_tm
{ {
public: public:
rlc_tm(); rlc_tm();
void init(log *rlc_entity_log_, void init(log *rlc_entity_log_,
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); mac_interface_timers *mac_timers);
void configure(srslte_rlc_config_t cnfg); void configure(srslte_rlc_config_t cnfg);
void reset(); void reset();
void stop(); void stop();
@ -72,7 +72,7 @@ private:
srsue::rrc_interface_rlc *rrc; srsue::rrc_interface_rlc *rrc;
// Thread-safe queues for MAC messages // Thread-safe queues for MAC messages
msg_queue ul_queue; rlc_tx_queue ul_queue;
}; };
} // namespace srsue } // namespace srsue

@ -0,0 +1,118 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsUE library.
*
* srsUE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsUE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
/******************************************************************************
* File: rlc_tx_queue.h
* Description: Queue used in RLC TM/UM/AM TX queues.
* Uses a blocking queue with bounded capacity to block higher layers
* when pushing Uplink traffic
* Reference:
*****************************************************************************/
#ifndef SRSLTE_MSG_QUEUE_H
#define SRSLTE_MSG_QUEUE_H
#include "srslte/common/block_queue.h"
#include "srslte/common/common.h"
#include <pthread.h>
namespace srslte {
class rlc_tx_queue : public block_queue<byte_buffer_t*>::call_mutexed_itf
{
public:
rlc_tx_queue(uint32_t capacity = 128) : queue((int) capacity) {
unread_bytes = 0;
queue.set_mutexed_itf(this);
}
// increase/decrease unread_bytes inside push/pop mutexed operations
void pushing(byte_buffer_t *msg) {
unread_bytes += msg->N_bytes;
}
void popping(byte_buffer_t *msg) {
if (unread_bytes > msg->N_bytes) {
unread_bytes -= msg->N_bytes;
} else {
unread_bytes = 0;
}
}
void write(byte_buffer_t *msg)
{
queue.push(msg);
}
void read(byte_buffer_t **msg)
{
byte_buffer_t *m = queue.wait_pop();
*msg = m;
}
bool try_read(byte_buffer_t **msg)
{
return queue.try_pop(msg);
}
void resize(uint32_t capacity)
{
queue.resize(capacity);
}
uint32_t size()
{
return (uint32_t) queue.size();
}
uint32_t size_bytes()
{
return unread_bytes;
}
uint32_t size_tail_bytes()
{
if (!queue.empty()) {
byte_buffer_t *m = queue.front();
if (m) {
return m->N_bytes;
}
}
return 0;
}
// This is a hack to reset N_bytes counter when queue is corrupted (see line 89)
void reset() {
unread_bytes = 0;
}
private:
bool is_empty() { return queue.empty(); }
block_queue<byte_buffer_t*> queue;
uint32_t unread_bytes;
};
} // namespace srslte
#endif // SRSLTE_MSG_QUEUE_H

@ -31,7 +31,7 @@
#include "srslte/common/log.h" #include "srslte/common/log.h"
#include "srslte/common/common.h" #include "srslte/common/common.h"
#include "srslte/interfaces/ue_interfaces.h" #include "srslte/interfaces/ue_interfaces.h"
#include "srslte/common/msg_queue.h" #include "srslte/upper/rlc_tx_queue.h"
#include "srslte/upper/rlc_common.h" #include "srslte/upper/rlc_common.h"
#include <pthread.h> #include <pthread.h>
#include <map> #include <map>
@ -50,17 +50,18 @@ class rlc_um
{ {
public: public:
rlc_um(); rlc_um();
~rlc_um();
void init(log *rlc_entity_log_, ~rlc_um();
uint32_t lcid_, void init(log *rlc_entity_log_,
srsue::pdcp_interface_rlc *pdcp_, uint32_t lcid_,
srsue::rrc_interface_rlc *rrc_, srsue::pdcp_interface_rlc *pdcp_,
mac_interface_timers *mac_timers_); srsue::rrc_interface_rlc *rrc_,
mac_interface_timers *mac_timers_);
void configure(srslte_rlc_config_t cnfg); void configure(srslte_rlc_config_t cnfg);
void reset(); void reset();
void stop(); void stop();
void empty_queue(); void empty_queue();
bool is_mrb();
rlc_mode_t get_mode(); rlc_mode_t get_mode();
uint32_t get_bearer(); uint32_t get_bearer();
@ -73,7 +74,7 @@ public:
uint32_t get_total_buffer_state(); uint32_t get_total_buffer_state();
int read_pdu(uint8_t *payload, uint32_t nof_bytes); int read_pdu(uint8_t *payload, uint32_t nof_bytes);
void write_pdu(uint8_t *payload, uint32_t nof_bytes); void write_pdu(uint8_t *payload, uint32_t nof_bytes);
int get_increment_sequence_num();
// Timeout callback interface // Timeout callback interface
void timer_expired(uint32_t timeout_id); void timer_expired(uint32_t timeout_id);
@ -86,11 +87,12 @@ 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;
mac_interface_timers *mac_timers; mac_interface_timers *mac_timers;
// TX SDU buffers // TX SDU buffers
msg_queue tx_sdu_queue; rlc_tx_queue tx_sdu_queue;
byte_buffer_t *tx_sdu; byte_buffer_t *tx_sdu;
byte_buffer_t tx_sdu_temp;
// Rx window // Rx window
std::map<uint32_t, rlc_umd_pdu_t> rx_window; std::map<uint32_t, rlc_umd_pdu_t> rx_window;
@ -136,6 +138,8 @@ private:
void reassemble_rx_sdus(); void reassemble_rx_sdus();
bool inside_reordering_window(uint16_t sn); bool inside_reordering_window(uint16_t sn);
void debug_state(); void debug_state();
std::string rb_name();
}; };
/**************************************************************************** /****************************************************************************

@ -1027,6 +1027,7 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_authentication_parameter_rand_ie(uint8 **ie_
Document Reference: 24.301 v10.2.0 Section 9.9.3.4 Document Reference: 24.301 v10.2.0 Section 9.9.3.4
*********************************************************************/ *********************************************************************/
LIBLTE_ERROR_ENUM liblte_mme_pack_authentication_response_parameter_ie(uint8 *res, LIBLTE_ERROR_ENUM liblte_mme_pack_authentication_response_parameter_ie(uint8 *res,
int res_len,
uint8 **ie_ptr) uint8 **ie_ptr)
{ {
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
@ -1035,12 +1036,13 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_authentication_response_parameter_ie(uint8 *r
if(res != NULL && if(res != NULL &&
ie_ptr != NULL) ie_ptr != NULL)
{ {
(*ie_ptr)[0] = 8; (*ie_ptr)[0] = res_len;
for(i=0; i<8; i++) *ie_ptr += 1;
for(i=0; i<res_len; i++)
{ {
(*ie_ptr)[i+1] = res[i]; (*ie_ptr)[i] = res[i];
} }
*ie_ptr += 9; *ie_ptr += res_len;
err = LIBLTE_SUCCESS; err = LIBLTE_SUCCESS;
} }
@ -2225,14 +2227,14 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_network_name_ie(LIBLTE_MME_NETWORK_NAME_STRUCT
uint32 i; uint32 i;
uint32 bit_offset; uint32 bit_offset;
uint32 byte_offset; uint32 byte_offset;
const char *char_str = net_name->name.c_str(); const char *char_str = net_name->name;
if(net_name != NULL && if(net_name != NULL &&
ie_ptr != NULL) ie_ptr != NULL)
{ {
bit_offset = 0; bit_offset = 0;
byte_offset = 2; byte_offset = 2;
for(i=0; i<net_name->name.size(); i++) for(i=0; i<strnlen(char_str, LIBLTE_STRING_LEN); i++)
{ {
if(char_str[i] == 0x0A || if(char_str[i] == 0x0A ||
char_str[i] == 0x0D || char_str[i] == 0x0D ||
@ -2319,6 +2321,7 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_network_name_ie(uint8
uint32 N_bytes; uint32 N_bytes;
uint8 spare_field; uint8 spare_field;
char tmp_char; char tmp_char;
uint32 str_cnt;
if(ie_ptr != NULL && if(ie_ptr != NULL &&
net_name != NULL) net_name != NULL)
@ -2328,8 +2331,9 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_network_name_ie(uint8
N_bytes = (*ie_ptr)[0]; N_bytes = (*ie_ptr)[0];
bit_offset = 0; bit_offset = 0;
byte_offset = 2; byte_offset = 2;
net_name->name = ""; str_cnt = 0;
while(byte_offset < N_bytes)
while(byte_offset < N_bytes && str_cnt < LIBLTE_STRING_LEN)
{ {
switch(bit_offset) switch(bit_offset)
{ {
@ -2389,7 +2393,10 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_network_name_ie(uint8
(tmp_char >= 0x61 && (tmp_char >= 0x61 &&
tmp_char <= 0x7A)) tmp_char <= 0x7A))
{ {
net_name->name += tmp_char; if (str_cnt < LIBLTE_STRING_LEN) {
net_name->name[str_cnt] = tmp_char;
str_cnt++;
}
} }
} }
@ -2412,10 +2419,18 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_network_name_ie(uint8
(tmp_char >= 0x61 && (tmp_char >= 0x61 &&
tmp_char <= 0x7A)) tmp_char <= 0x7A))
{ {
net_name->name += tmp_char; if (str_cnt < LIBLTE_STRING_LEN) {
net_name->name[str_cnt] = tmp_char;
str_cnt++;
}
} }
} }
if (str_cnt < LIBLTE_STRING_LEN) {
net_name->name[str_cnt] = '\0';
str_cnt++;
}
*ie_ptr += byte_offset + 1; *ie_ptr += byte_offset + 1;
err = LIBLTE_SUCCESS; err = LIBLTE_SUCCESS;
@ -3765,12 +3780,12 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_access_point_name_ie(LIBLTE_MME_ACCESS_POINT_N
if(apn != NULL && if(apn != NULL &&
ie_ptr != NULL) ie_ptr != NULL)
{ {
apn_str = apn->apn.c_str(); apn_str = apn->apn;
(*ie_ptr)[0] = apn->apn.length()+1; (*ie_ptr)[0] = strnlen(apn->apn, LIBLTE_STRING_LEN)+1;
len_idx = 0; len_idx = 0;
apn_idx = 0; apn_idx = 0;
label_len = 0; label_len = 0;
while(apn->apn.length() > apn_idx) while(strnlen(apn->apn, LIBLTE_STRING_LEN) > apn_idx)
{ {
(*ie_ptr)[1+apn_idx+1] = (uint8)apn_str[apn_idx]; (*ie_ptr)[1+apn_idx+1] = (uint8)apn_str[apn_idx];
apn_idx++; apn_idx++;
@ -3785,7 +3800,7 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_access_point_name_ie(LIBLTE_MME_ACCESS_POINT_N
} }
} }
(*ie_ptr)[1+len_idx] = label_len; (*ie_ptr)[1+len_idx] = label_len;
*ie_ptr += apn->apn.length() + 2; *ie_ptr += strnlen(apn->apn, LIBLTE_STRING_LEN) + 2;
err = LIBLTE_SUCCESS; err = LIBLTE_SUCCESS;
} }
@ -3799,26 +3814,31 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_access_point_name_ie(uint8
uint32 i; uint32 i;
uint32 ie_idx; uint32 ie_idx;
uint32 label_len; uint32 label_len;
uint32 str_cnt;
if(ie_ptr != NULL && if(ie_ptr != NULL &&
apn != NULL) apn != NULL)
{ {
apn->apn.clear();
ie_idx = 0; ie_idx = 0;
while(ie_idx < (*ie_ptr)[0]) str_cnt = 0;
while(ie_idx < (*ie_ptr)[0] && str_cnt < LIBLTE_STRING_LEN)
{ {
label_len = (*ie_ptr)[1+ie_idx]; label_len = (*ie_ptr)[1+ie_idx];
for(i=0; i<label_len; i++) for(i=0; i<label_len && str_cnt < LIBLTE_STRING_LEN; i++)
{ {
apn->apn += (char)((*ie_ptr)[1+ie_idx+i+1]); apn->apn[str_cnt] = (char)((*ie_ptr)[1+ie_idx+i+1]);
str_cnt++;
} }
ie_idx += label_len + 1; ie_idx += label_len + 1;
if(ie_idx < (*ie_ptr)[0]) if(ie_idx < (*ie_ptr)[0] && str_cnt < LIBLTE_STRING_LEN)
{ {
apn->apn += '.'; apn->apn[str_cnt] = '.';
str_cnt++;
} }
} }
apn->apn += "\0"; if (str_cnt < LIBLTE_STRING_LEN) {
apn->apn[str_cnt] = '\0';
}
*ie_ptr += (*ie_ptr)[0] + 1; *ie_ptr += (*ie_ptr)[0] + 1;
err = LIBLTE_SUCCESS; err = LIBLTE_SUCCESS;
@ -4398,7 +4418,7 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_pdn_address_ie(uint8
pdn_addr->addr[i] = (*ie_ptr)[2+i]; pdn_addr->addr[i] = (*ie_ptr)[2+i];
} }
} }
*ie_ptr += (*ie_ptr)[0]; *ie_ptr += (*ie_ptr)[0] + 1;
err = LIBLTE_SUCCESS; err = LIBLTE_SUCCESS;
} }
@ -6177,7 +6197,7 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_authentication_response_msg(LIBLTE_MME_AUTHENT
msg_ptr++; msg_ptr++;
// Authentication Response Parameter (RES) // Authentication Response Parameter (RES)
liblte_mme_pack_authentication_response_parameter_ie(auth_resp->res, &msg_ptr); liblte_mme_pack_authentication_response_parameter_ie(auth_resp->res, auth_resp->res_len, &msg_ptr);
// Fill in the number of bytes used // Fill in the number of bytes used
msg->N_bytes = msg_ptr - msg->msg; msg->N_bytes = msg_ptr - msg->msg;
@ -9943,7 +9963,7 @@ LIBLTE_ERROR_ENUM srslte_mme_pack_esm_information_request_msg(LIBLTE_MME_ESM_INF
if(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS != sec_hdr_type) if(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS != sec_hdr_type)
{ {
// Protocol Discriminator and Security Header Type // Protocol Discriminator and Security Header Type
*msg_ptr = (sec_hdr_type << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); *msg_ptr = (sec_hdr_type << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT);
msg_ptr++; msg_ptr++;
// MAC will be filled in later // MAC will be filled in later
@ -10022,10 +10042,19 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_esm_information_request_msg(LIBLTE_BYTE_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;
uint8 sec_hdr_type;
if(msg != NULL && if(msg != NULL &&
esm_info_req != NULL) esm_info_req != NULL)
{ {
// Security Header Type
sec_hdr_type = (msg->msg[0] & 0xF0) >> 4;
if(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) {
msg_ptr++;
} else{
msg_ptr += 6;
}
// EPS Bearer ID // EPS Bearer ID
esm_info_req->eps_bearer_id = (*msg_ptr >> 4); esm_info_req->eps_bearer_id = (*msg_ptr >> 4);
msg_ptr++; msg_ptr++;
@ -10053,6 +10082,8 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_esm_information_request_msg(LIBLTE_BYTE_MSG_
Document Reference: 24.301 v10.2.0 Section 8.3.14 Document Reference: 24.301 v10.2.0 Section 8.3.14
*********************************************************************/ *********************************************************************/
LIBLTE_ERROR_ENUM liblte_mme_pack_esm_information_response_msg(LIBLTE_MME_ESM_INFORMATION_RESPONSE_MSG_STRUCT *esm_info_resp, LIBLTE_ERROR_ENUM liblte_mme_pack_esm_information_response_msg(LIBLTE_MME_ESM_INFORMATION_RESPONSE_MSG_STRUCT *esm_info_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;
@ -10061,6 +10092,20 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_esm_information_response_msg(LIBLTE_MME_ESM_IN
if(esm_info_resp != NULL && if(esm_info_resp != NULL &&
msg != 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 EPS Bearer ID // Protocol Discriminator and EPS Bearer ID
*msg_ptr = (esm_info_resp->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); *msg_ptr = (esm_info_resp->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT);
msg_ptr++; msg_ptr++;
@ -10097,6 +10142,8 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_esm_information_response_msg(LIBLTE_MME_ESM_IN
return(err); return(err);
} }
LIBLTE_ERROR_ENUM srslte_mme_unpack_esm_information_response_msg(LIBLTE_BYTE_MSG_STRUCT *msg, LIBLTE_ERROR_ENUM srslte_mme_unpack_esm_information_response_msg(LIBLTE_BYTE_MSG_STRUCT *msg,
LIBLTE_MME_ESM_INFORMATION_RESPONSE_MSG_STRUCT *esm_info_resp) LIBLTE_MME_ESM_INFORMATION_RESPONSE_MSG_STRUCT *esm_info_resp)
{ {
@ -10114,7 +10161,7 @@ LIBLTE_ERROR_ENUM srslte_mme_unpack_esm_information_response_msg(LIBLTE_BYTE_MSG
{ {
msg_ptr++; msg_ptr++;
}else{ }else{
msg_ptr += 7; msg_ptr += 6;
} }
// EPS Bearer ID // EPS Bearer ID
esm_info_resp->eps_bearer_id = (*msg_ptr >> 4); esm_info_resp->eps_bearer_id = (*msg_ptr >> 4);

@ -327,13 +327,218 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_mbsfn_subframe_config_ie(uint8
} }
/********************************************************************* /*********************************************************************
IE Name: PMCH Info List IE Name: TMGI
Description: Specifies configuration of all PMCHs of an MBSFN area Description: Temporary Mobile Group Identity (PLMN + MBMS service ID)
Document Reference: 36.331 v10.0.0 Section 6.3.7 Document Reference: 36.331 v10.0.0 Section 6.3.7
*********************************************************************/ *********************************************************************/
// FIXME LIBLTE_ERROR_ENUM liblte_rrc_pack_tmgi_r9_ie(LIBLTE_RRC_TMGI_R9_STRUCT *tmgi,
uint8 **ie_ptr)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
if(tmgi != NULL &&
ie_ptr != NULL)
{
liblte_value_2_bits(tmgi->plmn_id_explicit?1:0, ie_ptr, 1);
if(tmgi->plmn_id_explicit){
liblte_rrc_pack_plmn_identity_ie(&tmgi->plmn_id_r9, ie_ptr);
}else{
liblte_value_2_bits(tmgi->plmn_index_r9-1, ie_ptr, 3);
}
liblte_value_2_bits(tmgi->serviceid_r9, ie_ptr, 24);
err = LIBLTE_SUCCESS;
}
return(err);
}
LIBLTE_ERROR_ENUM liblte_rrc_unpack_tmgi_r9_ie(uint8 **ie_ptr,
LIBLTE_RRC_TMGI_R9_STRUCT *tmgi)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
if(ie_ptr != NULL &&
tmgi != NULL)
{
tmgi->plmn_id_explicit = liblte_bits_2_value(ie_ptr, 1);
if(tmgi->plmn_id_explicit){
liblte_rrc_unpack_plmn_identity_ie(ie_ptr, &tmgi->plmn_id_r9);
}else{
tmgi->plmn_index_r9 = liblte_bits_2_value(ie_ptr, 3) + 1;
}
tmgi->serviceid_r9 = liblte_bits_2_value(ie_ptr, 24);
err = LIBLTE_SUCCESS;
}
return(err);
}
/*********************************************************************
IE Name: MBMS Session Info
Description: Information about an individual MBMS session
Document Reference: 36.331 v10.0.0 Section 6.3.7
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_rrc_pack_mbms_session_info_r9_ie(LIBLTE_RRC_MBMS_SESSION_INFO_R9_STRUCT *mbms_session_info,
uint8 **ie_ptr)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
if(mbms_session_info != NULL &&
ie_ptr != NULL)
{
// ext
liblte_value_2_bits(0, ie_ptr, 1);
liblte_value_2_bits(mbms_session_info->sessionid_r9_present?1:0, ie_ptr, 1);
liblte_rrc_pack_tmgi_r9_ie(&mbms_session_info->tmgi_r9, ie_ptr);
if(mbms_session_info->sessionid_r9_present){
liblte_value_2_bits(mbms_session_info->sessionid_r9, ie_ptr, 8);
}
liblte_value_2_bits(mbms_session_info->logicalchannelid_r9, ie_ptr, 5);
err = LIBLTE_SUCCESS;
}
return(err);
}
LIBLTE_ERROR_ENUM liblte_rrc_unpack_mbms_session_info_r9_ie(uint8 **ie_ptr,
LIBLTE_RRC_MBMS_SESSION_INFO_R9_STRUCT *mbms_session_info)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
if(ie_ptr != NULL &&
mbms_session_info != NULL)
{
// ext
bool ext = liblte_bits_2_value(ie_ptr, 1);
mbms_session_info->sessionid_r9_present = liblte_bits_2_value(ie_ptr, 1);
liblte_rrc_unpack_tmgi_r9_ie(ie_ptr, &mbms_session_info->tmgi_r9);
if(mbms_session_info->sessionid_r9_present){
mbms_session_info->sessionid_r9 = liblte_bits_2_value(ie_ptr, 8);
}
mbms_session_info->logicalchannelid_r9 = liblte_bits_2_value(ie_ptr, 5);
liblte_rrc_consume_noncrit_extension(ext, __func__, ie_ptr);
err = LIBLTE_SUCCESS;
}
return(err);
}
/*********************************************************************
IE Name: PMCH Config
Description: Contains configuration parameters of the sessions
carried by a PMCH
Document Reference: 36.331 v10.0.0 Section 6.3.7
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_rrc_pack_pmch_config_r9_ie(LIBLTE_RRC_PMCH_CONFIG_R9_STRUCT *pmch_cnfg,
uint8 **ie_ptr)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
if(pmch_cnfg != NULL &&
ie_ptr != NULL)
{
// ext
liblte_value_2_bits(0, ie_ptr, 1);
liblte_value_2_bits(pmch_cnfg->sf_alloc_end_r9, ie_ptr, 11);
liblte_value_2_bits(pmch_cnfg->datamcs_r9, ie_ptr, 5);
liblte_value_2_bits(pmch_cnfg->mch_schedulingperiod_r9, ie_ptr, 3);
err = LIBLTE_SUCCESS;
}
return(err);
}
LIBLTE_ERROR_ENUM liblte_rrc_unpack_pmch_config_r9_ie(uint8 **ie_ptr,
LIBLTE_RRC_PMCH_CONFIG_R9_STRUCT *pmch_cnfg)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
if(ie_ptr != NULL &&
pmch_cnfg != NULL)
{
// ext
bool ext = liblte_bits_2_value(ie_ptr, 1);
pmch_cnfg->sf_alloc_end_r9 = liblte_bits_2_value(ie_ptr, 11);
pmch_cnfg->datamcs_r9 = liblte_bits_2_value(ie_ptr, 5);
pmch_cnfg->mch_schedulingperiod_r9 = (LIBLTE_RRC_MCH_SCHEDULING_PERIOD_R9_ENUM)liblte_bits_2_value(ie_ptr, 3);
liblte_rrc_consume_noncrit_extension(ext, __func__, ie_ptr);
err = LIBLTE_SUCCESS;
}
return(err);
}
/*********************************************************************
IE Name: PMCH Info
Description: Specifies configuration of PMCH of an MBSFN area
Document Reference: 36.331 v10.0.0 Section 6.3.7
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_rrc_pack_pmch_info_r9_ie(LIBLTE_RRC_PMCH_INFO_R9_STRUCT *pmch_info,
uint8 **ie_ptr)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
uint32 i;
if(pmch_info != NULL &&
ie_ptr != NULL)
{
// ext
liblte_value_2_bits(0, ie_ptr, 1);
liblte_rrc_pack_pmch_config_r9_ie(&pmch_info->pmch_config_r9, ie_ptr);
liblte_value_2_bits(pmch_info->mbms_sessioninfolist_r9_size, ie_ptr, 5);
for(i=0; i<pmch_info->mbms_sessioninfolist_r9_size; i++){
liblte_rrc_pack_mbms_session_info_r9_ie(&pmch_info->mbms_sessioninfolist_r9[i], ie_ptr);
}
err = LIBLTE_SUCCESS;
}
return(err);
}
LIBLTE_ERROR_ENUM liblte_rrc_unpack_pmch_info_r9_ie(uint8 **ie_ptr,
LIBLTE_RRC_PMCH_INFO_R9_STRUCT *pmch_info)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
uint32 i;
if(ie_ptr != NULL &&
pmch_info != NULL)
{
// ext
bool ext = liblte_bits_2_value(ie_ptr, 1);
liblte_rrc_unpack_pmch_config_r9_ie(ie_ptr, &pmch_info->pmch_config_r9);
pmch_info->mbms_sessioninfolist_r9_size = liblte_bits_2_value(ie_ptr, 5);
for(i=0; i<pmch_info->mbms_sessioninfolist_r9_size; i++){
liblte_rrc_unpack_mbms_session_info_r9_ie(ie_ptr, &pmch_info->mbms_sessioninfolist_r9[i]);
}
liblte_rrc_consume_noncrit_extension(ext, __func__, ie_ptr);
err = LIBLTE_SUCCESS;
}
return(err);
}
/********************************************************************* /*********************************************************************
IE Name: C-RNTI IE Name: C-RNTI
@ -380,7 +585,7 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_c_rnti_ie(uint8 **ie_ptr,
Document Reference: 36.331 v10.0.0 Section 6.3.6 Document Reference: 36.331 v10.0.0 Section 6.3.6
*********************************************************************/ *********************************************************************/
LIBLTE_ERROR_ENUM liblte_rrc_pack_dedicated_info_cdma2000_ie(LIBLTE_SIMPLE_BYTE_MSG_STRUCT *ded_info_cdma2000, LIBLTE_ERROR_ENUM liblte_rrc_pack_dedicated_info_cdma2000_ie(LIBLTE_BYTE_MSG_STRUCT *ded_info_cdma2000,
uint8 **ie_ptr) uint8 **ie_ptr)
{ {
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
@ -412,7 +617,7 @@ LIBLTE_ERROR_ENUM liblte_rrc_pack_dedicated_info_cdma2000_ie(LIBLTE_SIMPLE_BYTE_
return(err); return(err);
} }
LIBLTE_ERROR_ENUM liblte_rrc_unpack_dedicated_info_cdma2000_ie(uint8 **ie_ptr, LIBLTE_ERROR_ENUM liblte_rrc_unpack_dedicated_info_cdma2000_ie(uint8 **ie_ptr,
LIBLTE_SIMPLE_BYTE_MSG_STRUCT *ded_info_cdma2000) LIBLTE_BYTE_MSG_STRUCT *ded_info_cdma2000)
{ {
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
uint32 i; uint32 i;
@ -452,7 +657,7 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_dedicated_info_cdma2000_ie(uint8
Document Reference: 36.331 v10.0.0 Section 6.3.6 Document Reference: 36.331 v10.0.0 Section 6.3.6
*********************************************************************/ *********************************************************************/
LIBLTE_ERROR_ENUM liblte_rrc_pack_dedicated_info_nas_ie(LIBLTE_SIMPLE_BYTE_MSG_STRUCT *ded_info_nas, LIBLTE_ERROR_ENUM liblte_rrc_pack_dedicated_info_nas_ie(LIBLTE_BYTE_MSG_STRUCT *ded_info_nas,
uint8 **ie_ptr) uint8 **ie_ptr)
{ {
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
@ -484,7 +689,7 @@ LIBLTE_ERROR_ENUM liblte_rrc_pack_dedicated_info_nas_ie(LIBLTE_SIMPLE_BYTE_MSG_S
return(err); return(err);
} }
LIBLTE_ERROR_ENUM liblte_rrc_unpack_dedicated_info_nas_ie(uint8 **ie_ptr, LIBLTE_ERROR_ENUM liblte_rrc_unpack_dedicated_info_nas_ie(uint8 **ie_ptr,
LIBLTE_SIMPLE_BYTE_MSG_STRUCT *ded_info_nas) LIBLTE_BYTE_MSG_STRUCT *ded_info_nas)
{ {
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
uint32 i; uint32 i;
@ -2715,8 +2920,10 @@ LIBLTE_ERROR_ENUM liblte_rrc_pack_report_config_eutra_ie(LIBLTE_RRC_REPORT_CONFI
liblte_value_2_bits(rep_cnfg_eutra->trigger_type, ie_ptr, 1); liblte_value_2_bits(rep_cnfg_eutra->trigger_type, ie_ptr, 1);
if(LIBLTE_RRC_TRIGGER_TYPE_EUTRA_EVENT == rep_cnfg_eutra->trigger_type) if(LIBLTE_RRC_TRIGGER_TYPE_EUTRA_EVENT == rep_cnfg_eutra->trigger_type)
{ {
// Event ID choice extension indicator
liblte_value_2_bits(0, ie_ptr, 1); // Choice with extension - unlikely to be >63 choices
// Event ID // Event ID
// FIXME: Handle extension properly
liblte_value_2_bits(rep_cnfg_eutra->event.event_id, ie_ptr, 3); liblte_value_2_bits(rep_cnfg_eutra->event.event_id, ie_ptr, 3);
if(LIBLTE_RRC_EVENT_ID_EUTRA_A1 == rep_cnfg_eutra->event.event_id) if(LIBLTE_RRC_EVENT_ID_EUTRA_A1 == rep_cnfg_eutra->event.event_id)
{ {
@ -8894,7 +9101,7 @@ LIBLTE_ERROR_ENUM liblte_rrc_pack_sys_info_block_type_2_ie(LIBLTE_RRC_SYS_INFO_B
liblte_value_2_bits(sib2->mbsfn_subfr_cnfg_list_size - 1, ie_ptr, 3); liblte_value_2_bits(sib2->mbsfn_subfr_cnfg_list_size - 1, ie_ptr, 3);
for(i=0; i<sib2->mbsfn_subfr_cnfg_list_size; i++) for(i=0; i<sib2->mbsfn_subfr_cnfg_list_size; i++)
{ {
liblte_rrc_pack_mbsfn_subframe_config_ie(&sib2->mbsfn_subfr_cnfg[i], ie_ptr); liblte_rrc_pack_mbsfn_subframe_config_ie(&sib2->mbsfn_subfr_cnfg_list[i], ie_ptr);
} }
} }
@ -8992,7 +9199,7 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_sys_info_block_type_2_ie(uint8
sib2->mbsfn_subfr_cnfg_list_size = liblte_bits_2_value(ie_ptr, 3) + 1; sib2->mbsfn_subfr_cnfg_list_size = liblte_bits_2_value(ie_ptr, 3) + 1;
for(i=0; i<sib2->mbsfn_subfr_cnfg_list_size; i++) for(i=0; i<sib2->mbsfn_subfr_cnfg_list_size; i++)
{ {
liblte_rrc_unpack_mbsfn_subframe_config_ie(ie_ptr, &sib2->mbsfn_subfr_cnfg[i]); liblte_rrc_unpack_mbsfn_subframe_config_ie(ie_ptr, &sib2->mbsfn_subfr_cnfg_list[i]);
} }
}else{ }else{
sib2->mbsfn_subfr_cnfg_list_size = 0; sib2->mbsfn_subfr_cnfg_list_size = 0;
@ -10286,7 +10493,7 @@ LIBLTE_ERROR_ENUM liblte_rrc_pack_sys_info_block_type_13_ie(LIBLTE_RRC_SYS_INFO_
{ {
liblte_rrc_pack_mbsfn_area_info_ie(&sib13->mbsfn_area_info_list_r9[i], ie_ptr); liblte_rrc_pack_mbsfn_area_info_ie(&sib13->mbsfn_area_info_list_r9[i], ie_ptr);
} }
liblte_rrc_pack_mbsfn_notification_config_ie(&sib13->mbms_notification_config, ie_ptr); liblte_rrc_pack_mbsfn_notification_config_ie(&sib13->mbsfn_notification_config, ie_ptr);
err = LIBLTE_SUCCESS; err = LIBLTE_SUCCESS;
} }
@ -10315,7 +10522,7 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_sys_info_block_type_13_ie(uint8
{ {
liblte_rrc_unpack_mbsfn_area_info_ie(ie_ptr, &sib13->mbsfn_area_info_list_r9[i]); liblte_rrc_unpack_mbsfn_area_info_ie(ie_ptr, &sib13->mbsfn_area_info_list_r9[i]);
} }
liblte_rrc_unpack_mbsfn_notification_config_ie(ie_ptr, &sib13->mbms_notification_config); liblte_rrc_unpack_mbsfn_notification_config_ie(ie_ptr, &sib13->mbsfn_notification_config);
liblte_rrc_consume_noncrit_extension(ext_ind, __func__, ie_ptr); liblte_rrc_consume_noncrit_extension(ext_ind, __func__, ie_ptr);
@ -12999,9 +13206,82 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_measurement_report_msg(LIBLTE_BIT_MSG_STRUCT
Description: Contains the MBMS control information applicable for Description: Contains the MBMS control information applicable for
an MBSFN area an MBSFN area
Document Reference: 36.331 v10.0.0 Section 6.2.2 Document Reference: 36.331 v10.0.0 Section 6.2.2
*********************************************************************/ *********************************************************************/
// FIXME LIBLTE_ERROR_ENUM liblte_rrc_pack_mbsfn_area_configuration_r9_msg(LIBLTE_RRC_MBSFN_AREA_CONFIGURATION_R9_STRUCT *mbsfn_area_cnfg,
LIBLTE_BIT_MSG_STRUCT *msg)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
uint8 *msg_ptr = msg->msg;
uint32 i;
if(mbsfn_area_cnfg != NULL &&
msg != NULL)
{
// Non-critical extension
liblte_value_2_bits(0, &msg_ptr, 1);
// commonsf_allocpatternlist_r9
liblte_value_2_bits(mbsfn_area_cnfg->commonsf_allocpatternlist_r9_size-1, &msg_ptr, 3);
for(i=0; i<mbsfn_area_cnfg->commonsf_allocpatternlist_r9_size; i++){
liblte_rrc_pack_mbsfn_subframe_config_ie(&mbsfn_area_cnfg->commonsf_allocpatternlist_r9[i], &msg_ptr);
}
// commonsf_allocperiod_r9
liblte_value_2_bits(mbsfn_area_cnfg->commonsf_allocperiod_r9, &msg_ptr, 3);
// pmch_infolist_r9
liblte_value_2_bits(mbsfn_area_cnfg->pmch_infolist_r9_size, &msg_ptr, 4);
for(i=0; i<mbsfn_area_cnfg->pmch_infolist_r9_size; i++){
liblte_rrc_pack_pmch_info_r9_ie(&mbsfn_area_cnfg->pmch_infolist_r9[i], &msg_ptr);
}
// Fill in the number of bits used
msg->N_bits = msg_ptr - msg->msg;
err = LIBLTE_SUCCESS;
}
return(err);
}
LIBLTE_ERROR_ENUM liblte_rrc_unpack_mbsfn_area_configuration_r9_msg(LIBLTE_BIT_MSG_STRUCT *msg,
LIBLTE_RRC_MBSFN_AREA_CONFIGURATION_R9_STRUCT *mbsfn_area_cnfg)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
uint8 *msg_ptr = msg->msg;
uint32 i;
bool ext;
if(msg != NULL &&
mbsfn_area_cnfg != NULL)
{
// Non-critical extension
ext = liblte_bits_2_value(&msg_ptr, 1);
liblte_rrc_warning_not_handled(ext, __func__);
// commonsf_allocpatternlist_r9
mbsfn_area_cnfg->commonsf_allocpatternlist_r9_size = liblte_bits_2_value(&msg_ptr, 3) + 1;
for(i=0; i<mbsfn_area_cnfg->commonsf_allocpatternlist_r9_size; i++){
liblte_rrc_unpack_mbsfn_subframe_config_ie(&msg_ptr, &mbsfn_area_cnfg->commonsf_allocpatternlist_r9[i]);
}
// commonsf_allocperiod_r9
mbsfn_area_cnfg->commonsf_allocperiod_r9 = (LIBLTE_RRC_MBSFN_COMMON_SF_ALLOC_PERIOD_R9_ENUM)liblte_bits_2_value(&msg_ptr, 3);
// pmch_infolist_r9
mbsfn_area_cnfg->pmch_infolist_r9_size = liblte_bits_2_value(&msg_ptr, 4);
for(i=0; i<mbsfn_area_cnfg->pmch_infolist_r9_size; i++){
liblte_rrc_unpack_pmch_info_r9_ie(&msg_ptr, &mbsfn_area_cnfg->pmch_infolist_r9[i]);
}
liblte_rrc_consume_noncrit_extension(ext, __func__, &msg_ptr);
err = LIBLTE_SUCCESS;
}
return(err);
}
/********************************************************************* /*********************************************************************
Message Name: Master Information Block Message Name: Master Information Block
@ -13102,7 +13382,7 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_dl_information_transfer_msg(LIBLTE_BIT_MSG_S
liblte_bits_2_value(&msg_ptr, 2); liblte_bits_2_value(&msg_ptr, 2);
// Optional indicator // Optional indicator
liblte_rrc_warning_not_handled(liblte_bits_2_value(&msg_ptr, 1), __func__);; liblte_rrc_warning_not_handled(liblte_bits_2_value(&msg_ptr, 1), __func__);
// Dedicated info type choice // Dedicated info type choice
dl_info_transfer->dedicated_info_type = (LIBLTE_RRC_DL_INFORMATION_TRANSFER_TYPE_ENUM)liblte_bits_2_value(&msg_ptr, 2); dl_info_transfer->dedicated_info_type = (LIBLTE_RRC_DL_INFORMATION_TRANSFER_TYPE_ENUM)liblte_bits_2_value(&msg_ptr, 2);
@ -13371,6 +13651,66 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_bcch_dlsch_msg(LIBLTE_BIT_MSG_STRUCT
return(err); return(err);
} }
/*********************************************************************
Message Name: MCCH Message
Description: Contains the set of RRC messages that may be sent
from the E-UTRAN to the UE on the MCCH logical
channel
Document Reference: 36.331 v10.0.0 Section 6.2.1
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_rrc_pack_mcch_msg(LIBLTE_RRC_MCCH_MSG_STRUCT *mcch_msg,
LIBLTE_BIT_MSG_STRUCT *msg)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
uint8 *msg_ptr = msg->msg;
uint8 ext = false;
if(mcch_msg != NULL &&
msg != NULL)
{
// MCCH choice
liblte_value_2_bits(0, &msg_ptr, 1);
err = liblte_rrc_pack_mbsfn_area_configuration_r9_msg(mcch_msg,
&global_msg);
if(global_msg.N_bits <= (LIBLTE_MAX_MSG_SIZE_BITS - 1))
{
memcpy(msg_ptr, global_msg.msg, global_msg.N_bits);
msg->N_bits = global_msg.N_bits + 1;
}else{
msg->N_bits = 0;
err = LIBLTE_ERROR_INVALID_INPUTS;
}
}
return(err);
}
LIBLTE_ERROR_ENUM liblte_rrc_unpack_mcch_msg(LIBLTE_BIT_MSG_STRUCT *msg,
LIBLTE_RRC_MCCH_MSG_STRUCT *mcch_msg)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
uint8 *msg_ptr = msg->msg;
uint32 N_bits_used;
if(msg != NULL &&
mcch_msg != NULL)
{
// MCCH choice
liblte_rrc_warning_not_handled(liblte_bits_2_value(&msg_ptr, 1), __func__);;
if((msg->N_bits-(msg_ptr-msg->msg)) <= (LIBLTE_MAX_MSG_SIZE_BITS - 1))
{
memcpy(global_msg.msg, msg_ptr, msg->N_bits-(msg_ptr-msg->msg));
err = liblte_rrc_unpack_mbsfn_area_configuration_r9_msg(&global_msg,
mcch_msg);
}
}
return(err);
}
/********************************************************************* /*********************************************************************
Message Name: PCCH Message Message Name: PCCH Message

File diff suppressed because it is too large Load Diff

@ -0,0 +1,62 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsUE library.
*
* srsUE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsUE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include "srslte/common/gen_mch_tables.h"
/******************************************************************************
* Key Generation
*****************************************************************************/
void generate_frame_table(uint8_t *table, uint8_t alloc)
{
table[1] = (alloc >> 5) & 0x01;
table[2] = (alloc >> 4) & 0x01;
table[3] = (alloc >> 3) & 0x01;
table[6] = (alloc >> 2) & 0x01;
table[7] = (alloc >> 1) & 0x01;
table[8] = (alloc >> 0) & 0x01;
}
void generate_mch_table(uint8_t *table, uint32_t sf_alloc, uint8_t num_frames)
{
if(num_frames == 1){
uint8_t alloc = (sf_alloc) & 0x3F;
generate_frame_table(table, alloc);
} else if(num_frames == 4){
for(uint32_t j=0; j<4; j++){
uint8_t alloc = (sf_alloc >> 6*(3-j)) & 0x3F;
generate_frame_table(&table[j*10], alloc);
}
}
}
void generate_mcch_table(uint8_t *table, uint32_t sf_alloc)
{
uint8_t alloc = (sf_alloc) & 0x3F;
generate_frame_table(table, alloc);
}

@ -136,7 +136,7 @@ void log_filter::all_log(srslte::LOG_LEVEL_ENUM level,
} }
void log_filter::console(const char * message, ...) { void log_filter::console(const char * message, ...) {
char *args_msg; 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)
@ -147,7 +147,7 @@ void log_filter::console(const char * message, ...) {
void log_filter::error(const char * message, ...) { void log_filter::error(const char * message, ...) {
if (level >= LOG_LEVEL_ERROR) { if (level >= LOG_LEVEL_ERROR) {
char *args_msg; 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)
@ -158,7 +158,7 @@ void log_filter::error(const char * message, ...) {
} }
void log_filter::warning(const char * message, ...) { void log_filter::warning(const char * message, ...) {
if (level >= LOG_LEVEL_WARNING) { if (level >= LOG_LEVEL_WARNING) {
char *args_msg; 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)
@ -169,7 +169,7 @@ void log_filter::warning(const char * message, ...) {
} }
void log_filter::info(const char * message, ...) { void log_filter::info(const char * message, ...) {
if (level >= LOG_LEVEL_INFO) { if (level >= LOG_LEVEL_INFO) {
char *args_msg; 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)
@ -180,7 +180,7 @@ void log_filter::info(const char * message, ...) {
} }
void log_filter::debug(const char * message, ...) { void log_filter::debug(const char * message, ...) {
if (level >= LOG_LEVEL_DEBUG) { if (level >= LOG_LEVEL_DEBUG) {
char *args_msg; 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)
@ -192,7 +192,7 @@ void log_filter::debug(const char * message, ...) {
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) { if (level >= LOG_LEVEL_ERROR) {
char *args_msg; 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)
@ -203,7 +203,7 @@ void log_filter::error_hex(const uint8_t *hex, int size, const char * message, .
} }
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) { if (level >= LOG_LEVEL_WARNING) {
char *args_msg; 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)
@ -214,7 +214,7 @@ void log_filter::warning_hex(const uint8_t *hex, int size, const char * message,
} }
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) { if (level >= LOG_LEVEL_INFO) {
char *args_msg; 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)
@ -225,7 +225,7 @@ void log_filter::info_hex(const uint8_t *hex, int size, const char * message, ..
} }
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) { if (level >= LOG_LEVEL_DEBUG) {
char *args_msg; 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)

@ -43,8 +43,8 @@ logger_file::logger_file()
logger_file::~logger_file() { logger_file::~logger_file() {
not_done = false; not_done = false;
log(new std::string("Closing log\n"));
if(inited) { if(inited) {
log(new std::string("Closing log\n"));
wait_thread_finish(); wait_thread_finish();
flush(); flush();
if (logfile) { if (logfile) {

@ -94,6 +94,10 @@ void mac_pcap::write_dl_pch(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, u
{ {
pack_and_write(pdu, pdu_len_bytes, 0, crc_ok, tti, SRSLTE_PRNTI, DIRECTION_DOWNLINK, P_RNTI); pack_and_write(pdu, pdu_len_bytes, 0, crc_ok, tti, SRSLTE_PRNTI, DIRECTION_DOWNLINK, P_RNTI);
} }
void mac_pcap::write_dl_mch(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti)
{
pack_and_write(pdu, pdu_len_bytes, 0, crc_ok, tti, SRSLTE_MRNTI, DIRECTION_DOWNLINK, M_RNTI);
}
void mac_pcap::write_dl_sirnti(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti) void mac_pcap::write_dl_sirnti(uint8_t* pdu, uint32_t pdu_len_bytes, bool crc_ok, uint32_t tti)
{ {
pack_and_write(pdu, pdu_len_bytes, 0, crc_ok, tti, SRSLTE_SIRNTI, DIRECTION_DOWNLINK, SI_RNTI); pack_and_write(pdu, pdu_len_bytes, 0, crc_ok, tti, SRSLTE_SIRNTI, DIRECTION_DOWNLINK, SI_RNTI);

@ -40,60 +40,15 @@ static uint32_t btable[64] = {
namespace srslte { namespace srslte {
void sch_pdu::fprint(FILE* stream) void sch_pdu::fprint(FILE* stream)
{ {
fprintf(stream, "MAC SDU for UL/DL-SCH. "); fprintf(stream, "MAC SDU for UL/DL-SCH. ");
pdu::fprint(stream); pdu::fprint(stream);
} }
void sch_subh::fprint(FILE* stream)
{
if (is_sdu()) {
fprintf(stream, "SDU LCHID=%d, SDU nof_bytes=%d\n", lcid, nof_bytes);
} else {
if (parent->is_ul()) {
switch(lcid) {
case CRNTI:
fprintf(stream, "C-RNTI CE\n");
break;
case PHR_REPORT:
fprintf(stream, "PHR\n");
break;
case TRUNC_BSR:
fprintf(stream, "Truncated BSR CE\n");
break;
case SHORT_BSR:
fprintf(stream, "Short BSR CE\n");
break;
case LONG_BSR:
fprintf(stream, "Long BSR CE\n");
break;
case PADDING:
fprintf(stream, "PADDING\n");
}
} else {
switch(lcid) {
case CON_RES_ID:
fprintf(stream, "Contention Resolution ID CE: 0x%lx\n", get_con_res_id());
break;
case TA_CMD:
fprintf(stream, "Time Advance Command CE: %d\n", get_ta_cmd());
break;
case DRX_CMD:
fprintf(stream, "DRX Command CE: Not implemented\n");
break;
case PADDING:
fprintf(stream, "PADDING\n");
}
}
}
}
void sch_pdu::parse_packet(uint8_t *ptr) void sch_pdu::parse_packet(uint8_t *ptr)
{ {
pdu::parse_packet(ptr); pdu::parse_packet(ptr);
// Correct size for last SDU // Correct size for last SDU
@ -103,8 +58,10 @@ void sch_pdu::parse_packet(uint8_t *ptr)
read_len += subheaders[i].size_plus_header(); read_len += subheaders[i].size_plus_header();
} }
if (pdu_len-read_len-1 >= 0) { int n_sub = pdu_len-read_len-1;
subheaders[nof_subheaders-1].set_payload_size(pdu_len-read_len-1);
if (n_sub >= 0) {
subheaders[nof_subheaders-1].set_payload_size(n_sub);
} else { } else {
fprintf(stderr,"Reading MAC PDU: negative payload for last subheader\n"); fprintf(stderr,"Reading MAC PDU: negative payload for last subheader\n");
} }
@ -155,7 +112,8 @@ uint8_t* sch_pdu::write_packet(srslte::log *log_h)
onetwo_padding = rem_len; onetwo_padding = rem_len;
rem_len = 0; rem_len = 0;
} }
/* Determine the header size and CE payload size */ /* Determine the header size and CE payload size */
uint32_t header_sz = 0; uint32_t header_sz = 0;
uint32_t ce_payload_sz = 0; uint32_t ce_payload_sz = 0;
@ -171,12 +129,12 @@ uint8_t* sch_pdu::write_packet(srslte::log *log_h)
header_sz += onetwo_padding; header_sz += onetwo_padding;
} }
if (ce_payload_sz + header_sz >= sdu_offset_start) { if (ce_payload_sz + header_sz >= sdu_offset_start) {
fprintf(stderr, "Writting PDU: header sz + ce_payload_sz >= sdu_offset_start (%d>=%d). pdu_len=%d, total_sdu_len=%d\n", fprintf(stderr, "Writing PDU: header sz + ce_payload_sz >= sdu_offset_start (%d>=%d). pdu_len=%d, total_sdu_len=%d\n",
header_sz + ce_payload_sz, sdu_offset_start, pdu_len, total_sdu_len); header_sz + ce_payload_sz, sdu_offset_start, pdu_len, total_sdu_len);
return NULL; return NULL;
} }
/* Start writting header and CE payload before the start of the SDU payload */ /* Start writing header and CE payload before the start of the SDU payload */
uint8_t *ptr = &buffer_tx[sdu_offset_start-header_sz-ce_payload_sz]; uint8_t *ptr = &buffer_tx[sdu_offset_start-header_sz-ce_payload_sz];
uint8_t *pdu_start_ptr = ptr; uint8_t *pdu_start_ptr = ptr;
@ -211,7 +169,6 @@ uint8_t* sch_pdu::write_packet(srslte::log *log_h)
subheaders[i].write_payload(&ptr); subheaders[i].write_payload(&ptr);
} }
} }
// Set padding to zeros (if any) // Set padding to zeros (if any)
if (rem_len > 0) { if (rem_len > 0) {
bzero(&pdu_start_ptr[pdu_len-rem_len], rem_len*sizeof(uint8_t)); bzero(&pdu_start_ptr[pdu_len-rem_len], rem_len*sizeof(uint8_t));
@ -275,19 +232,22 @@ uint32_t sch_pdu::size_header_sdu(uint32_t nbytes)
return 3; return 3;
} }
} }
bool sch_pdu::has_space_ce(uint32_t nbytes)
bool sch_pdu::has_space_ce(uint32_t nbytes, bool var_len)
{ {
if (rem_len >= nbytes + 1) { uint32_t head_len = var_len ? size_header_sdu(nbytes) : 1;
if (rem_len >= nbytes + head_len) {
return true; return true;
} else { } else {
return false; return false;
} }
} }
bool sch_pdu::update_space_ce(uint32_t nbytes) bool sch_pdu::update_space_ce(uint32_t nbytes, bool var_len)
{ {
uint32_t head_len = var_len ? size_header_sdu(nbytes) : 1;
if (has_space_ce(nbytes)) { if (has_space_ce(nbytes)) {
rem_len -= nbytes + 1; rem_len -= nbytes + head_len;
return true; return true;
} else { } else {
return false; return false;
@ -334,18 +294,22 @@ int sch_pdu::get_sdu_space()
void sch_subh::init() void sch_subh::init()
{ {
lcid = 0; lcid = 0;
nof_bytes = 0; nof_bytes = 0;
payload = NULL; payload = NULL;
nof_mch_sched_ce = 0;
cur_mch_sched_ce = 0;
} }
sch_subh::cetype sch_subh::ce_type() sch_subh::cetype sch_subh::ce_type()
{ {
if (lcid >= PHR_REPORT) { if (lcid >= PHR_REPORT && type == SCH_SUBH_TYPE) {
return (cetype) lcid; return (cetype)lcid;
} else { }
return SDU; if(lcid >= MCH_SCHED_INFO && type == MCH_SUBH_TYPE) {
return (cetype)lcid;
} }
return (cetype)SDU;
} }
void sch_subh::set_payload_size(uint32_t size) { void sch_subh::set_payload_size(uint32_t size) {
@ -353,48 +317,65 @@ void sch_subh::set_payload_size(uint32_t size) {
} }
uint32_t sch_subh::size_plus_header() { uint32_t sch_subh::size_plus_header() {
if (is_sdu()) { if (is_sdu() || is_var_len_ce()) {
return sch_pdu::size_header_sdu(nof_bytes) + nof_bytes; return sch_pdu::size_header_sdu(nof_bytes) + nof_bytes;
} else {
return nof_bytes + 1;
} }
// All others are 1-byte headers
return 1 + nof_bytes;
} }
uint32_t sch_subh::sizeof_ce(uint32_t lcid, bool is_ul) uint32_t sch_subh::sizeof_ce(uint32_t lcid, bool is_ul)
{ {
if (is_ul) { if (type == SCH_SUBH_TYPE) {
switch(lcid) { if (is_ul) {
case PHR_REPORT: switch(lcid) {
return 1; case PHR_REPORT:
case CRNTI: return 1;
return 2; case CRNTI:
case TRUNC_BSR: return 2;
return 1; case TRUNC_BSR:
case SHORT_BSR: return 1;
return 1; case SHORT_BSR:
case LONG_BSR: return 1;
return 3; case LONG_BSR:
case PADDING: return 3;
return 0; case PADDING:
} return 0;
} else { }
switch(lcid) { } else {
case CON_RES_ID: switch(lcid) {
return 6; case CON_RES_ID:
case TA_CMD: return 6;
return 1; case TA_CMD:
case DRX_CMD: return 1;
return 0; case DRX_CMD:
case PADDING: return 0;
return 0; case PADDING:
} return 0;
}
}
}
if (type == MCH_SUBH_TYPE) {
switch (lcid) {
case MCH_SCHED_INFO:
return nof_mch_sched_ce*2;
case PADDING:
return 0;
}
} }
return 0; return 0;
} }
bool sch_subh::is_sdu() bool sch_subh::is_sdu()
{ {
return ce_type() == SDU; return ce_type() == SDU;
} }
bool sch_subh::is_var_len_ce()
{
return (MCH_SCHED_INFO == ce_type()) && (MCH_SUBH_TYPE == type);
}
uint16_t sch_subh::get_c_rnti() uint16_t sch_subh::get_c_rnti()
{ {
if (payload) { if (payload) {
@ -403,6 +384,7 @@ uint16_t sch_subh::get_c_rnti()
return (uint16_t) w_payload_ce[0]<<8 | w_payload_ce[1]; return (uint16_t) w_payload_ce[0]<<8 | w_payload_ce[1];
} }
} }
uint64_t sch_subh::get_con_res_id() uint64_t sch_subh::get_con_res_id()
{ {
if (payload) { if (payload) {
@ -414,6 +396,7 @@ uint64_t sch_subh::get_con_res_id()
return 0; return 0;
} }
} }
float sch_subh::get_phr() float sch_subh::get_phr()
{ {
if (payload) { if (payload) {
@ -451,6 +434,21 @@ int sch_subh::get_bsr(uint32_t buff_size[4])
} }
} }
bool sch_subh::get_next_mch_sched_info(uint8_t *lcid_, uint16_t *mtch_stop)
{
if(payload) {
nof_mch_sched_ce = nof_bytes/2;
if(cur_mch_sched_ce < nof_mch_sched_ce) {
*lcid_ = (payload[cur_mch_sched_ce*2]&0xF8) >> 3;
*mtch_stop = ((uint16_t)(payload[cur_mch_sched_ce*2]&0x07)) << 8;
*mtch_stop += payload[cur_mch_sched_ce*2+1];
cur_mch_sched_ce++;
return true;
}
}
return false;
}
uint8_t sch_subh::get_ta_cmd() uint8_t sch_subh::get_ta_cmd()
{ {
if (payload) { if (payload) {
@ -459,42 +457,49 @@ uint8_t sch_subh::get_ta_cmd()
return 0; return 0;
} }
} }
uint32_t sch_subh::get_sdu_lcid() uint32_t sch_subh::get_sdu_lcid()
{ {
return lcid; return lcid;
} }
int sch_subh::get_payload_size()
uint32_t sch_subh::get_payload_size()
{ {
return nof_bytes; return nof_bytes;
} }
uint32_t sch_subh::get_header_size(bool is_last) { uint32_t sch_subh::get_header_size(bool is_last) {
if (!is_last) { if (!is_last) {
// For all subheaders, size can be 1, 2 or 3 bytes
if (is_sdu()) { if (is_sdu()) {
return sch_pdu::size_header_sdu(get_payload_size()); return sch_pdu::size_header_sdu(nof_bytes);
} else { }
return 1; if (lcid == MCH_SCHED_INFO && type == MCH_SUBH_TYPE) {
return sch_pdu::size_header_sdu(nof_bytes);
} }
return 1; // All others are 1-byte
} else { } else {
// Last subheader (CE or SDU) has always 1 byte header return 1; // Last subheader (CE or SDU) has always 1 byte header
return 1;
} }
} }
uint8_t* sch_subh::get_sdu_ptr() uint8_t* sch_subh::get_sdu_ptr()
{ {
return payload; return payload;
} }
void sch_subh::set_padding(uint32_t padding_len) void sch_subh::set_padding(uint32_t padding_len)
{ {
lcid = PADDING; lcid = PADDING;
nof_bytes = padding_len; nof_bytes = padding_len;
} }
void sch_subh::set_padding() void sch_subh::set_padding()
{ {
set_padding(0); set_padding(0);
} }
bool sch_subh::set_bsr(uint32_t buff_size[4], sch_subh::cetype format) bool sch_subh::set_bsr(uint32_t buff_size[4], sch_subh::cetype format)
{ {
uint32_t nonzero_lcg=0; uint32_t nonzero_lcg=0;
@ -577,6 +582,20 @@ bool sch_subh::set_ta_cmd(uint8_t ta_cmd)
} }
} }
bool sch_subh::set_next_mch_sched_info(uint8_t lcid_, uint16_t mtch_stop)
{
if (((sch_pdu*)parent)->has_space_ce(2, true)) {
w_payload_ce[nof_mch_sched_ce*2] = (lcid_&0x1F) << 3 | (uint8_t) ((mtch_stop&0x0700)>>8);
w_payload_ce[nof_mch_sched_ce*2+1] = (uint8_t) (mtch_stop&0xff);
nof_mch_sched_ce++;
lcid = MCH_SCHED_INFO;
((sch_pdu*)parent)->update_space_ce(2, true);
nof_bytes += 2;
return true;
}
return false;
}
int sch_subh::set_sdu(uint32_t lcid_, uint32_t requested_bytes, read_pdu_interface *sdu_itf) int sch_subh::set_sdu(uint32_t lcid_, uint32_t requested_bytes, read_pdu_interface *sdu_itf)
{ {
if (((sch_pdu*)parent)->has_space_sdu(requested_bytes)) { if (((sch_pdu*)parent)->has_space_sdu(requested_bytes)) {
@ -584,17 +603,22 @@ int sch_subh::set_sdu(uint32_t lcid_, uint32_t requested_bytes, read_pdu_interfa
payload = ((sch_pdu*)parent)->get_current_sdu_ptr(); payload = ((sch_pdu*)parent)->get_current_sdu_ptr();
// Copy data and get final number of bytes written to the MAC PDU // Copy data and get final number of bytes written to the MAC PDU
uint32_t sdu_sz = sdu_itf->read_pdu(lcid, payload, requested_bytes); int sdu_sz = sdu_itf->read_pdu(lcid, payload, requested_bytes);
if (sdu_sz < 0 || sdu_sz > requested_bytes) { if (sdu_sz < 0) {
return -1; return -1;
} }
if (sdu_sz == 0) { if (sdu_sz == 0) {
return 0; return 0;
} }
else {
// Save final number of written bytes
nof_bytes = sdu_sz;
// Save final number of written bytes if(nof_bytes > (int32_t)requested_bytes) {
nof_bytes = sdu_sz; return -1;
}
}
((sch_pdu*)parent)->add_sdu(nof_bytes); ((sch_pdu*)parent)->add_sdu(nof_bytes);
((sch_pdu*)parent)->update_space_sdu(nof_bytes); ((sch_pdu*)parent)->update_space_sdu(nof_bytes);
@ -627,7 +651,7 @@ void sch_subh::write_subheader(uint8_t** ptr, bool is_last)
{ {
*(*ptr) = (uint8_t) (is_last?0:(1<<5)) | ((uint8_t) lcid & 0x1f); *(*ptr) = (uint8_t) (is_last?0:(1<<5)) | ((uint8_t) lcid & 0x1f);
*ptr += 1; *ptr += 1;
if (is_sdu()) { if (is_sdu() || is_var_len_ce()) {
// MAC SDU: R/R/E/LCID/F/L subheader // MAC SDU: R/R/E/LCID/F/L subheader
// 2nd and 3rd octet // 2nd and 3rd octet
if (!is_last) { if (!is_last) {
@ -649,8 +673,8 @@ void sch_subh::write_payload(uint8_t** ptr)
if (is_sdu()) { if (is_sdu()) {
// SDU is written directly during subheader creation // SDU is written directly during subheader creation
} else { } else {
nof_bytes = sizeof_ce(lcid, parent->is_ul()); nof_bytes = sizeof_ce(lcid, parent->is_ul());
memcpy(*ptr, w_payload_ce, nof_bytes*sizeof(uint8_t)); memcpy(*ptr, w_payload_ce, nof_bytes*sizeof(uint8_t));
} }
*ptr += nof_bytes; *ptr += nof_bytes;
} }
@ -661,7 +685,7 @@ bool sch_subh::read_subheader(uint8_t** ptr)
bool e_bit = (bool) (*(*ptr) & 0x20)?true:false; bool e_bit = (bool) (*(*ptr) & 0x20)?true:false;
lcid = (uint8_t) *(*ptr) & 0x1f; lcid = (uint8_t) *(*ptr) & 0x1f;
*ptr += 1; *ptr += 1;
if (is_sdu()) { if (is_sdu() || is_var_len_ce()) {
if (e_bit) { if (e_bit) {
F_bit = (bool) (*(*ptr) & 0x80)?true:false; F_bit = (bool) (*(*ptr) & 0x80)?true:false;
nof_bytes = (uint32_t)*(*ptr) & 0x7f; nof_bytes = (uint32_t)*(*ptr) & 0x7f;
@ -679,12 +703,64 @@ bool sch_subh::read_subheader(uint8_t** ptr)
} }
return e_bit; return e_bit;
} }
void sch_subh::read_payload(uint8_t** ptr) void sch_subh::read_payload(uint8_t** ptr)
{ {
payload = *ptr; payload = *ptr;
*ptr += nof_bytes; *ptr += nof_bytes;
} }
void sch_subh::fprint(FILE* stream)
{
if (is_sdu()) {
fprintf(stream, "SDU LCHID=%d, SDU nof_bytes=%d\n", lcid, nof_bytes);
} else if (type == SCH_SUBH_TYPE) {
if (parent->is_ul()) {
switch(lcid) {
case CRNTI:
fprintf(stream, "C-RNTI CE\n");
break;
case PHR_REPORT:
fprintf(stream, "PHR\n");
break;
case TRUNC_BSR:
fprintf(stream, "Truncated BSR CE\n");
break;
case SHORT_BSR:
fprintf(stream, "Short BSR CE\n");
break;
case LONG_BSR:
fprintf(stream, "Long BSR CE\n");
break;
case PADDING:
fprintf(stream, "PADDING\n");
}
} else {
switch(lcid) {
case CON_RES_ID:
fprintf(stream, "Contention Resolution ID CE: 0x%lx\n", get_con_res_id());
break;
case TA_CMD:
fprintf(stream, "Time Advance Command CE: %d\n", get_ta_cmd());
break;
case DRX_CMD:
fprintf(stream, "DRX Command CE: Not implemented\n");
break;
case PADDING:
fprintf(stream, "PADDING\n");
}
}
} else if (type == MCH_SUBH_TYPE) {
switch(lcid) {
case MCH_SCHED_INFO:
fprintf(stream, "MCH Scheduling Info CE\n");
break;
case PADDING:
fprintf(stream, "PADDING\n");
}
}
}
uint8_t sch_subh::buff_size_table(uint32_t buffer_size) { uint8_t sch_subh::buff_size_table(uint32_t buffer_size) {
if (buffer_size == 0) { if (buffer_size == 0) {
return 0; return 0;
@ -712,12 +788,6 @@ uint8_t sch_subh::phr_report_table(float phr_value)
return (uint8_t) floor(phr_value+23); return (uint8_t) floor(phr_value+23);
} }
void rar_pdu::fprint(FILE* stream) void rar_pdu::fprint(FILE* stream)
{ {
fprintf(stream, "MAC PDU for RAR. "); fprintf(stream, "MAC PDU for RAR. ");
@ -727,26 +797,22 @@ void rar_pdu::fprint(FILE* stream)
pdu::fprint(stream); pdu::fprint(stream);
} }
void rar_subh::fprint(FILE* stream)
{
fprintf(stream, "RAPID: %d, Temp C-RNTI: %d, TA: %d, UL Grant: ", preamble, temp_rnti, ta);
srslte_vec_fprint_hex(stream, grant, 20);
}
rar_pdu::rar_pdu(uint32_t max_rars_) : pdu(max_rars_) rar_pdu::rar_pdu(uint32_t max_rars_) : pdu(max_rars_)
{ {
backoff_indicator = 0; backoff_indicator = 0;
has_backoff_indicator = false; has_backoff_indicator = false;
} }
uint8_t rar_pdu::get_backoff() uint8_t rar_pdu::get_backoff()
{ {
return backoff_indicator; return backoff_indicator;
} }
bool rar_pdu::has_backoff() bool rar_pdu::has_backoff()
{ {
return has_backoff_indicator; return has_backoff_indicator;
} }
void rar_pdu::set_backoff(uint8_t bi) void rar_pdu::set_backoff(uint8_t bi)
{ {
has_backoff_indicator = true; has_backoff_indicator = true;
@ -779,7 +845,11 @@ bool rar_pdu::write_packet(uint8_t* ptr)
return true; return true;
} }
void rar_subh::fprint(FILE* stream)
{
fprintf(stream, "RAPID: %d, Temp C-RNTI: %d, TA: %d, UL Grant: ", preamble, temp_rnti, ta);
srslte_vec_fprint_hex(stream, grant, 20);
}
void rar_subh::init() void rar_subh::init()
{ {
@ -787,38 +857,47 @@ void rar_subh::init()
ta = 0; ta = 0;
temp_rnti = 0; temp_rnti = 0;
} }
uint32_t rar_subh::get_rapid() uint32_t rar_subh::get_rapid()
{ {
return preamble; return preamble;
} }
void rar_subh::get_sched_grant(uint8_t grant_[RAR_GRANT_LEN]) void rar_subh::get_sched_grant(uint8_t grant_[RAR_GRANT_LEN])
{ {
memcpy(grant_, grant, sizeof(uint8_t)*RAR_GRANT_LEN); memcpy(grant_, grant, sizeof(uint8_t)*RAR_GRANT_LEN);
} }
uint32_t rar_subh::get_ta_cmd() uint32_t rar_subh::get_ta_cmd()
{ {
return ta; return ta;
} }
uint16_t rar_subh::get_temp_crnti() uint16_t rar_subh::get_temp_crnti()
{ {
return temp_rnti; return temp_rnti;
} }
void rar_subh::set_rapid(uint32_t rapid) void rar_subh::set_rapid(uint32_t rapid)
{ {
preamble = rapid; preamble = rapid;
} }
void rar_subh::set_sched_grant(uint8_t grant_[RAR_GRANT_LEN]) void rar_subh::set_sched_grant(uint8_t grant_[RAR_GRANT_LEN])
{ {
memcpy(grant, grant_, sizeof(uint8_t)*RAR_GRANT_LEN); memcpy(grant, grant_, sizeof(uint8_t)*RAR_GRANT_LEN);
} }
void rar_subh::set_ta_cmd(uint32_t ta_) void rar_subh::set_ta_cmd(uint32_t ta_)
{ {
ta = ta_; ta = ta_;
} }
void rar_subh::set_temp_crnti(uint16_t temp_rnti_) void rar_subh::set_temp_crnti(uint16_t temp_rnti_)
{ {
temp_rnti = temp_rnti_; temp_rnti = temp_rnti_;
} }
// Section 6.2.2 // Section 6.2.2
void rar_subh::write_subheader(uint8_t** ptr, bool is_last) void rar_subh::write_subheader(uint8_t** ptr, bool is_last)
{ {
@ -866,150 +945,3 @@ bool rar_subh::read_subheader(uint8_t** ptr)
} }
} }
//int main()
//{
// /* Test 1st message: CCCH + Short BSR + PHR */
// uint8_t buffer[10240];
// uint8_t ccch_payload[6] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x60};
// uint32_t bsr_st[4] = {1, 2, 3, 4};
// srsue::sch_pdu pdu(10);
// uint8_t *ptr;
// printf("------- CCCH + Short BSR + PHR no padding ----------\n");
// bzero(buffer, 10240);
// pdu.init_tx(buffer, 11, true);
// printf("Available space: %d\n", pdu.rem_size());
// pdu.new_subh();
// pdu.get()->set_sdu(0,6,ccch_payload);
// pdu.new_subh();
// pdu.get()->set_phr(10);
// pdu.new_subh();
// pdu.get()->set_bsr(bsr_st, srsue::sch_subh::SHORT_BSR);
// printf("Remaining space: %d\n", pdu.rem_size());
// ptr = pdu.write_packet();
// srslte_vec_fprint_byte(stdout, ptr, pdu.get_pdu_len());
// printf("\n");
// /* Test single SDU: SDU 15 + 1 byte header */
// printf("------- Single SDU no padding ----------\n");
// uint8_t dlsch_payload[15] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
// bzero(buffer, 10240);
// pdu.init_tx(buffer, 16, true);
// printf("Available space: %d\n", pdu.rem_size());
// pdu.new_subh();
// pdu.get()->set_sdu(1, 15, dlsch_payload);
// printf("Remaining space: %d\n", pdu.rem_size());
// ptr = pdu.write_packet();
// srslte_vec_fprint_byte(stdout, ptr, pdu.get_pdu_len());
// printf("\n");
// /* Test multiple SDU + multiword padding: SDU 8 + SDU 2 byte*/
// printf("------- Multiple SDU + multiword padding ----------\n");
// uint8_t dlsch_payload1[8] = {1,2,3,4,5,6,7,8};
// uint8_t dlsch_payload2[2] = {0xA, 0xB};
// bzero(buffer, 10240);
// pdu.init_tx(buffer, 18, true);
// printf("Available space: %d\n", pdu.rem_size());
// pdu.new_subh();
// pdu.get()->set_sdu(2, 8, dlsch_payload1);
// pdu.new_subh();
// pdu.get()->set_sdu(3, 2, dlsch_payload2);
// printf("Remaining space: %d\n", pdu.rem_size());
// ptr = pdu.write_packet();
// srslte_vec_fprint_byte(stdout, ptr, pdu.get_pdu_len());
// printf("\n");
// printf("------- Multiple SDU + 2word padding ----------\n");
// bzero(buffer, 10240);
// pdu.init_tx(buffer, 15, true);
// printf("Available space: %d\n", pdu.rem_size());
// pdu.new_subh();
// pdu.get()->set_sdu(2, 8, dlsch_payload1);
// pdu.new_subh();
// pdu.get()->set_sdu(3, 2, dlsch_payload2);
// printf("Remaining space: %d\n", pdu.rem_size());
// ptr = pdu.write_packet();
// srslte_vec_fprint_byte(stdout, ptr, pdu.get_pdu_len());
// printf("\n");
// printf("------- Multiple SDU + 1word padding ----------\n");
// bzero(buffer, 10240);
// pdu.init_tx(buffer, 14, true);
// printf("Available space: %d\n", pdu.rem_size());
// pdu.new_subh();
// pdu.get()->set_sdu(2, 8, dlsch_payload1);
// pdu.new_subh();
// pdu.get()->set_sdu(3, 2, dlsch_payload2);
// printf("Remaining space: %d\n", pdu.rem_size());
// ptr = pdu.write_packet();
// srslte_vec_fprint_byte(stdout, ptr, pdu.get_pdu_len());
// printf("\n");
// printf("------- Multiple SDU + 0word padding ----------\n");
// bzero(buffer, 10240);
// pdu.init_tx(buffer, 13, true);
// printf("Available space: %d\n", pdu.rem_size());
// pdu.new_subh();
// pdu.get()->set_sdu(2, 8, dlsch_payload1);
// pdu.new_subh();
// pdu.get()->set_sdu(3, 2, dlsch_payload2);
// printf("Remaining space: %d\n", pdu.rem_size());
// ptr = pdu.write_packet();
// srslte_vec_fprint_byte(stdout, ptr, pdu.get_pdu_len());
// printf("\n");
// printf("------- Multiple SDU + no space ----------\n");
// bzero(buffer, 10240);
// pdu.init_tx(buffer, 12, true);
// printf("Available space: %d\n", pdu.rem_size());
// pdu.new_subh();
// pdu.get()->set_sdu(2, 8, dlsch_payload1);
// pdu.new_subh();
// if (pdu.get()->set_sdu(3, 2, dlsch_payload2) < 0) {
// pdu.del_subh();
// }
// printf("Remaining space: %d\n", pdu.rem_size());
// ptr = pdu.write_packet();
// srslte_vec_fprint_byte(stdout, ptr, pdu.get_pdu_len());
// printf("\n");
// /* CE only */
// printf("------- CE only ----------\n");
// bzero(buffer, 10240);
// pdu.init_tx(buffer, 125, true);
// printf("Available space: %d\n", pdu.rem_size());
// pdu.new_subh();
// pdu.get()->set_phr(15);
// pdu.new_subh();
// pdu.get()->set_bsr(bsr_st, srsue::sch_subh::SHORT_BSR);
// printf("Remaining space: %d\n", pdu.rem_size());
// ptr = pdu.write_packet();
// srslte_vec_fprint_byte(stdout, ptr, pdu.get_pdu_len());
// printf("\n");
// /* Another test */
// printf("------- Another test ----------\n");
// uint8_t dlsch_payload3[602];
// bzero(buffer, 10240);
// pdu.init_tx(buffer, 75, true);
// printf("Available space: %d\n", pdu.rem_size());
// pdu.new_subh();
// pdu.get()->set_bsr(bsr_st, srsue::sch_subh::SHORT_BSR);
// pdu.new_subh();
// pdu.get()->set_sdu(3, 2, dlsch_payload3);
// pdu.new_subh();
// pdu.get()->set_sdu(3, 66, dlsch_payload3);
// pdu.new_subh();
// printf("Remaining space: %d\n", pdu.rem_size());
// ptr = pdu.write_packet();
// //srslte_vec_fprint_byte(stdout, ptr, pdu.get_pdu_len());
// printf("\n");
// return 0;
//}

@ -48,7 +48,7 @@ uint8_t* pdu_queue::request(uint32_t len)
fprintf(stderr, "Error request buffer of invalid size %d. Max bytes %d\n", len, MAX_PDU_LEN); fprintf(stderr, "Error request buffer of invalid size %d. Max bytes %d\n", len, MAX_PDU_LEN);
return NULL; return NULL;
} }
pdu_t *pdu = pool.allocate(); pdu_t *pdu = pool.allocate("pdu_queue::request");
if (!pdu) { if (!pdu) {
if (log_h) { if (log_h) {
log_h->error("Not enough buffers for MAC PDU\n"); log_h->error("Not enough buffers for MAC PDU\n");
@ -74,12 +74,13 @@ void pdu_queue::deallocate(uint8_t* pdu)
* This function enqueues the packet and returns quicly because ACK * This function enqueues the packet and returns quicly because ACK
* deadline is important here. * deadline is important here.
*/ */
void pdu_queue::push(uint8_t *ptr, uint32_t len, uint32_t tstamp) void pdu_queue::push(uint8_t *ptr, uint32_t len, channel_t channel, uint32_t tstamp)
{ {
if (ptr) { if (ptr) {
pdu_t *pdu = (pdu_t*) ptr; pdu_t *pdu = (pdu_t*) ptr;
pdu->len = len; pdu->len = len;
pdu->tstamp = tstamp; pdu->tstamp = tstamp;
pdu->channel = channel;
pdu_q.push(pdu); pdu_q.push(pdu);
} else { } else {
log_h->warning("Error pushing pdu: ptr is empty\n"); log_h->warning("Error pushing pdu: ptr is empty\n");
@ -88,15 +89,12 @@ void pdu_queue::push(uint8_t *ptr, uint32_t len, uint32_t tstamp)
bool pdu_queue::process_pdus() bool pdu_queue::process_pdus()
{ {
bool have_data = false; bool have_data = false;
uint32_t cnt = 0; uint32_t cnt = 0;
pdu_t *pdu; pdu_t *pdu;
while(pdu_q.try_pop(&pdu)) { while(pdu_q.try_pop(&pdu)) {
if (callback) { if (callback) {
callback->process_pdu(pdu->ptr, pdu->len, pdu->tstamp); callback->process_pdu(pdu->ptr, pdu->len, pdu->channel, pdu->tstamp);
}
if (!pool.deallocate(pdu)) {
log_h->warning("Error deallocating from buffer pool in process_pdus(): buffer not created in this pool.\n");
} }
cnt++; cnt++;
have_data = true; have_data = true;

@ -0,0 +1,90 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsUE library.
*
* srsUE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsUE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <stdint.h>
#include "srslte/srslte.h"
#include "srslte/common/pcap.h"
#include "srslte/common/rlc_pcap.h"
namespace srslte {
void rlc_pcap::enable(bool en)
{
enable_write = true;
}
void rlc_pcap::open(const char* filename, uint32_t ue_id)
{
fprintf(stdout, "Opening RLC PCAP with DLT=%d\n", RLC_LTE_DLT);
pcap_file = LTE_PCAP_Open(RLC_LTE_DLT, filename);
this->ue_id = ue_id;
enable_write = true;
}
void rlc_pcap::close()
{
fprintf(stdout, "Saving RLC PCAP file\n");
LTE_PCAP_Close(pcap_file);
}
void rlc_pcap::set_ue_id(uint16_t ue_id) {
this->ue_id = ue_id;
}
void rlc_pcap::pack_and_write(uint8_t* pdu, uint32_t pdu_len_bytes, uint8_t mode, uint8_t direction, uint8_t priority, uint8_t seqnumberlength, uint16_t ueid, uint16_t channel_type, uint16_t channel_id)
{
if (enable_write) {
RLC_Context_Info_t context;
context.rlcMode = mode;
context.direction = direction;
context.priority = priority;
context.sequenceNumberLength = seqnumberlength;
context.ueid = ueid;
context.channelType = channel_type;
context.channelId = channel_id;
context.pduLength = pdu_len_bytes;
if (pdu) {
LTE_PCAP_RLC_WritePDU(pcap_file, &context, pdu, pdu_len_bytes);
}
}
}
void rlc_pcap::write_dl_am_ccch(uint8_t* pdu, uint32_t pdu_len_bytes)
{
uint8_t priority = 0;
uint8_t seqnumberlength = 0; // normal length of 10bit
uint8_t channel_id = 0;
pack_and_write(pdu, pdu_len_bytes, RLC_AM_MODE, DIRECTION_DOWNLINK, priority, seqnumberlength, ue_id, CHANNEL_TYPE_CCCH, channel_id);
}
void rlc_pcap::write_ul_am_ccch(uint8_t* pdu, uint32_t pdu_len_bytes)
{
uint8_t priority = 0;
uint8_t seqnumberlength = 0; // normal length of 10bit
uint8_t channel_id = 0;
pack_and_write(pdu, pdu_len_bytes, RLC_AM_MODE, DIRECTION_UPLINK, priority, seqnumberlength, ue_id, CHANNEL_TYPE_CCCH, channel_id);
}
}

@ -29,6 +29,13 @@
#include "srslte/common/liblte_security.h" #include "srslte/common/liblte_security.h"
#include "srslte/common/snow_3g.h" #include "srslte/common/snow_3g.h"
#ifdef HAVE_MBEDTLS
#include "mbedtls/md5.h"
#endif
#ifdef HAVE_POLARSSL
#include "polarssl/md5.h"
#endif
namespace srslte { namespace srslte {
/****************************************************************************** /******************************************************************************
@ -126,7 +133,7 @@ uint8_t security_generate_k_up( uint8_t *k_enb,
uint8_t security_128_eia1( uint8_t *key, uint8_t security_128_eia1( uint8_t *key,
uint32_t count, uint32_t count,
uint8_t bearer, uint32_t bearer,
uint8_t direction, uint8_t direction,
uint8_t *msg, uint8_t *msg,
uint32_t msg_len, uint32_t msg_len,
@ -151,7 +158,7 @@ uint8_t security_128_eia1( uint8_t *key,
uint8_t security_128_eia2( uint8_t *key, uint8_t security_128_eia2( uint8_t *key,
uint32_t count, uint32_t count,
uint8_t bearer, uint32_t bearer,
uint8_t direction, uint8_t direction,
uint8_t *msg, uint8_t *msg,
uint32_t msg_len, uint32_t msg_len,
@ -166,6 +173,19 @@ uint8_t security_128_eia2( uint8_t *key,
mac); mac);
} }
uint8_t security_md5(const uint8_t *input, size_t len, uint8_t *output)
{
memset(output, 0x00, 16);
#ifdef HAVE_MBEDTLS
mbedtls_md5(input, len, output);
#endif // HAVE_MBEDTLS
#ifdef HAVE_POLARSSL
md5(input, len, output);
#endif
return SRSLTE_SUCCESS;
}
/****************************************************************************** /******************************************************************************
* Encryption / Decryption * Encryption / Decryption
*****************************************************************************/ *****************************************************************************/

@ -81,7 +81,6 @@ thread_pool::thread_pool(uint32_t max_workers_) :
status(max_workers_), status(max_workers_),
cvar(max_workers_), cvar(max_workers_),
mutex(max_workers_) mutex(max_workers_)
{ {
max_workers = max_workers_; max_workers = max_workers_;
for (uint32_t i=0;i<max_workers;i++) { for (uint32_t i=0;i<max_workers;i++) {

@ -45,6 +45,8 @@ int srslte_agc_init_acc(srslte_agc_t *q, srslte_agc_mode_t mode, uint32_t nof_fr
bzero(q, sizeof(srslte_agc_t)); bzero(q, sizeof(srslte_agc_t));
q->mode = mode; q->mode = mode;
q->nof_frames = nof_frames; q->nof_frames = nof_frames;
q->max_gain = 90.0;
q->min_gain = 0.0;
if (nof_frames > 0) { if (nof_frames > 0) {
q->y_tmp = srslte_vec_malloc(sizeof(float) * nof_frames); q->y_tmp = srslte_vec_malloc(sizeof(float) * nof_frames);
if (!q->y_tmp) { if (!q->y_tmp) {
@ -86,6 +88,13 @@ void srslte_agc_reset(srslte_agc_t *q) {
} }
} }
void srslte_agc_set_gain_range(srslte_agc_t *q, double min_gain, double max_gain) {
if (q) {
q->min_gain = min_gain;
q->max_gain = max_gain;
}
}
void srslte_agc_set_bandwidth(srslte_agc_t *q, float bandwidth) { void srslte_agc_set_bandwidth(srslte_agc_t *q, float bandwidth) {
q->bandwidth = bandwidth; q->bandwidth = bandwidth;
} }
@ -116,19 +125,23 @@ void srslte_agc_lock(srslte_agc_t *q, bool enable) {
void srslte_agc_process(srslte_agc_t *q, cf_t *signal, uint32_t len) { void srslte_agc_process(srslte_agc_t *q, cf_t *signal, uint32_t len) {
if (!q->lock) { if (!q->lock) {
float gain_db = 10*log10(q->gain); double gain_db = 10.0 * log10(q->gain);
float gain_uhd_db = 50.0; double gain_uhd_db = 50.0;
//float gain_uhd = 1.0;
float y = 0; float y = 0;
// Apply current gain to input signal // Apply current gain to input signal
if (!q->uhd_handler) { if (!q->uhd_handler) {
srslte_vec_sc_prod_cfc(signal, q->gain, signal, len); srslte_vec_sc_prod_cfc(signal, q->gain, signal, len);
} else { } else {
if (gain_db < 0) { if (gain_db < q->min_gain) {
gain_db = 5.0; gain_db = q->min_gain + 5.0;
} INFO("Warning: Rx signal strength is too high. Forcing minimum Rx gain %.2fdB\n", gain_db);
if (isinf(gain_db) || isnan(gain_db)) { } else if (gain_db > q->max_gain) {
gain_db = 40.0; gain_db = q->max_gain;
INFO("Warning: Rx signal strength is too weak. Forcing maximum Rx gain %.2fdB\n", gain_db);
} else if (isinf(gain_db) || isnan(gain_db)) {
gain_db = (q->min_gain + q->max_gain) / 2.0;
INFO("Warning: AGC went to an unknown state. Setting Rx gain to %.2fdB\n", gain_db);
} else { } else {
gain_uhd_db = q->set_gain_callback(q->uhd_handler, gain_db); gain_uhd_db = q->set_gain_callback(q->uhd_handler, gain_db);
q->gain = pow(10, gain_uhd_db/10); q->gain = pow(10, gain_uhd_db/10);

@ -124,7 +124,7 @@ int srslte_chest_dl_init(srslte_chest_dl_t *q, uint32_t max_prb)
perror("malloc"); perror("malloc");
goto clean_exit; goto clean_exit;
} }
q->pilot_recv_signal = srslte_vec_malloc(sizeof(cf_t) * pilot_vec_size); q->pilot_recv_signal = srslte_vec_malloc(sizeof(cf_t) * pilot_vec_size);
if (!q->pilot_recv_signal) { if (!q->pilot_recv_signal) {
perror("malloc"); perror("malloc");
@ -154,7 +154,8 @@ int srslte_chest_dl_init(srslte_chest_dl_t *q, uint32_t max_prb)
q->noise_alg = SRSLTE_NOISE_ALG_REFS; q->noise_alg = SRSLTE_NOISE_ALG_REFS;
q->rsrp_neighbour = false; q->rsrp_neighbour = false;
q->average_subframe = false;
q->smooth_filter_auto = false;
q->smooth_filter_len = 3; q->smooth_filter_len = 3;
srslte_chest_dl_set_smooth_filter3_coeff(q, 0.1); srslte_chest_dl_set_smooth_filter3_coeff(q, 0.1);
@ -211,9 +212,12 @@ int srslte_chest_dl_set_mbsfn_area_id(srslte_chest_dl_t *q, uint16_t mbsfn_area_
if (mbsfn_area_id < SRSLTE_MAX_MBSFN_AREA_IDS) { if (mbsfn_area_id < SRSLTE_MAX_MBSFN_AREA_IDS) {
if(!q->mbsfn_refs[mbsfn_area_id]) { if(!q->mbsfn_refs[mbsfn_area_id]) {
q->mbsfn_refs[mbsfn_area_id] = calloc(1, sizeof(srslte_refsignal_t)); q->mbsfn_refs[mbsfn_area_id] = calloc(1, sizeof(srslte_refsignal_t));
if(srslte_refsignal_mbsfn_init(q->mbsfn_refs[mbsfn_area_id], q->cell.nof_prb)) {
return SRSLTE_ERROR;
}
} }
if(q->mbsfn_refs[mbsfn_area_id]) { if(q->mbsfn_refs[mbsfn_area_id]) {
if(srslte_refsignal_mbsfn_init(q->mbsfn_refs[mbsfn_area_id], q->cell, mbsfn_area_id)) { if(srslte_refsignal_mbsfn_set_cell(q->mbsfn_refs[mbsfn_area_id], q->cell, mbsfn_area_id)) {
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
} }
@ -263,48 +267,72 @@ int srslte_chest_dl_set_cell(srslte_chest_dl_t *q, srslte_cell_t cell)
/* Uses the difference between the averaged and non-averaged pilot estimates */ /* Uses the difference between the averaged and non-averaged pilot estimates */
static float estimate_noise_pilots(srslte_chest_dl_t *q, uint32_t port_id, srslte_sf_t ch_mode) static float estimate_noise_pilots(srslte_chest_dl_t *q, uint32_t port_id, srslte_sf_t ch_mode)
{ {
int nref=SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id); const float weight = 1.0f;
float sum_power = 0.0f;
uint32_t count = 0;
uint32_t npilots = (ch_mode == SRSLTE_SF_MBSFN)?SRSLTE_REFSIGNAL_NUM_SF_MBSFN(q->cell.nof_prb, port_id):SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id);
uint32_t nsymbols = (ch_mode == SRSLTE_SF_MBSFN) ? srslte_refsignal_mbsfn_nof_symbols() : srslte_refsignal_cs_nof_symbols(port_id);
uint32_t nref = npilots / nsymbols;
uint32_t fidx = (ch_mode == SRSLTE_SF_MBSFN)?srslte_refsignal_mbsfn_fidx(1):srslte_refsignal_cs_fidx(q->cell, 0, port_id, 0);
if (q->average_subframe) { cf_t *input2d[nsymbols + 2];
if (ch_mode == SRSLTE_SF_MBSFN) { cf_t *tmp_noise = q->tmp_noise;
nref /= 4;
} else { for (int i = 0; i < nsymbols; i++) {
nref /= 2; input2d[i + 1] = &q->pilot_estimates[i * nref];
}
} }
/* Substract noisy pilot estimates */ input2d[0] = &q->tmp_noise[nref];
srslte_vec_sub_ccc(q->pilot_estimates_average, q->pilot_estimates, q->tmp_noise, nref); if (nsymbols > 3) {
srslte_vec_sc_prod_cfc(input2d[2], 2.0f, input2d[0], nref);
#ifdef FREQ_SEL_SNR srslte_vec_sub_ccc(input2d[0], input2d[4], input2d[0], nref);
/* Compute frequency-selective SNR */ } else {
srslte_vec_abs_square_cf(q->tmp_noise, q->snr_vector, nref); srslte_vec_sc_prod_cfc(input2d[2], 1.0f, input2d[0], nref);
srslte_vec_abs_square_cf(q->pilot_estimates, q->pilot_power, nref); }
srslte_vec_div_fff(q->pilot_power, q->snr_vector, q->snr_vector, nref);
input2d[nsymbols + 1] = &q->tmp_noise[nref * 2];
srslte_vec_fprint_f(stdout, q->snr_vector, nref); if (nsymbols > 3) {
#endif srslte_vec_sc_prod_cfc(input2d[nsymbols - 1], 2.0f, input2d[nsymbols + 1], nref);
srslte_vec_sub_ccc(input2d[nsymbols + 1], input2d[nsymbols - 3], input2d[nsymbols + 1], nref);
/* Compute average power. Normalized for filter len 3 using matlab */
float norm = 1;
if (q->average_subframe) {
norm = 32;
} else { } else {
if (q->smooth_filter_len == 3) { srslte_vec_sc_prod_cfc(input2d[nsymbols - 1], 1.0f, input2d[nsymbols + 1], nref);
float a = q->smooth_filter[0]; }
float norm3 = 6.143*a*a+0.04859*a-0.002774;
norm /= norm3; for (int i = 1; i < nsymbols + 1; i++) {
uint32_t offset = ((fidx < 3) ^ (i & 1)) ? 0 : 1;
srslte_vec_sc_prod_cfc(input2d[i], weight, tmp_noise, nref);
srslte_vec_sum_ccc(&input2d[i - 1][0], &tmp_noise[offset], &tmp_noise[offset], nref - offset);
srslte_vec_sum_ccc(&input2d[i - 1][1 - offset], &tmp_noise[0], &tmp_noise[0], nref + offset - 1);
if (offset) {
tmp_noise[0] += 2.0f * input2d[i - 1][0] - input2d[i - 1][1];
} else {
tmp_noise[nref - 1] += 2.0f * input2d[i - 1][nref - 2] - input2d[i - 1][nref - 1];
} }
srslte_vec_sum_ccc(&input2d[i + 1][0], &tmp_noise[offset], &tmp_noise[offset], nref - offset);
srslte_vec_sum_ccc(&input2d[i + 1][1 - offset], &tmp_noise[0], &tmp_noise[0], nref + offset - 1);
if (offset) {
tmp_noise[0] += 2.0f * input2d[i + 1][0] - input2d[i + 1][1];
} else {
tmp_noise[nref - 1] += 2.0f * input2d[i + 1][nref - 2] - input2d[i + 1][nref - 1];
}
srslte_vec_sc_prod_cfc(tmp_noise, 1.0f / (weight + 4.0f), tmp_noise, nref);
srslte_vec_sub_ccc(input2d[i], tmp_noise, tmp_noise, nref);
sum_power = srslte_vec_avg_power_cf(tmp_noise, nref);
count++;
} }
float power = norm*srslte_vec_avg_power_cf(q->tmp_noise, nref);
return power; return sum_power / (float) count * sqrtf(weight + 4.0f);
} }
static float estimate_noise_pss(srslte_chest_dl_t *q, cf_t *input, cf_t *ce) static float estimate_noise_pss(srslte_chest_dl_t *q, cf_t *input, cf_t *ce)
{ {
/* Get PSS from received signal */ /* Get PSS from received signal */
srslte_pss_get_slot(input, q->tmp_pss, q->cell.nof_prb, q->cell.cp); srslte_pss_get_slot(input, q->tmp_pss, q->cell.nof_prb, q->cell.cp);
/* Get channel estimates for PSS position */ /* Get channel estimates for PSS position */
srslte_pss_get_slot(ce, q->tmp_pss_noisy, q->cell.nof_prb, q->cell.cp); srslte_pss_get_slot(ce, q->tmp_pss_noisy, q->cell.nof_prb, q->cell.cp);
@ -313,7 +341,7 @@ static float estimate_noise_pss(srslte_chest_dl_t *q, cf_t *input, cf_t *ce)
/* Substract received signal */ /* Substract received signal */
srslte_vec_sub_ccc(q->tmp_pss_noisy, q->tmp_pss, q->tmp_pss_noisy, SRSLTE_PSS_LEN); srslte_vec_sub_ccc(q->tmp_pss_noisy, q->tmp_pss, q->tmp_pss_noisy, SRSLTE_PSS_LEN);
/* Compute average power */ /* Compute average power */
float power = q->cell.nof_ports*srslte_vec_avg_power_cf(q->tmp_pss_noisy, SRSLTE_PSS_LEN)/sqrt(2); float power = q->cell.nof_ports*srslte_vec_avg_power_cf(q->tmp_pss_noisy, SRSLTE_PSS_LEN)/sqrt(2);
return power; return power;
@ -322,14 +350,14 @@ static float estimate_noise_pss(srslte_chest_dl_t *q, cf_t *input, cf_t *ce)
/* Uses the 5 empty transmitted SC before and after the SSS and PSS sequences for noise estimation */ /* Uses the 5 empty transmitted SC before and after the SSS and PSS sequences for noise estimation */
static float estimate_noise_empty_sc(srslte_chest_dl_t *q, cf_t *input) { static float estimate_noise_empty_sc(srslte_chest_dl_t *q, cf_t *input) {
int k_sss = (SRSLTE_CP_NSYMB(q->cell.cp) - 2) * q->cell.nof_prb * SRSLTE_NRE + q->cell.nof_prb * SRSLTE_NRE / 2 - 31; int k_sss = (SRSLTE_CP_NSYMB(q->cell.cp) - 2) * q->cell.nof_prb * SRSLTE_NRE + q->cell.nof_prb * SRSLTE_NRE / 2 - 31;
float noise_power = 0; float noise_power = 0;
noise_power += srslte_vec_avg_power_cf(&input[k_sss-5], 5); // 5 empty SC before SSS noise_power += srslte_vec_avg_power_cf(&input[k_sss-5], 5); // 5 empty SC before SSS
noise_power += srslte_vec_avg_power_cf(&input[k_sss+62], 5); // 5 empty SC after SSS noise_power += srslte_vec_avg_power_cf(&input[k_sss+62], 5); // 5 empty SC after SSS
int k_pss = (SRSLTE_CP_NSYMB(q->cell.cp) - 1) * q->cell.nof_prb * SRSLTE_NRE + q->cell.nof_prb * SRSLTE_NRE / 2 - 31; int k_pss = (SRSLTE_CP_NSYMB(q->cell.cp) - 1) * q->cell.nof_prb * SRSLTE_NRE + q->cell.nof_prb * SRSLTE_NRE / 2 - 31;
noise_power += srslte_vec_avg_power_cf(&input[k_pss-5], 5); // 5 empty SC before PSS noise_power += srslte_vec_avg_power_cf(&input[k_pss-5], 5); // 5 empty SC before PSS
noise_power += srslte_vec_avg_power_cf(&input[k_pss+62], 5); // 5 empty SC after PSS noise_power += srslte_vec_avg_power_cf(&input[k_pss+62], 5); // 5 empty SC after PSS
return noise_power; return noise_power;
} }
#define cesymb(i) ce[SRSLTE_RE_IDX(q->cell.nof_prb,i,0)] #define cesymb(i) ce[SRSLTE_RE_IDX(q->cell.nof_prb,i,0)]
@ -362,11 +390,12 @@ static void interpolate_pilots(srslte_chest_dl_t *q, cf_t *pilot_estimates, cf_t
} }
} else { } else {
if (q->average_subframe) { if (q->average_subframe) {
fidx_offset = SRSLTE_MIN(srslte_refsignal_cs_fidx(q->cell, 0, port_id, 0), fidx_offset = q->cell.id % 3;
srslte_refsignal_cs_fidx(q->cell, 1, port_id, 0)); srslte_interp_linear_offset(&q->srslte_interp_lin_3,
srslte_interp_linear_offset(&q->srslte_interp_lin_3, &pilot_estimates[q->cell.nof_prb * l], pilot_estimates,
&ce[srslte_refsignal_cs_nsymbol(l, q->cell.cp, port_id) * q->cell.nof_prb ce,
* SRSLTE_NRE], fidx_offset, SRSLTE_NRE / 4 - fidx_offset); fidx_offset,
SRSLTE_NRE / 4 - fidx_offset);
} else { } else {
fidx_offset = srslte_refsignal_cs_fidx(q->cell, l, port_id, 0); fidx_offset = srslte_refsignal_cs_fidx(q->cell, l, port_id, 0);
srslte_interp_linear_offset(&q->srslte_interp_lin, &pilot_estimates[2 * q->cell.nof_prb * l], srslte_interp_linear_offset(&q->srslte_interp_lin, &pilot_estimates[2 * q->cell.nof_prb * l],
@ -379,7 +408,7 @@ static void interpolate_pilots(srslte_chest_dl_t *q, cf_t *pilot_estimates, cf_t
/* Now interpolate in the time domain between symbols */ /* Now interpolate in the time domain between symbols */
if (q->average_subframe) { if (q->average_subframe) {
// If we average per subframe, just copy the estimates in the time domain // If we average per subframe, just copy the estimates in the time domain
for (l=0;l<2*SRSLTE_CP_NSYMB(q->cell.cp);l++) { for (l=1;l<2*SRSLTE_CP_NSYMB(q->cell.cp);l++) {
memcpy(&ce[l*SRSLTE_NRE*q->cell.nof_prb], ce, sizeof(cf_t)*SRSLTE_NRE*q->cell.nof_prb); memcpy(&ce[l*SRSLTE_NRE*q->cell.nof_prb], ce, sizeof(cf_t)*SRSLTE_NRE*q->cell.nof_prb);
} }
} else { } else {
@ -443,6 +472,54 @@ void srslte_chest_dl_set_smooth_filter3_coeff(srslte_chest_dl_t* q, float w)
q->smooth_filter[1] = 1-2*w; q->smooth_filter[1] = 1-2*w;
} }
void srslte_chest_dl_set_smooth_filter_gauss(srslte_chest_dl_t* q, uint32_t order, float std_dev)
{
const uint32_t filterlen = order + 1;
const int center = (filterlen - 1) / 2;
float *filter = q->smooth_filter;
float norm_p = 0.0f;
if (filterlen) {
for (int i = 0; i < filterlen; i++) {
filter[i] = expf(-powf(i - center, 2) / (2.0f * powf(std_dev, 2)));
norm_p += powf(filter[i], 2);
}
const float norm = srslte_vec_acc_ff(filter, filterlen);
srslte_vec_sc_prod_fff(filter, 1.0f / norm, filter, filterlen);
q->smooth_filter_len = filterlen;
}
}
void srslte_chest_dl_set_smooth_filter_auto(srslte_chest_dl_t *q, bool enable) {
q->smooth_filter_auto = enable;
}
uint32_t srslte_chest_dl_interleave_pilots(srslte_chest_dl_t *q, cf_t *input, cf_t *tmp, cf_t *output, uint32_t port_id, srslte_sf_t ch_mode) {
uint32_t nsymbols = (ch_mode == SRSLTE_SF_MBSFN)?srslte_refsignal_mbsfn_nof_symbols(port_id):srslte_refsignal_cs_nof_symbols(port_id);
uint32_t nref = (ch_mode == SRSLTE_SF_MBSFN)?6*q->cell.nof_prb:2*q->cell.nof_prb;
uint32_t fidx = (ch_mode == SRSLTE_SF_MBSFN)?srslte_refsignal_mbsfn_fidx(1):srslte_refsignal_cs_fidx(q->cell, 0, port_id, 0);
if (fidx < 3) {
srslte_vec_interleave(input, &input[nref], tmp, nref);
for (int l = 2; l < nsymbols - 1; l += 2) {
srslte_vec_interleave_add(&input[l * nref], &input[(l + 1) * nref], tmp, nref);
}
} else {
srslte_vec_interleave(&input[nref], input, tmp, nref);
for (int l = 2; l < nsymbols - 1; l += 2) {
srslte_vec_interleave_add(&input[(l + 1) * nref], &input[l * nref], tmp, nref);
}
}
nref *= 2;
srslte_vec_sc_prod_cfc(tmp, 2.0f / nsymbols, output, nref);
return nref;
}
static void average_pilots(srslte_chest_dl_t *q, cf_t *input, cf_t *output, uint32_t port_id, srslte_sf_t ch_mode) { static void average_pilots(srslte_chest_dl_t *q, cf_t *input, cf_t *output, uint32_t port_id, srslte_sf_t ch_mode) {
uint32_t nsymbols = (ch_mode == SRSLTE_SF_MBSFN)?srslte_refsignal_mbsfn_nof_symbols(port_id):srslte_refsignal_cs_nof_symbols(port_id); uint32_t nsymbols = (ch_mode == SRSLTE_SF_MBSFN)?srslte_refsignal_mbsfn_nof_symbols(port_id):srslte_refsignal_cs_nof_symbols(port_id);
uint32_t nref = (ch_mode == SRSLTE_SF_MBSFN)?6*q->cell.nof_prb:2*q->cell.nof_prb; uint32_t nref = (ch_mode == SRSLTE_SF_MBSFN)?6*q->cell.nof_prb:2*q->cell.nof_prb;
@ -476,9 +553,16 @@ static void average_pilots(srslte_chest_dl_t *q, cf_t *input, cf_t *output, uint
} }
} }
uint32_t skip = (ch_mode == SRSLTE_SF_MBSFN)?2*q->cell.nof_prb:0;
if(ch_mode == SRSLTE_SF_MBSFN){
memcpy(&output[0],&input[0],skip*sizeof(cf_t));
}
// Average in the frequency domain // Average in the frequency domain
for (int l=0;l<nsymbols;l++) { for (int l=0;l<nsymbols;l++) {
srslte_conv_same_cf(&input[l*nref], q->smooth_filter, &output[l*nref], nref, q->smooth_filter_len); srslte_conv_same_cf(&input[l*nref + skip], q->smooth_filter, &output[l*nref + skip], nref, q->smooth_filter_len);
} }
} }
@ -523,7 +607,16 @@ void chest_interpolate_noise_est(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, ui
q->cfo = chest_estimate_cfo(q); q->cfo = chest_estimate_cfo(q);
} }
/* Estimate noise */
if (q->noise_alg == SRSLTE_NOISE_ALG_REFS) {
q->noise_estimate[rxant_id][port_id] = estimate_noise_pilots(q, port_id, ch_mode);
}
if (ce != NULL) { if (ce != NULL) {
if (q->smooth_filter_auto) {
srslte_chest_dl_set_smooth_filter_gauss(q, 4, q->noise_estimate[rxant_id][port_id] * 200.0f);
}
/* Smooth estimates (if applicable) and interpolate */ /* Smooth estimates (if applicable) and interpolate */
if (q->smooth_filter_len == 0 || (q->smooth_filter_len == 3 && q->smooth_filter[0] == 0)) { if (q->smooth_filter_len == 0 || (q->smooth_filter_len == 3 && q->smooth_filter[0] == 0)) {
interpolate_pilots(q, q->pilot_estimates, ce, port_id, ch_mode); interpolate_pilots(q, q->pilot_estimates, ce, port_id, ch_mode);
@ -533,13 +626,11 @@ void chest_interpolate_noise_est(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, ui
} }
/* Estimate noise power */ /* Estimate noise power */
if (q->noise_alg == SRSLTE_NOISE_ALG_REFS && q->smooth_filter_len > 0) { if (q->noise_alg == SRSLTE_NOISE_ALG_PSS) {
q->noise_estimate[rxant_id][port_id] = estimate_noise_pilots(q, port_id, ch_mode);
} else if (q->noise_alg == SRSLTE_NOISE_ALG_PSS) {
if (sf_idx == 0 || sf_idx == 5) { if (sf_idx == 0 || sf_idx == 5) {
q->noise_estimate[rxant_id][port_id] = estimate_noise_pss(q, input, ce); q->noise_estimate[rxant_id][port_id] = estimate_noise_pss(q, input, ce);
} }
} else { } else if (q->noise_alg != SRSLTE_NOISE_ALG_REFS) {
if (sf_idx == 0 || sf_idx == 5) { if (sf_idx == 0 || sf_idx == 5) {
q->noise_estimate[rxant_id][port_id] = estimate_noise_empty_sc(q, input); q->noise_estimate[rxant_id][port_id] = estimate_noise_empty_sc(q, input);
} }
@ -580,11 +671,10 @@ int srslte_chest_dl_estimate_port_mbsfn(srslte_chest_dl_t *q, cf_t *input, cf_t
srslte_vec_prod_conj_ccc(q->pilot_recv_signal, q->csr_refs.pilots[port_id/2][sf_idx], srslte_vec_prod_conj_ccc(q->pilot_recv_signal, q->csr_refs.pilots[port_id/2][sf_idx],
q->pilot_estimates, (2*q->cell.nof_prb)); q->pilot_estimates, (2*q->cell.nof_prb));
srslte_vec_prod_conj_ccc(q->pilot_recv_signal+(2*q->cell.nof_prb), q->mbsfn_refs[mbsfn_area_id]->pilots[port_id/2][sf_idx], srslte_vec_prod_conj_ccc(&q->pilot_recv_signal[(2*q->cell.nof_prb)], q->mbsfn_refs[mbsfn_area_id]->pilots[port_id/2][sf_idx],
q->pilot_estimates+(2*q->cell.nof_prb), SRSLTE_REFSIGNAL_NUM_SF_MBSFN(q->cell.nof_prb, port_id)-(2*q->cell.nof_prb)); &q->pilot_estimates[(2*q->cell.nof_prb)], SRSLTE_REFSIGNAL_NUM_SF_MBSFN(q->cell.nof_prb, port_id)-(2*q->cell.nof_prb));
chest_interpolate_noise_est(q, input, ce, sf_idx, port_id, rxant_id, SRSLTE_SF_MBSFN); chest_interpolate_noise_est(q, input, ce, sf_idx, port_id, rxant_id, SRSLTE_SF_MBSFN);
return 0; return 0;

@ -286,8 +286,8 @@ int srslte_chest_ul_estimate(srslte_chest_ul_t *q, cf_t *input, cf_t *ce,
if (ce != NULL) { if (ce != NULL) {
if (q->smooth_filter_len > 0) { if (q->smooth_filter_len > 0) {
average_pilots(q, q->pilot_estimates, ce, nrefs_sym, n_prb); average_pilots(q, q->pilot_estimates, ce, nrefs_sym, n_prb);
interpolate_pilots(q, ce, nrefs_sym, n_prb); interpolate_pilots(q, ce, nrefs_sym, n_prb);
/* If averaging, compute noise from difference between received and averaged estimates */ /* If averaging, compute noise from difference between received and averaged estimates */
q->noise_estimate = estimate_noise_pilots(q, ce, nrefs_sym, n_prb); q->noise_estimate = estimate_noise_pilots(q, ce, nrefs_sym, n_prb);
} else { } else {
@ -301,8 +301,7 @@ int srslte_chest_ul_estimate(srslte_chest_ul_t *q, cf_t *input, cf_t *ce,
q->noise_estimate = 0; q->noise_estimate = 0;
} }
} }
// Estimate received pilot power
// Estimate received pilot power
q->pilot_power = srslte_vec_avg_power_cf(q->pilot_recv_signal, nrefs_sf); q->pilot_power = srslte_vec_avg_power_cf(q->pilot_recv_signal, nrefs_sf);
return 0; return 0;
} }

@ -56,17 +56,17 @@ uint32_t srslte_refsignal_cs_v(uint32_t port_id, uint32_t ref_symbol_idx)
} }
break; break;
case 2: case 2:
if (ref_symbol_idx < 2) { if (ref_symbol_idx == 0) {
v = 0; v = 0;
} else { } else {
v = 3; v = 3;
} }
break; break;
case 3: case 3:
if (ref_symbol_idx < 2) { if (ref_symbol_idx == 0) {
v = 3; v = 3;
} else { } else {
v = 6; v = 0;
} }
break; break;
} }
@ -120,6 +120,7 @@ inline uint32_t srslte_refsignal_cs_nsymbol(uint32_t l, srslte_cp_t cp, uint32_t
return 1+l*SRSLTE_CP_NSYMB(cp); return 1+l*SRSLTE_CP_NSYMB(cp);
} }
} }
inline uint32_t srslte_refsignal_mbsfn_nsymbol(uint32_t l) inline uint32_t srslte_refsignal_mbsfn_nsymbol(uint32_t l)
{ {
uint32_t ret = 0; uint32_t ret = 0;
@ -176,22 +177,21 @@ free_and_exit:
} }
int srslte_refsignal_mbsfn_init(srslte_refsignal_t * q, srslte_cell_t cell, uint16_t mbsfn_area_id) int srslte_refsignal_mbsfn_init(srslte_refsignal_t * q, uint32_t max_prb)
{ {
int ret = SRSLTE_ERROR_INVALID_INPUTS; int ret = SRSLTE_ERROR_INVALID_INPUTS;
uint32_t i, p; uint32_t i, p;
if (q != NULL && if (q != NULL)
srslte_cell_isvalid(&cell))
{ {
ret = SRSLTE_ERROR; ret = SRSLTE_ERROR;
bzero(q, sizeof(srslte_refsignal_t)); bzero(q, sizeof(srslte_refsignal_t));
q->cell = cell;
q->type = SRSLTE_SF_MBSFN; q->type = SRSLTE_SF_MBSFN;
q->mbsfn_area_id = mbsfn_area_id;
for (p=0;p<2;p++) { for (p=0;p<2;p++) {
for (i=0;i<SRSLTE_NSUBFRAMES_X_FRAME;i++) { for (i=0;i<SRSLTE_NSUBFRAMES_X_FRAME;i++) {
q->pilots[p][i] = srslte_vec_malloc(sizeof(cf_t) * q->cell.nof_prb * 18); q->pilots[p][i] = srslte_vec_malloc(sizeof(cf_t) * max_prb * 18);
if (!q->pilots[p][i]) { if (!q->pilots[p][i]) {
perror("malloc"); perror("malloc");
goto free_and_exit; goto free_and_exit;
@ -199,9 +199,7 @@ int srslte_refsignal_mbsfn_init(srslte_refsignal_t * q, srslte_cell_t cell, uint
} }
} }
if(srslte_refsignal_mbsfn_gen_seq(q, q->cell, q->mbsfn_area_id)) {
goto free_and_exit;
}
ret = SRSLTE_SUCCESS; ret = SRSLTE_SUCCESS;
} }
@ -212,7 +210,24 @@ free_and_exit:
return ret; return ret;
} }
int srslte_refsignal_mbsfn_set_cell(srslte_refsignal_t * q, srslte_cell_t cell, uint16_t mbsfn_area_id){
int ret = SRSLTE_ERROR_INVALID_INPUTS;
q->cell = cell;
q->mbsfn_area_id = mbsfn_area_id;
if(srslte_refsignal_mbsfn_gen_seq(q, q->cell, q->mbsfn_area_id)) {
goto free_and_exit;
}
ret = SRSLTE_SUCCESS;
free_and_exit:
if (ret == SRSLTE_ERROR) {
srslte_refsignal_free(q);
}
return ret;
}
/** Allocates memory for the 20 slots in a subframe /** Allocates memory for the 20 slots in a subframe
@ -399,7 +414,7 @@ int srslte_refsignal_cs_get_sf(srslte_cell_t cell, uint32_t port_id, cf_t *sf_sy
for (l=0;l<srslte_refsignal_cs_nof_symbols(port_id);l++) { for (l=0;l<srslte_refsignal_cs_nof_symbols(port_id);l++) {
uint32_t nsymbol = srslte_refsignal_cs_nsymbol(l, cell.cp, port_id); uint32_t nsymbol = srslte_refsignal_cs_nsymbol(l, cell.cp, port_id);
/* Compute offset frequency index */ /* Compute offset frequency index */
fidx = ((srslte_refsignal_cs_v(port_id, l) + (cell.id % 6)) % 6); fidx = srslte_refsignal_cs_fidx(cell, l, port_id, 0);
for (i = 0; i < 2*cell.nof_prb; i++) { for (i = 0; i < 2*cell.nof_prb; i++) {
pilots[SRSLTE_REFSIGNAL_PILOT_IDX(i,l,cell)] = sf_symbols[SRSLTE_RE_IDX(cell.nof_prb, nsymbol, fidx)]; pilots[SRSLTE_REFSIGNAL_PILOT_IDX(i,l,cell)] = sf_symbols[SRSLTE_RE_IDX(cell.nof_prb, nsymbol, fidx)];
fidx += SRSLTE_NRE/2; // 2 references per PRB fidx += SRSLTE_NRE/2; // 2 references per PRB

@ -37,7 +37,9 @@ srslte_cell_t cell = {
6, // nof_prb 6, // nof_prb
1, // nof_ports 1, // nof_ports
1000, // cell_id 1000, // cell_id
SRSLTE_CP_NORM // cyclic prefix SRSLTE_CP_NORM, // cyclic prefix
SRSLTE_PHICH_NORM,
SRSLTE_PHICH_R_1_6
}; };
char *output_matlab = NULL; char *output_matlab = NULL;

@ -37,7 +37,8 @@ srslte_cell_t cell = {
1, // nof_ports 1, // nof_ports
0, 0,
1000, // cell_id 1000, // cell_id
SRSLTE_CP_NORM // cyclic prefix SRSLTE_CP_NORM, // cyclic prefix
SRSLTE_PHICH_NORM
}; };
char *output_matlab = NULL; char *output_matlab = NULL;
@ -116,6 +117,7 @@ int main(int argc, char **argv) {
perror("srslte_vec_malloc"); perror("srslte_vec_malloc");
goto do_exit; goto do_exit;
} }
bzero(ce, num_re*sizeof(cf_t));
if (cell.id == 1000) { if (cell.id == 1000) {
cid = 0; cid = 0;

@ -36,7 +36,9 @@ srslte_cell_t cell = {
100, // nof_prb 100, // nof_prb
SRSLTE_MAX_PORTS, // nof_ports SRSLTE_MAX_PORTS, // nof_ports
1, // cell_id 1, // cell_id
SRSLTE_CP_NORM // cyclic prefix SRSLTE_CP_NORM, // cyclic prefix
SRSLTE_PHICH_NORM,
SRSLTE_PHICH_R_1_6
}; };
void usage(char *prog) { void usage(char *prog) {

@ -66,7 +66,7 @@ int srslte_timestamp_sub(srslte_timestamp_t *t, time_t full_secs, double frac_se
t->frac_secs -= frac_secs; t->frac_secs -= frac_secs;
t->full_secs -= full_secs; t->full_secs -= full_secs;
if(t->frac_secs < 0){ if(t->frac_secs < 0){
t->frac_secs = 1-t->frac_secs; t->frac_secs = t->frac_secs + 1;
t->full_secs--; t->full_secs--;
} }
if(t->full_secs < 0) if(t->full_secs < 0)

@ -149,6 +149,7 @@ int srslte_ofdm_replan_(srslte_ofdm_t *q, srslte_cp_t cp, int symbol_sz, int nof
q->symbol_sz = (uint32_t) symbol_sz; q->symbol_sz = (uint32_t) symbol_sz;
q->nof_symbols = SRSLTE_CP_NSYMB(cp); q->nof_symbols = SRSLTE_CP_NSYMB(cp);
q->nof_symbols_mbsfn = SRSLTE_CP_NSYMB(SRSLTE_CP_EXT);
q->cp = cp; q->cp = cp;
q->nof_re = (uint32_t) nof_prb * SRSLTE_NRE; q->nof_re = (uint32_t) nof_prb * SRSLTE_NRE;
q->nof_guards = ((symbol_sz - q->nof_re) / 2); q->nof_guards = ((symbol_sz - q->nof_re) / 2);
@ -246,14 +247,15 @@ int srslte_ofdm_rx_init(srslte_ofdm_t *q, srslte_cp_t cp, cf_t *in_buffer, cf_t
return srslte_ofdm_init_(q, cp, in_buffer, out_buffer, symbol_sz, max_prb, SRSLTE_DFT_FORWARD); return srslte_ofdm_init_(q, cp, in_buffer, out_buffer, symbol_sz, max_prb, SRSLTE_DFT_FORWARD);
} }
int srslte_ofdm_rx_init_mbsfn(srslte_ofdm_t *q, srslte_cp_t cp, cf_t *in_buffer, cf_t *out_buffer, uint32_t nof_prb) int srslte_ofdm_rx_init_mbsfn(srslte_ofdm_t *q, srslte_cp_t cp, cf_t *in_buffer, cf_t *out_buffer, uint32_t max_prb)
{ {
int symbol_sz = srslte_symbol_sz(nof_prb); int symbol_sz = srslte_symbol_sz(max_prb);
if (symbol_sz < 0) { if (symbol_sz < 0) {
fprintf(stderr, "Error: Invalid nof_prb=%d\n", nof_prb); fprintf(stderr, "Error: Invalid nof_prb=%d\n", max_prb);
return -1; return -1;
} }
return srslte_ofdm_init_mbsfn_(q, cp, in_buffer, out_buffer, symbol_sz, nof_prb, SRSLTE_DFT_FORWARD, SRSLTE_SF_MBSFN); q->max_prb = max_prb;
return srslte_ofdm_init_mbsfn_(q, cp, in_buffer, out_buffer, symbol_sz, max_prb, SRSLTE_DFT_FORWARD, SRSLTE_SF_MBSFN);
} }
@ -292,7 +294,7 @@ int srslte_ofdm_tx_init_mbsfn(srslte_ofdm_t *q, srslte_cp_t cp, cf_t *in_buffer,
fprintf(stderr, "Error: Invalid nof_prb=%d\n", nof_prb); fprintf(stderr, "Error: Invalid nof_prb=%d\n", nof_prb);
return -1; return -1;
} }
q->max_prb = nof_prb;
ret = srslte_ofdm_init_mbsfn_(q, cp, in_buffer, out_buffer, symbol_sz, nof_prb, SRSLTE_DFT_BACKWARD, SRSLTE_SF_MBSFN); ret = srslte_ofdm_init_mbsfn_(q, cp, in_buffer, out_buffer, symbol_sz, nof_prb, SRSLTE_DFT_BACKWARD, SRSLTE_SF_MBSFN);
if (ret == SRSLTE_SUCCESS) { if (ret == SRSLTE_SUCCESS) {
@ -559,7 +561,6 @@ void srslte_ofdm_tx_slot(srslte_ofdm_t *q, int slot_in_sf) {
void srslte_ofdm_tx_slot_mbsfn(srslte_ofdm_t *q, cf_t *input, cf_t *output) void srslte_ofdm_tx_slot_mbsfn(srslte_ofdm_t *q, cf_t *input, cf_t *output)
{ {
uint32_t i, cp_len; uint32_t i, cp_len;
for(i=0;i<q->nof_symbols_mbsfn;i++) { for(i=0;i<q->nof_symbols_mbsfn;i++) {
cp_len = ( i>(q->non_mbsfn_region-1) )?SRSLTE_CP_LEN_EXT(q->symbol_sz):SRSLTE_CP_LEN_NORM(i, q->symbol_sz); cp_len = ( i>(q->non_mbsfn_region-1) )?SRSLTE_CP_LEN_EXT(q->symbol_sz):SRSLTE_CP_LEN_NORM(i, q->symbol_sz);
memcpy(&q->tmp[q->nof_guards], input, q->nof_re * sizeof(cf_t)); memcpy(&q->tmp[q->nof_guards], input, q->nof_re * sizeof(cf_t));

@ -69,6 +69,13 @@ int srslte_enb_dl_init(srslte_enb_dl_t *q, cf_t *out_buffer[SRSLTE_MAX_PORTS], u
goto clean_exit; goto clean_exit;
} }
} }
if (srslte_ofdm_tx_init_mbsfn(&q->ifft_mbsfn, SRSLTE_CP_EXT, q->sf_symbols[0], out_buffer[0], max_prb)) {
fprintf(stderr, "Error initiating FFT \n");
goto clean_exit;
}
if (srslte_pbch_init(&q->pbch)) { if (srslte_pbch_init(&q->pbch)) {
fprintf(stderr, "Error creating PBCH object\n"); fprintf(stderr, "Error creating PBCH object\n");
@ -82,7 +89,15 @@ int srslte_enb_dl_init(srslte_enb_dl_t *q, cf_t *out_buffer[SRSLTE_MAX_PORTS], u
fprintf(stderr, "Error creating PHICH object\n"); fprintf(stderr, "Error creating PHICH object\n");
goto clean_exit; goto clean_exit;
} }
int mbsfn_area_id = 1;
if (srslte_pmch_init(&q->pmch, max_prb)) {
fprintf(stderr, "Error creating PMCH object\n");
}
srslte_pmch_set_area_id(&q->pmch, mbsfn_area_id);
if (srslte_pdcch_init_enb(&q->pdcch, max_prb)) { if (srslte_pdcch_init_enb(&q->pdcch, max_prb)) {
fprintf(stderr, "Error creating PDCCH object\n"); fprintf(stderr, "Error creating PDCCH object\n");
goto clean_exit; goto clean_exit;
@ -97,7 +112,11 @@ int srslte_enb_dl_init(srslte_enb_dl_t *q, cf_t *out_buffer[SRSLTE_MAX_PORTS], u
fprintf(stderr, "Error initializing CSR signal (%d)\n",ret); fprintf(stderr, "Error initializing CSR signal (%d)\n",ret);
goto clean_exit; goto clean_exit;
} }
if (srslte_refsignal_mbsfn_init(&q->mbsfnr_signal, max_prb)) {
fprintf(stderr, "Error initializing CSR signal (%d)\n",ret);
goto clean_exit;
}
ret = SRSLTE_SUCCESS; ret = SRSLTE_SUCCESS;
} else { } else {
@ -117,15 +136,16 @@ void srslte_enb_dl_free(srslte_enb_dl_t *q)
for (int i = 0; i < SRSLTE_MAX_PORTS; i++) { for (int i = 0; i < SRSLTE_MAX_PORTS; i++) {
srslte_ofdm_tx_free(&q->ifft[i]); srslte_ofdm_tx_free(&q->ifft[i]);
} }
srslte_ofdm_tx_free(&q->ifft_mbsfn);
srslte_regs_free(&q->regs); srslte_regs_free(&q->regs);
srslte_pbch_free(&q->pbch); srslte_pbch_free(&q->pbch);
srslte_pcfich_free(&q->pcfich); srslte_pcfich_free(&q->pcfich);
srslte_phich_free(&q->phich); srslte_phich_free(&q->phich);
srslte_pdcch_free(&q->pdcch); srslte_pdcch_free(&q->pdcch);
srslte_pdsch_free(&q->pdsch); srslte_pdsch_free(&q->pdsch);
srslte_pmch_free(&q->pmch);
srslte_refsignal_free(&q->csr_signal); srslte_refsignal_free(&q->csr_signal);
srslte_refsignal_free(&q->mbsfnr_signal);
for (int i=0;i<SRSLTE_MAX_PORTS;i++) { for (int i=0;i<SRSLTE_MAX_PORTS;i++) {
if (q->sf_symbols[i]) { if (q->sf_symbols[i]) {
free(q->sf_symbols[i]); free(q->sf_symbols[i]);
@ -159,6 +179,15 @@ int srslte_enb_dl_set_cell(srslte_enb_dl_t *q, srslte_cell_t cell)
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
} }
if (srslte_ofdm_tx_set_prb(&q->ifft_mbsfn, SRSLTE_CP_EXT, q->cell.nof_prb)) {
fprintf(stderr, "Error re-planning ifft_mbsfn\n");
return SRSLTE_ERROR;
}
srslte_ofdm_set_non_mbsfn_region(&q->ifft_mbsfn, 2);
//srslte_ofdm_set_normalize(&q->ifft_mbsfn, true);
if (srslte_pbch_set_cell(&q->pbch, q->cell)) { if (srslte_pbch_set_cell(&q->pbch, q->cell)) {
fprintf(stderr, "Error creating PBCH object\n"); fprintf(stderr, "Error creating PBCH object\n");
return SRSLTE_ERROR; return SRSLTE_ERROR;
@ -181,11 +210,21 @@ int srslte_enb_dl_set_cell(srslte_enb_dl_t *q, srslte_cell_t cell)
fprintf(stderr, "Error creating PDSCH object\n"); fprintf(stderr, "Error creating PDSCH object\n");
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
if (srslte_pmch_set_cell(&q->pmch, q->cell)) {
fprintf(stderr, "Error creating PMCH object\n");
return SRSLTE_ERROR;
}
if (srslte_refsignal_cs_set_cell(&q->csr_signal, q->cell)) { if (srslte_refsignal_cs_set_cell(&q->csr_signal, q->cell)) {
fprintf(stderr, "Error initializing CSR signal (%d)\n",ret); fprintf(stderr, "Error initializing CSR signal (%d)\n",ret);
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
int mbsfn_area_id = 1;
if (srslte_refsignal_mbsfn_set_cell(&q->mbsfnr_signal, q->cell, mbsfn_area_id)) {
fprintf(stderr, "Error initializing MBSFNR signal (%d)\n",ret);
return SRSLTE_ERROR;
}
/* Generate PSS/SSS signals */ /* Generate PSS/SSS signals */
srslte_pss_generate(q->pss_signal, cell.id%3); srslte_pss_generate(q->pss_signal, cell.id%3);
srslte_sss_generate(q->sss_signal0, q->sss_signal5, cell.id); srslte_sss_generate(q->sss_signal0, q->sss_signal5, cell.id);
@ -201,6 +240,11 @@ int srslte_enb_dl_set_cell(srslte_enb_dl_t *q, srslte_cell_t cell)
void srslte_enb_dl_set_non_mbsfn_region(srslte_enb_dl_t *q, uint8_t non_mbsfn_region)
{
srslte_ofdm_set_non_mbsfn_region(&q->ifft_mbsfn, non_mbsfn_region);
}
void srslte_enb_dl_set_amp(srslte_enb_dl_t *q, float amp) void srslte_enb_dl_set_amp(srslte_enb_dl_t *q, float amp)
{ {
q->tx_amp = amp; q->tx_amp = amp;
@ -334,17 +378,30 @@ void srslte_enb_dl_put_base(srslte_enb_dl_t *q, uint32_t tti)
} }
void srslte_enb_dl_put_mbsfn_base(srslte_enb_dl_t *q, uint32_t tti)
{
uint32_t sf_idx1 = tti%10;
srslte_enb_dl_put_pcfich(q, sf_idx1);
srslte_refsignal_mbsfn_put_sf(q->cell, 0,q->csr_signal.pilots[0][sf_idx1], q->mbsfnr_signal.pilots[0][sf_idx1], q->sf_symbols[0]);
}
void srslte_enb_dl_gen_signal(srslte_enb_dl_t *q) void srslte_enb_dl_gen_signal(srslte_enb_dl_t *q)
{ {
// TODO: PAPR control // TODO: PAPR control
float norm_factor = (float) sqrt(q->cell.nof_prb)/15/sqrt(q->ifft[0].symbol_sz); float norm_factor = (float) sqrt(q->cell.nof_prb)/15/sqrt(q->ifft[0].symbol_sz);
for (int i = 0; i < q->cell.nof_ports; i++) { for (int i = 0; i < q->cell.nof_ports; i++) {
srslte_ofdm_tx_sf(&q->ifft[i]); srslte_ofdm_tx_sf(&q->ifft[i]);
srslte_vec_sc_prod_cfc(q->ifft[i].out_buffer, q->tx_amp*norm_factor, q->ifft[i].out_buffer, (uint32_t) SRSLTE_SF_LEN_PRB(q->cell.nof_prb)); srslte_vec_sc_prod_cfc(q->ifft[i].out_buffer, norm_factor, q->ifft[i].out_buffer, (uint32_t) SRSLTE_SF_LEN_PRB(q->cell.nof_prb));
} }
} }
void srslte_enb_dl_gen_signal_mbsfn(srslte_enb_dl_t *q)
{
float norm_factor = (float) sqrt(q->cell.nof_prb)/15/sqrt(q->ifft_mbsfn.symbol_sz);
srslte_ofdm_tx_sf(&q->ifft_mbsfn);
srslte_vec_sc_prod_cfc(q->ifft_mbsfn.out_buffer, norm_factor, q->ifft_mbsfn.out_buffer, (uint32_t) SRSLTE_SF_LEN_PRB(q->cell.nof_prb));
}
int srslte_enb_dl_add_rnti(srslte_enb_dl_t *q, uint16_t rnti) int srslte_enb_dl_add_rnti(srslte_enb_dl_t *q, uint16_t rnti)
{ {
return srslte_pdsch_set_rnti(&q->pdsch, rnti); return srslte_pdsch_set_rnti(&q->pdsch, rnti);
@ -438,7 +495,23 @@ int srslte_enb_dl_put_pdsch(srslte_enb_dl_t *q, srslte_ra_dl_grant_t *grant, srs
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
int srslte_enb_dl_put_pmch(srslte_enb_dl_t *q, srslte_ra_dl_grant_t *grant, srslte_softbuffer_tx_t *softbuffer, uint32_t sf_idx, uint8_t *data_mbms)
{
/* Encode PMCH */
int mbsfn_area_id = 1;
if (srslte_pmch_cfg(&q->pmch_cfg, q->cell, grant, q->cfi, sf_idx)) {
fprintf(stderr, "Error configuring PMCH\n");
return SRSLTE_ERROR;
}
/* Encode PMCH */
if (srslte_pmch_encode(&q->pmch, &q->pmch_cfg, softbuffer, data_mbms, mbsfn_area_id, q->sf_symbols)) {
fprintf(stderr, "Error encoding PDSCH\n");
return SRSLTE_ERROR;
}
return SRSLTE_SUCCESS;
}
void srslte_enb_dl_save_signal(srslte_enb_dl_t *q, srslte_softbuffer_tx_t *softbuffer, uint8_t *data, uint32_t tti, uint32_t rv_idx, uint16_t rnti, uint32_t cfi) void srslte_enb_dl_save_signal(srslte_enb_dl_t *q, srslte_softbuffer_tx_t *softbuffer, uint8_t *data, uint32_t tti, uint32_t rv_idx, uint16_t rnti, uint32_t cfi)
{ {

@ -40,7 +40,7 @@ uint32_t long_cb = 0;
void usage(char *prog) { void usage(char *prog) {
printf("Usage: %s\n", prog); printf("Usage: %s\n", prog);
printf("\t-l long_cb [Default check all]\n", long_cb); printf("\t-l long_cb [Default %u]\n", long_cb);
} }
void parse_args(int argc, char **argv) { void parse_args(int argc, char **argv) {

@ -244,6 +244,7 @@ int main(int argc, char **argv) {
for (j=0;j<coded_length;j++) { for (j=0;j<coded_length;j++) {
llr_s[j] = (int16_t) (100*llr[j]); llr_s[j] = (int16_t) (100*llr[j]);
} }
/* decoder */ /* decoder */
srslte_tdec_reset(&tdec, frame_length); srslte_tdec_reset(&tdec, frame_length);
@ -259,11 +260,12 @@ int main(int argc, char **argv) {
for (int n=0;n<SRSLTE_TDEC_MAX_NPAR;n++) { for (int n=0;n<SRSLTE_TDEC_MAX_NPAR;n++) {
if (n < nof_cb) { if (n < nof_cb) {
input[n] = llr_s; input[n] = llr_s;
output[n] = data_rx_bytes[n];
} else { } else {
input[n] = NULL; input[n] = NULL;
output[n] = NULL;
} }
output[n] = data_rx_bytes[n];
} }
gettimeofday(&tdata[1], NULL); gettimeofday(&tdata[1], NULL);
@ -297,13 +299,18 @@ int main(int argc, char **argv) {
if (errors) { if (errors) {
printf("%d Errors\n", errors/nof_cb); printf("%d Errors\n", errors/nof_cb);
} }
} }
for (int cb=0;cb<SRSLTE_TDEC_MAX_NPAR;cb++) {
if (data_rx_bytes[cb]) {
free(data_rx_bytes[cb]);
}
}
free(data_tx); free(data_tx);
free(symbols); free(symbols);
free(llr); free(llr);
free(llr_c); free(llr_c);
free(llr_s);
free(data_rx); free(data_rx);
srslte_tdec_free(&tdec); srslte_tdec_free(&tdec);

@ -278,6 +278,7 @@ int main(int argc, char **argv) {
free(symbols); free(symbols);
free(llr); free(llr);
free(llr_c); free(llr_c);
free(llr_s);
free(data_rx); free(data_rx);
free(data_rx2); free(data_rx2);

@ -513,7 +513,9 @@ void srslte_tdec_simd_decision_byte_cb(srslte_tdec_simd_t * h, uint8_t *output,
void srslte_tdec_simd_decision_byte(srslte_tdec_simd_t * h, uint8_t *output[SRSLTE_TDEC_MAX_NPAR], uint32_t long_cb) void srslte_tdec_simd_decision_byte(srslte_tdec_simd_t * h, uint8_t *output[SRSLTE_TDEC_MAX_NPAR], uint32_t long_cb)
{ {
for (int i=0;i<h->max_par_cb;i++) { for (int i=0;i<h->max_par_cb;i++) {
srslte_tdec_simd_decision_byte_cb(h, output[i], i, long_cb); if (output[i]) {
srslte_tdec_simd_decision_byte_cb(h, output[i], i, long_cb);
}
} }
} }

@ -54,7 +54,7 @@ int srslte_layermap_multiplex(cf_t *d[SRSLTE_MAX_CODEWORDS], cf_t *x[SRSLTE_MAX_
int nof_symbols[SRSLTE_MAX_CODEWORDS]) { int nof_symbols[SRSLTE_MAX_CODEWORDS]) {
if (nof_cw == nof_layers) { if (nof_cw == nof_layers) {
for (int i = 0; i < nof_cw; i++) { for (int i = 0; i < nof_cw; i++) {
srs_vec_cf_cpy(x[i], d[i], (uint32_t) nof_symbols[0]); srs_vec_cf_cpy(d[i], x[i], (uint32_t) nof_symbols[0]);
} }
return nof_symbols[0]; return nof_symbols[0];
} else if (nof_cw == 1) { } else if (nof_cw == 1) {

File diff suppressed because it is too large Load Diff

@ -333,5 +333,11 @@ int main(int argc, char **argv) {
} }
} }
for (i = 0; i < nof_tx_ports; i++) {
if (y[i]) {
free(y[i]);
}
}
exit(ret); exit(ret);
} }

@ -73,7 +73,9 @@ int srslte_dci_msg_to_dl_grant(srslte_dci_msg_t *msg, uint16_t msg_rnti,
} }
if (!dl_dci->is_ra_order) { if (!dl_dci->is_ra_order) {
srslte_ra_dl_dci_to_grant(dl_dci, nof_prb, msg_rnti, grant); if (srslte_ra_dl_dci_to_grant(dl_dci, nof_prb, msg_rnti, grant)) {
return ret;
}
if (SRSLTE_VERBOSE_ISINFO()) { if (SRSLTE_VERBOSE_ISINFO()) {
srslte_ra_pdsch_fprint(stdout, dl_dci, nof_prb); srslte_ra_pdsch_fprint(stdout, dl_dci, nof_prb);
@ -379,7 +381,7 @@ uint32_t srslte_dci_dl_info(char *info_str, uint32_t len, srslte_ra_dl_dci_t *dc
dci_msg->type2_alloc.riv, dci_msg->type2_alloc.riv,
dci_msg->type2_alloc.RB_start, dci_msg->type2_alloc.RB_start+dci_msg->type2_alloc.L_crb-1, dci_msg->type2_alloc.RB_start, dci_msg->type2_alloc.RB_start+dci_msg->type2_alloc.L_crb-1,
dci_msg->type2_alloc.mode==SRSLTE_RA_TYPE2_LOC?"local":"dist"); dci_msg->type2_alloc.mode==SRSLTE_RA_TYPE2_LOC?"local":"dist");
if (dci_msg->type2_alloc.mode==SRSLTE_RA_TYPE2_LOC) { if (dci_msg->type2_alloc.mode==SRSLTE_RA_TYPE2_DIST) {
n += snprintf(&info_str[n], len-n, ", ngap=%s, nprb1a=%d", n += snprintf(&info_str[n], len-n, ", ngap=%s, nprb1a=%d",
dci_msg->type2_alloc.n_gap==SRSLTE_RA_TYPE2_NG1?"ng1":"ng2", dci_msg->type2_alloc.n_gap==SRSLTE_RA_TYPE2_NG1?"ng1":"ng2",
dci_msg->type2_alloc.n_prb1a==SRSLTE_RA_TYPE2_NPRB1A_2?2:3); dci_msg->type2_alloc.n_prb1a==SRSLTE_RA_TYPE2_NPRB1A_2?2:3);

@ -221,7 +221,7 @@ int srslte_pcfich_decode_multi(srslte_pcfich_t *q, cf_t *sf_symbols[SRSLTE_MAX_P
/* no need for layer demapping */ /* no need for layer demapping */
srslte_predecoding_single_multi(q_symbols, q_ce[0], q->d, NULL, q->nof_rx_antennas, q->nof_symbols, 1.0f, noise_estimate); srslte_predecoding_single_multi(q_symbols, q_ce[0], q->d, NULL, q->nof_rx_antennas, q->nof_symbols, 1.0f, noise_estimate);
} else { } else {
srslte_predecoding_diversity_multi(q_symbols, q_ce, x, q->nof_rx_antennas, q->cell.nof_ports, q->nof_symbols, 1.0f); srslte_predecoding_diversity_multi(q_symbols, q_ce, x, NULL, q->nof_rx_antennas, q->cell.nof_ports, q->nof_symbols, 1.0f);
srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, q->nof_symbols / q->cell.nof_ports); srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, q->nof_symbols / q->cell.nof_ports);
} }

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

Loading…
Cancel
Save