adding remaining srsUE code

This commit is contained in:
Andre Puschmann 2017-05-30 15:38:04 +02:00
parent 5d66e9701f
commit 928ef71b82
59 changed files with 12432 additions and 0 deletions

View File

@ -292,3 +292,9 @@ include_directories(${PROJECT_SOURCE_DIR}/lib/include/srslte)
# Add the subdirectories
########################################################################
add_subdirectory(lib)
if(NOT DISABLE_SRSUE)
message(STATUS "Building with srsUE")
add_subdirectory(srsue)
else(NOT DISABLE_SRSUE)
message(STATUS "Building without srsUE")
endif(NOT DISABLE_SRSUE)

57
srsue/CHANGELOG Normal file
View File

@ -0,0 +1,57 @@
Change Log for Releases
==============================
## 001.004.000
* Fixed issues in RLC AM
* Added warning messages for unhandled ASN extensions
* Moved some classes from srsue to srslte namescape
* Improved compatibility with more eNodeBs
* Known Bugs:
* Found bug in PBR UL schedulign. Disabled PBR.
* Possible problem with UL TA compensation. Disabled TA from MAC commands (from RAR still enabled)
## 001.003.000
* Bugfixes:
* Moved UL signal pregeneration to after attach (causing timeout after ConnectionSetup)
* Fixed issue with incorrect TransactionID
* Fixed bug in PDN attach procedure
* Fixed bugs in RLC AM mode
* Fixed bug in BSR procedure
* Improvements:
* Added Aperiodic CQI support 3-1
* Added EIA1 support
* Added RLC AM resegmentation support
* Known bugs:
* Tun/tap write failure, seen at high rates with many retx (>70% retx)
* RRC Reestablishment procedure. Incorrect short-MAC computation
* BER performance at 20 MHz for MCS=28. More errors than expected.
## 001.002.000
* Bugfixes:
* UL BLER stdout metric bad formatting
* GW blocking when RLC queue was full
* Memory bug in RLC AM uplink
* Improvements:
* Management of radio link failure according to the specifications
* Known bugs:
* Tun/tap write failure, seen at high rates with many retx (>70% retx)
* RRC Reestablishment procedure. Incorrect short-MAC computation
* BER performance at 20 MHz for MCS=28. More errors than expected.
## 001.001.000
* Added support for BladeRF
* Added paging support, RRC reconnection
* Improved overall stability
* Calibrated RF front-end time advances
* Bugfix: PDCP SN size config bug for AM
* Bugfix: Added RRC Connection setup defaults

70
srsue/CMakeLists.txt Normal file
View File

@ -0,0 +1,70 @@
# Copyright 2015 Software Radio Systems Limited
#
# This file is part of srsUE
#
# 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/.
#
########################################################################
# Find boost
########################################################################
SET(BOOST_REQUIRED_COMPONENTS
program_options
system
)
if(UNIX AND EXISTS "/usr/lib64")
list(APPEND BOOST_LIBRARYDIR "/usr/lib64") #fedora 64-bit fix
endif(UNIX AND EXISTS "/usr/lib64")
set(Boost_ADDITIONAL_VERSIONS
"1.35.0" "1.35" "1.36.0" "1.36" "1.37.0" "1.37" "1.38.0" "1.38" "1.39.0" "1.39"
"1.40.0" "1.40" "1.41.0" "1.41" "1.42.0" "1.42" "1.43.0" "1.43" "1.44.0" "1.44"
"1.45.0" "1.45" "1.46.0" "1.46" "1.47.0" "1.47" "1.48.0" "1.48" "1.49.0" "1.49"
"1.50.0" "1.50" "1.51.0" "1.51" "1.52.0" "1.52" "1.53.0" "1.53" "1.54.0" "1.54"
"1.55.0" "1.55" "1.56.0" "1.56" "1.57.0" "1.57" "1.58.0" "1.58" "1.59.0" "1.59"
"1.60.0" "1.60" "1.61.0" "1.61" "1.62.0" "1.62" "1.63.0" "1.63" "1.64.0" "1.64"
"1.65.0" "1.65" "1.66.0" "1.66" "1.67.0" "1.67" "1.68.0" "1.68" "1.69.0" "1.69"
)
find_package(Boost "1.35" COMPONENTS ${BOOST_REQUIRED_COMPONENTS})
if(NOT Boost_FOUND)
message(FATAL_ERROR "Boost required to compile srsUE")
endif()
########################################################################
# Find dependencies
########################################################################
find_package(Threads REQUIRED)
########################################################################
# Setup the include and linker paths
########################################################################
include_directories(
${Boost_INCLUDE_DIRS}
${POLAR_INCLUDE_DIRS}
${PROJECT_SOURCE_DIR}/srsue/hdr
)
link_directories(
${Boost_LIBRARY_DIRS}
${POLAR_LIBRARY_DIRS}
)
########################################################################
# Add subdirectories
########################################################################
add_subdirectory(src)
add_subdirectory(test)

217
srsue/COPYRIGHT Normal file
View File

@ -0,0 +1,217 @@
Copyright (C) 2015-2016 Software Radio Systems Limited. All rights reserved.
The following software is used within srsUE:
-----------------------------------------------------------
OpenLTE (/liblte - used under AGPLv3)
-----------------------------------------------------------
Ben Wojtowicz, bwojtowi@gmail.com
Andrew Murphy, andrew.murphy@rd.bbc.co.uk (DCI 1C Unpack, SIB13 unpack/print)
-----------------------------------------------------------
PolarSSL (used under Apache 2.0 License below)
-----------------------------------------------------------
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

662
srsue/LICENSE Normal file
View File

@ -0,0 +1,662 @@
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU Affero General Public License is a free, copyleft license for
software and other kinds of works, specifically designed to ensure
cooperation with the community in the case of network server software.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
our General Public Licenses are intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.
When we speak of free software, we are referring to freedom, 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
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
Developers that use our General Public Licenses protect your rights
with two steps: (1) assert copyright on the software, and (2) offer
you this License which gives you legal permission to copy, distribute
and/or modify the software.
A secondary benefit of defending all users' freedom is that
improvements made in alternate versions of the program, if they
receive widespread use, become available for other developers to
incorporate. Many developers of free software are heartened and
encouraged by the resulting cooperation. However, in the case of
software used on network servers, this result may fail to come about.
The GNU General Public License permits making a modified version and
letting the public access it on a server without ever releasing its
source code to the public.
The GNU Affero General Public License is designed specifically to
ensure that, in such cases, the modified source code becomes available
to the community. It requires the operator of a network server to
provide the source code of the modified version running there to the
users of that server. Therefore, public use of a modified version, on
a publicly accessible server, gives the public access to the source
code of the modified version.
An older license, called the Affero General Public License and
published by Affero, was designed to accomplish similar goals. This is
a different license, not a version of the Affero GPL, but Affero has
released a new version of the Affero GPL which permits relicensing under
this license.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU Affero General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If 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 convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Remote Network Interaction; Use with the GNU General Public License.
Notwithstanding any other provision of this License, if you modify the
Program, your modified version must prominently offer all users
interacting with it remotely through a computer network (if your version
supports such interaction) an opportunity to receive the Corresponding
Source of your version by providing access to the Corresponding Source
from a network server at no charge, through some standard or customary
means of facilitating copying of software. This Corresponding Source
shall include the Corresponding Source for any work covered by version 3
of the GNU General Public License that is incorporated pursuant to the
following paragraph.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the work with which it is combined will remain governed by version
3 of the GNU General Public License.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU Affero 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
Program specifies that a certain numbered version of the GNU Affero General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU Affero General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU Affero General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "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 PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state 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 program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program 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.
This program 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.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If your software can interact with users remotely through a computer
network, you should also make sure that it provides a way for users to
get its source. For example, if your program is a web application, its
interface could display a "Source" link that leads users to an archive
of the code. There are many ways you could offer source, and different
solutions will be better for different programs; see section 13 for the
specific requirements.
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.
For more information on this, and how to apply and follow the GNU AGPL, see
<http://www.gnu.org/licenses/>.

99
srsue/README.md Normal file
View File

@ -0,0 +1,99 @@
srsUE
========
[![Coverity Scan Build Status](https://scan.coverity.com/projects/9987/badge.svg)](https://scan.coverity.com/projects/9987)
srsUE is a software radio LTE UE developed by SRS (www.softwareradiosystems.com). It is written in C++ and builds upon the srsLTE library (https://github.com/srslte/srslte). Running on an Intel Core i7-4790, srsUE achieves up to 60Mbps DL with a 20Mhz bandwidth SISO configuration.
srsUE is released under the AGPLv3 license and uses software from the OpenLTE project (http://sourceforge.net/projects/openlte) for some security functions and for RRC/NAS message parsing.
Compatibility
-------------
srsUE has been fully tested and validated with the following network equipment:
* Amarisoft LTE100 eNodeB and EPC
* Nokia FlexiRadio family FSMF system module with 1800MHz FHED radio module and TravelHawk EPC simulator
* Huawei DBS3900
* Octasic Flexicell LTE-FDD NIB
Features
--------
### PHY Layer
* LTE Release 8 compliant
* FDD configuration
* Tested bandwidths: 1.4, 3, 5, 10, 15 and 20 MHz
* Transmission mode 1 (single antenna) and 2 (transmit diversity)
* Cell search and synchronization procedure for the UE
* Frequency-based ZF and MMSE equalizer
* Highly optimized turbo decoder available in Intel SSE4.1/AVX (+100 Mbps) and standard C (+25 Mbps)
### Upper Layers
* LTE Release 8 compliant
* MAC, RLC, PDCP, RRC, NAS and GW layers
* Soft USIM supporting Milenage and XOR authentication
### User Interfaces
* Detailed log system with per-layer log levels and hex dumps
* MAC layer wireshark packet capture
* Command-line trace metrics
* Detailed input configuration file
### Network Interfaces
* Virtual network interface *tun_srsue* created upon network attach
Hardware
--------
The library currently supports the Ettus Universal Hardware Driver (UHD) and the bladeRF driver. Thus, any hardware supported by UHD or bladeRF can be used. There is no sampling rate conversion, therefore the hardware should support 30.72 MHz clock in order to work correctly with LTE sampling frequencies and decode signals from live LTE base stations.
We have tested the following hardware:
* USRP B210
* USRP X300
* bladeRF
Download & Install Instructions
-------------------------------
* Mandatory dependencies:
* srsLTE: https://github.com/srslte/srslte
* Boost: http://www.boost.org
* PolarSSL/mbed TLS https://tls.mbed.org
* RF front-end driver:
* UHD: https://github.com/EttusResearch/uhd
* BladeRF: https://github.com/Nuand/bladeRF
Download and build srsUE:
```
git clone https://github.com/srsLTE/srsUE.git
cd srsUE
mkdir build
cd build
cmake ../
make
```
The ue application can be found in build/ue/src
Running srsUE
-------------
* Copy and rename the provided configuration file ue.conf.example
* Check and set configuration parameters
* ```sudo ./ue ue.conf```
Disclaimer
----------
srsUE is provided with NO WARRANTY OF ANY KIND. Users of this software are expected to comply with all applicable local, national and international telecom and radio spectrum regulations.
Support
-------
Mailing list: http://www.softwareradiosystems.com/mailman/listinfo/srslte-users

92
srsue/hdr/mac/demux.h Normal file
View File

@ -0,0 +1,92 @@
/**
*
* \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 DEMUX_H
#define DEMUX_H
#include "common/interfaces.h"
#include "common/phy_interface.h"
#include "common/mac_interface.h"
#include "common/pdu_queue.h"
#include "common/log.h"
#include "common/timers.h"
#include "common/pdu.h"
/* Logical Channel Demultiplexing and MAC CE dissassemble */
namespace srsue {
class demux : public srslte::pdu_queue::process_callback
{
public:
demux();
void init(phy_interface_mac* phy_h_, rlc_interface_mac *rlc, srslte::log* log_h_, srslte::timers* timers_db_);
bool process_pdus();
uint8_t* request_buffer(uint32_t pid, uint32_t len);
void deallocate(uint8_t* payload_buffer_ptr);
void push_pdu(uint32_t pid, uint8_t *buff, uint32_t nof_bytes);
void push_pdu_temp_crnti(uint8_t *buff, uint32_t nof_bytes);
void set_uecrid_callback(bool (*callback)(void*, uint64_t), void *arg);
bool get_uecrid_successful();
void process_pdu(uint8_t *pdu, uint32_t nof_bytes);
private:
const static int NOF_HARQ_PID = 8;
const static int MAX_PDU_LEN = 150*1024/8; // ~ 150 Mbps
const static int NOF_BUFFER_PDUS = 64; // Number of PDU buffers per HARQ pid
uint8_t bcch_buffer[1024]; // BCCH PID has a dedicated buffer
bool (*uecrid_callback) (void*, uint64_t);
void *uecrid_callback_arg;
srslte::sch_pdu mac_msg;
srslte::sch_pdu pending_mac_msg;
void process_sch_pdu(srslte::sch_pdu *pdu);
bool process_ce(srslte::sch_subh *subheader);
bool is_uecrid_successful;
phy_interface_mac *phy_h;
srslte::log *log_h;
srslte::timers *timers_db;
rlc_interface_mac *rlc;
// Buffer of PDUs
srslte::pdu_queue pdus;
};
} // namespace srsue
#endif // DEMUX_H

120
srsue/hdr/mac/dl_harq.h Normal file
View File

@ -0,0 +1,120 @@
/**
*
* \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 DL_HARQ_H
#define DL_HARQ_H
#include "common/log.h"
#include "common/timers.h"
#include "mac/demux.h"
#include "mac/dl_sps.h"
#include "common/mac_pcap.h"
#include "common/mac_interface.h"
/* Downlink HARQ entity as defined in 5.3.2 of 36.321 */
namespace srsue {
class dl_harq_entity
{
public:
const static uint32_t NOF_HARQ_PROC = 8;
const static uint32_t HARQ_BCCH_PID = NOF_HARQ_PROC;
dl_harq_entity();
bool init(srslte::log *log_h_, mac_interface_rrc::mac_cfg_t *mac_cfg, srslte::timers *timers_, demux *demux_unit);
/***************** PHY->MAC interface for DL processes **************************/
void new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_dl_t *action);
void tb_decoded(bool ack, srslte_rnti_type_t rnti_type, uint32_t harq_pid);
void reset();
void start_pcap(srslte::mac_pcap* pcap);
int get_current_tbs(uint32_t harq_pid);
void set_si_window_start(int si_window_start);
float get_average_retx();
private:
class dl_harq_process {
public:
dl_harq_process();
bool init(uint32_t pid, dl_harq_entity *parent);
void reset();
bool is_sps();
void new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_dl_t *action);
void tb_decoded(bool ack);
int get_current_tbs();
private:
bool calc_is_new_transmission(mac_interface_phy::mac_grant_t grant);
bool is_initiated;
dl_harq_entity *harq_entity;
srslte::log *log_h;
bool is_new_transmission;
uint32_t pid;
uint8_t *payload_buffer_ptr;
bool ack;
uint32_t n_retx;
mac_interface_phy::mac_grant_t cur_grant;
srslte_softbuffer_rx_t softbuffer;
};
static bool generate_ack_callback(void *arg);
uint32_t get_harq_sps_pid(uint32_t tti);
dl_sps dl_sps_assig;
dl_harq_process proc[NOF_HARQ_PROC+1];
srslte::timers *timers_db;
mac_interface_rrc::mac_cfg_t *mac_cfg;
demux *demux_unit;
srslte::log *log_h;
srslte::mac_pcap *pcap;
uint16_t last_temporal_crnti;
int si_window_start;
float average_retx;
uint64_t nof_pkts;
};
} // namespace srsue
#endif // DL_HARQ_H

54
srsue/hdr/mac/dl_sps.h Normal file
View File

@ -0,0 +1,54 @@
/**
*
* \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 DL_SPS_H
#define DL_SPS_H
#include "common/mac_interface.h"
#include "common/log.h"
#include "common/timers.h"
/* Downlink Semi-Persistent schedulign (Section 5.10.1) */
namespace srsue {
class dl_sps
{
public:
void clear() {}
void reset() {}
bool get_pending_grant(uint32_t tti, mac_interface_phy::mac_grant_t *grant) {
return false;
}
private:
};
} // namespace srsue
#endif // DL_SPS_H

208
srsue/hdr/mac/mac.h Normal file
View File

@ -0,0 +1,208 @@
/**
*
* \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 MAC_H
#define MAC_H
#include "common/log.h"
#include "mac/dl_harq.h"
#include "mac/ul_harq.h"
#include "common/timers.h"
#include "mac/mac_metrics.h"
#include "mac/proc_ra.h"
#include "mac/proc_sr.h"
#include "mac/proc_bsr.h"
#include "mac/proc_phr.h"
#include "mac/mux.h"
#include "mac/demux.h"
#include "common/mac_pcap.h"
#include "common/phy_interface.h"
#include "common/mac_interface.h"
#include "common/tti_sync_cv.h"
#include "common/threads.h"
namespace srsue {
class mac
:public mac_interface_phy
,public mac_interface_rrc
,public srslte::mac_interface_timers
,public thread
,public srslte::timer_callback
{
public:
mac();
bool init(phy_interface_mac *phy, rlc_interface_mac *rlc, rrc_interface_mac* rrc, srslte::log *log_h);
void stop();
void get_metrics(mac_metrics_t &m);
/******** Interface from PHY (PHY -> MAC) ****************/
/* see mac_interface.h for comments */
void new_grant_ul(mac_grant_t grant, tb_action_ul_t *action);
void new_grant_ul_ack(mac_grant_t grant, bool ack, tb_action_ul_t *action);
void harq_recv(uint32_t tti, bool ack, tb_action_ul_t *action);
void new_grant_dl(mac_grant_t grant, tb_action_dl_t *action);
void tb_decoded(bool ack, srslte_rnti_type_t rnti_type, uint32_t harq_pid);
void bch_decoded_ok(uint8_t *payload, uint32_t len);
void pch_decoded_ok(uint32_t len);
void tti_clock(uint32_t tti);
/******** Interface from RLC (RLC -> MAC) ****************/
void bcch_start_rx();
void bcch_stop_rx();
void bcch_start_rx(int si_window_start, int si_window_length);
void pcch_start_rx();
void pcch_stop_rx();
void setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD);
void reconfiguration();
void reset();
/******** set/get MAC configuration ****************/
void set_config(mac_cfg_t *mac_cfg);
void get_config(mac_cfg_t *mac_cfg);
void set_config_main(LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT *main_cfg);
void set_config_rach(LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT *rach_cfg, uint32_t prach_config_index);
void set_config_sr(LIBLTE_RRC_SCHEDULING_REQUEST_CONFIG_STRUCT *sr_cfg);
void set_contention_id(uint64_t uecri);
void get_rntis(ue_rnti_t *rntis);
void timer_expired(uint32_t timer_id);
void start_pcap(srslte::mac_pcap* pcap);
srslte::timers::timer* get(uint32_t timer_id);
u_int32_t get_unique_id();
uint32_t get_current_tti();
enum {
HARQ_RTT,
TIME_ALIGNMENT,
CONTENTION_TIMER,
BSR_TIMER_PERIODIC,
BSR_TIMER_RETX,
PHR_TIMER_PERIODIC,
PHR_TIMER_PROHIBIT,
NOF_MAC_TIMERS
} mac_timers_t;
static const int MAC_NOF_UPPER_TIMERS = 20;
private:
void run_thread();
static const int MAC_MAIN_THREAD_PRIO = 5;
static const int MAC_PDU_THREAD_PRIO = 6;
// Interaction with PHY
srslte::tti_sync_cv ttisync;
phy_interface_mac *phy_h;
rlc_interface_mac *rlc_h;
rrc_interface_mac *rrc_h;
srslte::log *log_h;
// MAC configuration
mac_cfg_t config;
// UE-specific RNTIs
ue_rnti_t uernti;
uint32_t tti;
bool started;
bool is_synchronized;
uint16_t last_temporal_crnti;
uint16_t phy_rnti;
/* Multiplexing/Demultiplexing Units */
mux mux_unit;
demux demux_unit;
/* DL/UL HARQ */
dl_harq_entity dl_harq;
ul_harq_entity ul_harq;
/* MAC Uplink-related Procedures */
ra_proc ra_procedure;
sr_proc sr_procedure;
bsr_proc bsr_procedure;
phr_proc phr_procedure;
/* Buffers for PCH reception (not included in DL HARQ) */
const static uint32_t pch_payload_buffer_sz = 8*1024;
srslte_softbuffer_rx_t pch_softbuffer;
uint8_t pch_payload_buffer[pch_payload_buffer_sz];
/* Functions for MAC Timers */
srslte::timers timers_db;
void setup_timers();
void timeAlignmentTimerExpire();
// pointer to MAC PCAP object
srslte::mac_pcap* pcap;
bool signals_pregenerated;
bool is_first_ul_grant;
mac_metrics_t metrics;
/* Class to run upper-layer timers with normal priority */
class upper_timers : public periodic_thread {
public:
upper_timers();
void reset();
srslte::timers::timer* get(uint32_t timer_id);
uint32_t get_unique_id();
private:
void run_period();
srslte::timers timers_db;
};
upper_timers upper_timers_thread;
/* Class to process MAC PDUs from DEMUX unit */
class pdu_process : public thread {
public:
pdu_process(demux *demux_unit);
void notify();
void stop();
private:
void run_thread();
bool running;
bool have_data;
pthread_mutex_t mutex;
pthread_cond_t cvar;
demux* demux_unit;
};
pdu_process pdu_process_thread;
};
} // namespace srsue
#endif // MAC_H

View File

@ -0,0 +1,46 @@
/**
*
* \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 UE_MAC_METRICS_H
#define UE_MAC_METRICS_H
namespace srsue {
struct mac_metrics_t
{
int tx_pkts;
int tx_errors;
int tx_brate;
int rx_pkts;
int rx_errors;
int rx_brate;
int ul_buffer;
};
} // namespace srsue
#endif // UE_MAC_METRICS_H

116
srsue/hdr/mac/mux.h Normal file
View File

@ -0,0 +1,116 @@
/**
*
* \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 MUX_H
#define MUX_H
#include <pthread.h>
#include <vector>
#include "common/log.h"
#include "common/mac_interface.h"
#include "common/pdu.h"
#include "mac/proc_bsr.h"
#include "mac/proc_phr.h"
/* Logical Channel Multiplexing and Prioritization + Msg3 Buffer */
typedef struct {
int id;
int Bj;
int PBR; // -1 sets to infinity
uint32_t BSD;
uint32_t priority;
int sched_len;
int buffer_len;
} lchid_t;
namespace srsue {
class mux
{
public:
mux();
void reset();
void init(rlc_interface_mac *rlc, srslte::log *log_h, bsr_proc *bsr_procedure, phr_proc *phr_procedure_);
bool is_pending_any_sdu();
bool is_pending_sdu(uint32_t lcid);
uint8_t* pdu_get(uint8_t *payload, uint32_t pdu_sz, uint32_t tx_tti, uint32_t pid);
uint8_t* msg3_get(uint8_t* payload, uint32_t pdu_sz);
void msg3_flush();
bool msg3_is_transmitted();
void append_crnti_ce_next_tx(uint16_t crnti);
void set_priority(uint32_t lcid, uint32_t priority, int PBR_x_tti, uint32_t BSD);
void clear_lch(uint32_t lch_id);
void pusch_retx(uint32_t tx_tti, uint32_t pid);
private:
int find_lchid(uint32_t lch_id);
bool pdu_move_to_msg3(uint32_t pdu_sz);
bool allocate_sdu(uint32_t lcid, srslte::sch_pdu *pdu, int max_sdu_sz);
bool sched_sdu(lchid_t *ch, int *sdu_space, int max_sdu_sz);
const static int MIN_RLC_SDU_LEN = 0;
const static int MAX_NOF_SUBHEADERS = 20;
const static int MAX_HARQ_PROC = 8;
std::vector<lchid_t> lch;
// Keep track of the PIDs that transmitted BSR reports
bool pid_has_bsr[MAX_HARQ_PROC];
// Mutex for exclusive access
pthread_mutex_t mutex;
srslte::log *log_h;
rlc_interface_mac *rlc;
bsr_proc *bsr_procedure;
phr_proc *phr_procedure;
uint16_t pending_crnti_ce;
/* Msg3 Buffer */
static const uint32_t MSG3_BUFF_SZ = 128;
uint8_t msg3_buff[MSG3_BUFF_SZ];
/* PDU Buffer */
srslte::sch_pdu pdu_msg;
bool msg3_has_been_transmitted;
};
} // namespace srsue
#endif // MUX_H

59
srsue/hdr/mac/proc.h Normal file
View File

@ -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 PROC_H
#define PROC_H
#include <stdint.h>
/* Interface for a MAC procedure */
namespace srsue {
class proc
{
public:
proc() {
running = false;
}
void run() {
running = true;
}
void stop() {
running = false;
}
bool is_running() {
return running;
}
virtual void step(uint32_t tti) = 0;
private:
bool running;
};
} // namespace srsue
#endif // PROC_H

101
srsue/hdr/mac/proc_bsr.h Normal file
View File

@ -0,0 +1,101 @@
/**
*
* \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 PROCBSR_H
#define PROCBSR_H
#include <stdint.h>
#include "common/log.h"
#include "common/mac_interface.h"
#include "common/interfaces.h"
#include "common/timers.h"
/* Buffer status report procedure */
namespace srsue {
class bsr_proc : public srslte::timer_callback
{
public:
bsr_proc();
void init(rlc_interface_mac *rlc, srslte::log *log_h, mac_interface_rrc::mac_cfg_t *mac_cfg, srslte::timers *timers_db);
void step(uint32_t tti);
void reset();
void setup_lcg(uint32_t lcid, uint32_t new_lcg);
void set_priority(uint32_t lcid, uint32_t priority);
void timer_expired(uint32_t timer_id);
uint32_t get_buffer_state();
typedef enum {
LONG_BSR,
SHORT_BSR,
TRUNC_BSR
} bsr_format_t;
typedef struct {
bsr_format_t format;
uint32_t buff_size[4];
} bsr_t;
bool need_to_send_bsr_on_ul_grant(uint32_t grant_size, bsr_t *bsr);
bool generate_padding_bsr(uint32_t nof_padding_bytes, bsr_t *bsr);
bool need_to_send_sr(uint32_t tti);
bool need_to_reset_sr();
void set_tx_tti(uint32_t tti);
private:
const static int QUEUE_STATUS_PERIOD_MS = 500;
bool reset_sr;
mac_interface_rrc::mac_cfg_t *mac_cfg;
srslte::timers *timers_db;
srslte::log *log_h;
rlc_interface_mac *rlc;
bool initiated;
const static int MAX_LCID = 6;
int lcg[MAX_LCID];
uint32_t last_pending_data[MAX_LCID];
int priorities[MAX_LCID];
uint32_t find_max_priority_lcid();
typedef enum {NONE, REGULAR, PADDING, PERIODIC} triggered_bsr_type_t;
triggered_bsr_type_t triggered_bsr_type;
bool sr_is_sent;
uint32_t last_print;
uint32_t next_tx_tti;
void update_pending_data();
bool check_highest_channel();
bool check_single_channel();
bool generate_bsr(bsr_t *bsr, uint32_t nof_padding_bytes);
char* bsr_type_tostring(triggered_bsr_type_t type);
char* bsr_format_tostring(bsr_format_t format);
};
} // namespace srsue
#endif // PROCBSR_H

72
srsue/hdr/mac/proc_phr.h Normal file
View File

@ -0,0 +1,72 @@
/**
*
* \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 PROCPHR_H
#define PROCPHR_H
#include <stdint.h>
#include "common/timers.h"
#include "common/phy_interface.h"
#include "common/log.h"
#include "common/mac_interface.h"
/* Power headroom report procedure */
namespace srsue {
class phr_proc : public srslte::timer_callback
{
public:
phr_proc();
void init(phy_interface_mac* phy_h, srslte::log* log_h_, mac_interface_rrc::mac_cfg_t *mac_cfg, srslte::timers *timers_db_);
void step(uint32_t tti);
void reset();
bool generate_phr_on_ul_grant(float *phr);
void timer_expired(uint32_t timer_id);
private:
bool pathloss_changed();
srslte::log* log_h;
mac_interface_rrc::mac_cfg_t *mac_cfg;
phy_interface_mac* phy_h;
srslte::timers* timers_db;
bool initiated;
int timer_prohibit;
int timer_periodic;
int dl_pathloss_change;
int last_pathloss_db;
bool phr_is_triggered;
};
} // namespace srsue
#endif // PROCPHR_H

201
srsue/hdr/mac/proc_ra.h Normal file
View File

@ -0,0 +1,201 @@
/**
*
* \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 PROCRA_H
#define PROCRA_H
#include <stdint.h>
#include "common/log.h"
#include "common/timers.h"
#include "mac/mux.h"
#include "mac/demux.h"
#include "common/pdu.h"
#include "common/mac_pcap.h"
/* Random access procedure as specified in Section 5.1 of 36.321 */
namespace srsue {
class ra_proc : public srslte::timer_callback
{
public:
ra_proc() : rar_pdu_msg(20) {
bzero(&softbuffer_rar, sizeof(srslte_softbuffer_rx_t));
pcap = NULL;
backoff_interval_start = 0;
backoff_inteval = 0;
received_target_power_dbm = 0;
ra_rnti = 0;
current_ta = 0;
state = IDLE;
last_msg3_group = RA_GROUP_A;
msg3_transmitted = false;
first_rar_received = false;
phy_h = NULL;
log_h = NULL;
mac_cfg = NULL;
timers_db = NULL;
mux_unit = NULL;
demux_unit = NULL;
rrc = NULL;
transmitted_contention_id = 0;
transmitted_crnti = 0;
pdcch_to_crnti_received = PDCCH_CRNTI_NOT_RECEIVED;
started_by_pdcch = false;
rar_grant_nbytes = 0;
rar_grant_tti = 0;
msg3_flushed = false;
};
void init(phy_interface_mac *phy_h,
rrc_interface_mac *rrc_,
srslte::log *log_h,
mac_interface_rrc::ue_rnti_t *rntis,
mac_interface_rrc::mac_cfg_t *mac_cfg,
srslte::timers *timers_db,
mux *mux_unit,
demux *demux_unit);
void reset();
void start_pdcch_order();
void start_mac_order(uint32_t msg_len_bits = 56);
void step(uint32_t tti);
bool is_successful();
bool is_response_error();
bool is_contention_resolution();
void harq_retx();
bool is_error();
bool in_progress();
void pdcch_to_crnti(bool contains_uplink_grant);
void timer_expired(uint32_t timer_id);
void new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_dl_t* action);
void tb_decoded_ok();
void start_pcap(srslte::mac_pcap* pcap);
private:
static bool uecrid_callback(void *arg, uint64_t uecri);
bool contention_resolution_id_received(uint64_t uecri);
void process_timeadv_cmd(uint32_t ta_cmd);
void step_initialization();
void step_resource_selection();
void step_preamble_transmission();
void step_pdcch_setup();
void step_response_reception();
void step_response_error();
void step_backoff_wait();
void step_contention_resolution();
void step_completition();
// Buffer to receive RAR PDU
static const uint32_t MAX_RAR_PDU_LEN = 2048;
uint8_t rar_pdu_buffer[MAX_RAR_PDU_LEN];
srslte::rar_pdu rar_pdu_msg;
// Random Access parameters provided by higher layers defined in 5.1.1
uint32_t configIndex;
uint32_t nof_preambles;
uint32_t nof_groupA_preambles;
uint32_t nof_groupB_preambles;
uint32_t messagePowerOffsetGroupB;
uint32_t messageSizeGroupA;
uint32_t responseWindowSize;
uint32_t powerRampingStep;
uint32_t preambleTransMax;
uint32_t iniReceivedTargetPower;
int delta_preamble_db;
uint32_t contentionResolutionTimer;
uint32_t maskIndex;
int preambleIndex;
uint32_t new_ra_msg_len;
// Internal variables
uint32_t preambleTransmissionCounter;
uint32_t backoff_param_ms;
uint32_t sel_maskIndex;
uint32_t sel_preamble;
uint32_t backoff_interval_start;
uint32_t backoff_inteval;
int received_target_power_dbm;
uint32_t ra_rnti;
uint32_t current_ta;
srslte_softbuffer_rx_t softbuffer_rar;
enum {
IDLE = 0,
INITIALIZATION, // Section 5.1.1
RESOURCE_SELECTION, // Section 5.1.2
PREAMBLE_TRANSMISSION, // Section 5.1.3
PDCCH_SETUP,
RESPONSE_RECEPTION, // Section 5.1.4
RESPONSE_ERROR,
BACKOFF_WAIT,
CONTENTION_RESOLUTION, // Section 5.1.5
COMPLETION, // Section 5.1.6
COMPLETION_DONE,
RA_PROBLEM // Section 5.1.5 last part
} state;
typedef enum {RA_GROUP_A, RA_GROUP_B} ra_group_t;
ra_group_t last_msg3_group;
bool msg3_transmitted;
bool first_rar_received;
void read_params();
phy_interface_mac *phy_h;
srslte::log *log_h;
srslte::timers *timers_db;
mux *mux_unit;
demux *demux_unit;
srslte::mac_pcap *pcap;
rrc_interface_mac *rrc;
mac_interface_rrc::ue_rnti_t *rntis;
mac_interface_rrc::mac_cfg_t *mac_cfg;
uint64_t transmitted_contention_id;
uint16_t transmitted_crnti;
enum {
PDCCH_CRNTI_NOT_RECEIVED = 0,
PDCCH_CRNTI_UL_GRANT,
PDCCH_CRNTI_DL_GRANT
} pdcch_to_crnti_received;
bool started_by_pdcch;
uint32_t rar_grant_nbytes;
uint32_t rar_grant_tti;
bool msg3_flushed;
bool rar_received;
};
} // namespace srsue
#endif // PROCRA_H

68
srsue/hdr/mac/proc_sr.h Normal file
View File

@ -0,0 +1,68 @@
/**
*
* \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 PROCSR_H
#define PROCSR_H
#include <stdint.h>
#include "common/phy_interface.h"
#include "common/interfaces.h"
#include "common/log.h"
/* Scheduling Request procedure as defined in 5.4.4 of 36.321 */
namespace srsue {
class sr_proc
{
public:
sr_proc();
void init(phy_interface_mac *phy_h, rrc_interface_mac *rrc, srslte::log *log_h, mac_interface_rrc::mac_cfg_t *mac_cfg);
void step(uint32_t tti);
void reset();
void start();
bool need_random_access();
private:
bool need_tx(uint32_t tti);
uint32_t sr_counter;
uint32_t dsr_transmax;
bool is_pending_sr;
mac_interface_rrc::mac_cfg_t *mac_cfg;
rrc_interface_mac *rrc;
phy_interface_mac *phy_h;
srslte::log *log_h;
bool initiated;
bool do_ra;
};
} // namespace srsue
#endif // PROCSR_H

150
srsue/hdr/mac/ul_harq.h Normal file
View File

@ -0,0 +1,150 @@
/**
*
* \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 ULHARQ_H
#define ULHARQ_H
#include "common/mac_interface.h"
#include "common/log.h"
#include "mac/mux.h"
#include "mac/ul_sps.h"
#include "common/mac_pcap.h"
#include "common/timers.h"
/* Uplink HARQ entity as defined in 5.4.2 of 36.321 */
namespace srsue {
class ul_harq_entity
{
public:
const static uint32_t NOF_HARQ_PROC = 8;
static uint32_t pidof(uint32_t tti);
ul_harq_entity() {
pcap = NULL;
timers_db = NULL;
mux_unit = NULL;
log_h = NULL;
mac_cfg = NULL;
rntis = NULL;
average_retx = 0;
nof_pkts = 0;
}
bool init(srslte::log *log_h,
mac_interface_rrc::ue_rnti_t *rntis,
mac_interface_rrc::mac_cfg_t *mac_cfg,
srslte::timers* timers_,
mux *mux_unit);
void reset();
void reset_ndi();
void start_pcap(srslte::mac_pcap* pcap);
/***************** PHY->MAC interface for UL processes **************************/
void new_grant_ul(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_ul_t *action);
void new_grant_ul_ack(mac_interface_phy::mac_grant_t grant, bool ack, mac_interface_phy::tb_action_ul_t *action);
void harq_recv(uint32_t tti, bool ack, mac_interface_phy::tb_action_ul_t *action);
int get_current_tbs(uint32_t tti);
float get_average_retx();
private:
class ul_harq_process {
public:
ul_harq_process();
bool init(uint32_t pid, ul_harq_entity *parent);
void reset();
void reset_ndi();
void run_tti(uint32_t tti, mac_interface_phy::mac_grant_t *grant, mac_interface_phy::tb_action_ul_t* action);
uint32_t get_rv();
bool has_grant();
void set_harq_feedback(bool ack);
bool get_ndi();
bool is_sps();
uint32_t last_tx_tti();
uint32_t get_nof_retx();
int get_current_tbs();
private:
mac_interface_phy::mac_grant_t cur_grant;
uint32_t pid;
uint32_t current_tx_nb;
uint32_t current_irv;
bool harq_feedback;
bool ndi;
srslte::log *log_h;
ul_harq_entity *harq_entity;
bool is_grant_configured;
srslte_softbuffer_tx_t softbuffer;
bool is_msg3;
bool is_initiated;
uint32_t tti_last_tx;
const static int payload_buffer_len = 128*1024;
uint8_t *payload_buffer;
uint8_t *pdu_ptr;
void generate_retx(uint32_t tti_tx, mac_interface_phy::tb_action_ul_t *action);
void generate_retx(uint32_t tti_tx, mac_interface_phy::mac_grant_t *grant,
mac_interface_phy::tb_action_ul_t *action);
void generate_new_tx(uint32_t tti_tx, bool is_msg3, mac_interface_phy::mac_grant_t *grant,
mac_interface_phy::tb_action_ul_t *action);
void generate_tx(uint32_t tti_tx, mac_interface_phy::tb_action_ul_t *action);
};
void run_tti(uint32_t tti, mac_interface_phy::mac_grant_t *grant, mac_interface_phy::tb_action_ul_t* action);
void set_ack(uint32_t tti, bool ack);
ul_sps ul_sps_assig;
srslte::timers *timers_db;
mux *mux_unit;
ul_harq_process proc[NOF_HARQ_PROC];
srslte::log *log_h;
srslte::mac_pcap *pcap;
mac_interface_rrc::ue_rnti_t *rntis;
mac_interface_rrc::mac_cfg_t *mac_cfg;
float average_retx;
uint64_t nof_pkts;
};
} // namespace srsue
#endif // ULHARQ_H

53
srsue/hdr/mac/ul_sps.h Normal file
View File

@ -0,0 +1,53 @@
/**
*
* \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 ULSPS_H
#define ULSPS_H
#include "common/log.h"
#include "common/timers.h"
/* Uplink Semi-Persistent schedulign (Section 5.10.2) */
namespace srsue {
typedef _Complex float cf_t;
class ul_sps
{
public:
void clear() {}
void reset(uint32_t tti) {}
bool get_pending_grant(uint32_t tti, mac_interface_phy::mac_grant_t *grant) { return false; }
private:
};
} // namespace srsue
#endif // ULSPS_H

View File

@ -0,0 +1,73 @@
/**
*
* \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: metrics_stdout.h
* Description: Metrics class printing to stdout.
*****************************************************************************/
#ifndef METRICS_STDOUT_H
#define METRICS_STDOUT_H
#include <pthread.h>
#include <stdint.h>
#include <string>
#include "ue_metrics_interface.h"
namespace srsue {
class metrics_stdout
{
public:
metrics_stdout();
bool init(ue_metrics_interface *u, float report_period_secs=1.0);
void stop();
void toggle_print(bool b);
static void* metrics_thread_start(void *m);
void metrics_thread_run();
private:
void print_metrics();
void print_disconnect();
std::string float_to_string(float f, int digits);
std::string float_to_eng_string(float f, int digits);
std::string int_to_eng_string(int f, int digits);
ue_metrics_interface *ue_;
bool started;
bool do_print;
pthread_t metrics_thread;
ue_metrics_t metrics;
float metrics_report_period; // seconds
uint8_t n_reports;
};
} // namespace srsue
#endif // METRICS_STDOUT_H

165
srsue/hdr/phy/nbiot_phy.h Normal file
View File

@ -0,0 +1,165 @@
/**
*
* \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 UEPHY_H
#define UEPHY_H
#include "srslte/srslte.h"
#include "common/phy_interface.h"
#include "common/log.h"
#include "phy/phy_metrics.h"
#include "phy/phch_recv.h"
#include "phy/prach.h"
#include "phy/phch_worker.h"
#include "phy/phch_common.h"
#include "radio/radio.h"
#include "common/task_dispatcher.h"
#include "common/trace.h"
#include "common/mac_interface.h"
#include "common/interfaces.h"
namespace srsue {
typedef _Complex float cf_t;
class phy
: public phy_interface_mac
, public phy_interface_rrc
{
public:
phy();
bool init(srslte::radio *radio_handler,
mac_interface_phy *mac,
rrc_interface_phy *rrc,
srslte::log *log_h,
phy_args_t *args = NULL);
void stop();
void set_agc_enable(bool enabled);
void get_metrics(phy_metrics_t &m);
void set_crnti(uint16_t rnti);
static uint32_t tti_to_SFN(uint32_t tti);
static uint32_t tti_to_subf(uint32_t tti);
void enable_pregen_signals(bool enable);
void start_trace();
void write_trace(std::string filename);
/********** RRC INTERFACE ********************/
void reset();
bool status_is_sync();
void configure_ul_params(bool pregen_disabled = false);
void resync_sfn();
/********** MAC INTERFACE ********************/
/* Functions to synchronize with a cell */
void sync_start();
void sync_stop();
/* Instructs the PHY to configure using the parameters written by set_param() */
void configure_prach_params();
/* Transmits PRACH in the next opportunity */
void prach_send(uint32_t preamble_idx, int allowed_subframe = -1, float target_power_dbm = 0.0);
int prach_tx_tti();
/* Indicates the transmission of a SR signal in the next opportunity */
void sr_send();
int sr_last_tx_tti();
// Time advance commands
void set_timeadv_rar(uint32_t ta_cmd);
void set_timeadv(uint32_t ta_cmd);
/* Sets RAR grant payload */
void set_rar_grant(uint32_t tti, uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN]);
/* Instruct the PHY to decode PDCCH with the CRC scrambled with given RNTI */
void pdcch_ul_search(srslte_rnti_type_t rnti_type, uint16_t rnti, int tti_start = -1, int tti_end = -1);
void pdcch_dl_search(srslte_rnti_type_t rnti_type, uint16_t rnti, int tti_start = -1, int tti_end = -1);
void pdcch_ul_search_reset();
void pdcch_dl_search_reset();
/* Get/Set PHY parameters interface from RRC */
void get_config(phy_cfg_t *phy_cfg);
void set_config(phy_cfg_t *phy_cfg);
void set_config_dedicated(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *dedicated);
void set_config_common(phy_cfg_common_t *common);
void set_config_tdd(LIBLTE_RRC_TDD_CONFIG_STRUCT *tdd);
void set_config_64qam_en(bool enable);
float get_phr();
float get_pathloss_db();
uint32_t get_current_tti();
void get_current_cell(srslte_cell_t *cell);
void start_plot();
void start_channel_emulator(const char *filename, int *path_taps, int nof_paths, int nof_coeffs, int nof_samples, int nof_tti);
private:
uint32_t nof_workers;
const static int MAX_WORKERS = 4;
const static int DEFAULT_WORKERS = 2;
const static int SF_RECV_THREAD_PRIO = 1;
const static int WORKERS_THREAD_PRIO = 0;
srslte::radio *radio_handler;
srslte::log *log_h;
srslte::thread_pool workers_pool;
std::vector<phch_worker> workers;
phch_common workers_common;
phch_recv sf_recv;
prach prach_buffer;
srslte_cell_t cell;
phy_cfg_t config;
phy_args_t *args;
/* Current time advance */
uint32_t n_ta;
bool init_(srslte::radio *radio_handler, mac_interface_phy *mac, srslte::log *log_h, bool do_agc, uint32_t nof_workers);
void set_default_args(phy_args_t *args);
bool check_args(phy_args_t *args);
};
} // namespace srsue
#endif // UEPHY_H

162
srsue/hdr/phy/phch_common.h Normal file
View File

@ -0,0 +1,162 @@
/**
*
* \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 UEPHYWORKERCOMMON_H
#define UEPHYWORKERCOMMON_H
#include <pthread.h>
#include <string.h>
#include <vector>
#include "srslte/srslte.h"
#include "common/mac_interface.h"
#include "common/phy_interface.h"
#include "radio/radio.h"
#include "common/log.h"
#include "phy/phy_metrics.h"
//#define CONTINUOUS_TX
namespace srsue {
/* Subclass that manages variables common to all workers */
class phch_common {
public:
/* Common variables used by all phy workers */
phy_interface_rrc::phy_cfg_t *config;
phy_args_t *args;
srslte::log *log_h;
mac_interface_phy *mac;
srslte_ue_ul_t ue_ul;
/* Power control variables */
float pathloss;
float cur_pathloss;
float p0_preamble;
float cur_radio_power;
float cur_pusch_power;
float avg_rsrp_db;
float avg_rsrq_db;
float rx_gain_offset;
float avg_snr_db;
float avg_noise;
float avg_rsrp;
phch_common(uint32_t max_mutex = 3);
void init(phy_interface_rrc::phy_cfg_t *config,
phy_args_t *args,
srslte::log *_log,
srslte::radio *_radio,
mac_interface_phy *_mac);
/* For RNTI searches, -1 means now or forever */
void set_ul_rnti(srslte_rnti_type_t type, uint16_t rnti_value, int tti_start = -1, int tti_end = -1);
uint16_t get_ul_rnti(uint32_t tti);
srslte_rnti_type_t get_ul_rnti_type();
void set_dl_rnti(srslte_rnti_type_t type, uint16_t rnti_value, int tti_start = -1, int tti_end = -1);
uint16_t get_dl_rnti(uint32_t tti);
srslte_rnti_type_t get_dl_rnti_type();
void set_rar_grant(uint32_t tti, uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN]);
bool get_pending_rar(uint32_t tti, srslte_dci_rar_grant_t *rar_grant = NULL);
void reset_pending_ack(uint32_t tti);
void set_pending_ack(uint32_t tti, uint32_t I_lowest, uint32_t n_dmrs);
bool get_pending_ack(uint32_t tti);
bool get_pending_ack(uint32_t tti, uint32_t *I_lowest, uint32_t *n_dmrs);
void worker_end(uint32_t tti, bool tx_enable, cf_t *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time);
void set_nof_mutex(uint32_t nof_mutex);
bool sr_enabled;
int sr_last_tx_tti;
srslte::radio* get_radio();
void set_cell(const srslte_cell_t &c);
uint32_t get_nof_prb();
void set_dl_metrics(const dl_metrics_t &m);
void get_dl_metrics(dl_metrics_t &m);
void set_ul_metrics(const ul_metrics_t &m);
void get_ul_metrics(ul_metrics_t &m);
void set_sync_metrics(const sync_metrics_t &m);
void get_sync_metrics(sync_metrics_t &m);
void reset_ul();
private:
std::vector<pthread_mutex_t> tx_mutex;
bool is_first_of_burst;
srslte::radio *radio_h;
float cfo;
bool ul_rnti_active(uint32_t tti);
bool dl_rnti_active(uint32_t tti);
uint16_t ul_rnti, dl_rnti;
srslte_rnti_type_t ul_rnti_type, dl_rnti_type;
int ul_rnti_start, ul_rnti_end, dl_rnti_start, dl_rnti_end;
float time_adv_sec;
srslte_dci_rar_grant_t rar_grant;
bool rar_grant_pending;
uint32_t rar_grant_tti;
typedef struct {
bool enabled;
uint32_t I_lowest;
uint32_t n_dmrs;
} pending_ack_t;
pending_ack_t pending_ack[10];
bool is_first_tx;
uint32_t nof_workers;
uint32_t nof_mutex;
uint32_t max_mutex;
srslte_cell_t cell;
dl_metrics_t dl_metrics;
uint32_t dl_metrics_count;
bool dl_metrics_read;
ul_metrics_t ul_metrics;
uint32_t ul_metrics_count;
bool ul_metrics_read;
sync_metrics_t sync_metrics;
uint32_t sync_metrics_count;
bool sync_metrics_read;
};
} // namespace srsue
#endif // UEPHYWORKERCOMMON_H

122
srsue/hdr/phy/phch_recv.h Normal file
View File

@ -0,0 +1,122 @@
/**
*
* \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 UEPHYRECV_H
#define UEPHYRECV_H
#include "srslte/srslte.h"
#include "common/log.h"
#include "common/threads.h"
#include "common/thread_pool.h"
#include "radio/radio_multi.h"
#include "phy/prach.h"
#include "phy/phch_worker.h"
#include "phy/phch_common.h"
#include "common/interfaces.h"
namespace srsue {
typedef _Complex float cf_t;
class phch_recv : public thread
{
public:
phch_recv();
void init(srslte::radio_multi* radio_handler, mac_interface_phy *mac,rrc_interface_phy *rrc,
prach *prach_buffer, srslte::thread_pool *_workers_pool,
phch_common *_worker_com, srslte::log* _log_h, uint32_t nof_rx_antennas, uint32_t prio, int sync_cpu_affinity = -1);
void stop();
void set_agc_enable(bool enable);
void resync_sfn();
uint32_t get_current_tti();
void sync_start();
void sync_stop();
bool status_is_sync();
void set_time_adv_sec(float time_adv_sec);
void get_current_cell(srslte_cell_t *cell);
const static int MUTEX_X_WORKER = 4;
private:
void set_ue_sync_opts(srslte_ue_sync_t *q);
void run_thread();
int sync_sfn();
bool running;
srslte::radio_multi *radio_h;
mac_interface_phy *mac;
rrc_interface_phy *rrc;
srslte::log *log_h;
srslte::thread_pool *workers_pool;
phch_common *worker_com;
prach *prach_buffer;
srslte_ue_sync_t ue_sync;
srslte_ue_mib_t ue_mib;
uint32_t nof_rx_antennas;
cf_t *sf_buffer_sfn[SRSLTE_MAX_PORTS];
// Sync metrics
sync_metrics_t metrics;
enum {
IDLE, CELL_SEARCH, SYNCING, SYNC_DONE
} phy_state;
srslte_cell_t cell;
bool cell_is_set;
bool is_sfn_synched;
bool started;
float time_adv_sec;
bool radio_is_streaming;
uint32_t tti;
bool do_agc;
float last_gain;
float cellsearch_cfo;
uint32_t nof_tx_mutex;
uint32_t tx_mutex_cnt;
uint32_t sync_sfn_cnt;
const static uint32_t SYNC_SFN_TIMEOUT = 5000;
float ul_dl_factor;
bool cell_search(int force_N_id_2 = -1);
bool init_cell();
void free_cell();
};
} // namespace srsue
#endif // UEPHYRECV_H

155
srsue/hdr/phy/phch_worker.h Normal file
View File

@ -0,0 +1,155 @@
/**
*
* \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 UEPHYWORKER_H
#define UEPHYWORKER_H
#include <string.h>
#include "srslte/srslte.h"
#include "common/thread_pool.h"
#include "common/phy_interface.h"
#include "common/trace.h"
#include "phy/phch_common.h"
#define LOG_EXECTIME
namespace srsue {
class phch_worker : public srslte::thread_pool::worker
{
public:
phch_worker();
void reset();
void set_common(phch_common *phy);
bool init_cell(srslte_cell_t cell);
void free_cell();
/* Functions used by main PHY thread */
cf_t* get_buffer(uint32_t antenna_idx);
void set_tti(uint32_t tti, uint32_t tx_tti);
void set_tx_time(srslte_timestamp_t tx_time);
void set_cfo(float cfo);
void set_sample_offset(float sample_offset);
void set_ul_params(bool pregen_disabled = false);
void set_crnti(uint16_t rnti);
void enable_pregen_signals(bool enabled);
void start_trace();
void write_trace(std::string filename);
int read_ce_abs(float *ce_abs);
int read_pdsch_d(cf_t *pdsch_d);
void start_plot();
private:
/* Inherited from thread_pool::worker. Function called every subframe to run the DL/UL processing */
void work_imp();
/* Internal methods */
bool extract_fft_and_pdcch_llr();
/* ... for DL */
bool decode_pdcch_ul(mac_interface_phy::mac_grant_t *grant);
bool decode_pdcch_dl(mac_interface_phy::mac_grant_t *grant);
bool decode_phich(bool *ack);
bool decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload, srslte_softbuffer_rx_t* softbuffer, int rv, uint16_t rnti, uint32_t pid);
/* ... for UL */
void encode_pusch(srslte_ra_ul_grant_t *grant, uint8_t *payload, uint32_t current_tx_nb, srslte_softbuffer_tx_t *softbuffer,
uint32_t rv, uint16_t rnti, bool is_from_rar);
void encode_pucch();
void encode_srs();
void reset_uci();
void set_uci_sr();
void set_uci_periodic_cqi();
void set_uci_aperiodic_cqi();
void set_uci_ack(bool ack);
bool srs_is_ready_to_send();
float set_power(float tx_power);
void setup_tx_gain();
void update_measurements();
void tr_log_start();
void tr_log_end();
struct timeval tr_time[3];
srslte::trace<uint32_t> tr_exec;
bool trace_enabled;
/* Common objects */
phch_common *phy;
srslte_cell_t cell;
bool cell_initiated;
cf_t *signal_buffer[SRSLTE_MAX_PORTS];
uint32_t tti;
uint32_t tx_tti;
bool pregen_enabled;
uint32_t last_dl_pdcch_ncce;
bool rnti_is_set;
/* Objects for DL */
srslte_ue_dl_t ue_dl;
uint32_t cfi;
uint16_t dl_rnti;
/* Objects for UL */
srslte_ue_ul_t ue_ul;
srslte_timestamp_t tx_time;
srslte_uci_data_t uci_data;
uint16_t ul_rnti;
// UL configuration parameters
srslte_refsignal_srs_cfg_t srs_cfg;
srslte_pucch_cfg_t pucch_cfg;
srslte_refsignal_dmrs_pusch_cfg_t dmrs_cfg;
srslte_pusch_hopping_cfg_t pusch_hopping;
srslte_pucch_sched_t pucch_sched;
srslte_uci_cfg_t uci_cfg;
srslte_cqi_periodic_cfg_t period_cqi;
srslte_ue_ul_powerctrl_t power_ctrl;
uint32_t I_sr;
float cfo;
bool rar_cqi_request;
// Metrics
dl_metrics_t dl_metrics;
ul_metrics_t ul_metrics;
#ifdef LOG_EXECTIME
struct timeval logtime_start[3];
bool chest_done;
#endif
};
} // namespace srsue
#endif // UEPHYWORKER_H

167
srsue/hdr/phy/phy.h Normal file
View File

@ -0,0 +1,167 @@
/**
*
* \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 UEPHY_H
#define UEPHY_H
#include "srslte/srslte.h"
#include "common/phy_interface.h"
#include "common/log.h"
#include "phy/phy_metrics.h"
#include "phy/phch_recv.h"
#include "phy/prach.h"
#include "phy/phch_worker.h"
#include "phy/phch_common.h"
#include "radio/radio.h"
#include "common/task_dispatcher.h"
#include "common/trace.h"
#include "common/mac_interface.h"
#include "common/interfaces.h"
namespace srsue {
typedef _Complex float cf_t;
class phy
: public phy_interface_mac
, public phy_interface_rrc
{
public:
phy();
bool init(srslte::radio_multi *radio_handler,
mac_interface_phy *mac,
rrc_interface_phy *rrc,
srslte::log *log_h,
phy_args_t *args = NULL);
void stop();
void set_agc_enable(bool enabled);
void get_metrics(phy_metrics_t &m);
static uint32_t tti_to_SFN(uint32_t tti);
static uint32_t tti_to_subf(uint32_t tti);
void enable_pregen_signals(bool enable);
void start_trace();
void write_trace(std::string filename);
/********** RRC INTERFACE ********************/
void reset();
bool status_is_sync();
void configure_ul_params(bool pregen_disabled = false);
void resync_sfn();
/********** MAC INTERFACE ********************/
/* Functions to synchronize with a cell */
void sync_start();
void sync_stop();
/* Sets a C-RNTI allowing the PHY to pregenerate signals if necessary */
void set_crnti(uint16_t rnti);
/* Instructs the PHY to configure using the parameters written by set_param() */
void configure_prach_params();
/* Transmits PRACH in the next opportunity */
void prach_send(uint32_t preamble_idx, int allowed_subframe = -1, float target_power_dbm = 0.0);
int prach_tx_tti();
/* Indicates the transmission of a SR signal in the next opportunity */
void sr_send();
int sr_last_tx_tti();
// Time advance commands
void set_timeadv_rar(uint32_t ta_cmd);
void set_timeadv(uint32_t ta_cmd);
/* Sets RAR grant payload */
void set_rar_grant(uint32_t tti, uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN]);
/* Instruct the PHY to decode PDCCH with the CRC scrambled with given RNTI */
void pdcch_ul_search(srslte_rnti_type_t rnti_type, uint16_t rnti, int tti_start = -1, int tti_end = -1);
void pdcch_dl_search(srslte_rnti_type_t rnti_type, uint16_t rnti, int tti_start = -1, int tti_end = -1);
void pdcch_ul_search_reset();
void pdcch_dl_search_reset();
/* Get/Set PHY parameters interface from RRC */
void get_config(phy_cfg_t *phy_cfg);
void set_config(phy_cfg_t *phy_cfg);
void set_config_dedicated(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *dedicated);
void set_config_common(phy_cfg_common_t *common);
void set_config_tdd(LIBLTE_RRC_TDD_CONFIG_STRUCT *tdd);
void set_config_64qam_en(bool enable);
float get_phr();
float get_pathloss_db();
uint32_t get_current_tti();
void get_current_cell(srslte_cell_t *cell);
void start_plot();
private:
uint32_t nof_workers;
const static int MAX_WORKERS = 4;
const static int DEFAULT_WORKERS = 2;
const static int SF_RECV_THREAD_PRIO = 1;
const static int WORKERS_THREAD_PRIO = 0;
srslte::radio_multi *radio_handler;
srslte::log *log_h;
srslte::thread_pool workers_pool;
std::vector<phch_worker> workers;
phch_common workers_common;
phch_recv sf_recv;
prach prach_buffer;
srslte_cell_t cell;
phy_cfg_t config;
phy_args_t *args;
phy_args_t default_args;
/* Current time advance */
uint32_t n_ta;
bool init_(srslte::radio *radio_handler, mac_interface_phy *mac, srslte::log *log_h, bool do_agc, uint32_t nof_workers);
void set_default_args(phy_args_t *args);
bool check_args(phy_args_t *args);
};
} // namespace srsue
#endif // UEPHY_H

View File

@ -0,0 +1,68 @@
/**
*
* \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 UE_PHY_METRICS_H
#define UE_PHY_METRICS_H
namespace srsue {
struct sync_metrics_t
{
float cfo;
float sfo;
};
struct dl_metrics_t
{
float n;
float sinr;
float rsrp;
float rsrq;
float rssi;
float turbo_iters;
float mcs;
float pathloss;
float mabr_mbps;
};
struct ul_metrics_t
{
float mcs;
float power;
float mabr_mbps;
};
struct phy_metrics_t
{
sync_metrics_t sync;
dl_metrics_t dl;
ul_metrics_t ul;
};
} // namespace srsue
#endif // UE_PHY_METRICS_H

87
srsue/hdr/phy/prach.h Normal file
View File

@ -0,0 +1,87 @@
/**
*
* \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 UEPRACH_H
#define UEPRACH_H
#include <string.h>
#include "srslte/srslte.h"
#include "radio/radio.h"
#include "common/log.h"
#include "common/phy_interface.h"
namespace srsue {
class prach {
public:
prach() {
bzero(&prach_obj, sizeof(srslte_prach_t));
bzero(&cell, sizeof(srslte_cell_t));
bzero(&cfo_h, sizeof(srslte_cfo_t));
args = NULL;
config = NULL;
initiated = false;
signal_buffer = NULL;
transmitted_tti = 0;
target_power_dbm = 0;
}
void init(LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT *config, phy_args_t *args, srslte::log *log_h);
bool init_cell(srslte_cell_t cell);
void free_cell();
bool prepare_to_send(uint32_t preamble_idx, int allowed_subframe = -1, float target_power_dbm = -1);
bool is_ready_to_send(uint32_t current_tti);
int tx_tti();
void send(srslte::radio* radio_handler, float cfo, float pathloss, srslte_timestamp_t rx_time);
float get_p0_preamble();
static const uint32_t tx_advance_sf = 4; // Number of subframes to advance transmission
private:
LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT *config;
phy_args_t *args;
srslte::log *log_h;
int preamble_idx;
int allowed_subframe;
bool initiated;
uint32_t len;
cf_t *buffer[64];
srslte_prach_t prach_obj;
int transmitted_tti;
srslte_cell_t cell;
cf_t *signal_buffer;
srslte_cfo_t cfo_h;
float target_power_dbm;
};
} // namespace srsue
#endif // UEPRACH_H

201
srsue/hdr/ue.h Normal file
View File

@ -0,0 +1,201 @@
/**
*
* \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: ue.h
* Description: Top-level UE class. Creates and links all
* layers and helpers.
*****************************************************************************/
#ifndef UE_H
#define UE_H
#include <stdarg.h>
#include <string>
#include <pthread.h>
#include "radio/radio_multi.h"
#include "phy/phy.h"
#include "mac/mac.h"
#include "upper/rlc.h"
#include "upper/pdcp.h"
#include "upper/rrc.h"
#include "upper/nas.h"
#include "upper/gw.h"
#include "upper/usim.h"
#include "common/buffer_pool.h"
#include "common/interfaces.h"
#include "common/logger.h"
#include "common/log_filter.h"
#include "ue_metrics_interface.h"
namespace srsue {
/*******************************************************************************
UE Parameters
*******************************************************************************/
typedef struct {
float dl_freq;
float ul_freq;
float rx_gain;
float tx_gain;
uint32_t nof_rx_ant;
std::string device_name;
std::string device_args;
std::string time_adv_nsamples;
std::string burst_preamble;
}rf_args_t;
typedef struct {
bool enable;
std::string filename;
}pcap_args_t;
typedef struct {
bool enable;
std::string phy_filename;
std::string radio_filename;
}trace_args_t;
typedef struct {
std::string phy_level;
std::string mac_level;
std::string rlc_level;
std::string pdcp_level;
std::string rrc_level;
std::string gw_level;
std::string nas_level;
std::string usim_level;
std::string all_level;
int phy_hex_limit;
int mac_hex_limit;
int rlc_hex_limit;
int pdcp_hex_limit;
int rrc_hex_limit;
int gw_hex_limit;
int nas_hex_limit;
int usim_hex_limit;
int all_hex_limit;
std::string filename;
}log_args_t;
typedef struct {
bool enable;
}gui_args_t;
typedef struct {
phy_args_t phy;
float metrics_period_secs;
bool pregenerate_signals;
int ue_cateogry;
}expert_args_t;
typedef struct {
rf_args_t rf;
rf_cal_t rf_cal;
pcap_args_t pcap;
trace_args_t trace;
log_args_t log;
gui_args_t gui;
usim_args_t usim;
expert_args_t expert;
}all_args_t;
/*******************************************************************************
Main UE class
*******************************************************************************/
class ue
:public ue_interface
,public ue_metrics_interface
{
public:
static ue* get_instance(void);
static void cleanup(void);
bool init(all_args_t *args_);
void stop();
bool is_attached();
void start_plot();
static void rf_msg(srslte_rf_error_t error);
void handle_rf_msg(srslte_rf_error_t error);
// UE metrics interface
bool get_metrics(ue_metrics_t &m);
void pregenerate_signals(bool enable);
// Testing
void test_con_restablishment();
private:
static ue *instance;
ue();
~ue();
srslte::radio_multi radio;
srsue::phy phy;
srsue::mac mac;
srslte::mac_pcap mac_pcap;
srsue::rlc rlc;
srsue::pdcp pdcp;
srsue::rrc rrc;
srsue::nas nas;
srsue::gw gw;
srsue::usim usim;
srslte::logger logger;
srslte::log_filter rf_log;
srslte::log_filter phy_log;
srslte::log_filter mac_log;
srslte::log_filter rlc_log;
srslte::log_filter pdcp_log;
srslte::log_filter rrc_log;
srslte::log_filter nas_log;
srslte::log_filter gw_log;
srslte::log_filter usim_log;
srslte::byte_buffer_pool *pool;
all_args_t *args;
bool started;
rf_metrics_t rf_metrics;
srslte::LOG_LEVEL_ENUM level(std::string l);
bool check_srslte_version();
};
} // namespace srsue
#endif // UE_H

View File

@ -0,0 +1,63 @@
/**
*
* \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 UE_METRICS_INTERFACE_H
#define UE_METRICS_INTERFACE_H
#include <stdint.h>
#include "upper/gw_metrics.h"
#include "upper/rlc_metrics.h"
#include "mac/mac_metrics.h"
#include "phy/phy_metrics.h"
namespace srsue {
typedef struct {
uint32_t rf_o;
uint32_t rf_u;
uint32_t rf_l;
bool rf_error;
}rf_metrics_t;
typedef struct {
rf_metrics_t rf;
phy_metrics_t phy;
mac_metrics_t mac;
rlc_metrics_t rlc;
gw_metrics_t gw;
}ue_metrics_t;
// UE interface
class ue_metrics_interface
{
public:
virtual bool get_metrics(ue_metrics_t &m) = 0;
};
} // namespace srsue
#endif // UE_METRICS_INTERFACE_H

51
srsue/src/CMakeLists.txt Normal file
View File

@ -0,0 +1,51 @@
# Copyright 2015 Software Radio Systems Limited
#
# This file is part of srsUE
#
# 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/.
#
add_subdirectory(phy)
add_subdirectory(mac)
if (RPATH)
SET(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
endif (RPATH)
add_executable(ue main.cc ue.cc metrics_stdout.cc)
target_link_libraries(ue srsue_mac
srsue_phy
srslte_common
srslte_phy
srslte_upper
srslte_radio
${SRSLTE_LIBRARIES}
${LIBLTE_LIBRARY}
${CMAKE_THREAD_LIBS_INIT}
${Boost_LIBRARIES})
if (RPATH)
set_target_properties(ue PROPERTIES INSTALL_RPATH ".")
endif (RPATH)
########################################################################
# Option to run command after build (useful for remote builds)
########################################################################
if (NOT ${BUILD_CMD} STREQUAL "")
message(STATUS "Added custom post-build command: ${BUILD_CMD}")
add_custom_command(TARGET ue POST_BUILD COMMAND ${BUILD_CMD})
else(NOT ${BUILD_CMD} STREQUAL "")
message(STATUS "No post-build command defined")
endif (NOT ${BUILD_CMD} STREQUAL "")

View File

@ -0,0 +1,22 @@
# Copyright 2015 Software Radio Systems Limited
#
# This file is part of srsUE
#
# 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(GLOB SOURCES "*.cc")
add_library(srsue_mac ${SOURCES})
target_link_libraries(srsue_mac)

206
srsue/src/mac/demux.cc Normal file
View File

@ -0,0 +1,206 @@
/**
*
* \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/.
*
*/
#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#include "mac/mac.h"
#include "mac/demux.h"
#include "common/phy_interface.h"
namespace srsue {
demux::demux() : mac_msg(20), pending_mac_msg(20)
{
}
void demux::init(phy_interface_mac* phy_h_, rlc_interface_mac *rlc_, srslte::log* log_h_, srslte::timers* timers_db_)
{
phy_h = phy_h_;
log_h = log_h_;
rlc = rlc_;
timers_db = timers_db_;
pdus.init(this, log_h);
}
void demux::set_uecrid_callback(bool (*callback)(void*,uint64_t), void *arg) {
uecrid_callback = callback;
uecrid_callback_arg = arg;
}
bool demux::get_uecrid_successful() {
return is_uecrid_successful;
}
void demux::deallocate(uint8_t* payload_buffer_ptr)
{
if (payload_buffer_ptr != bcch_buffer) {
pdus.deallocate(payload_buffer_ptr);
}
}
uint8_t* demux::request_buffer(uint32_t pid, uint32_t len)
{
uint8_t *buff = NULL;
if (pid < NOF_HARQ_PID) {
return pdus.request(len);
} else if (pid == NOF_HARQ_PID) {
buff = bcch_buffer;
} else {
Error("Requested buffer for invalid PID=%d\n", pid);
}
return buff;
}
/* Demultiplexing of MAC PDU associated with a Temporal C-RNTI. The PDU will
* remain in buffer until demultiplex_pending_pdu() is called.
* This features is provided to enable the Random Access Procedure to decide
* wether the PDU shall pass to upper layers or not, which depends on the
* Contention Resolution result.
*
* Warning: this function does some processing here assuming ACK deadline is not an
* issue here because Temp C-RNTI messages have small payloads
*/
void demux::push_pdu_temp_crnti(uint8_t *buff, uint32_t nof_bytes)
{
if (nof_bytes > 0) {
// Unpack DLSCH MAC PDU
pending_mac_msg.init_rx(nof_bytes);
pending_mac_msg.parse_packet(buff);
// Look for Contention Resolution UE ID
is_uecrid_successful = false;
while(pending_mac_msg.next() && !is_uecrid_successful) {
if (pending_mac_msg.get()->ce_type() == srslte::sch_subh::CON_RES_ID) {
Debug("Found Contention Resolution ID CE\n");
is_uecrid_successful = uecrid_callback(uecrid_callback_arg, pending_mac_msg.get()->get_con_res_id());
}
}
pending_mac_msg.reset();
Debug("Saved MAC PDU with Temporal C-RNTI in buffer\n");
pdus.push(buff, nof_bytes);
} else {
Warning("Trying to push PDU with payload size zero\n");
}
}
/* Demultiplexing of logical channels and dissassemble of MAC CE
* This function enqueues the packet and returns quicly because ACK
* deadline is important here.
*/
void demux::push_pdu(uint32_t pid, uint8_t *buff, uint32_t nof_bytes)
{
if (pid < NOF_HARQ_PID) {
return pdus.push(buff, nof_bytes);
} else if (pid == NOF_HARQ_PID) {
/* Demultiplexing of MAC PDU associated with SI-RNTI. The PDU passes through
* the MAC in transparent mode.
* Warning: In this case function sends the message to RLC now, since SI blocks do not
* require ACK feedback to be transmitted quickly.
*/
Debug("Pushed BCCH MAC PDU in transparent mode\n");
rlc->write_pdu_bcch_dlsch(buff, nof_bytes);
} else {
Error("Pushed buffer for invalid PID=%d\n", pid);
}
}
bool demux::process_pdus()
{
return pdus.process_pdus();
}
void demux::process_pdu(uint8_t *mac_pdu, uint32_t nof_bytes)
{
// Unpack DLSCH MAC PDU
mac_msg.init_rx(nof_bytes);
mac_msg.parse_packet(mac_pdu);
process_sch_pdu(&mac_msg);
//srslte_vec_fprint_byte(stdout, mac_pdu, nof_bytes);
Debug("MAC PDU processed\n");
}
void demux::process_sch_pdu(srslte::sch_pdu *pdu_msg)
{
while(pdu_msg->next()) {
if (pdu_msg->get()->is_sdu()) {
bool route_pdu = true;
if (pdu_msg->get()->get_sdu_lcid() == 0) {
uint8_t *x = pdu_msg->get()->get_sdu_ptr();
uint32_t sum = 0;
for (int i=0;i<pdu_msg->get()->get_payload_size();i++) {
sum += x[i];
}
if (sum == 0) {
route_pdu = false;
Warning("Received all zero PDU\n");
}
}
// Route logical channel
if (route_pdu) {
Info("Delivering PDU for lcid=%d, %d bytes\n", pdu_msg->get()->get_sdu_lcid(), pdu_msg->get()->get_payload_size());
rlc->write_pdu(pdu_msg->get()->get_sdu_lcid(), pdu_msg->get()->get_sdu_ptr(), pdu_msg->get()->get_payload_size());
}
} else {
// Process MAC Control Element
if (!process_ce(pdu_msg->get())) {
Warning("Received Subheader with invalid or unkonwn LCID\n");
}
}
}
}
bool demux::process_ce(srslte::sch_subh *subh) {
switch(subh->ce_type()) {
case srslte::sch_subh::CON_RES_ID:
// Do nothing
break;
case srslte::sch_subh::TA_CMD:
phy_h->set_timeadv(subh->get_ta_cmd());
Info("Received TA=%d\n", subh->get_ta_cmd());
// Start or restart timeAlignmentTimer
timers_db->get(mac::TIME_ALIGNMENT)->reset();
timers_db->get(mac::TIME_ALIGNMENT)->run();
break;
case srslte::sch_subh::PADDING:
break;
default:
Error("MAC CE 0x%x not supported\n", subh->ce_type());
break;
}
return true;
}
}

337
srsue/src/mac/dl_harq.cc Normal file
View File

@ -0,0 +1,337 @@
/**
*
* \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/.
*
*/
#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#include "mac/mac.h"
#include "mac/dl_harq.h"
namespace srsue {
/***********************************************************
*
* HARQ ENTITY
*
*********************************************************/
dl_harq_entity::dl_harq_entity()
{
pcap = NULL;
}
bool dl_harq_entity::init(srslte::log* log_h_, mac_interface_rrc::mac_cfg_t *mac_cfg_, srslte::timers* timers_, demux *demux_unit_)
{
timers_db = timers_;
demux_unit = demux_unit_;
mac_cfg = mac_cfg_;
si_window_start = 0;
log_h = log_h_;
for (uint32_t i=0;i<NOF_HARQ_PROC+1;i++) {
if (!proc[i].init(i, this)) {
return false;
}
}
return true;
}
void dl_harq_entity::start_pcap(srslte::mac_pcap* pcap_)
{
pcap = pcap_;
}
void dl_harq_entity::reset()
{
for (uint32_t i=0;i<NOF_HARQ_PROC+1;i++) {
proc[i].reset();
}
dl_sps_assig.clear();
}
uint32_t dl_harq_entity::get_harq_sps_pid(uint32_t tti) {
return 0;
}
void dl_harq_entity::new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_dl_t* action)
{
if (grant.rnti_type != SRSLTE_RNTI_SPS) {
uint32_t harq_pid;
// Set BCCH PID for SI RNTI
if (grant.rnti_type == SRSLTE_RNTI_SI) {
harq_pid = HARQ_BCCH_PID;
} else {
harq_pid = grant.pid%NOF_HARQ_PROC;
}
if (grant.rnti_type == SRSLTE_RNTI_TEMP && last_temporal_crnti != grant.rnti) {
grant.ndi = true;
Info("Set NDI=1 for Temp-RNTI DL grant\n");
last_temporal_crnti = grant.rnti;
}
if (grant.rnti_type == SRSLTE_RNTI_USER && proc[harq_pid].is_sps()) {
grant.ndi = true;
Info("Set NDI=1 for C-RNTI DL grant\n");
}
proc[harq_pid].new_grant_dl(grant, action);
} else {
/* This is for SPS scheduling */
uint32_t harq_pid = get_harq_sps_pid(grant.tti)%NOF_HARQ_PROC;
if (grant.ndi) {
grant.ndi = false;
proc[harq_pid].new_grant_dl(grant, action);
} else {
if (grant.is_sps_release) {
dl_sps_assig.clear();
if (timers_db->get(mac::TIME_ALIGNMENT)->is_running()) {
//phy_h->send_sps_ack();
Warning("PHY Send SPS ACK not implemented\n");
}
} else {
Error("SPS not implemented\n");
//dl_sps_assig.reset(grant.tti, grant);
//grant.ndi = true;
//procs[harq_pid].save_grant();
}
}
}
}
void dl_harq_entity::tb_decoded(bool ack, srslte_rnti_type_t rnti_type, uint32_t harq_pid)
{
if (rnti_type == SRSLTE_RNTI_SI) {
proc[NOF_HARQ_PROC].tb_decoded(ack);
} else {
proc[harq_pid%NOF_HARQ_PROC].tb_decoded(ack);
}
}
int dl_harq_entity::get_current_tbs(uint32_t harq_pid)
{
return proc[harq_pid%NOF_HARQ_PROC].get_current_tbs();
}
bool dl_harq_entity::generate_ack_callback(void *arg)
{
demux *demux_unit = (demux*) arg;
return demux_unit->get_uecrid_successful();
}
void dl_harq_entity::set_si_window_start(int si_window_start_)
{
si_window_start = si_window_start_;
}
float dl_harq_entity::get_average_retx()
{
return average_retx;
}
/***********************************************************
*
* HARQ PROCESS
*
*********************************************************/
dl_harq_entity::dl_harq_process::dl_harq_process() {
is_initiated = false;
ack = false;
bzero(&cur_grant, sizeof(mac_interface_phy::mac_grant_t));
}
void dl_harq_entity::dl_harq_process::reset() {
ack = false;
payload_buffer_ptr = NULL;
bzero(&cur_grant, sizeof(mac_interface_phy::mac_grant_t));
if (is_initiated) {
srslte_softbuffer_rx_reset(&softbuffer);
}
}
bool dl_harq_entity::dl_harq_process::init(uint32_t pid_, dl_harq_entity *parent) {
if (srslte_softbuffer_rx_init(&softbuffer, 110)) {
Error("Error initiating soft buffer\n");
return false;
} else {
pid = pid_;
is_initiated = true;
harq_entity = parent;
log_h = harq_entity->log_h;
return true;
}
}
bool dl_harq_entity::dl_harq_process::is_sps()
{
return false;
}
bool dl_harq_entity::dl_harq_process::calc_is_new_transmission(mac_interface_phy::mac_grant_t grant) {
bool is_new_tb = true;
if (srslte_tti_interval(grant.tti, cur_grant.tti) <= 8 && grant.n_bytes == cur_grant.n_bytes ||
pid == HARQ_BCCH_PID)
{
is_new_tb = false;
}
if ((grant.ndi != cur_grant.ndi && !is_new_tb) || // NDI toggled for same TB
is_new_tb || // is new TB
(pid == HARQ_BCCH_PID && grant.rv == 0)) // Broadcast PID and 1st TX (RV=0)
{
is_new_transmission = true;
Debug("Set HARQ for new transmission\n");
} else {
is_new_transmission = false;
Debug("Set HARQ for retransmission\n");
}
return is_new_transmission;
}
void dl_harq_entity::dl_harq_process::new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_dl_t* action)
{
// Compute RV for BCCH when not specified in PDCCH format
if (pid == HARQ_BCCH_PID && grant.rv == -1) {
uint32_t k;
if ((grant.tti/10)%2 == 0 && grant.tti%10 == 5) { // This is SIB1, k is different
k = (grant.tti/20)%4;
grant.rv = ((uint32_t) ceilf((float)1.5*k))%4;
} else if (grant.rv == -1) {
k = (grant.tti-harq_entity->si_window_start)%4;
grant.rv = ((uint32_t) ceilf((float)1.5*k))%4;
}
}
calc_is_new_transmission(grant);
if (is_new_transmission) {
ack = false;
srslte_softbuffer_rx_reset_tbs(&softbuffer, cur_grant.n_bytes*8);
n_retx = 0;
}
// Save grant
grant.last_ndi = cur_grant.ndi;
grant.last_tti = cur_grant.tti;
memcpy(&cur_grant, &grant, sizeof(mac_interface_phy::mac_grant_t));
// Fill action structure
bzero(action, sizeof(mac_interface_phy::tb_action_dl_t));
action->default_ack = ack;
action->generate_ack = true;
action->decode_enabled = false;
// If data has not yet been successfully decoded
if (ack == false) {
// Instruct the PHY To combine the received data and attempt to decode it
payload_buffer_ptr = harq_entity->demux_unit->request_buffer(pid, cur_grant.n_bytes);
action->payload_ptr = payload_buffer_ptr;
if (!action->payload_ptr) {
action->decode_enabled = false;
Error("Can't get a buffer for TBS=%d\n", cur_grant.n_bytes);
return;
}
action->decode_enabled = true;
action->rv = cur_grant.rv;
action->rnti = cur_grant.rnti;
action->softbuffer = &softbuffer;
memcpy(&action->phy_grant, &cur_grant.phy_grant, sizeof(srslte_phy_grant_t));
n_retx++;
} else {
Warning("DL PID %d: Received duplicate TB. Discarting and retransmitting ACK\n", pid);
}
if (pid == HARQ_BCCH_PID || harq_entity->timers_db->get(mac::TIME_ALIGNMENT)->is_expired()) {
// Do not generate ACK
Debug("Not generating ACK\n");
action->generate_ack = false;
} else {
if (cur_grant.rnti_type == SRSLTE_RNTI_TEMP && ack == false) {
// Postpone ACK after contention resolution is resolved
action->generate_ack_callback = harq_entity->generate_ack_callback;
action->generate_ack_callback_arg = harq_entity->demux_unit;
Debug("ACK pending contention resolution\n");
} else {
Debug("Generating ACK\n");
}
}
}
int dl_harq_entity::dl_harq_process::get_current_tbs()
{
return cur_grant.n_bytes*8;
}
void dl_harq_entity::dl_harq_process::tb_decoded(bool ack_)
{
ack = ack_;
if (ack == true) {
if (pid == HARQ_BCCH_PID) {
if (harq_entity->pcap) {
harq_entity->pcap->write_dl_sirnti(payload_buffer_ptr, cur_grant.n_bytes, ack, cur_grant.tti);
}
Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit (BCCH)\n", cur_grant.n_bytes);
harq_entity->demux_unit->push_pdu(pid, payload_buffer_ptr, cur_grant.n_bytes);
} else {
if (harq_entity->pcap) {
harq_entity->pcap->write_dl_crnti(payload_buffer_ptr, cur_grant.n_bytes, cur_grant.rnti, ack, cur_grant.tti);
}
if (ack) {
if (cur_grant.rnti_type == SRSLTE_RNTI_TEMP) {
Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit (Temporal C-RNTI)\n", cur_grant.n_bytes);
harq_entity->demux_unit->push_pdu_temp_crnti(payload_buffer_ptr, cur_grant.n_bytes);
} else {
Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit\n", cur_grant.n_bytes);
harq_entity->demux_unit->push_pdu(pid, payload_buffer_ptr, cur_grant.n_bytes);
// Compute average number of retransmissions per packet
harq_entity->average_retx = SRSLTE_VEC_CMA((float) n_retx, harq_entity->average_retx, harq_entity->nof_pkts++);
}
}
}
} else {
harq_entity->demux_unit->deallocate(payload_buffer_ptr);
}
Info("DL %d: %s tbs=%d, rv=%d, ack=%s, ndi=%d (%d), tti=%d (%d)\n",
pid, is_new_transmission?"newTX":"reTX ",
cur_grant.n_bytes, cur_grant.rv, ack?"OK":"KO",
cur_grant.ndi, cur_grant.last_ndi, cur_grant.tti, cur_grant.last_tti);
if (ack && pid == HARQ_BCCH_PID) {
reset();
}
}
}

543
srsue/src/mac/mac.cc Normal file
View File

@ -0,0 +1,543 @@
/**
*
* \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/.
*
*/
#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#include <string.h>
#include <strings.h>
#include <pthread.h>
#include <unistd.h>
#include "common/log.h"
#include "mac/mac.h"
#include "common/pcap.h"
namespace srsue {
mac::mac() : ttisync(10240),
timers_db((uint32_t) NOF_MAC_TIMERS),
pdu_process_thread(&demux_unit)
{
started = false;
pcap = NULL;
signals_pregenerated = false;
bzero(&metrics, sizeof(mac_metrics_t));
}
bool mac::init(phy_interface_mac *phy, rlc_interface_mac *rlc, rrc_interface_mac *rrc, srslte::log *log_h_)
{
started = false;
phy_h = phy;
rlc_h = rlc;
rrc_h = rrc;
log_h = log_h_;
tti = 0;
is_synchronized = false;
last_temporal_crnti = 0;
phy_rnti = 0;
srslte_softbuffer_rx_init(&pch_softbuffer, 100);
bsr_procedure.init( rlc_h, log_h, &config, &timers_db);
phr_procedure.init(phy_h, log_h, &config, &timers_db);
mux_unit.init ( rlc_h, log_h, &bsr_procedure, &phr_procedure);
demux_unit.init (phy_h, rlc_h, log_h, &timers_db);
ra_procedure.init (phy_h, rrc, log_h, &uernti, &config, &timers_db, &mux_unit, &demux_unit);
sr_procedure.init (phy_h, rrc, log_h, &config);
ul_harq.init ( log_h, &uernti, &config, &timers_db, &mux_unit);
dl_harq.init ( log_h, &config, &timers_db, &demux_unit);
reset();
started = true;
start(MAC_MAIN_THREAD_PRIO);
return started;
}
void mac::stop()
{
started = false;
ttisync.increase();
upper_timers_thread.thread_cancel();
pdu_process_thread.stop();
wait_thread_finish();
}
void mac::start_pcap(srslte::mac_pcap* pcap_)
{
pcap = pcap_;
dl_harq.start_pcap(pcap);
ul_harq.start_pcap(pcap);
ra_procedure.start_pcap(pcap);
}
// Implement Section 5.8
void mac::reconfiguration()
{
}
// Implement Section 5.9
void mac::reset()
{
bzero(&metrics, sizeof(mac_metrics_t));
Info("Resetting MAC\n");
timers_db.stop_all();
upper_timers_thread.reset();
ul_harq.reset_ndi();
mux_unit.msg3_flush();
mux_unit.reset();
ra_procedure.reset();
sr_procedure.reset();
bsr_procedure.reset();
phr_procedure.reset();
dl_harq.reset();
phy_h->pdcch_dl_search_reset();
phy_h->pdcch_ul_search_reset();
signals_pregenerated = false;
is_first_ul_grant = true;
bzero(&uernti, sizeof(ue_rnti_t));
}
void mac::run_thread() {
int cnt=0;
Info("Waiting PHY to synchronize with cell\n");
phy_h->sync_start();
while(!phy_h->get_current_tti() && started) {
usleep(50000);
}
Debug("Setting ttysync to %d\n", phy_h->get_current_tti());
ttisync.set_producer_cntr(phy_h->get_current_tti());
while(started) {
/* Warning: Here order of invocation of procedures is important!! */
ttisync.wait();
tti = phy_h->get_current_tti();
if (started) {
log_h->step(tti);
// Step all procedures
bsr_procedure.step(tti);
phr_procedure.step(tti);
// Check if BSR procedure need to start SR
if (bsr_procedure.need_to_send_sr(tti)) {
Debug("Starting SR procedure by BSR request, PHY TTI=%d\n", tti);
sr_procedure.start();
}
if (bsr_procedure.need_to_reset_sr()) {
Debug("Resetting SR procedure by BSR request\n");
sr_procedure.reset();
}
sr_procedure.step(tti);
// Check SR if we need to start RA
if (sr_procedure.need_random_access()) {
ra_procedure.start_mac_order();
}
ra_procedure.step(tti);
if (ra_procedure.is_successful() && !signals_pregenerated) {
// Configure PHY to look for UL C-RNTI grants
phy_h->pdcch_ul_search(SRSLTE_RNTI_USER, uernti.crnti);
phy_h->pdcch_dl_search(SRSLTE_RNTI_USER, uernti.crnti);
// Pregenerate UL signals and C-RNTI scrambling sequences
Debug("Pre-computing C-RNTI scrambling sequences for C-RNTI=0x%x\n", uernti.crnti);
phy_h->set_crnti(uernti.crnti);
signals_pregenerated = true;
}
}
}
}
void mac::bcch_start_rx()
{
bcch_start_rx(tti, -1);
}
void mac::bcch_start_rx(int si_window_start, int si_window_length)
{
if (si_window_length >= 0 && si_window_start >= 0) {
dl_harq.set_si_window_start(si_window_start);
phy_h->pdcch_dl_search(SRSLTE_RNTI_SI, SRSLTE_SIRNTI, si_window_start, si_window_start+si_window_length);
} else {
phy_h->pdcch_dl_search(SRSLTE_RNTI_SI, SRSLTE_SIRNTI, si_window_start);
}
Info("SCHED: Searching for DL grant for SI-RNTI window_st=%d, window_len=%d\n", si_window_start, si_window_length);
}
void mac::bcch_stop_rx()
{
phy_h->pdcch_dl_search_reset();
}
void mac::pcch_start_rx()
{
phy_h->pdcch_dl_search(SRSLTE_RNTI_PCH, SRSLTE_PRNTI);
Info("SCHED: Searching for DL grant for P-RNTI\n");
}
void mac::pcch_stop_rx()
{
phy_h->pdcch_dl_search_reset();
}
void mac::tti_clock(uint32_t tti)
{
ttisync.increase();
}
void mac::bch_decoded_ok(uint8_t* payload, uint32_t len)
{
// Send MIB to RLC
rlc_h->write_pdu_bcch_bch(payload, len);
if (pcap) {
pcap->write_dl_bch(payload, len, true, phy_h->get_current_tti());
}
}
void mac::pch_decoded_ok(uint32_t len)
{
// Send PCH payload to RLC
rlc_h->write_pdu_pcch(pch_payload_buffer, len);
if (pcap) {
pcap->write_dl_pch(pch_payload_buffer, len, true, phy_h->get_current_tti());
}
}
void mac::tb_decoded(bool ack, srslte_rnti_type_t rnti_type, uint32_t harq_pid)
{
if (rnti_type == SRSLTE_RNTI_RAR) {
if (ack) {
ra_procedure.tb_decoded_ok();
}
} else {
dl_harq.tb_decoded(ack, rnti_type, harq_pid);
if (ack) {
pdu_process_thread.notify();
metrics.rx_brate += dl_harq.get_current_tbs(harq_pid);
} else {
metrics.rx_errors++;
}
metrics.rx_pkts++;
}
}
void mac::new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_dl_t* action)
{
if (grant.rnti_type == SRSLTE_RNTI_RAR) {
ra_procedure.new_grant_dl(grant, action);
} else if (grant.rnti_type == SRSLTE_RNTI_PCH) {
memcpy(&action->phy_grant, &grant.phy_grant, sizeof(srslte_phy_grant_t));
action->generate_ack = false;
action->decode_enabled = true;
srslte_softbuffer_rx_reset_cb(&pch_softbuffer, 1);
action->payload_ptr = pch_payload_buffer;
action->softbuffer = &pch_softbuffer;
action->rnti = grant.rnti;
action->rv = grant.rv;
if (grant.n_bytes > pch_payload_buffer_sz) {
Error("Received grant for PCH (%d bytes) exceeds buffer (%d bytes)\n", grant.n_bytes, pch_payload_buffer_sz);
action->decode_enabled = false;
}
} else {
// If PDCCH for C-RNTI and RA procedure in Contention Resolution, notify it
if (grant.rnti_type == SRSLTE_RNTI_USER && ra_procedure.is_contention_resolution()) {
ra_procedure.pdcch_to_crnti(false);
}
dl_harq.new_grant_dl(grant, action);
}
}
uint32_t mac::get_current_tti()
{
return phy_h->get_current_tti();
}
void mac::new_grant_ul(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_ul_t* action)
{
/* Start PHR Periodic timer on first UL grant */
if (is_first_ul_grant) {
is_first_ul_grant = false;
timers_db.get(mac::PHR_TIMER_PERIODIC)->run();
}
if (grant.rnti_type == SRSLTE_RNTI_USER && ra_procedure.is_contention_resolution()) {
ra_procedure.pdcch_to_crnti(true);
}
ul_harq.new_grant_ul(grant, action);
metrics.tx_pkts++;
}
void mac::new_grant_ul_ack(mac_interface_phy::mac_grant_t grant, bool ack, mac_interface_phy::tb_action_ul_t* action)
{
int tbs = ul_harq.get_current_tbs(tti);
ul_harq.new_grant_ul_ack(grant, ack, action);
if (!ack) {
metrics.tx_errors++;
} else {
metrics.tx_brate += tbs;
}
metrics.tx_pkts++;
if (!ack && ra_procedure.is_contention_resolution()) {
ra_procedure.harq_retx();
}
if (grant.rnti_type == SRSLTE_RNTI_USER && ra_procedure.is_contention_resolution()) {
ra_procedure.pdcch_to_crnti(true);
}
}
void mac::harq_recv(uint32_t tti, bool ack, mac_interface_phy::tb_action_ul_t* action)
{
int tbs = ul_harq.get_current_tbs(tti);
ul_harq.harq_recv(tti, ack, action);
if (!ack) {
metrics.tx_errors++;
metrics.tx_pkts++;
} else {
metrics.tx_brate += tbs;
}
if (!ack && ra_procedure.is_contention_resolution()) {
ra_procedure.harq_retx();
}
}
void mac::setup_timers()
{
int value = liblte_rrc_time_alignment_timer_num[config.main.time_alignment_timer];
if (value > 0) {
timers_db.get(TIME_ALIGNMENT)->set(this, value);
}
}
void mac::timer_expired(uint32_t timer_id)
{
switch(timer_id) {
case TIME_ALIGNMENT:
timeAlignmentTimerExpire();
break;
default:
break;
}
}
/* Function called on expiry of TimeAlignmentTimer */
void mac::timeAlignmentTimerExpire()
{
printf("timeAlignmentTimer has expired value=%d ms\n", timers_db.get(TIME_ALIGNMENT)->get_timeout());
rrc_h->release_pucch_srs();
dl_harq.reset();
ul_harq.reset();
}
void mac::get_rntis(ue_rnti_t* rntis)
{
memcpy(rntis, &uernti, sizeof(ue_rnti_t));
}
void mac::set_contention_id(uint64_t uecri)
{
uernti.contention_id = uecri;
}
void mac::get_config(mac_cfg_t* mac_cfg)
{
memcpy(mac_cfg, &config, sizeof(mac_cfg_t));
}
void mac::set_config(mac_cfg_t* mac_cfg)
{
memcpy(&config, mac_cfg, sizeof(mac_cfg_t));
setup_timers();
}
void mac::set_config_main(LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT* main_cfg)
{
memcpy(&config.main, main_cfg, sizeof(LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT));
setup_timers();
}
void mac::set_config_rach(LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT* rach_cfg, uint32_t prach_config_index)
{
memcpy(&config.rach, rach_cfg, sizeof(LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT));
config.prach_config_index = prach_config_index;
}
void mac::set_config_sr(LIBLTE_RRC_SCHEDULING_REQUEST_CONFIG_STRUCT* sr_cfg)
{
memcpy(&config.sr, sr_cfg, sizeof(LIBLTE_RRC_SCHEDULING_REQUEST_CONFIG_STRUCT));
}
void mac::setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD)
{
Info("Logical Channel Setup: LCID=%d, LCG=%d, priority=%d, PBR=%d, BSd=%d\n",
lcid, lcg, priority, PBR_x_tti, BSD);
mux_unit.set_priority(lcid, priority, PBR_x_tti, BSD);
bsr_procedure.setup_lcg(lcid, lcg);
bsr_procedure.set_priority(lcid, priority);
}
uint32_t mac::get_unique_id()
{
return upper_timers_thread.get_unique_id();
}
/* Front-end to upper-layer timers */
srslte::timers::timer* mac::get(uint32_t timer_id)
{
return upper_timers_thread.get(timer_id);
}
void mac::get_metrics(mac_metrics_t &m)
{
Info("DL retx: %.2f \%%, perpkt: %.2f, UL retx: %.2f \%% perpkt: %.2f\n",
metrics.rx_pkts?((float) 100*metrics.rx_errors/metrics.rx_pkts):0.0,
dl_harq.get_average_retx(),
metrics.tx_pkts?((float) 100*metrics.tx_errors/metrics.tx_pkts):0.0,
dl_harq.get_average_retx());
metrics.ul_buffer = (int) bsr_procedure.get_buffer_state();
m = metrics;
bzero(&metrics, sizeof(mac_metrics_t));
}
/********************************************************
*
* Class to run upper-layer timers with normal priority
*
*******************************************************/
mac::upper_timers::upper_timers() : timers_db(MAC_NOF_UPPER_TIMERS)
{
start_periodic(1000, MAC_MAIN_THREAD_PRIO+1);
}
void mac::upper_timers::run_period()
{
timers_db.step_all();
}
srslte::timers::timer* mac::upper_timers::get(uint32_t timer_id)
{
return timers_db.get(timer_id%MAC_NOF_UPPER_TIMERS);
}
uint32_t mac::upper_timers::get_unique_id()
{
return timers_db.get_unique_id();
}
void mac::upper_timers::reset()
{
timers_db.stop_all();
}
/********************************************************
*
* Class that runs a thread to process DL MAC PDUs from
* DEMU unit
*
*******************************************************/
mac::pdu_process::pdu_process(demux *demux_unit_)
{
demux_unit = demux_unit_;
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cvar, NULL);
have_data = false;
start(MAC_PDU_THREAD_PRIO);
}
void mac::pdu_process::stop()
{
pthread_mutex_lock(&mutex);
running = false;
pthread_cond_signal(&cvar);
pthread_mutex_unlock(&mutex);
wait_thread_finish();
}
void mac::pdu_process::notify()
{
pthread_mutex_lock(&mutex);
have_data = true;
pthread_cond_signal(&cvar);
pthread_mutex_unlock(&mutex);
}
void mac::pdu_process::run_thread()
{
running = true;
while(running) {
have_data = demux_unit->process_pdus();
if (!have_data) {
pthread_mutex_lock(&mutex);
while(!have_data && running) {
pthread_cond_wait(&cvar, &mutex);
}
pthread_mutex_unlock(&mutex);
}
}
}
}

358
srsue/src/mac/mux.cc Normal file
View File

@ -0,0 +1,358 @@
/**
*
* \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/.
*
*/
#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#include "mac/mux.h"
#include "mac/mac.h"
#include <set>
#include <algorithm>
namespace srsue {
mux::mux() : pdu_msg(MAX_NOF_SUBHEADERS)
{
pthread_mutex_init(&mutex, NULL);
pending_crnti_ce = 0;
log_h = NULL;
rlc = NULL;
bsr_procedure = NULL;
phr_procedure = NULL;
msg3_flush();
}
void mux::init(rlc_interface_mac *rlc_, srslte::log *log_h_, bsr_proc *bsr_procedure_, phr_proc *phr_procedure_)
{
log_h = log_h_;
rlc = rlc_;
bsr_procedure = bsr_procedure_;
phr_procedure = phr_procedure_;
reset();
}
void mux::reset()
{
lch.clear();
pending_crnti_ce = 0;
}
bool mux::is_pending_any_sdu()
{
for (int i=0;i<lch.size();i++) {
if (rlc->get_buffer_state(lch[i].id)) {
return true;
}
}
return false;
}
bool mux::is_pending_sdu(uint32_t lch_id) {
return rlc->get_buffer_state(lch_id)>0;
}
int mux::find_lchid(uint32_t lcid)
{
for (int i=0;i<lch.size();i++) {
if(lch[i].id == lcid) {
return i;
}
}
return -1;
}
bool sortPriority(lchid_t u1, lchid_t u2) {
return u1.priority < u2.priority;
}
void mux::clear_lch(uint32_t lch_id)
{
int pos = find_lchid(lch_id);
if (pos >= 0) {
lch.erase(lch.begin()+pos);
} else {
Error("Deleting logical channel id %d. Does not exist\n", lch_id);
}
}
void mux::set_priority(uint32_t lch_id, uint32_t new_priority, int set_PBR, uint32_t set_BSD)
{
int pos = find_lchid(lch_id);
// Create new channel if it does not exist
if (pos < 0) {
lchid_t ch;
ch.id = lch_id;
ch.priority = new_priority;
ch.BSD = set_BSD;
ch.PBR = set_PBR;
ch.Bj = 0;
lch.push_back(ch);
} else {
lch[pos].priority = new_priority;
lch[pos].PBR = set_PBR;
lch[pos].BSD = set_BSD;
}
// sort according to priority (increasing is lower priority)
std::sort(lch.begin(), lch.end(), sortPriority);
}
srslte::sch_subh::cetype bsr_format_convert(bsr_proc::bsr_format_t format) {
switch(format) {
case bsr_proc::LONG_BSR:
return srslte::sch_subh::LONG_BSR;
case bsr_proc::SHORT_BSR:
return srslte::sch_subh::SHORT_BSR;
case bsr_proc::TRUNC_BSR:
return srslte::sch_subh::TRUNC_BSR;
}
}
void mux::pusch_retx(uint32_t tx_tti, uint32_t pid)
{
if (pid_has_bsr[pid%MAX_HARQ_PROC]) {
bsr_procedure->set_tx_tti(tx_tti);
}
}
// Multiplexing and logical channel priorization as defined in Section 5.4.3
uint8_t* mux::pdu_get(uint8_t *payload, uint32_t pdu_sz, uint32_t tx_tti, uint32_t pid)
{
pthread_mutex_lock(&mutex);
// Update Bj
for (int i=0;i<lch.size();i++) {
// Add PRB unless it's infinity
if (lch[i].PBR >= 0) {
lch[i].Bj += lch[i].PBR;
}
if (lch[i].Bj >= lch[i].BSD) {
lch[i].Bj = lch[i].BSD*lch[i].PBR;
}
}
// Logical Channel Procedure
pdu_msg.init_tx(payload, pdu_sz, true);
// MAC control element for C-RNTI or data from UL-CCCH
if (!allocate_sdu(0, &pdu_msg, -1)) {
if (pending_crnti_ce) {
if (pdu_msg.new_subh()) {
if (!pdu_msg.get()->set_c_rnti(pending_crnti_ce)) {
Warning("Pending C-RNTI CE could not be inserted in MAC PDU\n");
}
}
}
}
pending_crnti_ce = 0;
bsr_proc::bsr_t bsr;
bool regular_bsr = bsr_procedure->need_to_send_bsr_on_ul_grant(pdu_msg.rem_size(), &bsr);
bool bsr_is_inserted = false;
// MAC control element for BSR, with exception of BSR included for padding;
if (regular_bsr) {
if (pdu_msg.new_subh()) {
pdu_msg.get()->set_bsr(bsr.buff_size, bsr_format_convert(bsr.format));
bsr_is_inserted = true;
}
}
// MAC control element for PHR
float phr_value;
if (phr_procedure->generate_phr_on_ul_grant(&phr_value)) {
if (pdu_msg.new_subh()) {
pdu_msg.get()->set_phr(phr_value);
}
}
// Update buffer states for all logical channels
int sdu_space = pdu_msg.get_sdu_space();
for (int i=0;i<lch.size();i++) {
lch[i].buffer_len = rlc->get_buffer_state(lch[i].id);
lch[i].sched_len = 0;
}
// data from any Logical Channel, except data from UL-CCCH;
// first only those with positive Bj
for (int i=0;i<lch.size();i++) {
if (lch[i].id != 0) {
if (sched_sdu(&lch[i], &sdu_space, (lch[i].PBR<0)?-1:lch[i].Bj) && lch[i].PBR >= 0) {
lch[i].Bj -= lch[i].sched_len;
}
}
}
// If resources remain, allocate regardless of their Bj value
for (int i=0;i<lch.size();i++) {
if (lch[i].id != 0) {
sched_sdu(&lch[i], &sdu_space, -1);
}
}
// Maximize the grant utilization
if (lch.size() > 0) {
for (int i=lch.size()-1;i--;i>=0) {
if (lch[i].sched_len > 0) {
lch[i].sched_len = -1;
break;
}
}
}
// Now allocate the SDUs from the RLC
for (int i=0;i<lch.size();i++) {
if (lch[i].sched_len != 0) {
log_h->info("Allocating scheduled lch=%d len=%d\n", lch[i].id, lch[i].sched_len);
allocate_sdu(lch[i].id, &pdu_msg, lch[i].sched_len);
}
}
if (!regular_bsr) {
// Insert Padding BSR if not inserted Regular/Periodic BSR
if (bsr_procedure->generate_padding_bsr(pdu_msg.rem_size(), &bsr)) {
if (pdu_msg.new_subh()) {
pdu_msg.get()->set_bsr(bsr.buff_size, bsr_format_convert(bsr.format));
bsr_is_inserted = true;
}
}
}
log_h->debug("Assembled MAC PDU msg size %d/%d bytes\n", pdu_msg.get_pdu_len()-pdu_msg.rem_size(), pdu_sz);
/* Generate MAC PDU and save to buffer */
uint8_t *ret = pdu_msg.write_packet(log_h);
pid_has_bsr[pid%MAX_HARQ_PROC] = bsr_is_inserted;
if (bsr_is_inserted) {
bsr_procedure->set_tx_tti(tx_tti);
}
pthread_mutex_unlock(&mutex);
return ret;
}
void mux::append_crnti_ce_next_tx(uint16_t crnti) {
pending_crnti_ce = crnti;
}
bool mux::sched_sdu(lchid_t *ch, int *sdu_space, int max_sdu_sz)
{
if (*sdu_space > 0) {
// Get n-th pending SDU pointer and length
int sched_len = ch->buffer_len;
if (sched_len > 0) { // there is pending SDU to allocate
if (sched_len > max_sdu_sz && max_sdu_sz >= 0) {
sched_len = max_sdu_sz;
}
if (sched_len > *sdu_space) {
sched_len = *sdu_space;
}
log_h->info("SDU: scheduled lcid=%d, rlc_buffer=%d, allocated=%d/%d\n",
ch->id, ch->buffer_len, sched_len, *sdu_space);
*sdu_space -= sched_len;
ch->buffer_len -= sched_len;
ch->sched_len += sched_len;
return true;
}
}
return false;
}
bool mux::allocate_sdu(uint32_t lcid, srslte::sch_pdu* pdu_msg, int max_sdu_sz)
{
// Get n-th pending SDU pointer and length
int sdu_len = rlc->get_buffer_state(lcid);
if (sdu_len > 0) { // there is pending SDU to allocate
int buffer_state = sdu_len;
if (sdu_len > max_sdu_sz && max_sdu_sz >= 0) {
sdu_len = max_sdu_sz;
}
int sdu_space = pdu_msg->get_sdu_space();
if (sdu_len > sdu_space) {
sdu_len = sdu_space;
}
if (sdu_len > MIN_RLC_SDU_LEN) {
if (pdu_msg->new_subh()) { // there is space for a new subheader
int sdu_len2 = sdu_len;
sdu_len = pdu_msg->get()->set_sdu(lcid, sdu_len, rlc);
if (sdu_len > 0) { // new SDU could be added
Info("SDU: allocated lcid=%d, rlc_buffer=%d, allocated=%d/%d, max_sdu_sz=%d, remaining=%d\n",
lcid, buffer_state, sdu_len, sdu_space, max_sdu_sz, pdu_msg->rem_size());
return true;
} else {
Warning("SDU: rlc_buffer=%d, allocated=%d/%d, remaining=%d\n",
buffer_state, sdu_len, sdu_space, pdu_msg->rem_size());
pdu_msg->del_subh();
}
}
}
}
return false;
}
void mux::msg3_flush()
{
if (log_h) {
Debug("Msg3 buffer flushed\n");
}
msg3_has_been_transmitted = false;
bzero(msg3_buff, sizeof(MSG3_BUFF_SZ));
}
bool mux::msg3_is_transmitted()
{
return msg3_has_been_transmitted;
}
/* Returns a pointer to the Msg3 buffer */
uint8_t* mux::msg3_get(uint8_t *payload, uint32_t pdu_sz)
{
uint8_t* msg3_buff_start_pdu = pdu_get(msg3_buff, pdu_sz, 0, 0);
if (!msg3_buff_start_pdu) {
Error("Moving PDU from Mux unit to Msg3 buffer\n");
return NULL;
}
memcpy(payload, msg3_buff_start_pdu, sizeof(uint8_t)*pdu_sz);
msg3_has_been_transmitted = true;
return payload;
}
}

403
srsue/src/mac/proc_bsr.cc Normal file
View File

@ -0,0 +1,403 @@
/**
*
* \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/.
*
*/
#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#include "mac/proc_bsr.h"
#include "mac/mac.h"
#include "mac/mux.h"
namespace srsue {
bsr_proc::bsr_proc()
{
initiated = false;
last_print = 0;
next_tx_tti = 0;
triggered_bsr_type=NONE;
}
void bsr_proc::init(rlc_interface_mac *rlc_, srslte::log* log_h_, mac_interface_rrc::mac_cfg_t *mac_cfg_, srslte::timers *timers_db_)
{
log_h = log_h_;
rlc = rlc_;
mac_cfg = mac_cfg_;
timers_db = timers_db_;
reset();
initiated = true;
}
void bsr_proc::reset()
{
timers_db->get(mac::BSR_TIMER_PERIODIC)->stop();
timers_db->get(mac::BSR_TIMER_PERIODIC)->reset();
timers_db->get(mac::BSR_TIMER_RETX)->stop();
timers_db->get(mac::BSR_TIMER_RETX)->reset();
reset_sr = false;
sr_is_sent = false;
triggered_bsr_type = NONE;
for (int i=0;i<MAX_LCID;i++) {
lcg[i] = -1;
priorities[i] = -1;
last_pending_data[i] = 0;
}
lcg[0] = 0;
priorities[0] = 99;
next_tx_tti = 0;
}
/* Process Periodic BSR */
void bsr_proc::timer_expired(uint32_t timer_id) {
switch(timer_id) {
case mac::BSR_TIMER_PERIODIC:
if (triggered_bsr_type == NONE) {
// Check condition 4 in Sec 5.4.5
triggered_bsr_type = PERIODIC;
Info("BSR: Triggering Periodic BSR\n");
}
break;
case mac::BSR_TIMER_RETX:
// Enable reTx of SR only if periodic timer is not infinity
int periodic = liblte_rrc_periodic_bsr_timer_num[mac_cfg->main.ulsch_cnfg.periodic_bsr_timer];
if (periodic >= 0) {
triggered_bsr_type = REGULAR;
Info("BSR: Triggering BSR reTX\n");
sr_is_sent = false;
}
break;
}
}
// Checks if data is available for a a channel with higher priority than others
bool bsr_proc::check_highest_channel() {
int pending_data_lcid = -1;
for (int i=0;i<MAX_LCID && pending_data_lcid == -1;i++) {
if (lcg[i] >= 0) {
if (rlc->get_buffer_state(i) > 0) {
pending_data_lcid = i;
for (int j=0;j<MAX_LCID;j++) {
if (rlc->get_buffer_state(j) > 0) {
if (priorities[j] > priorities[i]) {
pending_data_lcid = -1;
}
}
}
}
}
}
if (pending_data_lcid >= 0) {
// If there is new data available for this logical channel
uint32_t nbytes = rlc->get_buffer_state(pending_data_lcid);
if (nbytes > last_pending_data[pending_data_lcid])
{
if (triggered_bsr_type != REGULAR) {
Info("BSR: Triggered REGULAR BSR for Max Priority LCID=%d\n", pending_data_lcid);
}
triggered_bsr_type = REGULAR;
return true;
}
}
return false;
}
uint32_t bsr_proc::get_buffer_state() {
uint32_t buffer = 0;
for (int i=0;i<MAX_LCID;i++) {
if (lcg[i] >= 0) {
buffer += rlc->get_buffer_state(i);
}
}
return buffer;
}
// Checks if only one logical channel has data avaiable for Tx
bool bsr_proc::check_single_channel() {
uint32_t pending_data_lcid = 0;
uint32_t nof_nonzero_lcid = 0;
for (int i=0;i<MAX_LCID;i++) {
if (lcg[i] >= 0) {
if (rlc->get_buffer_state(i) > 0) {
pending_data_lcid = i;
nof_nonzero_lcid++;
}
}
}
if (nof_nonzero_lcid == 1) {
uint32_t nbytes = rlc->get_buffer_state(pending_data_lcid);
// If there is new data available for this logical channel
if (nbytes > last_pending_data[pending_data_lcid]) {
triggered_bsr_type = REGULAR;
Info("BSR: Triggered REGULAR BSR for single LCID=%d\n", pending_data_lcid);
return true;
}
}
return false;
}
void bsr_proc::update_pending_data() {
for (int i=0;i<MAX_LCID;i++) {
last_pending_data[i] = rlc->get_buffer_state(i);
}
}
bool bsr_proc::generate_bsr(bsr_t *bsr, uint32_t nof_padding_bytes) {
bool ret = false;
uint32_t nof_lcg=0;
bzero(bsr, sizeof(bsr_t));
for (int i=0;i<MAX_LCID;i++) {
if (lcg[i] >= 0) {
uint32_t n = rlc->get_buffer_state(i);
bsr->buff_size[lcg[i]] += n;
if (n > 0) {
nof_lcg++;
ret = true;
}
}
}
if (triggered_bsr_type == PADDING) {
if (nof_padding_bytes < 4) {
// If space only for short
if (nof_lcg > 1) {
bsr->format = TRUNC_BSR;
uint32_t max_prio_ch = find_max_priority_lcid();
for (int i=0;i<4;i++) {
if (lcg[max_prio_ch] != i) {
bsr->buff_size[i] = 0;
}
}
} else {
bsr->format = SHORT_BSR;
}
} else {
// If space for long BSR
bsr->format = LONG_BSR;
}
} else {
bsr->format = SHORT_BSR;
if (nof_lcg > 1) {
bsr->format = LONG_BSR;
}
}
return ret;
}
// Checks if Regular BSR must be assembled, as defined in 5.4.5
// Padding BSR is assembled when called by mux_unit when UL grant is received
// Periodic BSR is triggered by the expiration of the timers
void bsr_proc::step(uint32_t tti)
{
if (!initiated) {
return;
}
int periodic = liblte_rrc_periodic_bsr_timer_num[mac_cfg->main.ulsch_cnfg.periodic_bsr_timer];
if (periodic != timers_db->get(mac::BSR_TIMER_PERIODIC)->get_timeout() && periodic > 0)
{
timers_db->get(mac::BSR_TIMER_PERIODIC)->set(this, periodic);
timers_db->get(mac::BSR_TIMER_PERIODIC)->run();
Info("BSR: Configured timer periodic %d ms\n", periodic);
}
int retx = liblte_rrc_retransmission_bsr_timer_num[mac_cfg->main.ulsch_cnfg.retx_bsr_timer];
if (retx != timers_db->get(mac::BSR_TIMER_RETX)->get_timeout() && retx > 0)
{
timers_db->get(mac::BSR_TIMER_RETX)->set(this, retx);
timers_db->get(mac::BSR_TIMER_RETX)->run();
Info("BSR: Configured timer reTX %d ms\n", retx);
}
// Check condition 1 in Sec 5.4.5
if (triggered_bsr_type == NONE) {
check_single_channel();
}
// Higher priority channel is reported regardless of a BSR being already triggered
check_highest_channel();
update_pending_data();
if ((tti - last_print)%10240 > QUEUE_STATUS_PERIOD_MS) {
char str[128];
bzero(str, 128);
for (int i=0;i<MAX_LCID;i++) {
sprintf(str, "%s%d (%d), ", str, rlc->get_buffer_state(i), last_pending_data[i]);
}
Info("BSR: QUEUE status: %s\n", str);
last_print = tti;
}
}
char* bsr_proc::bsr_type_tostring(triggered_bsr_type_t type) {
switch(type) {
case bsr_proc::REGULAR:
return (char*) "Regular";
case bsr_proc::PADDING:
return (char*) "Padding";
case bsr_proc::PERIODIC:
return (char*) "Periodic";
default:
return (char*) "Regular";
}
}
char* bsr_proc::bsr_format_tostring(bsr_format_t format) {
switch(format) {
case bsr_proc::LONG_BSR:
return (char*) "Long";
case bsr_proc::SHORT_BSR:
return (char*) "Short";
case bsr_proc::TRUNC_BSR:
return (char*) "Truncated";
}
}
bool bsr_proc::need_to_send_bsr_on_ul_grant(uint32_t grant_size, bsr_t *bsr)
{
bool ret = false;
uint32_t bsr_sz = 0;
if (triggered_bsr_type == PERIODIC || triggered_bsr_type == REGULAR) {
/* Check if grant + MAC SDU headers is enough to accomodate all pending data */
int total_data = 0;
for (int i=0;i<MAX_LCID && total_data < grant_size;i++) {
total_data += srslte::sch_pdu::size_header_sdu(rlc->get_buffer_state(i))+rlc->get_buffer_state(i);
}
total_data--; // Because last SDU has no size header
/* All triggered BSRs shall be cancelled in case the UL grant can accommodate all pending data available for transmission
but is not sufficient to additionally accommodate the BSR MAC control element plus its subheader.
*/
generate_bsr(bsr, 0);
bsr_sz = bsr->format==LONG_BSR?3:1;
if (total_data <= grant_size && total_data + 1 + bsr_sz > grant_size) {
Debug("Grant is not enough to accomodate the BSR MAC CE\n");
} else {
Debug("BSR: Including Regular BSR: grant_size=%d, total_data=%d, bsr_sz=%d\n",
grant_size, total_data, bsr_sz);
ret = true;
}
if (timers_db->get(mac::BSR_TIMER_PERIODIC)->get_timeout() && bsr->format != TRUNC_BSR) {
timers_db->get(mac::BSR_TIMER_PERIODIC)->reset();
timers_db->get(mac::BSR_TIMER_PERIODIC)->run();
}
}
// Cancel all triggered BSR and SR
triggered_bsr_type = NONE;
reset_sr = true;
// Restart or Start ReTX timer
if (timers_db->get(mac::BSR_TIMER_RETX)->get_timeout()) {
timers_db->get(mac::BSR_TIMER_RETX)->reset();
timers_db->get(mac::BSR_TIMER_RETX)->run();
}
return ret;
}
bool bsr_proc::generate_padding_bsr(uint32_t nof_padding_bytes, bsr_t *bsr)
{
bool ret = false;
if (triggered_bsr_type != NONE || nof_padding_bytes >= 2) {
if (triggered_bsr_type == NONE) {
triggered_bsr_type = PADDING;
}
generate_bsr(bsr, nof_padding_bytes);
ret = true;
Info("BSR: Including BSR type %s, format %s, nof_padding_bytes=%d\n",
bsr_type_tostring(triggered_bsr_type), bsr_format_tostring(bsr->format), nof_padding_bytes);
if (timers_db->get(mac::BSR_TIMER_PERIODIC)->get_timeout() && bsr->format != TRUNC_BSR) {
timers_db->get(mac::BSR_TIMER_PERIODIC)->reset();
timers_db->get(mac::BSR_TIMER_PERIODIC)->run();
}
}
return ret;
}
void bsr_proc::set_tx_tti(uint32_t tti) {
Debug("BSR: Set next_tx_tti=%d\n", tti);
next_tx_tti = tti;
}
bool bsr_proc::need_to_reset_sr() {
if (reset_sr) {
reset_sr = false;
sr_is_sent = false;
Debug("BSR: SR reset. sr_is_sent and reset_rs false\n");
return true;
} else {
return false;
}
}
bool bsr_proc::need_to_send_sr(uint32_t tti) {
if (!sr_is_sent && triggered_bsr_type == REGULAR) {
if (srslte_tti_interval(tti,next_tx_tti)>0 && srslte_tti_interval(tti,next_tx_tti) < 10240-4) {
reset_sr = false;
sr_is_sent = true;
Info("BSR: Need to send sr: sr_is_sent=true, reset_sr=false, tti=%d, next_tx_tti=%d\n", tti, next_tx_tti);
return true;
} else {
Debug("BSR: Not sending SR because tti=%d, next_tx_tti=%d\n", tti, next_tx_tti);
}
}
return false;
}
void bsr_proc::setup_lcg(uint32_t lcid, uint32_t new_lcg)
{
if (lcid < MAX_LCID && new_lcg < 4) {
lcg[lcid] = new_lcg;
}
}
void bsr_proc::set_priority(uint32_t lcid, uint32_t priority) {
if (lcid < MAX_LCID) {
priorities[lcid] = priority;
}
}
uint32_t bsr_proc::find_max_priority_lcid() {
uint32_t max_prio = 0, max_idx = 0;
for (int i=0;i<MAX_LCID;i++) {
if (priorities[i] > max_prio) {
max_prio = priorities[i];
max_idx = i;
}
}
return max_idx;
}
}

156
srsue/src/mac/proc_phr.cc Normal file
View File

@ -0,0 +1,156 @@
/**
*
* \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/.
*
*/
#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#include "mac/proc_phr.h"
#include "mac/mac.h"
#include "mac/mux.h"
#include "common/phy_interface.h"
namespace srsue {
phr_proc::phr_proc()
{
initiated = false;
}
void phr_proc::init(phy_interface_mac* phy_h_, srslte::log* log_h_, mac_interface_rrc::mac_cfg_t *mac_cfg_, srslte::timers *timers_db_)
{
phy_h = phy_h_;
log_h = log_h_;
mac_cfg = mac_cfg_;
timers_db = timers_db_;
initiated = true;
reset();
}
void phr_proc::reset()
{
phr_is_triggered = false;
timer_periodic = -2;
timer_prohibit = -2;
dl_pathloss_change = -2;
}
bool phr_proc::pathloss_changed() {
int min_change = liblte_rrc_dl_pathloss_change_num[mac_cfg->main.phr_cnfg.dl_pathloss_change];
int cur_pathloss_db = (int) phy_h->get_pathloss_db();
if (abs(cur_pathloss_db - last_pathloss_db) > min_change && min_change > 0) {
last_pathloss_db = cur_pathloss_db;
return true;
} else {
return false;
}
}
/* Trigger PHR when timers exire */
void phr_proc::timer_expired(uint32_t timer_id) {
switch(timer_id) {
case mac::PHR_TIMER_PERIODIC:
timers_db->get(mac::PHR_TIMER_PERIODIC)->reset();
timers_db->get(mac::PHR_TIMER_PERIODIC)->run();
Debug("PHR: Triggered by timer periodic (timer expired).\n");
phr_is_triggered = true;
break;
case mac::PHR_TIMER_PROHIBIT:
int pathloss_db = liblte_rrc_dl_pathloss_change_num[mac_cfg->main.phr_cnfg.dl_pathloss_change];
if (pathloss_changed()) {
Info("PHR: Triggered by pathloss difference. cur_pathloss_db=%f (timer expired)\n", last_pathloss_db);
phr_is_triggered = true;
}
break;
}
}
void phr_proc::step(uint32_t tti)
{
if (!initiated) {
return;
}
if (mac_cfg->main.phr_cnfg.setup_present) {
int cfg_timer_periodic = liblte_rrc_periodic_phr_timer_num[mac_cfg->main.phr_cnfg.periodic_phr_timer];
// Setup timers and trigger PHR when configuration changed by higher layers
if (timer_periodic != cfg_timer_periodic && cfg_timer_periodic > 0)
{
timer_periodic = cfg_timer_periodic;
timers_db->get(mac::PHR_TIMER_PERIODIC)->set(this, timer_periodic);
timers_db->get(mac::PHR_TIMER_PERIODIC)->run();
phr_is_triggered = true;
Info("PHR: Configured timer periodic %d ms\n", timer_periodic);
}
}
int cfg_timer_prohibit = liblte_rrc_prohibit_phr_timer_num[mac_cfg->main.phr_cnfg.prohibit_phr_timer];
if (timer_prohibit != cfg_timer_prohibit && cfg_timer_prohibit > 0)
{
timer_prohibit = cfg_timer_prohibit;
timers_db->get(mac::PHR_TIMER_PROHIBIT)->set(this, timer_prohibit);
timers_db->get(mac::PHR_TIMER_PROHIBIT)->run();
Info("PHR: Configured timer prohibit %d ms\n", timer_prohibit);
phr_is_triggered = true;
}
if (pathloss_changed() && timers_db->get(mac::PHR_TIMER_PROHIBIT)->is_expired())
{
Info("PHR: Triggered by pathloss difference. cur_pathloss_db=%f\n", last_pathloss_db);
phr_is_triggered = true;
}
}
bool phr_proc::generate_phr_on_ul_grant(float *phr)
{
if (phr_is_triggered) {
if (phr) {
*phr = phy_h->get_phr();
}
Debug("PHR: Generating PHR=%f\n", phr?*phr:0.0);
timers_db->get(mac::PHR_TIMER_PERIODIC)->reset();
timers_db->get(mac::PHR_TIMER_PROHIBIT)->reset();
timers_db->get(mac::PHR_TIMER_PERIODIC)->run();
timers_db->get(mac::PHR_TIMER_PROHIBIT)->run();
phr_is_triggered = false;
return true;
} else {
return false;
}
}
}

565
srsue/src/mac/proc_ra.cc Normal file
View File

@ -0,0 +1,565 @@
/**
*
* \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/.
*
*/
#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#include <stdlib.h>
#include <stdint.h>
#include <signal.h>
#include "mac/proc_ra.h"
#include "mac/mac.h"
#include "mac/mux.h"
/* Random access procedure as specified in Section 5.1 of 36.321 */
namespace srsue {
// Table 7.2-1. Backoff Parameter values
uint32_t backoff_table[16] = {0, 10, 20, 30, 40, 60, 80, 120, 160, 240, 320, 480, 960, 960, 960, 960};
// Table 7.6-1: DELTA_PREAMBLE values.
int delta_preamble_db_table[5] = {0, 0, -3, -3, 8};
void ra_proc::init(phy_interface_mac* phy_h_,
rrc_interface_mac *rrc_,
srslte::log* log_h_,
mac_interface_rrc::ue_rnti_t *rntis_,
mac_interface_rrc::mac_cfg_t *mac_cfg_,
srslte::timers* timers_db_,
mux* mux_unit_,
demux* demux_unit_)
{
phy_h = phy_h_;
log_h = log_h_;
mac_cfg = mac_cfg_;
rntis = rntis_;
timers_db = timers_db_;
mux_unit = mux_unit_;
demux_unit= demux_unit_;
rrc = rrc_;
srslte_softbuffer_rx_init(&softbuffer_rar, 10);
// Tell demux to call us when a UE CRID is received
demux_unit->set_uecrid_callback(uecrid_callback, this);
reset();
}
void ra_proc::reset() {
state = IDLE;
msg3_transmitted = false;
started_by_pdcch = false;
}
void ra_proc::start_pcap(srslte::mac_pcap* pcap_)
{
pcap = pcap_;
}
void ra_proc::read_params() {
// Read initialization parameters
configIndex = mac_cfg->prach_config_index;
preambleIndex = 0; // pass when called from higher layers for non-contention based RA
maskIndex = 0; // same
nof_preambles = liblte_rrc_number_of_ra_preambles_num[mac_cfg->rach.num_ra_preambles];
if (mac_cfg->rach.preambles_group_a_cnfg.present) {
nof_groupA_preambles = liblte_rrc_size_of_ra_preambles_group_a_num[mac_cfg->rach.preambles_group_a_cnfg.size_of_ra];
} else {
nof_groupA_preambles = nof_preambles;
}
if (nof_groupA_preambles > nof_preambles) {
nof_groupA_preambles = nof_preambles;
}
nof_groupB_preambles = nof_preambles - nof_groupA_preambles;
if (nof_groupB_preambles) {
messagePowerOffsetGroupB= liblte_rrc_message_power_offset_group_b_num[mac_cfg->rach.preambles_group_a_cnfg.msg_pwr_offset_group_b];
messageSizeGroupA = liblte_rrc_message_size_group_a_num[mac_cfg->rach.preambles_group_a_cnfg.msg_size];
}
responseWindowSize = liblte_rrc_ra_response_window_size_num[mac_cfg->rach.ra_resp_win_size];
powerRampingStep = liblte_rrc_power_ramping_step_num[mac_cfg->rach.pwr_ramping_step];
preambleTransMax = liblte_rrc_preamble_trans_max_num[mac_cfg->rach.preamble_trans_max];
iniReceivedTargetPower = liblte_rrc_preamble_initial_received_target_power_num[mac_cfg->rach.preamble_init_rx_target_pwr];
contentionResolutionTimer = liblte_rrc_mac_contention_resolution_timer_num[mac_cfg->rach.mac_con_res_timer];
delta_preamble_db = delta_preamble_db_table[configIndex%5];
if (contentionResolutionTimer > 0) {
timers_db->get(mac::CONTENTION_TIMER)->set(this, contentionResolutionTimer);
}
}
bool ra_proc::in_progress()
{
return (state > IDLE && state != COMPLETION_DONE);
}
bool ra_proc::is_successful() {
return state == COMPLETION_DONE;
}
bool ra_proc::is_response_error() {
return state == RESPONSE_ERROR;
}
bool ra_proc::is_contention_resolution() {
return state == CONTENTION_RESOLUTION;
}
bool ra_proc::is_error() {
return state == RA_PROBLEM;
}
const char* state_str[12] = {"Idle",
"RA: INIT: ",
"RA: Select: ",
"RA: TX: ",
"RA: PDCCH: ",
"RA: Rx: ",
"RA: RxErr: ",
"RA: Backof: ",
"RA: ConRes: ",
"RA: Done: ",
"RA: Done: ",
"RA: Error: "};
#define rError(fmt, ...) Error("%s" fmt, state_str[state], ##__VA_ARGS__)
#define rInfo(fmt, ...) Info("%s" fmt, state_str[state], ##__VA_ARGS__)
#define rDebug(fmt, ...) Debug("%s" fmt, state_str[state], ##__VA_ARGS__)
// Process Timing Advance Command as defined in Section 5.2
void ra_proc::process_timeadv_cmd(uint32_t ta) {
if (preambleIndex == 0) {
// Preamble not selected by UE MAC
phy_h->set_timeadv_rar(ta);
timers_db->get(mac::TIME_ALIGNMENT)->reset();
timers_db->get(mac::TIME_ALIGNMENT)->run();
Debug("Applying RAR TA CMD %d\n", ta);
} else {
// Preamble selected by UE MAC
if (!timers_db->get(mac::TIME_ALIGNMENT)->is_running()) {
phy_h->set_timeadv_rar(ta);
timers_db->get(mac::TIME_ALIGNMENT)->run();
Debug("Applying RAR TA CMD %d\n", ta);
} else {
// Ignore TA CMD
Warning("Ignoring RAR TA CMD because timeAlignmentTimer still running\n");
}
}
}
void ra_proc::step_initialization() {
read_params();
pdcch_to_crnti_received = PDCCH_CRNTI_NOT_RECEIVED;
transmitted_contention_id = 0;
preambleTransmissionCounter = 1;
first_rar_received = true;
mux_unit->msg3_flush();
msg3_flushed = false;
backoff_param_ms = 0;
// FIXME: This is because RA in Connected state not working in amarisoft
transmitted_crnti = rntis->crnti;
if(transmitted_crnti) {
state = RESPONSE_ERROR;
}
// Instruct phy to configure PRACH
phy_h->configure_prach_params();
state = RESOURCE_SELECTION;
}
void ra_proc::step_resource_selection() {
ra_group_t sel_group;
if (preambleIndex > 0) {
// Preamble is chosen by Higher layers (ie Network)
sel_maskIndex = maskIndex;
sel_preamble = (uint32_t) preambleIndex%nof_preambles;
} else {
// Preamble is chosen by MAC UE
if (!msg3_transmitted) {
if (nof_groupB_preambles > 0 && new_ra_msg_len > messageSizeGroupA) { // Check also pathloss (Pcmax,deltaPreamble and powerOffset)
sel_group = RA_GROUP_B;
} else {
sel_group = RA_GROUP_A;
}
last_msg3_group = sel_group;
} else {
sel_group = last_msg3_group;
}
if (sel_group == RA_GROUP_A) {
if (nof_groupA_preambles) {
sel_preamble = preambleTransmissionCounter%nof_groupA_preambles;
} else {
rError("Selected group preamble A but nof_groupA_preambles=0\n");
state = RA_PROBLEM;
return;
}
} else {
if (nof_groupB_preambles) {
sel_preamble = nof_groupA_preambles + rand()%nof_groupB_preambles;
} else {
rError("Selected group preamble B but nof_groupA_preambles=0\n");
state = RA_PROBLEM;
return;
}
}
sel_maskIndex = 0;
}
rDebug("Selected preambleIndex=%d maskIndex=%d GroupA=%d, GroupB=%d\n",
sel_preamble, sel_maskIndex,nof_groupA_preambles, nof_groupB_preambles);
state = PREAMBLE_TRANSMISSION;
}
void ra_proc::step_preamble_transmission() {
received_target_power_dbm = iniReceivedTargetPower +
delta_preamble_db +
(preambleTransmissionCounter-1)*powerRampingStep;
rar_received = false;
phy_h->prach_send(sel_preamble, sel_maskIndex - 1, received_target_power_dbm);
state = PDCCH_SETUP;
}
void ra_proc::step_pdcch_setup() {
int ra_tti = phy_h->prach_tx_tti();
if (ra_tti > 0) {
ra_rnti = 1+ra_tti%10;
rInfo("seq=%d, ra-rnti=0x%x, ra-tti=%d\n", sel_preamble, ra_rnti, ra_tti);
log_h->console("Random Access Transmission: seq=%d, ra-rnti=0x%x\n", sel_preamble, ra_rnti);
phy_h->pdcch_dl_search(SRSLTE_RNTI_RAR, ra_rnti, ra_tti+3, ra_tti+3+responseWindowSize);
state = RESPONSE_RECEPTION;
}
}
void ra_proc::new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_dl_t* action)
{
if (grant.n_bytes < MAX_RAR_PDU_LEN) {
rDebug("DL grant found RA-RNTI=%d\n", ra_rnti);
action->decode_enabled = true;
action->default_ack = false;
action->generate_ack = false;
action->payload_ptr = rar_pdu_buffer;
action->rnti = grant.rnti;
memcpy(&action->phy_grant, &grant.phy_grant, sizeof(srslte_phy_grant_t));
action->rv = grant.rv;
action->softbuffer = &softbuffer_rar;
rar_grant_nbytes = grant.n_bytes;
rar_grant_tti = grant.tti;
if (action->rv == 0) {
srslte_softbuffer_rx_reset(&softbuffer_rar);
}
} else {
rError("Received RAR grant exceeds buffer length (%d>%d)\n", grant.n_bytes, MAX_RAR_PDU_LEN);
action->decode_enabled = false;
state = RESPONSE_ERROR;
}
}
void ra_proc::tb_decoded_ok() {
if (pcap) {
pcap->write_dl_ranti(rar_pdu_buffer, rar_grant_nbytes, ra_rnti, true, rar_grant_tti);
}
rDebug("RAR decoded successfully TBS=%d\n", rar_grant_nbytes);
rar_pdu_msg.init_rx(rar_grant_nbytes);
rar_pdu_msg.parse_packet(rar_pdu_buffer);
// Set Backoff parameter
if (rar_pdu_msg.has_backoff()) {
backoff_param_ms = backoff_table[rar_pdu_msg.get_backoff()%16];
} else {
backoff_param_ms = 0;
}
current_ta = 0;
while(rar_pdu_msg.next()) {
if (rar_pdu_msg.get()->get_rapid() == sel_preamble) {
rar_received = true;
process_timeadv_cmd(rar_pdu_msg.get()->get_ta_cmd());
// FIXME: Indicate received target power
//phy_h->set_target_power_rar(iniReceivedTargetPower, (preambleTransmissionCounter-1)*powerRampingStep);
uint8_t grant[srslte::rar_subh::RAR_GRANT_LEN];
rar_pdu_msg.get()->get_sched_grant(grant);
phy_h->pdcch_dl_search_reset();
phy_h->set_rar_grant(rar_grant_tti, grant);
current_ta = rar_pdu_msg.get()->get_ta_cmd();
rInfo("RAPID=%d, TA=%d\n", sel_preamble, rar_pdu_msg.get()->get_ta_cmd());
if (preambleIndex > 0) {
// Preamble selected by Network
state = COMPLETION;
} else {
// Preamble selected by UE MAC
rntis->temp_rnti = rar_pdu_msg.get()->get_temp_crnti();
phy_h->pdcch_dl_search(SRSLTE_RNTI_TEMP, rar_pdu_msg.get()->get_temp_crnti());
if (first_rar_received) {
first_rar_received = false;
// Save transmitted C-RNTI (if any)
transmitted_crnti = rntis->crnti;
// If we have a C-RNTI, tell Mux unit to append C-RNTI CE if no CCCH SDU transmission
if (transmitted_crnti) {
rDebug("Appending C-RNTI MAC CE in next transmission\n");
mux_unit->append_crnti_ce_next_tx(transmitted_crnti);
phy_h->pdcch_ul_search(SRSLTE_RNTI_USER, transmitted_crnti);
phy_h->pdcch_dl_search(SRSLTE_RNTI_USER, transmitted_crnti);
}
}
rDebug("Going to Contention Resolution state\n");
state = CONTENTION_RESOLUTION;
// Start contention resolution timer
timers_db->get(mac::CONTENTION_TIMER)->reset();
timers_db->get(mac::CONTENTION_TIMER)->run();
}
} else {
rDebug("Found RAR for preamble %d\n", rar_pdu_msg.get()->get_rapid());
}
}
}
void ra_proc::step_response_reception() {
// do nothing. Processing done in tb_decoded_ok()
int ra_tti = phy_h->prach_tx_tti();
if (ra_tti >= 0 && !rar_received) {
uint32_t interval = srslte_tti_interval(phy_h->get_current_tti(), ra_tti+3+responseWindowSize);
if (interval > 1 && interval < 100) {
rDebug("RA response not received within the response window\n");
state = RESPONSE_ERROR;
}
}
}
void ra_proc::step_response_error() {
preambleTransmissionCounter++;
if (preambleTransmissionCounter >= preambleTransMax + 1) {
rError("Maximum number of transmissions reached (%d)\n", preambleTransMax);
rrc->ra_problem();
state = RA_PROBLEM;
} else {
backoff_interval_start = phy_h->get_current_tti();
if (backoff_param_ms) {
backoff_inteval = rand()%backoff_param_ms;
} else {
backoff_inteval = 0;
}
if (backoff_inteval) {
rDebug("Backoff wait interval %d\n", backoff_inteval);
state = BACKOFF_WAIT;
} else {
rDebug("Transmitting inmediatly (%d/%d)\n", preambleTransmissionCounter, preambleTransMax);
state = RESOURCE_SELECTION;
}
}
}
void ra_proc::step_backoff_wait() {
if (srslte_tti_interval(phy_h->get_current_tti(), backoff_interval_start) >= backoff_inteval) {
state = RESOURCE_SELECTION;
}
}
bool ra_proc::uecrid_callback(void *arg, uint64_t uecri) {
return ((ra_proc*) arg)->contention_resolution_id_received(uecri);
}
// Random Access initiated by RRC by the transmission of CCCH SDU
bool ra_proc::contention_resolution_id_received(uint64_t rx_contention_id) {
bool uecri_successful = false;
rDebug("MAC PDU Contains Contention Resolution ID CE\n");
// MAC PDU successfully decoded and contains MAC CE contention Id
timers_db->get(mac::CONTENTION_TIMER)->stop();
if (transmitted_contention_id == rx_contention_id)
{
// UE Contention Resolution ID included in MAC CE matches the CCCH SDU transmitted in Msg3
rntis->crnti = rntis->temp_rnti;
// finish the disassembly and demultiplexing of the MAC PDU
uecri_successful = true;
state = COMPLETION;
} else {
rInfo("Transmitted UE Contention Id differs from received Contention ID (0x%lx != 0x%lx)\n",
transmitted_contention_id, rx_contention_id);
// Discard MAC PDU
uecri_successful = false;
// Contention Resolution not successfully is like RAR not successful
// FIXME: Need to flush Msg3 HARQ buffer. Why?
state = RESPONSE_ERROR;
}
rntis->temp_rnti = 0;
return uecri_successful;
}
void ra_proc::step_contention_resolution() {
// If Msg3 has been sent
if (mux_unit->msg3_is_transmitted())
{
msg3_transmitted = true;
if (transmitted_crnti)
{
// Random Access with transmission of MAC C-RNTI CE
if ((!started_by_pdcch && pdcch_to_crnti_received == PDCCH_CRNTI_UL_GRANT) ||
started_by_pdcch && pdcch_to_crnti_received != PDCCH_CRNTI_NOT_RECEIVED)
{
rDebug("PDCCH for C-RNTI received\n");
timers_db->get(mac::CONTENTION_TIMER)->stop();
rntis->temp_rnti = 0;
state = COMPLETION;
}
pdcch_to_crnti_received = PDCCH_CRNTI_NOT_RECEIVED;
} else {
// RA with transmission of CCCH SDU is resolved in contention_resolution_id_received() callback function
if (!transmitted_contention_id) {
// Save transmitted UE contention id, as defined by higher layers
transmitted_contention_id = rntis->contention_id;
rntis->contention_id = 0;
}
}
} else {
rDebug("Msg3 not yet transmitted\n");
}
}
void ra_proc::step_completition() {
log_h->console("Random Access Complete. c-rnti=0x%x, ta=%d\n", rntis->crnti, current_ta);
rInfo("Random Access Complete. c-rnti=0x%x, ta=%d\n", rntis->crnti, current_ta);
if (!msg3_flushed) {
mux_unit->msg3_flush();
msg3_flushed = true;
}
msg3_transmitted = false;
state = COMPLETION_DONE;
}
void ra_proc::step(uint32_t tti_)
{
switch(state) {
case IDLE:
break;
case INITIALIZATION:
step_initialization();
break;
case RESOURCE_SELECTION:
step_resource_selection();
break;
case PREAMBLE_TRANSMISSION:
step_preamble_transmission();
break;
case PDCCH_SETUP:
step_pdcch_setup();
break;
case RESPONSE_RECEPTION:
step_response_reception();
break;
case RESPONSE_ERROR:
step_response_error();
break;
case BACKOFF_WAIT:
step_backoff_wait();
break;
case CONTENTION_RESOLUTION:
step_contention_resolution();
break;
case COMPLETION:
step_completition();
case COMPLETION_DONE:
break;
}
}
void ra_proc::start_mac_order(uint32_t msg_len_bits)
{
if (state == IDLE || state == COMPLETION_DONE || state == RA_PROBLEM) {
started_by_pdcch = false;
new_ra_msg_len = msg_len_bits;
state = INITIALIZATION;
rInfo("Starting PRACH by MAC order\n");
}
}
void ra_proc::start_pdcch_order()
{
if (state == IDLE || state == COMPLETION_DONE || state == RA_PROBLEM) {
started_by_pdcch = true;
state = INITIALIZATION;
rInfo("Starting PRACH by PDCCH order\n");
}
}
// Contention Resolution Timer is expired (Section 5.1.5)
void ra_proc::timer_expired(uint32_t timer_id)
{
rInfo("Contention Resolution Timer expired. Stopping PDCCH Search and going to Response Error\n");
rntis->temp_rnti = 0;
state = RESPONSE_ERROR;
phy_h->pdcch_dl_search_reset();
}
void ra_proc::pdcch_to_crnti(bool contains_uplink_grant) {
rDebug("PDCCH to C-RNTI received %s UL grant\n", contains_uplink_grant?"with":"without");
if (contains_uplink_grant) {
pdcch_to_crnti_received = PDCCH_CRNTI_UL_GRANT;
} else if (pdcch_to_crnti_received == PDCCH_CRNTI_NOT_RECEIVED) {
pdcch_to_crnti_received = PDCCH_CRNTI_DL_GRANT;
}
}
void ra_proc::harq_retx()
{
timers_db->get(mac::CONTENTION_TIMER)->reset();
}
}

129
srsue/src/mac/proc_sr.cc Normal file
View File

@ -0,0 +1,129 @@
/**
*
* \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/.
*
*/
#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#include "mac/proc_sr.h"
namespace srsue {
sr_proc::sr_proc() {
initiated = false;
}
void sr_proc::init(phy_interface_mac* phy_h_, rrc_interface_mac *rrc_, srslte::log* log_h_, mac_interface_rrc::mac_cfg_t *mac_cfg_)
{
log_h = log_h_;
rrc = rrc_;
mac_cfg = mac_cfg_;
phy_h = phy_h_;
initiated = true;
do_ra = false;
}
void sr_proc::reset()
{
is_pending_sr = false;
}
bool sr_proc::need_tx(uint32_t tti)
{
int last_tx_tti = phy_h->sr_last_tx_tti();
if (last_tx_tti >= 0) {
if (tti > last_tx_tti) {
if (tti - last_tx_tti > 8) {
return true;
}
} else {
uint32_t interval = 10240-last_tx_tti+tti;
if (interval > 8 && tti < 8) {
return true;
}
}
}
return false;
}
void sr_proc::step(uint32_t tti)
{
if (initiated) {
if (is_pending_sr) {
if (mac_cfg->sr.setup_present) {
if (sr_counter < dsr_transmax) {
if (sr_counter == 0 || need_tx(tti)) {
sr_counter++;
Info("SR: Signalling PHY sr_counter=%d\n", sr_counter);
phy_h->sr_send();
}
} else {
if (need_tx(tti)) {
Info("SR: Releasing PUCCH/SRS resources, sr_counter=%d, dsr_transmax=%d\n",
sr_counter, dsr_transmax);
log_h->console("Scheduling request failed: releasing RRC connection...\n");
rrc->release_pucch_srs();
do_ra = true;
is_pending_sr = false;
}
}
} else {
Info("SR: PUCCH not configured. Starting RA procedure\n");
do_ra = true;
reset();
}
}
}
}
bool sr_proc::need_random_access() {
if (initiated) {
if (do_ra) {
do_ra = false;
return true;
} else {
return false;
}
}
return false;
}
void sr_proc::start()
{
if (initiated) {
if (!is_pending_sr) {
sr_counter = 0;
is_pending_sr = true;
}
dsr_transmax = liblte_rrc_dsr_trans_max_num[mac_cfg->sr.dsr_trans_max];
Debug("SR: Starting Procedure. dsrTransMax=%d\n", dsr_transmax);
}
}
}

394
srsue/src/mac/ul_harq.cc Normal file
View File

@ -0,0 +1,394 @@
/**
*
* \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/.
*
*/
#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#include "common/log.h"
#include "mac/mac.h"
#include "mac/ul_harq.h"
namespace srsue {
/***********************************************************
*
* HARQ ENTITY
*
*********************************************************/
bool ul_harq_entity::init(srslte::log *log_h_,
mac_interface_rrc::ue_rnti_t *rntis_,
mac_interface_rrc::mac_cfg_t *mac_cfg_,
srslte::timers *timers_db_,
mux *mux_unit_) {
log_h = log_h_;
mux_unit = mux_unit_;
mac_cfg = mac_cfg_;
rntis = rntis_;
timers_db = timers_db_;
for (uint32_t i=0;i<NOF_HARQ_PROC;i++) {
if (!proc[i].init(i, this)) {
return false;
}
}
return true;
}
uint32_t ul_harq_entity::pidof(uint32_t tti) {
return (uint32_t) tti%NOF_HARQ_PROC;
}
void ul_harq_entity::start_pcap(srslte::mac_pcap* pcap_)
{
pcap = pcap_;
}
void ul_harq_entity::reset() {
for (uint32_t i=0;i<NOF_HARQ_PROC;i++) {
proc[i].reset();
}
ul_sps_assig.clear();
}
void ul_harq_entity::reset_ndi() {
for (uint32_t i=0;i<NOF_HARQ_PROC;i++) {
proc[i].reset_ndi();
}
}
int ul_harq_entity::get_current_tbs(uint32_t tti) {
int tti_harq = (int) tti-4;
if (tti_harq < 0) {
tti_harq += 10240;
}
uint32_t pid_harq = pidof(tti_harq);
return proc[pid_harq].get_current_tbs();
}
void ul_harq_entity::set_ack(uint32_t tti, bool ack) {
int tti_harq = (int) tti - 4;
if (tti_harq < 0) {
tti_harq += 10240;
}
uint32_t pid_harq = pidof(tti_harq);
if (proc[pid_harq].has_grant() && proc[pid_harq].last_tx_tti() <= tti_harq) {
proc[pid_harq].set_harq_feedback(ack);
}
}
void ul_harq_entity::harq_recv(uint32_t tti, bool ack, mac_interface_phy::tb_action_ul_t* action)
{
set_ack(tti, ack);
run_tti(tti, NULL, action);
}
// Implements Section 5.4.1
void ul_harq_entity::new_grant_ul(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_ul_t* action)
{
if (grant.rnti_type == SRSLTE_RNTI_USER ||
grant.rnti_type == SRSLTE_RNTI_TEMP ||
grant.rnti_type == SRSLTE_RNTI_RAR)
{
if (grant.rnti_type == SRSLTE_RNTI_USER && proc[pidof(grant.tti)].is_sps()) {
grant.ndi = true;
}
run_tti(grant.tti, &grant, action);
} else if (grant.rnti_type == SRSLTE_RNTI_SPS) {
if (grant.ndi) {
grant.ndi = proc[pidof(grant.tti)].get_ndi();
run_tti(grant.tti, &grant, action);
} else {
Info("Not implemented\n");
}
}
}
void ul_harq_entity::new_grant_ul_ack(mac_interface_phy::mac_grant_t grant, bool ack, mac_interface_phy::tb_action_ul_t* action)
{
set_ack(grant.tti, ack);
new_grant_ul(grant, action);
}
// Implements Section 5.4.2.1
// Called with UL grant
void ul_harq_entity::run_tti(uint32_t tti, mac_interface_phy::mac_grant_t *grant, mac_interface_phy::tb_action_ul_t* action)
{
uint32_t tti_tx = (tti+4)%10240;
proc[pidof(tti_tx)].run_tti(tti_tx, grant, action);
}
float ul_harq_entity::get_average_retx()
{
return average_retx;
}
/***********************************************************
*
* HARQ PROCESS
*
*********************************************************/
static int rv_of_irv[4] = {0, 2, 3, 1};
static int irv_of_rv[4] = {0, 3, 1, 2};
ul_harq_entity::ul_harq_process::ul_harq_process() {
current_tx_nb = 0;
current_irv = 0;
is_initiated = false;
is_grant_configured = false;
tti_last_tx = 0;
bzero(&cur_grant, sizeof(mac_interface_phy::mac_grant_t));
}
void ul_harq_entity::ul_harq_process::reset() {
current_tx_nb = 0;
current_irv = 0;
tti_last_tx = 0;
is_grant_configured = false;
bzero(&cur_grant, sizeof(mac_interface_phy::mac_grant_t));
}
bool ul_harq_entity::ul_harq_process::has_grant() {
return is_grant_configured;
}
void ul_harq_entity::ul_harq_process::reset_ndi() {
ndi = false;
}
bool ul_harq_entity::ul_harq_process::get_ndi()
{
return ndi;
}
uint32_t ul_harq_entity::ul_harq_process::get_rv()
{
return rv_of_irv[current_irv%4];
}
void ul_harq_entity::ul_harq_process::set_harq_feedback(bool ack) {
harq_feedback = ack;
// UL packet successfully delivered
if (ack) {
Info("UL %d: HARQ = ACK for UL transmission. Discarting TB.\n", pid);
reset();
} else {
Info("UL %d: HARQ = NACK for UL transmission\n", pid);
}
}
bool ul_harq_entity::ul_harq_process::init(uint32_t pid_, ul_harq_entity* parent) {
if (srslte_softbuffer_tx_init(&softbuffer, 110)) {
fprintf(stderr, "Error initiating soft buffer\n");
return false;
} else {
is_initiated = true;
harq_entity = parent;
log_h = harq_entity->log_h;
pid = pid_;
payload_buffer = (uint8_t*) srslte_vec_malloc(payload_buffer_len*sizeof(uint8_t));
if (!payload_buffer) {
Error("Allocating memory\n");
return false;
}
pdu_ptr = payload_buffer;
return true;
}
}
void ul_harq_entity::ul_harq_process::run_tti(uint32_t tti_tx, mac_interface_phy::mac_grant_t* grant, mac_interface_phy::tb_action_ul_t* action)
{
int max_retx;
if (is_msg3) {
max_retx = harq_entity->mac_cfg->rach.max_harq_msg3_tx;
} else {
max_retx = liblte_rrc_max_harq_tx_num[harq_entity->mac_cfg->main.ulsch_cnfg.max_harq_tx];
}
// Receive and route HARQ feedbacks
if (grant) {
if ((!grant->rnti_type == SRSLTE_RNTI_TEMP && grant->ndi != get_ndi()) ||
(grant->rnti_type == SRSLTE_RNTI_USER && !has_grant()) ||
grant->is_from_rar)
{
// New transmission
// Uplink grant in a RAR
if (grant->is_from_rar) {
Debug("Getting Msg3 buffer payload, grant size=%d bytes\n", grant->n_bytes);
pdu_ptr = harq_entity->mux_unit->msg3_get(payload_buffer, grant->n_bytes);
if (pdu_ptr) {
generate_new_tx(tti_tx, true, grant, action);
} else {
Warning("UL RAR grant available but no Msg3 on buffer\n");
}
// Normal UL grant
} else {
// Request a MAC PDU from the Multiplexing & Assemble Unit
pdu_ptr = harq_entity->mux_unit->pdu_get(payload_buffer, grant->n_bytes, tti_tx, pid);
if (pdu_ptr) {
generate_new_tx(tti_tx, false, grant, action);
} else {
Warning("Uplink grant but no MAC PDU in Multiplex Unit buffer\n");
}
}
} else {
// Adaptive Re-TX
if (current_tx_nb >= max_retx) {
Info("UL %d: Maximum number of ReTX reached (%d). Discarting TB.\n", pid, max_retx);
reset();
action->expect_ack = false;
} else {
generate_retx(tti_tx, grant, action);
}
}
} else if (has_grant()) {
// Non-Adaptive Re-Tx
if (current_tx_nb >= max_retx) {
Info("UL %d: Maximum number of ReTX reached (%d). Discarting TB.\n", pid, max_retx);
reset();
action->expect_ack = false;
} else {
generate_retx(tti_tx, action);
}
}
if (harq_entity->pcap && grant) {
if (grant->is_from_rar) {
grant->rnti = harq_entity->rntis->temp_rnti;
}
harq_entity->pcap->write_ul_crnti(pdu_ptr, grant->n_bytes, grant->rnti, get_nof_retx(), tti_tx);
}
}
int ul_harq_entity::ul_harq_process::get_current_tbs()
{
return cur_grant.n_bytes*8;
}
void ul_harq_entity::ul_harq_process::generate_retx(uint32_t tti_tx, mac_interface_phy::tb_action_ul_t *action)
{
generate_retx(tti_tx, NULL, action);
}
// Retransmission with or w/o grant (Section 5.4.2.2)
void ul_harq_entity::ul_harq_process::generate_retx(uint32_t tti_tx, mac_interface_phy::mac_grant_t *grant,
mac_interface_phy::tb_action_ul_t *action)
{
if (grant) {
// HARQ entity requests an adaptive transmission
if (grant->rv) {
current_irv = irv_of_rv[grant->rv%4];
}
memcpy(&cur_grant, grant, sizeof(mac_interface_phy::mac_grant_t));
harq_feedback = false;
Info("UL %d: Adaptive retx=%d, RV=%d, TBS=%d\n",
pid, current_tx_nb, get_rv(), grant->n_bytes);
generate_tx(tti_tx, action);
} else {
Info("UL %d: Non-Adaptive retx=%d, RV=%d, TBS=%d\n",
pid, current_tx_nb, get_rv(), cur_grant.n_bytes);
// HARQ entity requests a non-adaptive transmission
if (!harq_feedback) {
generate_tx(tti_tx, action);
}
}
// On every Msg3 retransmission, restart mac-ContentionResolutionTimer as defined in Section 5.1.5
if (is_msg3) {
harq_entity->timers_db->get(mac::CONTENTION_TIMER)->reset();
}
harq_entity->mux_unit->pusch_retx(tti_tx, pid);
}
// New transmission (Section 5.4.2.2)
void ul_harq_entity::ul_harq_process::generate_new_tx(uint32_t tti_tx, bool is_msg3_,
mac_interface_phy::mac_grant_t *grant,
mac_interface_phy::tb_action_ul_t *action)
{
if (grant) {
// Compute average number of retransmissions per packet considering previous packet
harq_entity->average_retx = SRSLTE_VEC_CMA((float) current_tx_nb, harq_entity->average_retx, harq_entity->nof_pkts++);
memcpy(&cur_grant, grant, sizeof(mac_interface_phy::mac_grant_t));
harq_feedback = false;
is_grant_configured = true;
current_tx_nb = 0;
current_irv = 0;
is_msg3 = is_msg3_;
Info("UL %d: New TX%s, RV=%d, TBS=%d, RNTI=%d\n",
pid, is_msg3?" for Msg3":"", get_rv(), cur_grant.n_bytes, cur_grant.rnti);
generate_tx(tti_tx, action);
}
}
// Transmission of pending frame (Section 5.4.2.2)
void ul_harq_entity::ul_harq_process::generate_tx(uint32_t tti_tx, mac_interface_phy::tb_action_ul_t *action)
{
action->current_tx_nb = current_tx_nb;
current_tx_nb++;
action->expect_ack = true;
action->rnti = is_msg3?harq_entity->rntis->temp_rnti:cur_grant.rnti;
action->rv = cur_grant.rv>0?cur_grant.rv:get_rv();
action->softbuffer = &softbuffer;
action->tx_enabled = true;
action->payload_ptr = pdu_ptr;
memcpy(&action->phy_grant, &cur_grant.phy_grant, sizeof(srslte_phy_grant_t));
current_irv = (current_irv+1)%4;
tti_last_tx = tti_tx;
}
bool ul_harq_entity::ul_harq_process::is_sps()
{
return false;
}
uint32_t ul_harq_entity::ul_harq_process::last_tx_tti()
{
return tti_last_tx;
}
uint32_t ul_harq_entity::ul_harq_process::get_nof_retx()
{
return current_tx_nb;
}
}

379
srsue/src/main.cc Normal file
View File

@ -0,0 +1,379 @@
/**
*
* \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 <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <pthread.h>
#include <iostream>
#include <fstream>
#include <string>
#include <boost/program_options.hpp>
#include <boost/program_options/parsers.hpp>
#include "ue.h"
#include "metrics_stdout.h"
#include "srslte/version.h"
using namespace std;
using namespace srsue;
namespace bpo = boost::program_options;
/**********************************************************************
* Program arguments processing
***********************************************************************/
string config_file;
void parse_args(all_args_t *args, int argc, char* argv[]) {
// Command line only options
bpo::options_description general("General options");
general.add_options()
("help,h", "Produce help message")
("version,v", "Print version information and exit")
;
// Command line or config file options
bpo::options_description common("Configuration options");
common.add_options()
("rf.dl_freq", bpo::value<float>(&args->rf.dl_freq)->default_value(2680000000), "Downlink centre frequency")
("rf.ul_freq", bpo::value<float>(&args->rf.ul_freq)->default_value(2560000000), "Uplink centre frequency")
("rf.rx_gain", bpo::value<float>(&args->rf.rx_gain)->default_value(-1), "Front-end receiver gain")
("rf.tx_gain", bpo::value<float>(&args->rf.tx_gain)->default_value(-1), "Front-end transmitter gain")
("rf.nof_rx_ant", bpo::value<uint32_t>(&args->rf.nof_rx_ant)->default_value(1), "Number of RX antennas")
("rf.device_name", bpo::value<string>(&args->rf.device_name)->default_value("auto"), "Front-end device name")
("rf.device_args", bpo::value<string>(&args->rf.device_args)->default_value("auto"), "Front-end device arguments")
("rf.time_adv_nsamples", bpo::value<string>(&args->rf.time_adv_nsamples)->default_value("auto"), "Transmission time advance")
("rf.burst_preamble_us", bpo::value<string>(&args->rf.burst_preamble)->default_value("auto"), "Transmission time advance")
("pcap.enable", bpo::value<bool>(&args->pcap.enable)->default_value(false), "Enable MAC packet captures for wireshark")
("pcap.filename", bpo::value<string>(&args->pcap.filename)->default_value("ue.pcap"), "MAC layer capture filename")
("trace.enable", bpo::value<bool>(&args->trace.enable)->default_value(false), "Enable PHY and radio timing traces")
("trace.phy_filename",bpo::value<string>(&args->trace.phy_filename)->default_value("ue.phy_trace"), "PHY timing traces filename")
("trace.radio_filename",bpo::value<string>(&args->trace.radio_filename)->default_value("ue.radio_trace"), "Radio timing traces filename")
("gui.enable", bpo::value<bool>(&args->gui.enable)->default_value(false), "Enable GUI plots")
("log.phy_level", bpo::value<string>(&args->log.phy_level), "PHY log level")
("log.phy_hex_limit", bpo::value<int>(&args->log.phy_hex_limit), "PHY log hex dump limit")
("log.mac_level", bpo::value<string>(&args->log.mac_level), "MAC log level")
("log.mac_hex_limit", bpo::value<int>(&args->log.mac_hex_limit), "MAC log hex dump limit")
("log.rlc_level", bpo::value<string>(&args->log.rlc_level), "RLC log level")
("log.rlc_hex_limit", bpo::value<int>(&args->log.rlc_hex_limit), "RLC log hex dump limit")
("log.pdcp_level", bpo::value<string>(&args->log.pdcp_level), "PDCP log level")
("log.pdcp_hex_limit",bpo::value<int>(&args->log.pdcp_hex_limit), "PDCP log hex dump limit")
("log.rrc_level", bpo::value<string>(&args->log.rrc_level), "RRC log level")
("log.rrc_hex_limit", bpo::value<int>(&args->log.rrc_hex_limit), "RRC log hex dump limit")
("log.gw_level", bpo::value<string>(&args->log.gw_level), "GW log level")
("log.gw_hex_limit", bpo::value<int>(&args->log.gw_hex_limit), "GW log hex dump limit")
("log.nas_level", bpo::value<string>(&args->log.nas_level), "NAS log level")
("log.nas_hex_limit", bpo::value<int>(&args->log.nas_hex_limit), "NAS log hex dump limit")
("log.usim_level", bpo::value<string>(&args->log.usim_level), "USIM log level")
("log.usim_hex_limit",bpo::value<int>(&args->log.usim_hex_limit), "USIM log hex dump limit")
("log.all_level", bpo::value<string>(&args->log.all_level)->default_value("info"), "ALL log level")
("log.all_hex_limit", bpo::value<int>(&args->log.all_hex_limit)->default_value(32), "ALL log hex dump limit")
("log.filename", bpo::value<string>(&args->log.filename)->default_value("/tmp/ue.log"),"Log filename")
("usim.algo", bpo::value<string>(&args->usim.algo), "USIM authentication algorithm")
("usim.op", bpo::value<string>(&args->usim.op), "USIM operator variant")
("usim.amf", bpo::value<string>(&args->usim.amf), "USIM authentication management field")
("usim.imsi", bpo::value<string>(&args->usim.imsi), "USIM IMSI")
("usim.imei", bpo::value<string>(&args->usim.imei), "USIM IMEI")
("usim.k", bpo::value<string>(&args->usim.k), "USIM K")
/* Expert section */
("expert.phy.worker_cpu_mask",
bpo::value<int>(&args->expert.phy.worker_cpu_mask)->default_value(254),
"cpu bit mask (eg 255 = 1111 1111)")
("expert.phy.sync_cpu_affinity",
bpo::value<int>(&args->expert.phy.sync_cpu_affinity)->default_value(2),
"index of the core used by the sync thread")
("expert.ue_category",
bpo::value<int>(&args->expert.ue_cateogry)->default_value(4),
"UE Category (1 to 5)")
("expert.metrics_period_secs",
bpo::value<float>(&args->expert.metrics_period_secs)->default_value(1.0),
"Periodicity for metrics in seconds")
("expert.pregenerate_signals",
bpo::value<bool>(&args->expert.pregenerate_signals)->default_value(false),
"Pregenerate uplink signals after attach. Improves CPU performance.")
("expert.rssi_sensor_enabled",
bpo::value<bool>(&args->expert.phy.rssi_sensor_enabled)->default_value(true),
"Enable or disable RF frontend RSSI sensor. In some USRP devices can cause segmentation fault")
("expert.prach_gain",
bpo::value<float>(&args->expert.phy.prach_gain)->default_value(-1.0),
"Disable PRACH power control")
("expert.cqi_max",
bpo::value<int>(&args->expert.phy.cqi_max)->default_value(15),
"Upper bound on the maximum CQI to be reported. Default 15.")
("expert.cqi_fixed",
bpo::value<int>(&args->expert.phy.cqi_fixed)->default_value(-1),
"Fixes the reported CQI to a constant value. Default disabled.")
("expert.snr_ema_coeff",
bpo::value<float>(&args->expert.phy.snr_ema_coeff)->default_value(0.1),
"Sets the SNR exponential moving average coefficient (Default 0.1)")
("expert.snr_estim_alg",
bpo::value<string>(&args->expert.phy.snr_estim_alg)->default_value("refs"),
"Sets the noise estimation algorithm. (Default refs)")
("expert.pdsch_max_its",
bpo::value<int>(&args->expert.phy.pdsch_max_its)->default_value(4),
"Maximum number of turbo decoder iterations")
("expert.attach_enable_64qam",
bpo::value<bool>(&args->expert.phy.attach_enable_64qam)->default_value(false),
"PUSCH 64QAM modulation before attachment")
("expert.nof_phy_threads",
bpo::value<int>(&args->expert.phy.nof_phy_threads)->default_value(2),
"Number of PHY threads")
("expert.equalizer_mode",
bpo::value<string>(&args->expert.phy.equalizer_mode)->default_value("mmse"),
"Equalizer mode")
("expert.cfo_integer_enabled",
bpo::value<bool>(&args->expert.phy.cfo_integer_enabled)->default_value(false),
"Enables integer CFO estimation and correction.")
("expert.cfo_correct_tol_hz",
bpo::value<float>(&args->expert.phy.cfo_correct_tol_hz)->default_value(50.0),
"Tolerance (in Hz) for digial CFO compensation.")
("expert.time_correct_period",
bpo::value<int>(&args->expert.phy.time_correct_period)->default_value(5),
"Period for sampling time offset correction.")
("expert.sfo_correct_disable",
bpo::value<bool>(&args->expert.phy.sfo_correct_disable)->default_value(false),
"Disables phase correction before channel estimation.")
("expert.sss_algorithm",
bpo::value<string>(&args->expert.phy.sss_algorithm)->default_value("full"),
"Selects the SSS estimation algorithm.")
("expert.estimator_fil_w",
bpo::value<float>(&args->expert.phy.estimator_fil_w)->default_value(0.1),
"Chooses the coefficients for the 3-tap channel estimator centered filter.")
("rf_calibration.tx_corr_dc_gain", bpo::value<float>(&args->rf_cal.tx_corr_dc_gain)->default_value(0.0), "TX DC offset gain correction")
("rf_calibration.tx_corr_dc_phase", bpo::value<float>(&args->rf_cal.tx_corr_dc_phase)->default_value(0.0), "TX DC offset phase correction")
("rf_calibration.tx_corr_iq_i", bpo::value<float>(&args->rf_cal.tx_corr_iq_i)->default_value(0.0), "TX IQ imbalance inphase correction")
("rf_calibration.tx_corr_iq_q", bpo::value<float>(&args->rf_cal.tx_corr_iq_q)->default_value(0.0), "TX IQ imbalance quadrature correction")
;
// Positional options - config file location
bpo::options_description position("Positional options");
position.add_options()
("config_file", bpo::value< string >(&config_file), "UE configuration file")
;
bpo::positional_options_description p;
p.add("config_file", -1);
// these options are allowed on the command line
bpo::options_description cmdline_options;
cmdline_options.add(common).add(position).add(general);
// parse the command line and store result in vm
bpo::variables_map vm;
bpo::store(bpo::command_line_parser(argc, argv).options(cmdline_options).positional(p).run(), vm);
bpo::notify(vm);
// help option was given - print usage and exit
if (vm.count("help")) {
cout << "Usage: " << argv[0] << " [OPTIONS] config_file" << endl << endl;
cout << common << endl << general << endl;
exit(0);
}
// print version number and exit
if (vm.count("version")) {
cout << "Version " <<
srslte_get_version_major() << "." <<
srslte_get_version_minor() << "." <<
srslte_get_version_patch() << endl;
exit(0);
}
// no config file given - print usage and exit
if (!vm.count("config_file")) {
cout << "Error: Configuration file not provided" << endl;
cout << "Usage: " << argv[0] << " [OPTIONS] config_file" << endl << endl;
exit(0);
} else {
cout << "Reading configuration file " << config_file << "..." << endl;
ifstream conf(config_file.c_str(), ios::in);
if(conf.fail()) {
cout << "Failed to read configuration file " << config_file << " - exiting" << endl;
exit(1);
}
bpo::store(bpo::parse_config_file(conf, common), vm);
bpo::notify(vm);
}
// Apply all_level to any unset layers
if (vm.count("log.all_level")) {
if(!vm.count("log.phy_level")) {
args->log.phy_level = args->log.all_level;
}
if(!vm.count("log.mac_level")) {
args->log.mac_level = args->log.all_level;
}
if(!vm.count("log.rlc_level")) {
args->log.rlc_level = args->log.all_level;
}
if(!vm.count("log.pdcp_level")) {
args->log.pdcp_level = args->log.all_level;
}
if(!vm.count("log.rrc_level")) {
args->log.rrc_level = args->log.all_level;
}
if(!vm.count("log.nas_level")) {
args->log.nas_level = args->log.all_level;
}
if(!vm.count("log.gw_level")) {
args->log.gw_level = args->log.all_level;
}
if(!vm.count("log.usim_level")) {
args->log.usim_level = args->log.all_level;
}
}
// Apply all_hex_limit to any unset layers
if (vm.count("log.all_hex_limit")) {
if(!vm.count("log.phy_hex_limit")) {
args->log.phy_hex_limit = args->log.all_hex_limit;
}
if(!vm.count("log.mac_hex_limit")) {
args->log.mac_hex_limit = args->log.all_hex_limit;
}
if(!vm.count("log.rlc_hex_limit")) {
args->log.rlc_hex_limit = args->log.all_hex_limit;
}
if(!vm.count("log.pdcp_hex_limit")) {
args->log.pdcp_hex_limit = args->log.all_hex_limit;
}
if(!vm.count("log.rrc_hex_limit")) {
args->log.rrc_hex_limit = args->log.all_hex_limit;
}
if(!vm.count("log.nas_hex_limit")) {
args->log.nas_hex_limit = args->log.all_hex_limit;
}
if(!vm.count("log.gw_hex_limit")) {
args->log.gw_hex_limit = args->log.all_hex_limit;
}
if(!vm.count("log.usim_hex_limit")) {
args->log.usim_hex_limit = args->log.all_hex_limit;
}
}
}
static bool running = true;
static bool do_metrics = false;
void sig_int_handler(int signo)
{
running = false;
}
void *input_loop(void *m)
{
metrics_stdout *metrics = (metrics_stdout*)m;
char key;
while(running) {
cin >> key;
if('t' == key) {
do_metrics = !do_metrics;
if(do_metrics) {
cout << "Enter t to stop trace." << endl;
} else {
cout << "Enter t to restart trace." << endl;
}
metrics->toggle_print(do_metrics);
}
}
return NULL;
}
int main(int argc, char *argv[])
{
signal(SIGINT, sig_int_handler);
all_args_t args;
metrics_stdout metrics;
ue *ue = ue::get_instance();
cout << "--- Software Radio Systems LTE UE ---" << endl << endl;
parse_args(&args, argc, argv);
if(!ue->init(&args)) {
exit(1);
}
metrics.init(ue, args.expert.metrics_period_secs);
pthread_t input;
pthread_create(&input, NULL, &input_loop, &metrics);
bool plot_started = false;
bool signals_pregenerated = false;
while(running) {
if (ue->is_attached()) {
if (!signals_pregenerated && args.expert.pregenerate_signals) {
ue->pregenerate_signals(true);
signals_pregenerated = true;
}
if (!plot_started && args.gui.enable) {
ue->start_plot();
plot_started = true;
}
}
sleep(1);
}
pthread_cancel(input);
metrics.stop();
ue->stop();
ue->cleanup();
cout << "--- exiting ---" << endl;
exit(0);
}

180
srsue/src/metrics_stdout.cc Normal file
View File

@ -0,0 +1,180 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2015 The srsUE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \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 "metrics_stdout.h"
#include <unistd.h>
#include <sstream>
#include <stdlib.h>
#include <math.h>
#include <float.h>
#include <iomanip>
#include <iostream>
#include <stdio.h>
using namespace std;
namespace srsue{
char const * const prefixes[2][9] =
{
{ "", "m", "u", "n", "p", "f", "a", "z", "y", },
{ "", "k", "M", "G", "T", "P", "E", "Z", "Y", },
};
metrics_stdout::metrics_stdout()
:started(false)
,do_print(false)
,n_reports(10)
{
}
bool metrics_stdout::init(ue_metrics_interface *u, float report_period_secs)
{
ue_ = u;
metrics_report_period = report_period_secs;
started = true;
pthread_create(&metrics_thread, NULL, &metrics_thread_start, this);
return true;
}
void metrics_stdout::stop()
{
if(started)
{
started = false;
pthread_join(metrics_thread, NULL);
}
}
void metrics_stdout::toggle_print(bool b)
{
do_print = b;
}
void* metrics_stdout::metrics_thread_start(void *m_)
{
metrics_stdout *m = (metrics_stdout*)m_;
m->metrics_thread_run();
return NULL;
}
void metrics_stdout::metrics_thread_run()
{
while(started)
{
usleep(metrics_report_period*1e6);
if(ue_->get_metrics(metrics)) {
print_metrics();
} else {
print_disconnect();
}
}
}
void metrics_stdout::print_metrics()
{
if(!do_print)
return;
if(++n_reports > 10)
{
n_reports = 0;
cout << endl;
cout << "--Signal--------------DL------------------------------UL----------------------" << endl;
cout << " rsrp pl cfo mcs snr turbo brate bler mcs buff brate bler" << endl;
}
cout << float_to_string(metrics.phy.dl.rsrp, 2);
cout << float_to_string(metrics.phy.dl.pathloss, 2);
cout << float_to_eng_string(metrics.phy.sync.cfo, 2);
cout << float_to_string(metrics.phy.dl.mcs, 2);
cout << float_to_string(metrics.phy.dl.sinr, 2);
cout << float_to_string(metrics.phy.dl.turbo_iters, 2);
cout << float_to_eng_string((float) metrics.mac.rx_brate/metrics_report_period, 2);
if (metrics.mac.rx_pkts > 0) {
cout << float_to_string((float) 100*metrics.mac.rx_errors/metrics.mac.rx_pkts, 1) << "%";
} else {
cout << float_to_string(0, 2) << "%";
}
cout << float_to_string(metrics.phy.ul.mcs, 2);
cout << float_to_eng_string((float) metrics.mac.ul_buffer, 2);
cout << float_to_eng_string((float) metrics.mac.tx_brate/metrics_report_period, 2);
if (metrics.mac.tx_pkts > 0) {
cout << float_to_string((float) 100*metrics.mac.tx_errors/metrics.mac.tx_pkts, 1) << "%";
} else {
cout << float_to_string(0, 2) << "%";
}
cout << endl;
if(metrics.rf.rf_error) {
printf("RF status: O=%d, U=%d, L=%d\n", metrics.rf.rf_o, metrics.rf.rf_u, metrics.rf.rf_l);
}
}
void metrics_stdout::print_disconnect()
{
if(do_print) {
cout << "--- disconnected ---" << endl;
}
}
std::string metrics_stdout::float_to_string(float f, int digits)
{
std::ostringstream os;
const int precision = (f == 0.0) ? digits-1 : digits - log10(fabs(f))-2*DBL_EPSILON;
os << std::setw(6) << std::fixed << std::setprecision(precision) << f;
return os.str();
}
std::string metrics_stdout::float_to_eng_string(float f, int digits)
{
const int degree = (f == 0.0) ? 0 : lrint( floor( log10( fabs( f ) ) / 3) );
std::string factor;
if ( abs( degree ) < 9 )
{
if(degree < 0)
factor = prefixes[0][ abs( degree ) ];
else
factor = prefixes[1][ abs( degree ) ];
} else {
return "failed";
}
const double scaled = f * pow( 1000.0, -degree );
if (degree != 0) {
return float_to_string(scaled, digits) + factor;
} else {
return " " + float_to_string(scaled, digits) + factor;
}
}
} // namespace srsue

View File

@ -0,0 +1,26 @@
# Copyright 2015 Software Radio Systems Limited
#
# This file is part of srsUE
#
# 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(GLOB SOURCES "*.cc")
add_library(srsue_phy ${SOURCES})
target_link_libraries(srsue_phy ${SRSLTE_PHY_LIBRARY})
if(ENABLE_GUI AND SRSGUI_FOUND)
target_link_libraries(srsue_phy ${SRSGUI_LIBRARIES})
endif(ENABLE_GUI AND SRSGUI_FOUND)

View File

@ -0,0 +1,334 @@
/**
*
* \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 <assert.h>
#include <string.h>
#include "srslte/srslte.h"
#include "phy/phch_common.h"
#define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Info(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Debug(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define TX_MODE_CONTINUOUS 0
namespace srsue {
cf_t zeros[50000];
phch_common::phch_common(uint32_t max_mutex_) : tx_mutex(max_mutex_)
{
config = NULL;
args = NULL;
log_h = NULL;
radio_h = NULL;
mac = NULL;
max_mutex = max_mutex_;
nof_mutex = 0;
sr_enabled = false;
is_first_of_burst = true;
is_first_tx = true;
rar_grant_pending = false;
pathloss = 0;
cur_pathloss = 0;
cur_pusch_power = 0;
p0_preamble = 0;
cur_radio_power = 0;
rx_gain_offset = 0;
sr_last_tx_tti = -1;
cur_pusch_power = 0;
bzero(zeros, 50000*sizeof(cf_t));
bzero(&dl_metrics, sizeof(dl_metrics_t));
dl_metrics_read = true;
dl_metrics_count = 0;
bzero(&ul_metrics, sizeof(ul_metrics_t));
ul_metrics_read = true;
ul_metrics_count = 0;
bzero(&sync_metrics, sizeof(sync_metrics_t));
sync_metrics_read = true;
sync_metrics_count = 0;
}
void phch_common::init(phy_interface_rrc::phy_cfg_t *_config, phy_args_t *_args, srslte::log *_log, srslte::radio *_radio, mac_interface_phy *_mac)
{
log_h = _log;
radio_h = _radio;
mac = _mac;
config = _config;
args = _args;
is_first_tx = true;
sr_last_tx_tti = -1;
for (int i=0;i<nof_mutex;i++) {
pthread_mutex_init(&tx_mutex[i], NULL);
}
}
void phch_common::set_nof_mutex(uint32_t nof_mutex_) {
nof_mutex = nof_mutex_;
assert(nof_mutex <= max_mutex);
}
bool phch_common::ul_rnti_active(uint32_t tti) {
if ((tti >= ul_rnti_start && ul_rnti_start >= 0 || ul_rnti_start < 0) &&
(tti < ul_rnti_end && ul_rnti_end >= 0 || ul_rnti_end < 0))
{
return true;
} else {
return false;
}
}
bool phch_common::dl_rnti_active(uint32_t tti) {
Debug("tti=%d, dl_rnti_start=%d, dl_rnti_end=%d, dl_rnti=0x%x\n", tti, dl_rnti_start, dl_rnti_end, dl_rnti);
if (((tti >= dl_rnti_start && dl_rnti_start >= 0) || dl_rnti_start < 0) &&
((tti < dl_rnti_end && dl_rnti_end >= 0) || dl_rnti_end < 0))
{
bool ret = true;
// FIXME: This scheduling decision belongs to RRC
if (dl_rnti_type == SRSLTE_RNTI_SI) {
if (dl_rnti_end - dl_rnti_start > 1) { // This is not a SIB1
if ((tti/10)%2 == 0 && (tti%10) == 5) { // Skip subframe #5 for which SFN mod 2 = 0
ret = false;
}
}
}
return ret;
} else {
return false;
}
}
srslte::radio* phch_common::get_radio()
{
return radio_h;
}
// Unpack RAR grant as defined in Section 6.2 of 36.213
void phch_common::set_rar_grant(uint32_t tti, uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN])
{
srslte_dci_rar_grant_unpack(&rar_grant, grant_payload);
rar_grant_pending = true;
// PUSCH is at n+6 or n+7 and phch_worker assumes default delay of 4 ttis
if (rar_grant.ul_delay) {
rar_grant_tti = (tti + 3) % 10240;
} else {
rar_grant_tti = (tti + 2) % 10240;
}
}
bool phch_common::get_pending_rar(uint32_t tti, srslte_dci_rar_grant_t *rar_grant_)
{
if (rar_grant_pending && tti >= rar_grant_tti) {
if (rar_grant_) {
rar_grant_pending = false;
memcpy(rar_grant_, &rar_grant, sizeof(srslte_dci_rar_grant_t));
}
return true;
}
return false;
}
/* Common variables used by all phy workers */
uint16_t phch_common::get_ul_rnti(uint32_t tti) {
if (ul_rnti_active(tti)) {
return ul_rnti;
} else {
return 0;
}
}
srslte_rnti_type_t phch_common::get_ul_rnti_type() {
return ul_rnti_type;
}
void phch_common::set_ul_rnti(srslte_rnti_type_t type, uint16_t rnti_value, int tti_start, int tti_end) {
ul_rnti = rnti_value;
ul_rnti_type = type;
ul_rnti_start = tti_start;
ul_rnti_end = tti_end;
}
uint16_t phch_common::get_dl_rnti(uint32_t tti) {
if (dl_rnti_active(tti)) {
return dl_rnti;
} else {
return 0;
}
}
srslte_rnti_type_t phch_common::get_dl_rnti_type() {
return dl_rnti_type;
}
void phch_common::set_dl_rnti(srslte_rnti_type_t type, uint16_t rnti_value, int tti_start, int tti_end) {
dl_rnti = rnti_value;
dl_rnti_type = type;
dl_rnti_start = tti_start;
dl_rnti_end = tti_end;
Debug("Set DL rnti: start=%d, end=%d, value=0x%x\n", tti_start, tti_end, rnti_value);
}
void phch_common::reset_pending_ack(uint32_t tti) {
pending_ack[tti%10].enabled = false;
}
void phch_common::set_pending_ack(uint32_t tti, uint32_t I_lowest, uint32_t n_dmrs) {
pending_ack[tti%10].enabled = true;
pending_ack[tti%10].I_lowest = I_lowest;
pending_ack[tti%10].n_dmrs = n_dmrs;
Debug("Set pending ACK for tti=%d I_lowest=%d, n_dmrs=%d\n", tti, I_lowest, n_dmrs);
}
bool phch_common::get_pending_ack(uint32_t tti) {
return get_pending_ack(tti, NULL, NULL);
}
bool phch_common::get_pending_ack(uint32_t tti, uint32_t *I_lowest, uint32_t *n_dmrs) {
if (I_lowest) {
*I_lowest = pending_ack[tti%10].I_lowest;
}
if (n_dmrs) {
*n_dmrs = pending_ack[tti%10].n_dmrs;
}
return pending_ack[tti%10].enabled;
}
/* The transmisison of UL subframes must be in sequence. Each worker uses this function to indicate
* that all processing is done and data is ready for transmission or there is no transmission at all (tx_enable).
* In that case, the end of burst message will be send to the radio
*/
void phch_common::worker_end(uint32_t tti, bool tx_enable,
cf_t *buffer, uint32_t nof_samples,
srslte_timestamp_t tx_time)
{
// Wait previous TTIs to be transmitted
if (is_first_tx) {
is_first_tx = false;
} else {
pthread_mutex_lock(&tx_mutex[tti%nof_mutex]);
}
radio_h->set_tti(tti);
if (tx_enable) {
radio_h->tx(buffer, nof_samples, tx_time);
is_first_of_burst = false;
} else {
if (TX_MODE_CONTINUOUS) {
if (!is_first_of_burst) {
radio_h->tx(zeros, nof_samples, tx_time);
}
} else {
if (!is_first_of_burst) {
radio_h->tx_end();
is_first_of_burst = true;
}
}
}
// Trigger next transmission
pthread_mutex_unlock(&tx_mutex[(tti+1)%nof_mutex]);
// Trigger MAC clock
mac->tti_clock(tti);
}
void phch_common::set_cell(const srslte_cell_t &c) {
cell = c;
}
uint32_t phch_common::get_nof_prb() {
return cell.nof_prb;
}
void phch_common::set_dl_metrics(const dl_metrics_t &m) {
if(dl_metrics_read) {
dl_metrics = m;
dl_metrics_count = 1;
dl_metrics_read = false;
} else {
dl_metrics_count++;
dl_metrics.mcs = dl_metrics.mcs + (m.mcs - dl_metrics.mcs)/dl_metrics_count;
dl_metrics.n = dl_metrics.n + (m.n - dl_metrics.n)/dl_metrics_count;
dl_metrics.rsrp = dl_metrics.rsrp + (m.rsrp - dl_metrics.rsrp)/dl_metrics_count;
dl_metrics.rsrq = dl_metrics.rsrq + (m.rsrq - dl_metrics.rsrq)/dl_metrics_count;
dl_metrics.rssi = dl_metrics.rssi + (m.rssi - dl_metrics.rssi)/dl_metrics_count;
dl_metrics.sinr = dl_metrics.sinr + (m.sinr - dl_metrics.sinr)/dl_metrics_count;
dl_metrics.pathloss = dl_metrics.pathloss + (m.pathloss - dl_metrics.pathloss)/dl_metrics_count;
dl_metrics.turbo_iters = dl_metrics.turbo_iters + (m.turbo_iters - dl_metrics.turbo_iters)/dl_metrics_count;
}
}
void phch_common::get_dl_metrics(dl_metrics_t &m) {
m = dl_metrics;
dl_metrics_read = true;
}
void phch_common::set_ul_metrics(const ul_metrics_t &m) {
if(ul_metrics_read) {
ul_metrics = m;
ul_metrics_count = 1;
ul_metrics_read = false;
} else {
ul_metrics_count++;
ul_metrics.mcs = ul_metrics.mcs + (m.mcs - ul_metrics.mcs)/ul_metrics_count;
ul_metrics.power = ul_metrics.power + (m.power - ul_metrics.power)/ul_metrics_count;
}
}
void phch_common::get_ul_metrics(ul_metrics_t &m) {
m = ul_metrics;
ul_metrics_read = true;
}
void phch_common::set_sync_metrics(const sync_metrics_t &m) {
if(sync_metrics_read) {
sync_metrics = m;
sync_metrics_count = 1;
sync_metrics_read = false;
} else {
sync_metrics_count++;
sync_metrics.cfo = sync_metrics.cfo + (m.cfo - sync_metrics.cfo)/sync_metrics_count;
sync_metrics.sfo = sync_metrics.sfo + (m.sfo - sync_metrics.sfo)/sync_metrics_count;
}
}
void phch_common::get_sync_metrics(sync_metrics_t &m) {
m = sync_metrics;
sync_metrics_read = true;
}
void phch_common::reset_ul()
{
is_first_tx = true;
is_first_of_burst = true;
for (int i=0;i<nof_mutex;i++) {
pthread_mutex_trylock(&tx_mutex[i]);
pthread_mutex_unlock(&tx_mutex[i]);
}
}
}

502
srsue/src/phy/phch_recv.cc Normal file
View File

@ -0,0 +1,502 @@
/**
*
* \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 <unistd.h>
#include "srslte/srslte.h"
#include "common/log.h"
#include "phy/phch_worker.h"
#include "phy/phch_common.h"
#include "phy/phch_recv.h"
#define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Info(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Debug(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
namespace srsue {
phch_recv::phch_recv() {
running = false;
}
void phch_recv::init(srslte::radio_multi* _radio_handler, mac_interface_phy *_mac, rrc_interface_phy *_rrc,
prach* _prach_buffer, srslte::thread_pool* _workers_pool,
phch_common* _worker_com, srslte::log* _log_h, uint32_t nof_rx_antennas_, uint32_t prio, int sync_cpu_affinity)
{
radio_h = _radio_handler;
log_h = _log_h;
mac = _mac;
rrc = _rrc;
workers_pool = _workers_pool;
worker_com = _worker_com;
prach_buffer = _prach_buffer;
nof_rx_antennas = nof_rx_antennas_;
tx_mutex_cnt = 0;
running = true;
phy_state = IDLE;
time_adv_sec = 0;
cell_is_set = false;
sync_sfn_cnt = 0;
for (int i=0;i<nof_rx_antennas;i++) {
sf_buffer_sfn[i] = (cf_t*) srslte_vec_malloc(sizeof(cf_t)*3*SRSLTE_SF_LEN_PRB(100));
}
nof_tx_mutex = MUTEX_X_WORKER*workers_pool->get_nof_workers();
worker_com->set_nof_mutex(nof_tx_mutex);
if(sync_cpu_affinity < 0){
start(prio);
} else {
start_cpu(prio, sync_cpu_affinity);
}
}
void phch_recv::stop() {
running = false;
wait_thread_finish();
for (int i=0;i<nof_rx_antennas;i++) {
if (sf_buffer_sfn[i]) {
free(sf_buffer_sfn[i]);
}
}
}
void phch_recv::set_agc_enable(bool enable)
{
do_agc = enable;
}
int radio_recv_wrapper_cs(void *h, cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time)
{
srslte::radio_multi *radio_h = (srslte::radio_multi*) h;
if (radio_h->rx_now(data, nsamples, rx_time)) {
int offset = nsamples-radio_h->get_tti_len();
if (abs(offset)<10 && offset != 0) {
radio_h->tx_offset(offset);
} else if (nsamples<10) {
radio_h->tx_offset(nsamples);
}
return nsamples;
} else {
return -1;
}
}
double callback_set_rx_gain(void *h, double gain) {
srslte::radio_multi *radio_handler = (srslte::radio_multi*) h;
return radio_handler->set_rx_gain_th(gain);
}
void phch_recv::set_time_adv_sec(float _time_adv_sec) {
time_adv_sec = _time_adv_sec;
}
void phch_recv::set_ue_sync_opts(srslte_ue_sync_t *q) {
if (worker_com->args->cfo_integer_enabled) {
srslte_ue_sync_cfo_i_detec_en(q, true);
}
float cfo_tol = worker_com->args->cfo_correct_tol_hz;
srslte_cfo_set_tol(&q->strack.cfocorr, cfo_tol/(15000*q->fft_size));
srslte_cfo_set_tol(&q->sfind.cfocorr, cfo_tol/(15000*q->fft_size));
int time_correct_period = worker_com->args->time_correct_period;
if (time_correct_period > 0) {
srslte_ue_sync_set_sample_offset_correct_period(q, time_correct_period);
}
sss_alg_t sss_alg = SSS_FULL;
if (!worker_com->args->sss_algorithm.compare("diff")) {
sss_alg = SSS_DIFF;
} else if (!worker_com->args->sss_algorithm.compare("partial")) {
sss_alg = SSS_PARTIAL_3;
} else if (!worker_com->args->sss_algorithm.compare("full")){
sss_alg = SSS_FULL;
} else {
Warning("Invalid SSS algorithm %s. Using 'full'\n", worker_com->args->sss_algorithm.c_str());
}
srslte_sync_set_sss_algorithm(&q->strack, (sss_alg_t) sss_alg);
srslte_sync_set_sss_algorithm(&q->sfind, (sss_alg_t) sss_alg);
}
bool phch_recv::init_cell() {
cell_is_set = false;
if (!srslte_ue_mib_init(&ue_mib, cell))
{
if (!srslte_ue_sync_init_multi(&ue_sync, cell, radio_recv_wrapper_cs, nof_rx_antennas, radio_h))
{
// Set options defined in expert section
set_ue_sync_opts(&ue_sync);
for (int i=0;i<workers_pool->get_nof_workers();i++) {
if (!((phch_worker*) workers_pool->get_worker(i))->init_cell(cell)) {
Error("Error setting cell: initiating PHCH worker\n");
return false;
}
}
radio_h->set_tti_len(SRSLTE_SF_LEN_PRB(cell.nof_prb));
if (do_agc) {
srslte_ue_sync_start_agc(&ue_sync, callback_set_rx_gain, last_gain);
}
srslte_ue_sync_set_cfo(&ue_sync, cellsearch_cfo);
cell_is_set = true;
} else {
Error("Error setting cell: initiating ue_sync");
}
} else {
Error("Error setting cell: initiating ue_mib\n");
}
return cell_is_set;
}
void phch_recv::free_cell()
{
if (cell_is_set) {
for (int i=0;i<workers_pool->get_nof_workers();i++) {
((phch_worker*) workers_pool->get_worker(i))->free_cell();
}
prach_buffer->free_cell();
}
}
bool phch_recv::cell_search(int force_N_id_2)
{
uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN];
uint8_t bch_payload_bits[SRSLTE_BCH_PAYLOAD_LEN/8];
srslte_ue_cellsearch_result_t found_cells[3];
srslte_ue_cellsearch_t cs;
bzero(found_cells, 3*sizeof(srslte_ue_cellsearch_result_t));
log_h->console("Searching for cell...\n");
if (srslte_ue_cellsearch_init_multi(&cs, SRSLTE_DEFAULT_MAX_FRAMES_PSS, radio_recv_wrapper_cs, nof_rx_antennas, radio_h)) {
Error("Initiating UE cell search\n");
return false;
}
srslte_ue_cellsearch_set_nof_valid_frames(&cs, SRSLTE_DEFAULT_NOF_VALID_PSS_FRAMES);
// Set options defined in expert section
set_ue_sync_opts(&cs.ue_sync);
if (do_agc) {
srslte_ue_sync_start_agc(&cs.ue_sync, callback_set_rx_gain, last_gain);
}
radio_h->set_rx_srate(1.92e6);
radio_h->start_rx();
/* Find a cell in the given N_id_2 or go through the 3 of them to find the strongest */
uint32_t max_peak_cell = 0;
int ret = SRSLTE_ERROR;
if (force_N_id_2 >= 0 && force_N_id_2 < 3) {
ret = srslte_ue_cellsearch_scan_N_id_2(&cs, force_N_id_2, &found_cells[force_N_id_2]);
max_peak_cell = force_N_id_2;
} else {
ret = srslte_ue_cellsearch_scan(&cs, found_cells, &max_peak_cell);
}
last_gain = srslte_agc_get_gain(&cs.ue_sync.agc);
radio_h->stop_rx();
srslte_ue_cellsearch_free(&cs);
if (ret < 0) {
Error("Error decoding MIB: Error searching PSS\n");
return false;
} else if (ret == 0) {
Error("Error decoding MIB: Could not find any PSS in this frequency\n");
return false;
}
// Save result
cell.id = found_cells[max_peak_cell].cell_id;
cell.cp = found_cells[max_peak_cell].cp;
cellsearch_cfo = found_cells[max_peak_cell].cfo;
log_h->console("Found CELL ID: %d CP: %s, CFO: %.1f KHz.\nTrying to decode MIB...\n",
cell.id, srslte_cp_string(cell.cp), cellsearch_cfo/1000);
srslte_ue_mib_sync_t ue_mib_sync;
if (srslte_ue_mib_sync_init_multi(&ue_mib_sync, cell.id, cell.cp, radio_recv_wrapper_cs, nof_rx_antennas, radio_h)) {
Error("Initiating UE MIB synchronization\n");
return false;
}
// Set options defined in expert section
set_ue_sync_opts(&ue_mib_sync.ue_sync);
if (do_agc) {
srslte_ue_sync_start_agc(&ue_mib_sync.ue_sync, callback_set_rx_gain, last_gain);
}
srslte_ue_sync_set_cfo(&ue_mib_sync.ue_sync, cellsearch_cfo);
/* Find and decode MIB */
uint32_t sfn;
int sfn_offset;
radio_h->start_rx();
ret = srslte_ue_mib_sync_decode(&ue_mib_sync,
SRSLTE_DEFAULT_MAX_FRAMES_PBCH,
bch_payload, &cell.nof_ports, &sfn_offset);
radio_h->stop_rx();
last_gain = srslte_agc_get_gain(&ue_mib_sync.ue_sync.agc);
cellsearch_cfo = srslte_ue_sync_get_cfo(&ue_mib_sync.ue_sync);
srslte_ue_mib_sync_free(&ue_mib_sync);
if (ret == 1) {
srslte_pbch_mib_unpack(bch_payload, &cell, NULL);
worker_com->set_cell(cell);
srslte_cell_fprint(stdout, &cell, 0);
srslte_bit_pack_vector(bch_payload, bch_payload_bits, SRSLTE_BCH_PAYLOAD_LEN);
mac->bch_decoded_ok(bch_payload_bits, SRSLTE_BCH_PAYLOAD_LEN/8);
return true;
} else {
Warning("Error decoding MIB: Error decoding PBCH\n");
return false;
}
}
int phch_recv::sync_sfn(void) {
int ret = SRSLTE_ERROR;
uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN];
srslte_ue_sync_decode_sss_on_track(&ue_sync, true);
ret = srslte_ue_sync_zerocopy_multi(&ue_sync, sf_buffer_sfn);
if (ret < 0) {
Error("Error calling ue_sync_get_buffer");
return -1;
}
if (ret == 1) {
if (srslte_ue_sync_get_sfidx(&ue_sync) == 0) {
int sfn_offset=0;
Info("SYNC: Decoding MIB...\n");
int n = srslte_ue_mib_decode(&ue_mib, sf_buffer_sfn[0], bch_payload, NULL, &sfn_offset);
if (n < 0) {
Error("Error decoding MIB while synchronising SFN");
return -1;
} else if (n == SRSLTE_UE_MIB_FOUND) {
uint32_t sfn;
srslte_pbch_mib_unpack(bch_payload, &cell, &sfn);
sfn = (sfn + sfn_offset)%1024;
tti = sfn*10;
srslte_ue_sync_decode_sss_on_track(&ue_sync, true);
Info("SYNC: DONE, TTI=%d, sfn_offset=%d\n", tti, sfn_offset);
srslte_ue_mib_reset(&ue_mib);
return 1;
}
}
} else {
Debug("SYNC: PSS/SSS not found...\n");
}
return 0;
}
void phch_recv::resync_sfn() {
sync_sfn_cnt = 0;
phy_state = SYNCING;
}
void phch_recv::run_thread()
{
int sync_res;
phch_worker *worker = NULL;
cf_t *buffer[SRSLTE_MAX_PORTS];
while(running) {
switch(phy_state) {
case CELL_SEARCH:
if (cell_search()) {
log_h->console("Initializating cell configuration...\n");
init_cell();
float srate = (float) srslte_sampling_freq_hz(cell.nof_prb);
if (30720%((int) srate/1000) == 0) {
radio_h->set_master_clock_rate(30.72e6);
} else {
radio_h->set_master_clock_rate(23.04e6);
}
log_h->console("Setting Sampling frequency %.2f MHz\n", (float) srate/1000000);
radio_h->set_rx_srate(srate);
radio_h->set_tx_srate(srate);
ul_dl_factor = radio_h->get_tx_freq()/radio_h->get_rx_freq();
Info("SYNC: Cell found. Synchronizing...\n");
phy_state = SYNCING;
sync_sfn_cnt = 0;
srslte_ue_mib_reset(&ue_mib);
}
break;
case SYNCING:
srslte_ue_sync_decode_sss_on_track(&ue_sync, true);
if (!radio_is_streaming) {
// Start streaming
radio_h->start_rx();
radio_is_streaming = true;
}
switch(sync_sfn()) {
default:
log_h->console("Going IDLE\n");
phy_state = IDLE;
break;
case 1:
srslte_ue_sync_set_agc_period(&ue_sync, 20);
phy_state = SYNC_DONE;
break;
case 0:
break;
}
sync_sfn_cnt++;
if (sync_sfn_cnt >= SYNC_SFN_TIMEOUT) {
sync_sfn_cnt = 0;
radio_h->stop_rx();
radio_is_streaming = false;
log_h->console("Timeout while synchronizing SFN\n");
log_h->warning("Timeout while synchronizing SFN\n");
}
break;
case SYNC_DONE:
tti = (tti+1)%10240;
worker = (phch_worker*) workers_pool->wait_worker(tti);
sync_res = 0;
if (worker) {
for (int i=0;i<nof_rx_antennas;i++) {
buffer[i] = worker->get_buffer(i);
}
sync_res = srslte_ue_sync_zerocopy_multi(&ue_sync, buffer);
if (sync_res == 1) {
log_h->step(tti);
Debug("Worker %d synchronized\n", worker->get_id());
metrics.sfo = srslte_ue_sync_get_sfo(&ue_sync);
metrics.cfo = srslte_ue_sync_get_cfo(&ue_sync);
worker->set_cfo(ul_dl_factor*metrics.cfo/15000);
worker_com->set_sync_metrics(metrics);
float sample_offset = (float) srslte_ue_sync_get_sfo(&ue_sync)/1000;
worker->set_sample_offset(sample_offset);
/* Compute TX time: Any transmission happens in TTI+4 thus advance 4 ms the reception time */
srslte_timestamp_t rx_time, tx_time, tx_time_prach;
srslte_ue_sync_get_last_timestamp(&ue_sync, &rx_time);
srslte_timestamp_copy(&tx_time, &rx_time);
srslte_timestamp_add(&tx_time, 0, 4e-3 - time_adv_sec);
worker->set_tx_time(tx_time);
Debug("Settting TTI=%d, tx_mutex=%d to worker %d\n", tti, tx_mutex_cnt, worker->get_id());
worker->set_tti(tti, tx_mutex_cnt);
tx_mutex_cnt = (tx_mutex_cnt+1)%nof_tx_mutex;
// Check if we need to TX a PRACH
if (prach_buffer->is_ready_to_send(tti)) {
srslte_timestamp_copy(&tx_time_prach, &rx_time);
srslte_timestamp_add(&tx_time_prach, 0, prach::tx_advance_sf*1e-3);
prach_buffer->send(radio_h, ul_dl_factor*metrics.cfo/15000, worker_com->pathloss, tx_time_prach);
radio_h->tx_end();
worker_com->p0_preamble = prach_buffer->get_p0_preamble();
worker_com->cur_radio_power = SRSLTE_MIN(SRSLTE_PC_MAX, worker_com->pathloss + worker_com->p0_preamble);
}
workers_pool->start_worker(worker);
// Notify RRC in-sync every 1 frame
if ((tti%10) == 0) {
rrc->in_sync();
log_h->debug("Sending in-sync to RRC\n");
}
} else {
log_h->console("Sync error.\n");
log_h->error("Sync error. Sending out-of-sync to RRC\n");
// Notify RRC of out-of-sync frame
rrc->out_of_sync();
worker->release();
worker_com->reset_ul();
phy_state = SYNCING;
}
} else {
// wait_worker() only returns NULL if it's being closed. Quit now to avoid unnecessary loops here
running = false;
}
break;
case IDLE:
usleep(1000);
break;
}
}
}
uint32_t phch_recv::get_current_tti()
{
return tti;
}
bool phch_recv::status_is_sync()
{
return phy_state == SYNC_DONE;
}
void phch_recv::get_current_cell(srslte_cell_t* cell_)
{
if (cell_) {
memcpy(cell_, &cell, sizeof(srslte_cell_t));
}
}
void phch_recv::sync_start()
{
radio_h->set_master_clock_rate(30.72e6);
phy_state = CELL_SEARCH;
}
void phch_recv::sync_stop()
{
free_cell();
radio_h->stop_rx();
radio_is_streaming = false;
phy_state = IDLE;
}
}

1168
srsue/src/phy/phch_worker.cc Normal file

File diff suppressed because it is too large Load Diff

364
srsue/src/phy/phy.cc Normal file
View File

@ -0,0 +1,364 @@
/**
*
* \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 <string>
#include <sstream>
#include <string.h>
#include <strings.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/mman.h>
#include "srslte/srslte.h"
#include "common/threads.h"
#include "common/log.h"
#include "phy/phy.h"
#include "phy/phch_worker.h"
#define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Info(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Debug(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
using namespace std;
namespace srsue {
phy::phy() : workers_pool(MAX_WORKERS),
workers(MAX_WORKERS),
workers_common(phch_recv::MUTEX_X_WORKER*MAX_WORKERS)
{
}
void phy::set_default_args(phy_args_t *args)
{
args->ul_pwr_ctrl_en = false;
args->prach_gain = -1;
args->cqi_max = -1;
args->cqi_fixed = -1;
args->snr_ema_coeff = 0.1;
args->snr_estim_alg = "refs";
args->pdsch_max_its = 4;
args->attach_enable_64qam = false;
args->nof_phy_threads = DEFAULT_WORKERS;
args->equalizer_mode = "mmse";
args->cfo_integer_enabled = false;
args->cfo_correct_tol_hz = 50;
args->time_correct_period = 5;
args->sfo_correct_disable = false;
args->sss_algorithm = "full";
args->estimator_fil_w = 0.1;
}
bool phy::check_args(phy_args_t *args)
{
if (args->nof_phy_threads > 3) {
log_h->console("Error in PHY args: nof_phy_threads must be 1, 2 or 3\n");
return false;
}
if (args->estimator_fil_w > 1.0) {
log_h->console("Error in PHY args: estimator_fil_w must be 0<=w<=1\n");
return false;
}
if (args->snr_ema_coeff > 1.0) {
log_h->console("Error in PHY args: snr_ema_coeff must be 0<=w<=1\n");
return false;
}
return true;
}
bool phy::init(srslte::radio_multi* radio_handler_, mac_interface_phy *mac, rrc_interface_phy *rrc,
srslte::log *log_h_, phy_args_t *phy_args)
{
mlockall(MCL_CURRENT | MCL_FUTURE);
n_ta = 0;
log_h = log_h_;
radio_handler = radio_handler_;
if (!phy_args) {
args = &default_args;
set_default_args(args);
} else {
args = phy_args;
}
if (!check_args(args)) {
return false;
}
nof_workers = args->nof_phy_threads;
// Add workers to workers pool and start threads
for (int i=0;i<nof_workers;i++) {
workers[i].set_common(&workers_common);
workers_pool.init_worker(i, &workers[i], WORKERS_THREAD_PRIO, args->worker_cpu_mask);
}
prach_buffer.init(&config.common.prach_cnfg, args, log_h);
workers_common.init(&config, args, log_h, radio_handler, mac);
// Warning this must be initialized after all workers have been added to the pool
sf_recv.init(radio_handler, mac, rrc, &prach_buffer, &workers_pool, &workers_common, log_h, args->nof_rx_ant, SF_RECV_THREAD_PRIO, args->sync_cpu_affinity);
// Disable UL signal pregeneration until the attachment
enable_pregen_signals(false);
return true;
}
void phy::set_agc_enable(bool enabled)
{
sf_recv.set_agc_enable(enabled);
}
void phy::start_trace()
{
for (int i=0;i<nof_workers;i++) {
workers[i].start_trace();
}
}
void phy::write_trace(std::string filename)
{
for (int i=0;i<nof_workers;i++) {
string i_str = static_cast<ostringstream*>( &(ostringstream() << i) )->str();
workers[i].write_trace(filename + "_" + i_str);
}
}
void phy::stop()
{
sf_recv.stop();
workers_pool.stop();
}
void phy::get_metrics(phy_metrics_t &m) {
workers_common.get_dl_metrics(m.dl);
workers_common.get_ul_metrics(m.ul);
workers_common.get_sync_metrics(m.sync);
int dl_tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(m.dl.mcs), workers_common.get_nof_prb());
int ul_tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(m.ul.mcs), workers_common.get_nof_prb());
m.dl.mabr_mbps = dl_tbs/1000.0; // TBS is bits/ms - convert to mbps
m.ul.mabr_mbps = ul_tbs/1000.0; // TBS is bits/ms - convert to mbps
Info("PHY: MABR estimates. DL: %4.6f Mbps. UL: %4.6f Mbps.\n", m.dl.mabr_mbps, m.ul.mabr_mbps);
}
void phy::set_timeadv_rar(uint32_t ta_cmd) {
n_ta = srslte_N_ta_new_rar(ta_cmd);
sf_recv.set_time_adv_sec(((float) n_ta)*SRSLTE_LTE_TS);
Info("PHY: Set TA RAR: ta_cmd: %d, n_ta: %d, ta_usec: %.1f\n", ta_cmd, n_ta, ((float) n_ta)*SRSLTE_LTE_TS*1e6);
}
void phy::set_timeadv(uint32_t ta_cmd) {
n_ta = srslte_N_ta_new(n_ta, ta_cmd);
//sf_recv.set_time_adv_sec(((float) n_ta)*SRSLTE_LTE_TS);
Warning("Not supported: Set TA: ta_cmd: %d, n_ta: %d, ta_usec: %.1f\n", ta_cmd, n_ta, ((float) n_ta)*SRSLTE_LTE_TS*1e6);
}
void phy::configure_prach_params()
{
if (sf_recv.status_is_sync()) {
Debug("Configuring PRACH parameters\n");
srslte_cell_t cell;
sf_recv.get_current_cell(&cell);
if (!prach_buffer.init_cell(cell)) {
Error("Configuring PRACH parameters\n");
}
} else {
Error("Cell is not synchronized\n");
}
}
void phy::configure_ul_params(bool pregen_disabled)
{
Info("PHY: Configuring UL parameters\n");
for (int i=0;i<nof_workers;i++) {
workers[i].set_ul_params(pregen_disabled);
}
}
float phy::get_phr()
{
float phr = radio_handler->get_max_tx_power() - workers_common.cur_pusch_power;
return phr;
}
float phy::get_pathloss_db()
{
return workers_common.cur_pathloss;
}
void phy::pdcch_ul_search(srslte_rnti_type_t rnti_type, uint16_t rnti, int tti_start, int tti_end)
{
workers_common.set_ul_rnti(rnti_type, rnti, tti_start, tti_end);
}
void phy::pdcch_dl_search(srslte_rnti_type_t rnti_type, uint16_t rnti, int tti_start, int tti_end)
{
workers_common.set_dl_rnti(rnti_type, rnti, tti_start, tti_end);
}
void phy::pdcch_dl_search_reset()
{
workers_common.set_dl_rnti(SRSLTE_RNTI_USER, 0);
}
void phy::pdcch_ul_search_reset()
{
workers_common.set_ul_rnti(SRSLTE_RNTI_USER, 0);
}
void phy::get_current_cell(srslte_cell_t *cell)
{
sf_recv.get_current_cell(cell);
}
void phy::prach_send(uint32_t preamble_idx, int allowed_subframe, float target_power_dbm)
{
if (!prach_buffer.prepare_to_send(preamble_idx, allowed_subframe, target_power_dbm)) {
Error("Preparing PRACH to send\n");
}
}
int phy::prach_tx_tti()
{
return prach_buffer.tx_tti();
}
void phy::reset()
{
// TODO
n_ta = 0;
pdcch_dl_search_reset();
for(uint32_t i=0;i<nof_workers;i++) {
workers[i].reset();
}
}
uint32_t phy::get_current_tti()
{
return sf_recv.get_current_tti();
}
void phy::sr_send()
{
workers_common.sr_enabled = true;
workers_common.sr_last_tx_tti = -1;
}
int phy::sr_last_tx_tti()
{
return workers_common.sr_last_tx_tti;
}
bool phy::status_is_sync()
{
return sf_recv.status_is_sync();
}
void phy::resync_sfn() {
sf_recv.resync_sfn();
}
void phy::sync_start()
{
sf_recv.sync_start();
}
void phy::sync_stop()
{
sf_recv.sync_stop();
}
void phy::set_rar_grant(uint32_t tti, uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN])
{
workers_common.set_rar_grant(tti, grant_payload);
}
void phy::set_crnti(uint16_t rnti) {
for(uint32_t i=0;i<nof_workers;i++) {
workers[i].set_crnti(rnti);
}
}
// Start GUI
void phy::start_plot() {
workers[0].start_plot();
}
void phy::enable_pregen_signals(bool enable)
{
for(uint32_t i=0;i<nof_workers;i++) {
workers[i].enable_pregen_signals(enable);
}
}
uint32_t phy::tti_to_SFN(uint32_t tti) {
return tti/10;
}
uint32_t phy::tti_to_subf(uint32_t tti) {
return tti%10;
}
void phy::get_config(phy_interface_rrc::phy_cfg_t* phy_cfg)
{
memcpy(phy_cfg, &config, sizeof(phy_cfg_t));
}
void phy::set_config(phy_interface_rrc::phy_cfg_t* phy_cfg)
{
memcpy(&config, phy_cfg, sizeof(phy_cfg_t));
}
void phy::set_config_64qam_en(bool enable)
{
config.enable_64qam = enable;
}
void phy::set_config_common(phy_interface_rrc::phy_cfg_common_t* common)
{
memcpy(&config.common, common, sizeof(phy_cfg_common_t));
}
void phy::set_config_dedicated(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT* dedicated)
{
memcpy(&config.dedicated, dedicated, sizeof(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT));
}
void phy::set_config_tdd(LIBLTE_RRC_TDD_CONFIG_STRUCT* tdd)
{
memcpy(&config.common.tdd_cnfg, tdd, sizeof(LIBLTE_RRC_TDD_CONFIG_STRUCT));
}
}

205
srsue/src/phy/prach.cc Normal file
View File

@ -0,0 +1,205 @@
/**
*
* \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 <string.h>
#include <strings.h>
#include <pthread.h>
#include "srslte/srslte.h"
#include "common/log.h"
#include "phy/prach.h"
#include "phy/phy.h"
#include "common/phy_interface.h"
#define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Info(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Debug(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
namespace srsue {
void prach::free_cell()
{
if (initiated) {
for (int i=0;i<64;i++) {
if (buffer[i]) {
free(buffer[i]);
}
}
if (signal_buffer) {
free(signal_buffer);
}
srslte_cfo_free(&cfo_h);
srslte_prach_free(&prach_obj);
}
}
void prach::init(LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT *config_, phy_args_t *args_, srslte::log* log_h_)
{
log_h = log_h_;
config = config_;
args = args_;
}
bool prach::init_cell(srslte_cell_t cell_)
{
// TODO: Check if other PRACH parameters changed
if (cell_.id != cell.id || !initiated) {
if (initiated) {
free_cell();
}
cell = cell_;
preamble_idx = -1;
uint32_t configIdx = config->prach_cnfg_info.prach_config_index;
uint32_t rootSeq = config->root_sequence_index;
uint32_t zeroCorrConfig = config->prach_cnfg_info.zero_correlation_zone_config;
uint32_t freq_offset = config->prach_cnfg_info.prach_freq_offset;
bool highSpeed = config->prach_cnfg_info.high_speed_flag;
if (6 + freq_offset > cell.nof_prb) {
log_h->console("Error no space for PRACH: frequency offset=%d, N_rb_ul=%d\n", freq_offset, cell.nof_prb);
log_h->error("Error no space for PRACH: frequency offset=%d, N_rb_ul=%d\n", freq_offset, cell.nof_prb);
return false;
}
if (srslte_prach_init(&prach_obj, srslte_symbol_sz(cell.nof_prb),
configIdx, rootSeq, highSpeed, zeroCorrConfig))
{
Error("Initiating PRACH library\n");
return false;
}
len = prach_obj.N_seq + prach_obj.N_cp;
for (int i=0;i<64;i++) {
buffer[i] = (cf_t*) srslte_vec_malloc(len*sizeof(cf_t));
if(!buffer[i]) {
return false;
}
if(srslte_prach_gen(&prach_obj, i, freq_offset, buffer[i])) {
Error("Generating PRACH preamble %d\n", i);
return false;
}
}
srslte_cfo_init(&cfo_h, len);
srslte_cfo_set_tol(&cfo_h, 0);
signal_buffer = (cf_t*) srslte_vec_malloc(len*sizeof(cf_t));
initiated = signal_buffer?true:false;
transmitted_tti = -1;
Debug("PRACH Initiated %s\n", initiated?"OK":"KO");
}
return initiated;
}
bool prach::prepare_to_send(uint32_t preamble_idx_, int allowed_subframe_, float target_power_dbm_)
{
if (initiated && preamble_idx_ < 64) {
preamble_idx = preamble_idx_;
target_power_dbm = target_power_dbm_;
allowed_subframe = allowed_subframe_;
transmitted_tti = -1;
Debug("PRACH prepare to send preamble %d\n", preamble_idx);
return true;
} else {
if (!initiated) {
Error("PRACH not initiated\n");
} else if (preamble_idx_ >= 64) {
Error("Invalid preamble %d\n", preamble_idx_);
}
return false;
}
}
bool prach::is_ready_to_send(uint32_t current_tti_) {
if (initiated && preamble_idx >= 0 && preamble_idx < 64) {
// consider the number of subframes the transmission must be anticipated
uint32_t current_tti = (current_tti_ + tx_advance_sf)%10240;
if (srslte_prach_tti_opportunity(&prach_obj, current_tti, allowed_subframe)) {
Debug("PRACH Buffer: Ready to send at tti: %d (now is %d)\n", current_tti, current_tti_);
transmitted_tti = current_tti;
return true;
}
}
return false;
}
int prach::tx_tti() {
return transmitted_tti;
}
float prach::get_p0_preamble()
{
return target_power_dbm;
}
void prach::send(srslte::radio *radio_handler, float cfo, float pathloss, srslte_timestamp_t tx_time)
{
// Get current TX gain
float old_gain = radio_handler->get_tx_gain();
// Correct CFO before transmission
srslte_cfo_correct(&cfo_h, buffer[preamble_idx], signal_buffer, cfo / srslte_symbol_sz(cell.nof_prb));
// If power control is enabled, choose amplitude and power
if (args->ul_pwr_ctrl_en) {
// Get PRACH transmission power
float tx_power = SRSLTE_MIN(SRSLTE_PC_MAX, pathloss + target_power_dbm);
// Get output power for amplitude 1
radio_handler->set_tx_power(tx_power);
// Scale signal
float digital_power = srslte_vec_avg_power_cf(signal_buffer, len);
float scale = sqrtf(pow(10,tx_power/10)/digital_power);
srslte_vec_sc_prod_cfc(signal_buffer, scale, signal_buffer, len);
log_h->console("PRACH: Pathloss=%.2f dB, Target power %.2f dBm, TX_power %.2f dBm, TX_gain %.1f dB\n",
pathloss, target_power_dbm, tx_power, radio_handler->get_tx_gain(), scale);
} else {
float prach_gain = args->prach_gain;
if (prach_gain > 0) {
radio_handler->set_tx_gain(prach_gain);
}
Debug("TX PRACH: Power control for PRACH is disabled, setting gain to %.0f dB\n", prach_gain);
}
radio_handler->tx(signal_buffer, len, tx_time);
radio_handler->tx_end();
Info("PRACH: Transmitted preamble=%d, CFO=%.2f KHz, tx_time=%f\n",
preamble_idx, cfo*15, tx_time.frac_secs);
preamble_idx = -1;
radio_handler->set_tx_gain(old_gain);
Debug("Restoring TX gain to %.0f dB\n", old_gain);
}
} // namespace srsue

View File

@ -0,0 +1,53 @@
/**
*
* \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 <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <string>
using namespace std;
int main(int argc, char *argv[])
{
if (argc != 2) {
std::cout << "Please call with the binary to provide net admin capabilities to as a parameter." << std::endl;
std::cout << "E.g. ./set_net_admin_caps myprogCalling " << std::endl;
return -1;
}
std::string command("setcap 'cap_net_admin=eip' ");
command += argv[1];
std::cout << "Calling " << command << " with root rights." << std::endl;
setuid(0);
system(command.c_str());
return 0;
}

319
srsue/src/ue.cc Normal file
View File

@ -0,0 +1,319 @@
/**
*
* \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 "ue.h"
//#include "srslte_version_check.h"
#include "srslte/srslte.h"
#include <pthread.h>
#include <iostream>
#include <string>
#include <algorithm>
#include <iterator>
using namespace srslte;
namespace srsue{
ue* ue::instance = NULL;
pthread_mutex_t ue_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
ue* ue::get_instance(void)
{
pthread_mutex_lock(&ue_instance_mutex);
if(NULL == instance) {
instance = new ue();
}
pthread_mutex_unlock(&ue_instance_mutex);
return(instance);
}
void ue::cleanup(void)
{
pthread_mutex_lock(&ue_instance_mutex);
if(NULL != instance) {
delete instance;
instance = NULL;
}
pthread_mutex_unlock(&ue_instance_mutex);
}
ue::ue()
:started(false)
{
pool = byte_buffer_pool::get_instance();
}
ue::~ue()
{
byte_buffer_pool::cleanup();
}
bool ue::init(all_args_t *args_)
{
args = args_;
logger.init(args->log.filename);
rf_log.init("RF ", &logger);
phy_log.init("PHY ", &logger, true);
mac_log.init("MAC ", &logger, true);
rlc_log.init("RLC ", &logger);
pdcp_log.init("PDCP", &logger);
rrc_log.init("RRC ", &logger);
nas_log.init("NAS ", &logger);
gw_log.init("GW ", &logger);
usim_log.init("USIM", &logger);
// Init logs
logger.log("\n\n");
rf_log.set_level(srslte::LOG_LEVEL_INFO);
phy_log.set_level(level(args->log.phy_level));
mac_log.set_level(level(args->log.mac_level));
rlc_log.set_level(level(args->log.rlc_level));
pdcp_log.set_level(level(args->log.pdcp_level));
rrc_log.set_level(level(args->log.rrc_level));
nas_log.set_level(level(args->log.nas_level));
gw_log.set_level(level(args->log.gw_level));
usim_log.set_level(level(args->log.usim_level));
phy_log.set_hex_limit(args->log.phy_hex_limit);
mac_log.set_hex_limit(args->log.mac_hex_limit);
rlc_log.set_hex_limit(args->log.rlc_hex_limit);
pdcp_log.set_hex_limit(args->log.pdcp_hex_limit);
rrc_log.set_hex_limit(args->log.rrc_hex_limit);
nas_log.set_hex_limit(args->log.nas_hex_limit);
gw_log.set_hex_limit(args->log.gw_hex_limit);
usim_log.set_hex_limit(args->log.usim_hex_limit);
// Set up pcap and trace
if(args->pcap.enable)
{
mac_pcap.open(args->pcap.filename.c_str());
mac.start_pcap(&mac_pcap);
}
if(args->trace.enable)
{
phy.start_trace();
radio.start_trace();
}
// Init layers
/* Start Radio */
char *dev_name = NULL;
if (args->rf.device_name.compare("auto")) {
dev_name = (char*) args->rf.device_name.c_str();
}
char *dev_args = NULL;
if (args->rf.device_args.compare("auto")) {
dev_args = (char*) args->rf.device_args.c_str();
}
printf("Opening RF device with %d RX antennas...\n", args->rf.nof_rx_ant);
if(!radio.init_multi(args->rf.nof_rx_ant, dev_args, dev_name))
{
printf("Failed to find device %s with args %s\n",
args->rf.device_name.c_str(), args->rf.device_args.c_str());
return false;
}
// Set RF options
if (args->rf.time_adv_nsamples.compare("auto")) {
radio.set_tx_adv(atoi(args->rf.time_adv_nsamples.c_str()));
}
if (args->rf.burst_preamble.compare("auto")) {
radio.set_burst_preamble(atof(args->rf.burst_preamble.c_str()));
}
radio.set_manual_calibration(&args->rf_cal);
// Set PHY options
args->expert.phy.nof_rx_ant = args->rf.nof_rx_ant;
if (args->rf.tx_gain > 0) {
args->expert.phy.ul_pwr_ctrl_en = false;
} else {
args->expert.phy.ul_pwr_ctrl_en = true;
}
phy.init(&radio, &mac, &rrc, &phy_log, &args->expert.phy);
if (args->rf.rx_gain < 0) {
radio.start_agc(false);
radio.set_tx_rx_gain_offset(10);
phy.set_agc_enable(true);
} else {
radio.set_rx_gain(args->rf.rx_gain);
}
if (args->rf.tx_gain > 0) {
radio.set_tx_gain(args->rf.tx_gain);
} else {
radio.set_tx_gain(args->rf.rx_gain);
std::cout << std::endl <<
"Warning: TX gain was not set. " <<
"Using open-loop power control (not working properly)" << std::endl << std::endl;
}
radio.register_error_handler(rf_msg);
radio.set_rx_freq(args->rf.dl_freq);
radio.set_tx_freq(args->rf.ul_freq);
phy_log.console("Setting frequency: DL=%.1f Mhz, UL=%.1f MHz\n", args->rf.dl_freq/1e6, args->rf.ul_freq/1e6);
mac.init(&phy, &rlc, &rrc, &mac_log);
rlc.init(&pdcp, &rrc, this, &rlc_log, &mac);
pdcp.init(&rlc, &rrc, &gw, &pdcp_log, SECURITY_DIRECTION_UPLINK);
rrc.init(&phy, &mac, &rlc, &pdcp, &nas, &usim, &mac, &rrc_log);
rrc.set_ue_category(args->expert.ue_cateogry);
nas.init(&usim, &rrc, &gw, &nas_log);
gw.init(&pdcp, &rrc, this, &gw_log);
usim.init(&args->usim, &usim_log);
started = true;
return true;
}
void ue::pregenerate_signals(bool enable)
{
phy.enable_pregen_signals(enable);
}
void ue::test_con_restablishment() {
rrc.test_con_restablishment();
}
void ue::stop()
{
if(started)
{
usim.stop();
nas.stop();
rrc.stop();
// Caution here order of stop is very important to avoid locks
// Stop RLC and PDCP before GW to avoid locking on queue
rlc.stop();
pdcp.stop();
gw.stop();
// PHY must be stopped before radio otherwise it will lock on rf_recv()
mac.stop();
phy.stop();
radio.stop();
usleep(1e5);
if(args->pcap.enable)
{
mac_pcap.close();
}
if(args->trace.enable)
{
phy.write_trace(args->trace.phy_filename);
radio.write_trace(args->trace.radio_filename);
}
started = false;
}
}
bool ue::is_attached()
{
return (EMM_STATE_REGISTERED == nas.get_state());
}
void ue::start_plot() {
phy.start_plot();
}
bool ue::get_metrics(ue_metrics_t &m)
{
m.rf = rf_metrics;
bzero(&rf_metrics, sizeof(rf_metrics_t));
rf_metrics.rf_error = false; // Reset error flag
if(EMM_STATE_REGISTERED == nas.get_state()) {
if(RRC_STATE_RRC_CONNECTED == rrc.get_state()) {
phy.get_metrics(m.phy);
mac.get_metrics(m.mac);
rlc.get_metrics(m.rlc);
gw.get_metrics(m.gw);
return true;
}
}
return false;
}
void ue::rf_msg(srslte_rf_error_t error)
{
ue *u = ue::get_instance();
u->handle_rf_msg(error);
}
void ue::handle_rf_msg(srslte_rf_error_t error)
{
if(error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_OVERFLOW) {
rf_metrics.rf_o++;
rf_metrics.rf_error = true;
rf_log.warning("Overflow\n");
}else if(error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_UNDERFLOW) {
rf_metrics.rf_u++;
rf_metrics.rf_error = true;
rf_log.warning("Underflow\n");
} else if(error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_LATE) {
rf_metrics.rf_l++;
rf_metrics.rf_error = true;
rf_log.warning("Late\n");
} else if (error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_OTHER) {
std::string str(error.msg);
str.erase(std::remove(str.begin(), str.end(), '\n'), str.end());
str.erase(std::remove(str.begin(), str.end(), '\r'), str.end());
str.push_back('\n');
rf_log.info(str);
}
}
srslte::LOG_LEVEL_ENUM ue::level(std::string l)
{
std::transform(l.begin(), l.end(), l.begin(), ::toupper);
if("NONE" == l){
return srslte::LOG_LEVEL_NONE;
}else if("ERROR" == l){
return srslte::LOG_LEVEL_ERROR;
}else if("WARNING" == l){
return srslte::LOG_LEVEL_WARNING;
}else if("INFO" == l){
return srslte::LOG_LEVEL_INFO;
}else if("DEBUG" == l){
return srslte::LOG_LEVEL_DEBUG;
}else{
return srslte::LOG_LEVEL_NONE;
}
}
} // namespace srsue

22
srsue/test/CMakeLists.txt Normal file
View File

@ -0,0 +1,22 @@
# Copyright 2015 Software Radio Systems Limited
#
# This file is part of srsUE
#
# 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/.
#
add_subdirectory(phy)
add_subdirectory(mac)
add_subdirectory(upper)

View File

@ -0,0 +1,22 @@
# Copyright 2015 Software Radio Systems Limited
#
# This file is part of srsUE
#
# 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/.
#
add_executable(mac_test mac_test.cc)
target_link_libraries(mac_test srsue_mac srsue_phy srslte_common srslte_phy srslte_radio srslte_asn1 ${SRSLTE_LIBRARIES} ${LIBLTE_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES})

495
srsue/test/mac/mac_test.cc Normal file
View File

@ -0,0 +1,495 @@
/**
*
* \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 <unistd.h>
#include <signal.h>
#include "asn1/liblte_rrc.h"
#include "radio/radio_multi.h"
#include "phy/phy.h"
#include "common/mac_interface.h"
#include "common/log_stdout.h"
#include "mac/mac.h"
#include "common/mac_pcap.h"
/**********************************************************************
* Program arguments processing
***********************************************************************/
typedef struct {
float rf_rx_freq;
float rf_tx_freq;
float rf_rx_gain;
float rf_tx_gain;
int verbose;
bool do_trace;
bool do_pcap;
}prog_args_t;
void args_default(prog_args_t *args) {
args->rf_rx_freq = -1.0;
args->rf_tx_freq = -1.0;
args->rf_rx_gain = -1; // set to autogain
args->rf_tx_gain = -1;
args->verbose = 0;
args->do_trace = false;
args->do_pcap = false;
}
void usage(prog_args_t *args, char *prog) {
printf("Usage: %s [gGtpv] -f rx_frequency (in Hz) -F tx_frequency (in Hz)\n", prog);
printf("\t-g RF RX gain [Default AGC]\n");
printf("\t-G RF TX gain [Default same as RX gain (AGC)]\n");
printf("\t-t Enable trace [Default disabled]\n");
printf("\t-p Enable PCAP capture [Default disabled]\n");
printf("\t-v [increase verbosity, default none]\n");
}
void parse_args(prog_args_t *args, int argc, char **argv) {
int opt;
args_default(args);
while ((opt = getopt(argc, argv, "gGftpFv")) != -1) {
switch (opt) {
case 'g':
args->rf_rx_gain = atof(argv[optind]);
break;
case 'G':
args->rf_tx_gain = atof(argv[optind]);
break;
case 'f':
args->rf_rx_freq = atof(argv[optind]);
break;
case 'F':
args->rf_tx_freq = atof(argv[optind]);
break;
case 't':
args->do_trace = true;
break;
case 'p':
args->do_pcap = true;
break;
case 'v':
args->verbose++;
break;
default:
usage(args, argv[0]);
exit(-1);
}
}
if (args->rf_rx_freq < 0 || args->rf_tx_freq < 0) {
usage(args, argv[0]);
exit(-1);
}
}
// Determine SI messages scheduling as in 36.331 5.2.3 Acquisition of an SI message
uint32_t sib_start_tti(uint32_t tti, uint32_t period, uint32_t x) {
return (period*10*(1+tti/(period*10))+x)%10240; // the 1 means next opportunity
}
void setup_mac_phy_sib2(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2, srsue::mac *mac, srsue::phy *phy) {
// Apply RACH configuration
srsue::mac_interface_rrc::mac_cfg_t mac_cfg;
mac->get_config(&mac_cfg);
memcpy(&mac_cfg.rach, &sib2->rr_config_common_sib.rach_cnfg, sizeof(LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT));
mac->set_config(&mac_cfg);
printf("Set RACH ConfigCommon: NofPreambles=%d, ResponseWindow=%d, ContentionResolutionTimer=%d ms, MaxTrials=%d\n",
liblte_rrc_number_of_ra_preambles_num[sib2->rr_config_common_sib.rach_cnfg.num_ra_preambles],
liblte_rrc_ra_response_window_size_num[sib2->rr_config_common_sib.rach_cnfg.ra_resp_win_size],
liblte_rrc_mac_contention_resolution_timer_num[sib2->rr_config_common_sib.rach_cnfg.mac_con_res_timer],
liblte_rrc_preamble_trans_max_num[sib2->rr_config_common_sib.rach_cnfg.preamble_trans_max]);
// Apply PHY RR Config Common
srsue::phy_interface_rrc::phy_cfg_common_t common;
memcpy(&common.pdsch_cnfg, &sib2->rr_config_common_sib.pdsch_cnfg, sizeof(LIBLTE_RRC_PDSCH_CONFIG_COMMON_STRUCT));
memcpy(&common.pusch_cnfg, &sib2->rr_config_common_sib.pusch_cnfg, sizeof(LIBLTE_RRC_PUSCH_CONFIG_COMMON_STRUCT));
memcpy(&common.pucch_cnfg, &sib2->rr_config_common_sib.pucch_cnfg, sizeof(LIBLTE_RRC_PUCCH_CONFIG_COMMON_STRUCT));
memcpy(&common.ul_pwr_ctrl, &sib2->rr_config_common_sib.ul_pwr_ctrl, sizeof(LIBLTE_RRC_UL_POWER_CONTROL_COMMON_STRUCT));
memcpy(&common.prach_cnfg, &sib2->rr_config_common_sib.prach_cnfg, sizeof(LIBLTE_RRC_PRACH_CONFIG_STRUCT));
if (sib2->rr_config_common_sib.srs_ul_cnfg.present) {
memcpy(&common.srs_ul_cnfg, &sib2->rr_config_common_sib.srs_ul_cnfg, sizeof(LIBLTE_RRC_SRS_UL_CONFIG_COMMON_STRUCT));
} else {
// default is release
common.srs_ul_cnfg.present = false;
}
phy->set_config_common(&common);
phy->configure_ul_params();
printf("Set PUSCH ConfigCommon: HopOffset=%d, RSGroup=%d, RSNcs=%d, N_sb=%d\n",
sib2->rr_config_common_sib.pusch_cnfg.pusch_hopping_offset,
sib2->rr_config_common_sib.pusch_cnfg.ul_rs.group_assignment_pusch,
sib2->rr_config_common_sib.pusch_cnfg.ul_rs.cyclic_shift,
sib2->rr_config_common_sib.pusch_cnfg.n_sb);
printf("Set PUCCH ConfigCommon: DeltaShift=%d, CyclicShift=%d, N1=%d, NRB=%d\n",
liblte_rrc_delta_pucch_shift_num[sib2->rr_config_common_sib.pucch_cnfg.delta_pucch_shift],
sib2->rr_config_common_sib.pucch_cnfg.n_cs_an,
sib2->rr_config_common_sib.pucch_cnfg.n1_pucch_an,
sib2->rr_config_common_sib.pucch_cnfg.n_rb_cqi);
printf("Set PRACH ConfigCommon: SeqIdx=%d, HS=%d, FreqOffset=%d, ZC=%d, ConfigIndex=%d\n",
sib2->rr_config_common_sib.prach_cnfg.root_sequence_index,
sib2->rr_config_common_sib.prach_cnfg.prach_cnfg_info.high_speed_flag?1:0,
sib2->rr_config_common_sib.prach_cnfg.prach_cnfg_info.prach_freq_offset,
sib2->rr_config_common_sib.prach_cnfg.prach_cnfg_info.zero_correlation_zone_config,
sib2->rr_config_common_sib.prach_cnfg.prach_cnfg_info.prach_config_index);
printf("Set SRS ConfigCommon: BW-Configuration=%d, SF-Configuration=%d, ACKNACK=%d\n",
sib2->rr_config_common_sib.srs_ul_cnfg.bw_cnfg,
sib2->rr_config_common_sib.srs_ul_cnfg.subfr_cnfg,
sib2->rr_config_common_sib.srs_ul_cnfg.ack_nack_simul_tx);
}
void process_connsetup(LIBLTE_RRC_CONNECTION_SETUP_STRUCT *msg, srsue::mac *mac, srsue::phy *phy) {
// FIXME: There's an error parsing the connectionSetup message. This value is hard-coded:
if (msg->rr_cnfg.phy_cnfg_ded_present) {
phy->set_config_dedicated(&msg->rr_cnfg.phy_cnfg_ded);
}
printf("Set PHY configuration: SR-n_pucch=%d, SR-ConfigIndex=%d, SRS-ConfigIndex=%d, SRS-bw=%d, SRS-Nrcc=%d, SRS-hop=%d, SRS-Ncs=%d\n",
msg->rr_cnfg.phy_cnfg_ded.sched_request_cnfg.sr_pucch_resource_idx,
msg->rr_cnfg.phy_cnfg_ded.sched_request_cnfg.sr_cnfg_idx,
msg->rr_cnfg.phy_cnfg_ded.srs_ul_cnfg_ded.srs_cnfg_idx,
msg->rr_cnfg.phy_cnfg_ded.srs_ul_cnfg_ded.srs_bandwidth,
msg->rr_cnfg.phy_cnfg_ded.srs_ul_cnfg_ded.freq_domain_pos,
msg->rr_cnfg.phy_cnfg_ded.srs_ul_cnfg_ded.srs_hopping_bandwidth,
msg->rr_cnfg.phy_cnfg_ded.srs_ul_cnfg_ded.cyclic_shift);
srsue::mac_interface_rrc::mac_cfg_t mac_set;
mac->get_config(&mac_set);
memcpy(&mac_set.main, &msg->rr_cnfg.mac_main_cnfg, sizeof(LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT));
// SR is a PHY config but is needed by SR procedure in 36.321 5.4.4
memcpy(&mac_set.sr, &msg->rr_cnfg.phy_cnfg_ded.sched_request_cnfg, sizeof(LIBLTE_RRC_SCHEDULING_REQUEST_CONFIG_STRUCT));
mac->set_config(&mac_set);
printf("Set MAC configuration: dsr-TransMAX: %d, harq-MaxReTX=%d, bsr-TimerReTX=%d, bsr-TimerPeriodic=%d\n",
liblte_rrc_dsr_trans_max_num[msg->rr_cnfg.phy_cnfg_ded.sched_request_cnfg.dsr_trans_max],
liblte_rrc_max_harq_tx_num[msg->rr_cnfg.mac_main_cnfg.explicit_value.ulsch_cnfg.max_harq_tx],
liblte_rrc_retransmission_bsr_timer_num[msg->rr_cnfg.mac_main_cnfg.explicit_value.ulsch_cnfg.retx_bsr_timer],
liblte_rrc_periodic_bsr_timer_num[msg->rr_cnfg.mac_main_cnfg.explicit_value.ulsch_cnfg.periodic_bsr_timer]);
phy->configure_ul_params();
// Setup radio bearers
for (int i=0;i<msg->rr_cnfg.srb_to_add_mod_list_size;i++) {
if (msg->rr_cnfg.srb_to_add_mod_list[i].lc_default_cnfg_present) {
printf("Setting up Default Configuration for SRB%d \n", msg->rr_cnfg.srb_to_add_mod_list[i].srb_id);
switch(msg->rr_cnfg.srb_to_add_mod_list[i].srb_id) {
case 1:
mac->setup_lcid(1, 0, 1, -1, -1);
break;
case 2:
mac->setup_lcid(2, 0, 3, -1, -1);
break;
}
}
}
// for (int i=0;i<msg->rr_cnfg.drb_to_add_mod_list_size;i++) {
// printf("Setting up DRB%d\n", msg->rr_cnfg.drb_to_add_mod_list[i].drb_id);
// // todo
// }
}
// Hex bytes for the connection setup complete packet
// Got hex bytes from http://www.sharetechnote.com/html/RACH_LTE.html
uint8_t setupComplete_segm[2][41] ={ {
0x88, 0x00, 0x00, 0x20, 0x21, 0x90, 0xa0, 0x12, 0x00, 0x00, 0x80, 0xf0, 0x5e, 0x3b, 0xf1, 0x04,
0x64, 0x04, 0x1d, 0x20, 0x44, 0x2f, 0xd8, 0x4b, 0xd1, 0x02, 0x00, 0x00, 0x83, 0x03, 0x41, 0xb0,
0xe5, 0x60, 0x13, 0x81, 0x83},
{0xb0, 0x01, 0x01, 0x01, 0x48, 0x4b, 0xd1, 0x00, 0x7d, 0x21, 0x70, 0x28, 0x01, 0x5c, 0x08, 0x80,
0x00, 0xc4, 0x0f, 0x97, 0x80, 0xd0, 0x4c, 0x4b, 0xd1, 0x00, 0xc0, 0x58, 0x44, 0x0d, 0x5d, 0x62,
0x99, 0x74, 0x04, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00}
};
uint8_t setupComplete[80] = {
0x88, 0x00, 0x00, 0x20, 0x21, 0x90, 0xa0, 0x12, 0x00, 0x00, 0x80, 0xf0, 0x5e, 0x3b, 0xf1, 0x04,
0x64, 0x04, 0x1d, 0x20, 0x44, 0x2f, 0xd8, 0x4b, 0xd1, 0x02, 0x00, 0x00, 0x83, 0x03, 0x41, 0xb0,
0xe5, 0x60, 0x13, 0x81, 0x83, 0x48, 0x4b, 0xd1, 0x00, 0x7d, 0x21, 0x70, 0x28, 0x01, 0x5c, 0x08, 0x80,
0x00, 0xc4, 0x0f, 0x97, 0x80, 0xd0, 0x4c, 0x4b, 0xd1, 0x00, 0xc0, 0x58, 0x44, 0x0d, 0x5d, 0x62,
0x99, 0x74, 0x04, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00};
uint32_t lengths[2] = {37, 41};
uint8_t reply[2] = {0x00, 0x04};
srslte::radio_multi radio;
srsue::phy phy;
srsue::mac mac;
srslte::mac_pcap mac_pcap;
prog_args_t prog_args;
void sig_int_handler(int signo)
{
if (prog_args.do_trace) {
//radio.write_trace("radio");
phy.write_trace("phy");
}
if (prog_args.do_pcap) {
mac_pcap.close();
}
mac.stop();
exit(0);
}
class rlctest : public srsue::rlc_interface_mac {
public:
bool mib_decoded;
bool sib1_decoded;
bool sib2_decoded;
bool connsetup_decoded;
int nsegm_dcch;
int send_ack;
uint8_t si_window_len, sib2_period;
rlctest() {
mib_decoded = false;
sib1_decoded = false;
sib2_decoded = false;
connsetup_decoded = false;
nsegm_dcch = 0;
si_window_len = 0;
sib2_period = 0;
send_ack = 0;
}
uint32_t get_total_buffer_state(uint32_t lcid) {
return get_buffer_state(lcid);
}
uint32_t get_buffer_state(uint32_t lcid) {
if (lcid == 0) {
if (sib2_decoded && !connsetup_decoded) {
return 6;
}
} else if (lcid == 1) {
if (connsetup_decoded && nsegm_dcch < 2) {
return lengths[nsegm_dcch];
} else if (send_ack == 1) {
return 2;
}
}
return 0;
}
int read_pdu(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes)
{
if (lcid == 0) {
LIBLTE_RRC_UL_CCCH_MSG_STRUCT ul_ccch_msg;
// Prepare ConnectionRequest packet
ul_ccch_msg.msg_type = LIBLTE_RRC_UL_CCCH_MSG_TYPE_RRC_CON_REQ;
ul_ccch_msg.msg.rrc_con_req.ue_id_type = LIBLTE_RRC_CON_REQ_UE_ID_TYPE_RANDOM_VALUE;
ul_ccch_msg.msg.rrc_con_req.ue_id.random = 1000;
ul_ccch_msg.msg.rrc_con_req.cause = LIBLTE_RRC_CON_REQ_EST_CAUSE_MO_SIGNALLING;
liblte_rrc_pack_ul_ccch_msg(&ul_ccch_msg, &bit_msg);
uint64_t uecri=0;
uint8_t *ue_cri_ptr = (uint8_t*) &uecri;
uint32_t nbytes = bit_msg.N_bits/8;
uint8_t *ptr = bit_msg.msg;
for (int i=0;i<nbytes;i++) {
ue_cri_ptr[nbytes-i-1] = (uint8_t) srslte_bit_pack(&ptr, 8);
}
printf("Setting UE contention resolution ID: %lu\n", uecri);
mac.set_contention_id(uecri);
// Send ConnectionRequest Packet
printf("Send ConnectionRequest %d/%d bytes\n", nbytes, nof_bytes);
srslte_bit_pack_vector(bit_msg.msg, payload, nbytes*8);
bzero(&payload[nbytes], (nof_bytes-nbytes)*sizeof(uint8_t));
return nof_bytes;
} else if (lcid == 1) {
if (nsegm_dcch < 2) {
if (nof_bytes >= 80) {
printf("Sending Connection Setup Complete length 80\n");
memcpy(payload, setupComplete, 80);
return 80;
} else {
uint32_t r = 0;
if (nof_bytes >= lengths[nsegm_dcch]) {
printf("Sending Connection Setup Complete %d/2 length %d\n", nsegm_dcch, lengths[nsegm_dcch]);
memcpy(payload, setupComplete_segm[nsegm_dcch], lengths[nsegm_dcch]);
r = lengths[nsegm_dcch];
nsegm_dcch++;
} else {
r = 0;
}
return r;
}
} else if (send_ack == 1) {
printf("Send RLC ACK\n");
memcpy(payload, reply, 2*sizeof(uint8_t));
send_ack = 2;
return 2;
}
}
return 0;
}
void write_pdu(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes) {
if (lcid == 0) {
LIBLTE_RRC_DL_CCCH_MSG_STRUCT dl_ccch_msg;
printf("ConnSetup received %d bytes\n", nof_bytes);
srslte_vec_fprint_byte(stdout, payload, nof_bytes);
srslte_bit_unpack_vector(payload, bit_msg.msg, nof_bytes*8);
bit_msg.N_bits = nof_bytes*8;
liblte_rrc_unpack_dl_ccch_msg(&bit_msg, &dl_ccch_msg);
printf("Response: %s\n", liblte_rrc_dl_ccch_msg_type_text[dl_ccch_msg.msg_type]);
switch (dl_ccch_msg.msg_type) {
case LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_SETUP:
// Process ConnectionSetup
process_connsetup(&dl_ccch_msg.msg.rrc_con_setup, &mac, &phy);
connsetup_decoded = true;
break;
case LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_REJ:
break;
}
} else if (lcid == 1) {
printf("Received on DCCH0 %d bytes\n", nof_bytes);
if (send_ack == 0) {
send_ack = 1;
}
}
}
void write_pdu_bcch_bch(uint8_t *payload, uint32_t nof_bytes)
{
LIBLTE_RRC_MIB_STRUCT mib;
srslte_vec_fprint_byte(stdout, payload, nof_bytes);
srslte_bit_unpack_vector(payload, bit_msg.msg, nof_bytes*8);
bit_msg.N_bits = nof_bytes*8;
liblte_rrc_unpack_bcch_bch_msg(&bit_msg, &mib);
printf("MIB received %d bytes, BW=%s MHz\n", nof_bytes, liblte_rrc_dl_bandwidth_text[mib.dl_bw]);
mib_decoded = true;
}
void write_pdu_bcch_dlsch(uint8_t *payload, uint32_t nof_bytes)
{
LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT dlsch_msg;
srslte_bit_unpack_vector(payload, bit_msg.msg, nof_bytes*8);
bit_msg.N_bits = nof_bytes*8;
liblte_rrc_unpack_bcch_dlsch_msg(&bit_msg, &dlsch_msg);
if (dlsch_msg.N_sibs > 0) {
if (dlsch_msg.sibs[0].sib_type == LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1 && !sib1_decoded) {
si_window_len = liblte_rrc_si_window_length_num[dlsch_msg.sibs[0].sib.sib1.si_window_length];
sib2_period = liblte_rrc_si_periodicity_num[dlsch_msg.sibs[0].sib.sib1.sched_info[0].si_periodicity];
printf("SIB1 received %d bytes, CellID=%d, si_window=%d, sib2_period=%d\n",
nof_bytes, dlsch_msg.sibs[0].sib.sib1.cell_id&0xfff, si_window_len, sib2_period);
sib1_decoded = true;
mac.bcch_stop_rx();
} else if (dlsch_msg.sibs[0].sib_type == LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2) {
printf("SIB2 received %d bytes\n", nof_bytes);
setup_mac_phy_sib2(&dlsch_msg.sibs[0].sib.sib2, &mac, &phy);
sib2_decoded = true;
mac.bcch_stop_rx();
}
}
}
void write_pdu_pcch(uint8_t *payload, uint32_t nof_bytes) {}
private:
LIBLTE_BIT_MSG_STRUCT bit_msg;
LIBLTE_BYTE_MSG_STRUCT byte_msg;
};
int main(int argc, char *argv[])
{
srslte::log_stdout mac_log("MAC"), phy_log("PHY");
rlctest my_rlc;
parse_args(&prog_args, argc, argv);
switch (prog_args.verbose) {
case 1:
mac_log.set_level(srslte::LOG_LEVEL_INFO);
phy_log.set_level(srslte::LOG_LEVEL_INFO);
break;
case 2:
mac_log.set_level(srslte::LOG_LEVEL_DEBUG);
phy_log.set_level(srslte::LOG_LEVEL_DEBUG);
break;
}
// Capture SIGINT to write traces
if (prog_args.do_trace) {
signal(SIGINT, sig_int_handler);
//radio.start_trace();
phy.start_trace();
}
if (prog_args.do_pcap) {
if (!prog_args.do_trace) {
signal(SIGINT, sig_int_handler);
}
mac_pcap.open("/tmp/ue_mac.pcap");
mac.start_pcap(&mac_pcap);
}
// Init Radio and PHY
radio.init();
phy.init(&radio, &mac, NULL, &phy_log);
if (prog_args.rf_rx_gain > 0 && prog_args.rf_tx_gain > 0) {
radio.set_rx_gain(prog_args.rf_rx_gain);
radio.set_tx_gain(prog_args.rf_tx_gain);
} else {
radio.start_agc(false);
radio.set_tx_rx_gain_offset(10);
phy.set_agc_enable(true);
}
// Init MAC
mac.init(&phy, &my_rlc, NULL, &mac_log);
// Set RX freq
radio.set_rx_freq(prog_args.rf_rx_freq);
radio.set_tx_freq(prog_args.rf_tx_freq);
while(1) {
uint32_t tti;
if (my_rlc.mib_decoded && mac.get_current_tti()) {
if (!my_rlc.sib1_decoded) {
usleep(10000);
tti = mac.get_current_tti();
mac.bcch_start_rx(sib_start_tti(tti, 2, 5), 1);
} else if (!my_rlc.sib2_decoded) {
usleep(10000);
tti = mac.get_current_tti();
mac.bcch_start_rx(sib_start_tti(tti, my_rlc.sib2_period, 0), my_rlc.si_window_len);
}
}
usleep(50000);
}
}

View File

@ -0,0 +1,24 @@
# Copyright 2015 Software Radio Systems Limited
#
# This file is part of srsUE
#
# 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/.
#
add_executable(ue_itf_test_sib1 ue_itf_test_sib1.cc)
target_link_libraries(ue_itf_test_sib1 srsue_phy srslte_common srslte_phy srslte_radio ${SRSLTE_LIBRARIES} ${LIBLTE_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES})
add_executable(ue_itf_test_prach ue_itf_test_prach.cc)
target_link_libraries(ue_itf_test_prach srsue_phy srslte_common srslte_phy srslte_radio ${SRSLTE_LIBRARIES} ${LIBLTE_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES})

View File

@ -0,0 +1,388 @@
/**
*
* \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 <unistd.h>
#include "srslte/phy/utils/debug.h"
#include "phy/phy.h"
#include "common/phy_interface.h"
#include "common/log_stdout.h"
#include "radio/radio_multi.h"
/**********************************************************************
* Program arguments processing
***********************************************************************/
typedef struct {
float rf_rx_freq;
float rf_tx_freq;
float rf_rx_gain;
float rf_tx_gain;
bool continous;
}prog_args_t;
prog_args_t prog_args;
uint32_t srsapps_verbose = 0;
void args_default(prog_args_t *args) {
args->rf_rx_freq = -1.0;
args->rf_tx_freq = -1.0;
args->rf_rx_gain = -1; // set to autogain
args->rf_tx_gain = -1;
args->continous = false;
}
void usage(prog_args_t *args, char *prog) {
printf("Usage: %s [gGcv] -f rx_frequency -F tx_frequency (in Hz)\n", prog);
printf("\t-g RF RX gain [Default AGC]\n");
printf("\t-G RF TX gain [Default same as RX gain (AGC)]\n");
printf("\t-c Run continuously [Default only once]\n");
printf("\t-v [increase verbosity, default none]\n");
}
void parse_args(prog_args_t *args, int argc, char **argv) {
int opt;
args_default(args);
while ((opt = getopt(argc, argv, "gGfFcv")) != -1) {
switch (opt) {
case 'g':
args->rf_rx_gain = atof(argv[optind]);
break;
case 'G':
args->rf_tx_gain = atof(argv[optind]);
break;
case 'f':
args->rf_rx_freq = atof(argv[optind]);
break;
case 'F':
args->rf_tx_freq = atof(argv[optind]);
break;
case 'c':
args->continous = true;
break;
case 'v':
srsapps_verbose++;
break;
default:
usage(args, argv[0]);
exit(-1);
}
}
if (args->rf_rx_freq < 0 || args->rf_tx_freq < 0) {
usage(args, argv[0]);
exit(-1);
}
}
typedef enum{
rar_header_type_bi = 0,
rar_header_type_rapid,
rar_header_type_n_items,
}rar_header_t;
static const char rar_header_text[rar_header_type_n_items][8] = {"BI", "RAPID"};
typedef struct {
rar_header_t hdr_type;
bool hopping_flag;
uint32_t tpc_command;
bool ul_delay;
bool csi_req;
uint16_t rba;
uint16_t timing_adv_cmd;
uint16_t temp_c_rnti;
uint8_t mcs;
uint8_t RAPID;
uint8_t BI;
}rar_msg_t;
int rar_unpack(uint8_t *buffer, rar_msg_t *msg)
{
int ret = SRSLTE_ERROR;
uint8_t *ptr = buffer;
if(buffer != NULL &&
msg != NULL)
{
ptr++;
msg->hdr_type = (rar_header_t) *ptr++;
if(msg->hdr_type == rar_header_type_bi) {
ptr += 2;
msg->BI = srslte_bit_pack(&ptr, 4);
ret = SRSLTE_SUCCESS;
} else if (msg->hdr_type == rar_header_type_rapid) {
msg->RAPID = srslte_bit_pack(&ptr, 6);
ptr++;
msg->timing_adv_cmd = srslte_bit_pack(&ptr, 11);
msg->hopping_flag = *ptr++;
msg->rba = srslte_bit_pack(&ptr, 10);
msg->mcs = srslte_bit_pack(&ptr, 4);
msg->tpc_command = srslte_bit_pack(&ptr, 3);
msg->ul_delay = *ptr++;
msg->csi_req = *ptr++;
msg->temp_c_rnti = srslte_bit_pack(&ptr, 16);
ret = SRSLTE_SUCCESS;
}
}
return(ret);
}
srsue::phy my_phy;
bool bch_decoded = false;
uint8_t payload[10240];
uint8_t payload_bits[10240];
const uint8_t conn_request_msg[] = {0x20, 0x06, 0x1F, 0x5C, 0x2C, 0x04, 0xB2, 0xAC, 0xF6, 0x00, 0x00, 0x00};
enum mac_state {RA, RAR, CONNREQUEST, CONNSETUP} state = RA;
uint32_t preamble_idx = 0;
rar_msg_t rar_msg;
uint32_t nof_rtx_connsetup = 0;
uint32_t rv_value[4] = {0, 2, 3, 1};
void config_phy() {
srsue::phy_interface_rrc::phy_cfg_t config;
config.common.prach_cnfg.prach_cnfg_info.prach_config_index = 0;
config.common.prach_cnfg.prach_cnfg_info.prach_freq_offset = 0;
config.common.prach_cnfg.prach_cnfg_info.high_speed_flag = false;
config.common.prach_cnfg.root_sequence_index = 0;
config.common.prach_cnfg.prach_cnfg_info.zero_correlation_zone_config = 11;
config.common.pusch_cnfg.ul_rs.group_hopping_enabled = false;
config.common.pusch_cnfg.ul_rs.sequence_hopping_enabled = false;
config.common.pusch_cnfg.n_sb = 2;
config.common.pusch_cnfg.ul_rs.cyclic_shift = 0;
config.common.pusch_cnfg.ul_rs.group_assignment_pusch = 0;
config.common.pusch_cnfg.pusch_hopping_offset = 0;
config.common.pucch_cnfg.delta_pucch_shift = LIBLTE_RRC_DELTA_PUCCH_SHIFT_DS2;
config.common.pucch_cnfg.n_cs_an = 0;
config.common.pucch_cnfg.n1_pucch_an = 1;
my_phy.configure_ul_params();
my_phy.configure_prach_params();
}
srslte_softbuffer_rx_t softbuffer_rx;
srslte_softbuffer_tx_t softbuffer_tx;
uint16_t temp_c_rnti;
/******** MAC Interface implementation */
class testmac : public srsue::mac_interface_phy
{
public:
testmac() {
rar_rnti_set = false;
}
bool rar_rnti_set;
void pch_decoded_ok(uint32_t len) {}
void tti_clock(uint32_t tti) {
if (!rar_rnti_set) {
int prach_tti = my_phy.prach_tx_tti();
if (prach_tti > 0) {
my_phy.pdcch_dl_search(SRSLTE_RNTI_RAR, 1+prach_tti%10, prach_tti+3, prach_tti+13);
rar_rnti_set = true;
}
}
}
void new_grant_ul(mac_grant_t grant, tb_action_ul_t *action) {
printf("New grant UL\n");
memcpy(payload, conn_request_msg, grant.n_bytes*sizeof(uint8_t));
action->current_tx_nb = nof_rtx_connsetup;
action->rv = rv_value[nof_rtx_connsetup%4];
action->softbuffer = &softbuffer_tx;
action->rnti = temp_c_rnti;
action->expect_ack = (nof_rtx_connsetup < 5)?true:false;
action->payload_ptr = payload;
memcpy(&action->phy_grant, &grant.phy_grant, sizeof(srslte_phy_grant_t));
memcpy(&last_grant, &grant, sizeof(mac_grant_t));
action->tx_enabled = true;
if (action->rv == 0) {
srslte_softbuffer_tx_reset(&softbuffer_tx);
}
my_phy.pdcch_dl_search(SRSLTE_RNTI_USER, temp_c_rnti);
}
void new_grant_ul_ack(mac_grant_t grant, bool ack, tb_action_ul_t *action) {
printf("New grant UL ACK\n");
}
void harq_recv(uint32_t tti, bool ack, tb_action_ul_t *action) {
printf("harq recv hi=%d\n", ack?1:0);
if (!ack) {
nof_rtx_connsetup++;
action->current_tx_nb = nof_rtx_connsetup;
action->rv = rv_value[nof_rtx_connsetup%4];
action->softbuffer = &softbuffer_tx;
action->rnti = temp_c_rnti;
action->expect_ack = true;
memcpy(&action->phy_grant, &last_grant.phy_grant, sizeof(srslte_phy_grant_t));
action->tx_enabled = true;
if (action->rv == 0) {
srslte_softbuffer_tx_reset(&softbuffer_tx);
}
printf("Retransmission %d, rv=%d\n", nof_rtx_connsetup, action->rv);
}
}
void new_grant_dl(mac_grant_t grant, tb_action_dl_t *action) {
action->decode_enabled = true;
action->default_ack = false;
if (grant.rnti == 2) {
action->generate_ack = false;
} else {
action->generate_ack = true;
}
action->payload_ptr = payload;
action->rnti = grant.rnti;
memcpy(&action->phy_grant, &grant.phy_grant, sizeof(srslte_phy_grant_t));
memcpy(&last_grant, &grant, sizeof(mac_grant_t));
action->rv = grant.rv;
action->softbuffer = &softbuffer_rx;
if (action->rv == 0) {
srslte_softbuffer_rx_reset(&softbuffer_rx);
}
}
void tb_decoded(bool ack, srslte_rnti_type_t rnti_type, uint32_t harq_pid) {
if (ack) {
if (rnti_type == SRSLTE_RNTI_RAR) {
my_phy.pdcch_dl_search_reset();
srslte_bit_unpack_vector(payload, payload_bits, last_grant.n_bytes*8);
rar_unpack(payload_bits, &rar_msg);
if (rar_msg.RAPID == preamble_idx) {
printf("Received RAR at TTI: %d\n", last_grant.tti);
my_phy.set_timeadv_rar(rar_msg.timing_adv_cmd);
temp_c_rnti = rar_msg.temp_c_rnti;
if (last_grant.n_bytes*8 > 20 + SRSLTE_RAR_GRANT_LEN) {
uint8_t rar_grant[SRSLTE_RAR_GRANT_LEN];
memcpy(rar_grant, &payload_bits[20], sizeof(uint8_t)*SRSLTE_RAR_GRANT_LEN);
my_phy.set_rar_grant(last_grant.tti, rar_grant);
}
} else {
printf("Received RAR RAPID=%d\n", rar_msg.RAPID);
}
} else {
printf("Received Connection Setup\n");
my_phy.pdcch_dl_search_reset();
}
}
}
void bch_decoded_ok(uint8_t *payload, uint32_t len) {
printf("BCH decoded\n");
bch_decoded = true;
srslte_cell_t cell;
my_phy.get_current_cell(&cell);
srslte_softbuffer_rx_init(&softbuffer_rx, cell.nof_prb);
srslte_softbuffer_tx_init(&softbuffer_tx, cell.nof_prb);
}
private:
mac_grant_t last_grant;
};
testmac my_mac;
srslte::radio_multi radio;
int main(int argc, char *argv[])
{
srslte::log_stdout log("PHY");
parse_args(&prog_args, argc, argv);
// Init Radio and PHY
radio.init();
my_phy.init(&radio, &my_mac, NULL, &log);
if (prog_args.rf_rx_gain > 0 && prog_args.rf_tx_gain > 0) {
radio.set_rx_gain(prog_args.rf_rx_gain);
radio.set_tx_gain(prog_args.rf_tx_gain);
} else {
radio.start_agc(false);
radio.set_tx_rx_gain_offset(10);
my_phy.set_agc_enable(true);
}
if (srsapps_verbose == 1) {
log.set_level(srslte::LOG_LEVEL_INFO);
printf("Log level info\n");
}
if (srsapps_verbose == 2) {
log.set_level(srslte::LOG_LEVEL_DEBUG);
printf("Log level debug\n");
}
// Give it time to create thread
sleep(1);
// Set RX freq
radio.set_rx_freq(prog_args.rf_rx_freq);
radio.set_tx_freq(prog_args.rf_tx_freq);
// Instruct the PHY to configure PRACH parameters and sync to current cell
my_phy.sync_start();
while(!my_phy.status_is_sync()) {
usleep(20000);
}
// Setup PHY parameters
config_phy();
/* Instruct PHY to send PRACH and prepare it for receiving RAR */
my_phy.prach_send(preamble_idx);
/* go to idle and process each tti */
bool running = true;
while(running) {
sleep(1);
}
my_phy.stop();
radio.stop_rx();
}

View File

@ -0,0 +1,214 @@
/**
*
* \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 <unistd.h>
#include "srslte/phy/utils/debug.h"
#include "phy/phy.h"
#include "common/log_stdout.h"
#include "common/mac_interface.h"
#include "radio/radio_multi.h"
/**********************************************************************
* Program arguments processing
***********************************************************************/
typedef struct {
float rf_freq;
float rf_gain;
}prog_args_t;
uint32_t srsapps_verbose = 0;
prog_args_t prog_args;
void args_default(prog_args_t *args) {
args->rf_freq = -1.0;
args->rf_gain = -1.0;
}
void usage(prog_args_t *args, char *prog) {
printf("Usage: %s [gv] -f rx_frequency (in Hz)\n", prog);
printf("\t-g RF RX gain [Default AGC]\n");
printf("\t-v [increase verbosity, default none]\n");
}
void parse_args(prog_args_t *args, int argc, char **argv) {
int opt;
args_default(args);
while ((opt = getopt(argc, argv, "gfv")) != -1) {
switch (opt) {
case 'g':
args->rf_gain = atof(argv[optind]);
break;
case 'f':
args->rf_freq = atof(argv[optind]);
break;
case 'v':
srsapps_verbose++;
break;
default:
usage(args, argv[0]);
exit(-1);
}
}
if (args->rf_freq < 0) {
usage(args, argv[0]);
exit(-1);
}
}
srsue::phy my_phy;
bool bch_decoded = false;
uint32_t total_pkts=0;
uint32_t total_dci=0;
uint32_t total_oks=0;
uint8_t payload[1024];
srslte_softbuffer_rx_t softbuffer;
/******** MAC Interface implementation */
class testmac : public srsue::mac_interface_phy
{
public:
void new_grant_ul(mac_grant_t grant, tb_action_ul_t *action) {
printf("New grant UL\n");
}
void new_grant_ul_ack(mac_grant_t grant, bool ack, tb_action_ul_t *action) {
printf("New grant UL ACK\n");
}
void harq_recv(uint32_t tti, bool ack, tb_action_ul_t *action) {
printf("harq recv\n");
}
void new_grant_dl(mac_grant_t grant, tb_action_dl_t *action) {
total_dci++;
action->decode_enabled = true;
action->default_ack = false;
action->generate_ack = false;
action->payload_ptr = payload;
memcpy(&action->phy_grant, &grant.phy_grant, sizeof(srslte_phy_grant_t));
action->rv = ((uint32_t) ceilf((float)3*((my_phy.tti_to_SFN(grant.tti)/2)%4)/2))%4;
action->softbuffer = &softbuffer;
action->rnti = grant.rnti;
if (action->rv == 0) {
srslte_softbuffer_rx_reset(&softbuffer);
}
}
void tb_decoded(bool ack, srslte_rnti_type_t rnti, uint32_t harq_pid) {
if (ack) {
total_oks++;
}
}
void pch_decoded_ok(uint32_t len) {}
void bch_decoded_ok(uint8_t *payload, uint32_t len) {
printf("BCH decoded\n");
bch_decoded = true;
srslte_cell_t cell;
my_phy.get_current_cell(&cell);
srslte_softbuffer_rx_init(&softbuffer, cell.nof_prb);
}
void tti_clock(uint32_t tti) {
}
};
testmac my_mac;
srslte::radio_multi radio;
int main(int argc, char *argv[])
{
srslte::log_stdout log("PHY");
parse_args(&prog_args, argc, argv);
// Init Radio and PHY
radio.init();
my_phy.init(&radio, &my_mac, NULL, &log);
if (prog_args.rf_gain > 0) {
radio.set_rx_gain(prog_args.rf_gain);
} else {
radio.start_agc(false);
my_phy.set_agc_enable(true);
}
if (srsapps_verbose == 1) {
log.set_level(srslte::LOG_LEVEL_INFO);
printf("Log level info\n");
}
if (srsapps_verbose == 2) {
log.set_level(srslte::LOG_LEVEL_DEBUG);
printf("Log level debug\n");
}
// Give it time to create thread
sleep(1);
// Set RX freq and gain
radio.set_rx_freq(prog_args.rf_freq);
my_phy.sync_start();
bool running = true;
while(running) {
if (bch_decoded && my_phy.status_is_sync()) {
uint32_t tti = my_phy.get_current_tti();
// SIB1 is scheduled in subframe #5 of even frames, try to decode next frame SIB1
tti = (((tti/20)*20) + 25)%10240;
my_phy.pdcch_dl_search(SRSLTE_RNTI_SI, SRSLTE_SIRNTI, tti, tti+1);
total_pkts++;
}
usleep(30000);
if (bch_decoded && my_phy.status_is_sync() && total_pkts > 0) {
if (srslte_verbose == SRSLTE_VERBOSE_NONE && srsapps_verbose == 0) {
float gain = prog_args.rf_gain;
if (gain < 0) {
gain = radio.get_rx_gain();
}
printf("PDCCH BLER %.1f \%% PDSCH BLER %.1f \%% (total pkts: %5u) Gain: %.1f dB\r",
100-(float) 100*total_dci/total_pkts,
(float) 100*(1 - total_oks/total_pkts),
total_pkts, gain);
}
}
}
my_phy.stop();
radio.stop_rx();
}

View File

@ -0,0 +1,42 @@
# Copyright 2015 Software Radio Systems Limited
#
# This file is part of srsUE
#
# 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/.
#
# IP traffic over RLC test
add_executable(ip_test ip_test.cc)
target_link_libraries(ip_test srsue_mac
srsue_phy
srslte_common
srslte_phy
srslte_radio
srslte_upper
${SRSLTE_LIBRARIES}
${LIBLTE_LIBRARY}
${CMAKE_THREAD_LIBS_INIT}
${Boost_LIBRARIES})
########################################################################
# Option to run command after build (useful for remote builds)
########################################################################
if (NOT ${BUILD_CMD} STREQUAL "")
message(STATUS "Added custom post-build command: ${BUILD_CMD}")
add_custom_command(TARGET ip_test POST_BUILD COMMAND ${BUILD_CMD})
else(NOT ${BUILD_CMD} STREQUAL "")
message(STATUS "No post-build command defined")
endif (NOT ${BUILD_CMD} STREQUAL "")

645
srsue/test/upper/ip_test.cc Normal file
View File

@ -0,0 +1,645 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <linux/ip.h>
#include <linux/if.h>
#include <linux/if_tun.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <assert.h>
#include "srslte/phy/utils/debug.h"
#include "mac/mac.h"
#include "phy/phy.h"
#include "common/threads.h"
#include "common/common.h"
#include "common/buffer_pool.h"
#include "common/logger.h"
#include "common/log_filter.h"
#include "upper/rlc.h"
#include "upper/rrc.h"
#include "radio/radio_multi.h"
#define START_TUNTAP
#define USE_RADIO
#define PRINT_GW 0
/**********************************************************************
* Program arguments processing
***********************************************************************/
#define LCID 3
typedef struct {
float rx_freq;
float tx_freq;
float rx_gain;
float tx_gain;
int time_adv;
std::string ip_address;
}prog_args_t;
uint32_t srsapps_verbose = 1;
prog_args_t prog_args;
void args_default(prog_args_t *args) {
args->tx_freq = 2.505e9;
args->rx_freq = 2.625e9;
args->rx_gain = 50.0;
args->tx_gain = 70.0;
args->time_adv = -1; // calibrated for b210
args->ip_address = "192.168.3.2";
}
void usage(prog_args_t *args, char *prog) {
printf("Usage: %s [gGIrfFtv]\n", prog);
printf("\t-f RX frequency [Default %.1f MHz]\n", args->rx_freq/1e6);
printf("\t-F TX frequency [Default %.1f MHz]\n", args->tx_freq/1e6);
printf("\t-g RX gain [Default %.1f]\n", args->rx_gain);
printf("\t-G TX gain [Default %.1f]\n", args->tx_gain);
printf("\t-I IP address [Default %s]\n", args->ip_address.c_str());
printf("\t-t time advance (in samples) [Default %d]\n", args->time_adv);
printf("\t-v [increase verbosity, default none]\n");
}
void parse_args(prog_args_t *args, int argc, char **argv) {
int opt;
args_default(args);
while ((opt = getopt(argc, argv, "gGfFItv")) != -1) {
switch (opt) {
case 'g':
args->rx_gain = atof(argv[optind]);
break;
case 'G':
args->tx_gain = atof(argv[optind]);
break;
case 'f':
args->rx_freq = atof(argv[optind]);
break;
case 'F':
args->tx_freq = atof(argv[optind]);
break;
case 'I':
args->ip_address = argv[optind];
break;
case 't':
args->time_adv = atoi(argv[optind]);
break;
case 'v':
srsapps_verbose++;
break;
default:
usage(args, argv[0]);
exit(-1);
}
}
if (args->rx_freq < 0 || args->tx_freq < 0) {
usage(args, argv[0]);
exit(-1);
}
}
int setup_if_addr(char *ip_addr);
// Define dummy RLC always transmitts
class tester : public srsue::pdcp_interface_rlc,
public srsue::rrc_interface_rlc,
public srsue::rrc_interface_phy,
public srsue::rrc_interface_mac,
public srsue::ue_interface,
public thread
{
public:
tester() {
state = srsue::RRC_STATE_SIB1_SEARCH;
read_enable = true;
}
void init(srsue::phy *phy_, srsue::mac *mac_, srsue::rlc *rlc_, srslte::log *log_h_, std::string ip_address) {
log_h = log_h_;
rlc = rlc_;
mac = mac_;
phy = phy_;
#ifdef START_TUNTAP
if (init_tuntap((char*) ip_address.c_str())) {
log_h->error("Initiating IP address\n");
}
#endif
pool = srslte::byte_buffer_pool::get_instance();
// Start reader thread
running=true;
start();
}
void sib_search()
{
bool searching = true;
uint32_t tti ;
uint32_t si_win_start, si_win_len;
uint16_t period;
uint32_t nof_sib1_trials = 0;
const int SIB1_SEARCH_TIMEOUT = 30;
while(searching)
{
switch(state)
{
case srsue::RRC_STATE_SIB1_SEARCH:
// Instruct MAC to look for SIB1
while(!phy->status_is_sync()){
usleep(50000);
}
usleep(10000);
tti = mac->get_current_tti();
si_win_start = sib_start_tti(tti, 2, 5);
mac->bcch_start_rx(si_win_start, 1);
log_h->info("Instructed MAC to search for SIB1, win_start=%d, win_len=%d\n",
si_win_start, 1);
nof_sib1_trials++;
if (nof_sib1_trials >= SIB1_SEARCH_TIMEOUT) {
log_h->info("Timeout while searching for SIB1. Resynchronizing SFN...\n");
log_h->console("Timeout while searching for SIB1. Resynchronizing SFN...\n");
phy->resync_sfn();
nof_sib1_trials = 0;
}
break;
case srsue::RRC_STATE_SIB2_SEARCH:
// Instruct MAC to look for SIB2
usleep(10000);
tti = mac->get_current_tti();
period = liblte_rrc_si_periodicity_num[sib1.sched_info[0].si_periodicity];
si_win_start = sib_start_tti(tti, period, 0);
si_win_len = liblte_rrc_si_window_length_num[sib1.si_window_length];
mac->bcch_start_rx(si_win_start, si_win_len);
log_h->info("Instructed MAC to search for SIB2, win_start=%d, win_len=%d\n",
si_win_start, si_win_len);
break;
default:
searching = false;
break;
}
usleep(100000);
}
}
bool is_sib_received() {
return state == srsue::RRC_STATE_WAIT_FOR_CON_SETUP;
}
void release_pucch_srs() {}
void ra_problem() {}
void write_pdu_bcch_bch(srslte::byte_buffer_t *pdu) {}
void write_pdu_bcch_dlsch(srslte::byte_buffer_t *pdu)
{
log_h->info_hex(pdu->msg, pdu->N_bytes, "BCCH DLSCH message received.");
log_h->info("BCCH DLSCH message Stack latency: %ld us\n", pdu->get_latency_us());
LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT dlsch_msg;
srslte_bit_unpack_vector(pdu->msg, bit_buf.msg, pdu->N_bytes*8);
bit_buf.N_bits = pdu->N_bytes*8;
pool->deallocate(pdu);
liblte_rrc_unpack_bcch_dlsch_msg((LIBLTE_BIT_MSG_STRUCT*)&bit_buf, &dlsch_msg);
if (dlsch_msg.N_sibs > 0) {
if (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1 == dlsch_msg.sibs[0].sib_type && srsue::RRC_STATE_SIB1_SEARCH == state) {
// Handle SIB1
memcpy(&sib1, &dlsch_msg.sibs[0].sib.sib1, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT));
log_h->info("SIB1 received, CellID=%d, si_window=%d, sib2_period=%d\n",
sib1.cell_id&0xfff,
liblte_rrc_si_window_length_num[sib1.si_window_length],
liblte_rrc_si_periodicity_num[sib1.sched_info[0].si_periodicity]);
std::stringstream ss;
for(int i=0;i<sib1.N_plmn_ids;i++){
ss << " PLMN Id: MCC " << sib1.plmn_id[i].id.mcc << " MNC " << sib1.plmn_id[i].id.mnc;
}
log_h->console("SIB1 received, CellID=%d, %s\n",
sib1.cell_id&0xfff,
ss.str().c_str());
state = srsue::RRC_STATE_SIB2_SEARCH;
mac->bcch_stop_rx();
//TODO: Use all SIB1 info
} else if (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2 == dlsch_msg.sibs[0].sib_type && srsue::RRC_STATE_SIB2_SEARCH == state) {
// Handle SIB2
memcpy(&sib2, &dlsch_msg.sibs[0].sib.sib2, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT));
log_h->console("SIB2 received\n");
log_h->info("SIB2 received\n");
state = srsue::RRC_STATE_WAIT_FOR_CON_SETUP;
mac->bcch_stop_rx();
apply_sib2_configs();
srslte::byte_buffer_t *sdu = pool->allocate();
assert(sdu);
// Send Msg3
sdu->N_bytes = 10;
for (int i=0;i<sdu->N_bytes;i++) {
sdu->msg[i] = i+1;
}
uint64_t uecri = 0;
uint8_t *ue_cri_ptr = (uint8_t*) &uecri;
uint32_t nbytes = 6;
for (int i=0;i<nbytes;i++) {
ue_cri_ptr[nbytes-i-1] = sdu->msg[i];
}
log_h->info("Setting UE contention resolution ID: %d\n", uecri);
mac->set_contention_id(uecri);
rlc->write_sdu(0, sdu);
}
}
}
void write_pdu_pcch(srslte::byte_buffer_t *sdu) {}
void max_retx_attempted(){}
void in_sync() {};
void out_of_sync() {};
void write_pdu(uint32_t lcid, srslte::byte_buffer_t *sdu)
{
int n=0;
switch(lcid) {
case LCID:
n = write(tun_fd, sdu->msg, sdu->N_bytes);
if (n != sdu->N_bytes) {
log_h->error("TUN/TAP write failure n=%d, nof_bytes=%d\n", n, sdu->N_bytes);
return;
}
log_h->debug_hex(sdu->msg, sdu->N_bytes,
"Wrote %d bytes to TUN/TAP\n",
sdu->N_bytes);
pool->deallocate(sdu);
break;
case 0:
log_h->info("Received ConnectionSetupComplete\n");
// Setup a single UM bearer
LIBLTE_RRC_RLC_CONFIG_STRUCT cfg;
bzero(&cfg, sizeof(LIBLTE_RRC_RLC_CONFIG_STRUCT));
cfg.rlc_mode = LIBLTE_RRC_RLC_MODE_UM_BI;
cfg.dl_um_bi_rlc.t_reordering = LIBLTE_RRC_T_REORDERING_MS100;
cfg.dl_um_bi_rlc.sn_field_len = LIBLTE_RRC_SN_FIELD_LENGTH_SIZE10;
cfg.ul_um_bi_rlc.sn_field_len = LIBLTE_RRC_SN_FIELD_LENGTH_SIZE10;
rlc->add_bearer(LCID, &cfg);
mac->setup_lcid(LCID, 0, 1, -1, 100000);
LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT dedicated;
bzero(&dedicated, sizeof(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT));
dedicated.pusch_cnfg_ded.beta_offset_ack_idx = 5;
dedicated.pusch_cnfg_ded.beta_offset_ri_idx = 12;
dedicated.pusch_cnfg_ded.beta_offset_cqi_idx = 15;
dedicated.pusch_cnfg_ded_present = true;
dedicated.sched_request_cnfg.dsr_trans_max = LIBLTE_RRC_DSR_TRANS_MAX_N4;
dedicated.sched_request_cnfg.sr_pucch_resource_idx = 0;
dedicated.sched_request_cnfg.sr_cnfg_idx = 35;
dedicated.sched_request_cnfg.setup_present = true;
dedicated.sched_request_cnfg_present = true;
phy->set_config_dedicated(&dedicated);
phy->configure_ul_params();
srsue::mac_interface_rrc::mac_cfg_t mac_cfg;
mac->get_config(&mac_cfg);
memcpy(&mac_cfg.sr, &dedicated.sched_request_cnfg, sizeof(LIBLTE_RRC_SCHEDULING_REQUEST_CONFIG_STRUCT));
mac_cfg.main.ulsch_cnfg.periodic_bsr_timer = LIBLTE_RRC_PERIODIC_BSR_TIMER_SF40;
mac->set_config(&mac_cfg);
break;
default:
log_h->error("Received message for lcid=%d\n", lcid);
break;
}
}
private:
int tun_fd;
bool running;
srslte::log *log_h;
srslte::byte_buffer_pool *pool;
srsue::rlc *rlc;
srsue::mac *mac;
srsue::phy *phy;
srslte::bit_buffer_t bit_buf;
srsue::rrc_state_t state;
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT sib1;
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT sib2;
bool read_enable;
// Determine SI messages scheduling as in 36.331 5.2.3 Acquisition of an SI message
uint32_t sib_start_tti(uint32_t tti, uint32_t period, uint32_t x) {
return (period*10*(1+tti/(period*10))+x)%10240; // the 1 means next opportunity
}
int init_tuntap(char *ip_address) {
read_enable = true;
tun_fd = setup_if_addr(ip_address);
if (tun_fd<0) {
fprintf(stderr, "Error setting up IP %s\n", ip_address);
return -1;
}
printf("Created tun/tap interface at IP %s\n", ip_address);
return 0;
}
void run_thread() {
struct iphdr *ip_pkt;
uint32_t idx = 0;
int32_t N_bytes;
srslte::byte_buffer_t *pdu = pool->allocate();
log_h->info("TUN/TAP reader thread running\n");
while(running) {
N_bytes = read(tun_fd, &pdu->msg[idx], SRSUE_MAX_BUFFER_SIZE_BYTES-SRSUE_BUFFER_HEADER_OFFSET - idx);
if(N_bytes > 0 && read_enable)
{
pdu->N_bytes = idx + N_bytes;
ip_pkt = (struct iphdr*)pdu->msg;
log_h->debug_hex(pdu->msg, pdu->N_bytes,
"Read %d bytes from TUN/TAP\n",
N_bytes);
// Check if entire packet was received
if(ntohs(ip_pkt->tot_len) == pdu->N_bytes)
{
log_h->info_hex(pdu->msg, pdu->N_bytes, "UL PDU");
// Send PDU directly to PDCP
pdu->set_timestamp();
rlc->write_sdu(LCID, pdu);
pdu = pool->allocate();
idx = 0;
} else{
idx += N_bytes;
}
}else{
log_h->error("Failed to read from TUN interface - gw receive thread exiting.\n");
break;
}
}
}
void apply_sib2_configs()
{
// Apply RACH timeAlginmentTimer configuration
srsue::mac_interface_rrc::mac_cfg_t cfg;
mac->get_config(&cfg);
cfg.main.time_alignment_timer = sib2.time_alignment_timer;
memcpy(&cfg.rach, &sib2.rr_config_common_sib.rach_cnfg, sizeof(LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT));
cfg.prach_config_index = sib2.rr_config_common_sib.prach_cnfg.root_sequence_index;
mac->set_config(&cfg);
log_h->info("Set RACH ConfigCommon: NofPreambles=%d, ResponseWindow=%d, ContentionResolutionTimer=%d ms\n",
liblte_rrc_number_of_ra_preambles_num[sib2.rr_config_common_sib.rach_cnfg.num_ra_preambles],
liblte_rrc_ra_response_window_size_num[sib2.rr_config_common_sib.rach_cnfg.ra_resp_win_size],
liblte_rrc_mac_contention_resolution_timer_num[sib2.rr_config_common_sib.rach_cnfg.mac_con_res_timer]);
// Apply PHY RR Config Common
srsue::phy_interface_rrc::phy_cfg_common_t common;
memcpy(&common.pdsch_cnfg, &sib2.rr_config_common_sib.pdsch_cnfg, sizeof(LIBLTE_RRC_PDSCH_CONFIG_COMMON_STRUCT));
memcpy(&common.pusch_cnfg, &sib2.rr_config_common_sib.pusch_cnfg, sizeof(LIBLTE_RRC_PUSCH_CONFIG_COMMON_STRUCT));
memcpy(&common.pucch_cnfg, &sib2.rr_config_common_sib.pucch_cnfg, sizeof(LIBLTE_RRC_PUCCH_CONFIG_COMMON_STRUCT));
memcpy(&common.ul_pwr_ctrl, &sib2.rr_config_common_sib.ul_pwr_ctrl, sizeof(LIBLTE_RRC_UL_POWER_CONTROL_COMMON_STRUCT));
memcpy(&common.prach_cnfg, &sib2.rr_config_common_sib.prach_cnfg, sizeof(LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT));
if (sib2.rr_config_common_sib.srs_ul_cnfg.present) {
memcpy(&common.srs_ul_cnfg, &sib2.rr_config_common_sib.srs_ul_cnfg, sizeof(LIBLTE_RRC_SRS_UL_CONFIG_COMMON_STRUCT));
} else {
// default is release
common.srs_ul_cnfg.present = false;
}
phy->set_config_common(&common);
phy->configure_ul_params();
log_h->info("Set PUSCH ConfigCommon: HopOffset=%d, RSGroup=%d, RSNcs=%d, N_sb=%d\n",
sib2.rr_config_common_sib.pusch_cnfg.pusch_hopping_offset,
sib2.rr_config_common_sib.pusch_cnfg.ul_rs.group_assignment_pusch,
sib2.rr_config_common_sib.pusch_cnfg.ul_rs.cyclic_shift,
sib2.rr_config_common_sib.pusch_cnfg.n_sb);
log_h->info("Set PUCCH ConfigCommon: DeltaShift=%d, CyclicShift=%d, N1=%d, NRB=%d\n",
liblte_rrc_delta_pucch_shift_num[sib2.rr_config_common_sib.pucch_cnfg.delta_pucch_shift],
sib2.rr_config_common_sib.pucch_cnfg.n_cs_an,
sib2.rr_config_common_sib.pucch_cnfg.n1_pucch_an,
sib2.rr_config_common_sib.pucch_cnfg.n_rb_cqi);
log_h->info("Set PRACH ConfigCommon: SeqIdx=%d, HS=%d, FreqOffset=%d, ZC=%d, ConfigIndex=%d\n",
sib2.rr_config_common_sib.prach_cnfg.root_sequence_index,
sib2.rr_config_common_sib.prach_cnfg.prach_cnfg_info.high_speed_flag?1:0,
sib2.rr_config_common_sib.prach_cnfg.prach_cnfg_info.prach_freq_offset,
sib2.rr_config_common_sib.prach_cnfg.prach_cnfg_info.zero_correlation_zone_config,
sib2.rr_config_common_sib.prach_cnfg.prach_cnfg_info.prach_config_index);
log_h->info("Set SRS ConfigCommon: BW-Configuration=%d, SF-Configuration=%d, ACKNACK=%d\n",
sib2.rr_config_common_sib.srs_ul_cnfg.bw_cnfg,
sib2.rr_config_common_sib.srs_ul_cnfg.subfr_cnfg,
sib2.rr_config_common_sib.srs_ul_cnfg.ack_nack_simul_tx);
}
};
// Create classes
srslte::logger logger;
srslte::log_filter log_phy;
srslte::log_filter log_mac;
srslte::log_filter log_rlc;
srslte::log_filter log_tester;
srslte::mac_pcap mac_pcap;
srsue::phy my_phy;
srsue::mac my_mac;
srsue::rlc rlc;
srslte::radio_multi my_radio;
// Local classes for testing
tester my_tester;
bool running = true;
void sig_int_handler(int signo)
{
running = false;
}
int main(int argc, char *argv[])
{
parse_args(&prog_args, argc, argv);
// set to null to disable pcap
const char *pcap_filename = "/tmp/ip_test.pcap";
logger.init("/tmp/ip_test_ue.log");
log_phy.init("PHY ", &logger, true);
log_mac.init("MAC ", &logger, true);
log_rlc.init("RLC ", &logger);
log_tester.init("TEST", &logger);
logger.log("\n\n");
if (srsapps_verbose == 1) {
log_phy.set_level(srslte::LOG_LEVEL_INFO);
log_phy.set_hex_limit(100);
log_mac.set_level(srslte::LOG_LEVEL_DEBUG);
log_mac.set_hex_limit(100);
log_rlc.set_level(srslte::LOG_LEVEL_DEBUG);
log_rlc.set_hex_limit(1000);
log_tester.set_level(srslte::LOG_LEVEL_DEBUG);
log_tester.set_hex_limit(100);
printf("Log level info\n");
}
if (srsapps_verbose == 2) {
log_phy.set_level(srslte::LOG_LEVEL_DEBUG);
log_phy.set_hex_limit(100);
log_mac.set_level(srslte::LOG_LEVEL_DEBUG);
log_mac.set_hex_limit(100);
log_rlc.set_level(srslte::LOG_LEVEL_DEBUG);
log_rlc.set_hex_limit(100);
log_tester.set_level(srslte::LOG_LEVEL_DEBUG);
log_tester.set_hex_limit(100);
srslte_verbose = SRSLTE_VERBOSE_DEBUG;
printf("Log level debug\n");
}
// Init Radio and PHY
#ifdef USE_RADIO
my_radio.init();
#else
my_radio.init(NULL, "dummy");
#endif
my_radio.set_tx_freq(prog_args.tx_freq);
my_radio.set_tx_gain(prog_args.tx_gain);
my_radio.set_rx_freq(prog_args.rx_freq);
my_radio.set_rx_gain(prog_args.rx_gain);
if (prog_args.time_adv >= 0) {
printf("Setting TA=%d samples\n",prog_args.time_adv);
my_radio.set_tx_adv(prog_args.time_adv);
}
my_phy.init(&my_radio, &my_mac, &my_tester, &log_phy, NULL);
my_mac.init(&my_phy, &rlc, &my_tester, &log_mac);
rlc.init(&my_tester, &my_tester, &my_tester, &log_rlc, &my_mac);
my_tester.init(&my_phy, &my_mac, &rlc, &log_tester, prog_args.ip_address);
if (pcap_filename) {
mac_pcap.open(pcap_filename);
my_mac.start_pcap(&mac_pcap);
signal(SIGINT, sig_int_handler);
}
// Set MAC defaults
LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT default_cfg;
bzero(&default_cfg, sizeof(LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT));
default_cfg.ulsch_cnfg.max_harq_tx = LIBLTE_RRC_MAX_HARQ_TX_N5;
default_cfg.ulsch_cnfg.periodic_bsr_timer = LIBLTE_RRC_PERIODIC_BSR_TIMER_INFINITY;
default_cfg.ulsch_cnfg.retx_bsr_timer = LIBLTE_RRC_RETRANSMISSION_BSR_TIMER_SF2560;
default_cfg.ulsch_cnfg.tti_bundling = false;
default_cfg.drx_cnfg.setup_present = false;
default_cfg.phr_cnfg.setup_present = false;
default_cfg.time_alignment_timer = LIBLTE_RRC_TIME_ALIGNMENT_TIMER_INFINITY;
my_mac.set_config_main(&default_cfg);
while(running) {
if (my_tester.is_sib_received()) {
printf("Main running\n");
sleep(1);
} else {
my_tester.sib_search();
}
}
if (pcap_filename) {
mac_pcap.close();
}
my_phy.stop();
my_mac.stop();
}
/******************* This is copied from srsue gw **********************/
int setup_if_addr(char *ip_addr)
{
char *dev = (char*) "tun_srsue";
// Construct the TUN device
int tun_fd = open("/dev/net/tun", O_RDWR);
if(0 > tun_fd)
{
perror("open");
return(-1);
}
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
strncpy(ifr.ifr_ifrn.ifrn_name, dev, IFNAMSIZ);
if(0 > ioctl(tun_fd, TUNSETIFF, &ifr))
{
perror("ioctl");
return -1;
}
// Bring up the interface
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if(0 > ioctl(sock, SIOCGIFFLAGS, &ifr))
{
perror("socket");
return -1;
}
ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
if(0 > ioctl(sock, SIOCSIFFLAGS, &ifr))
{
perror("ioctl");
return -1;
}
// Setup the IP address
sock = socket(AF_INET, SOCK_DGRAM, 0);
ifr.ifr_addr.sa_family = AF_INET;
((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr = inet_addr(ip_addr);
if(0 > ioctl(sock, SIOCSIFADDR, &ifr))
{
perror("ioctl");
return -1;
}
ifr.ifr_netmask.sa_family = AF_INET;
((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr.s_addr = inet_addr("255.255.255.0");
if(0 > ioctl(sock, SIOCSIFNETMASK, &ifr))
{
perror("ioctl");
return -1;
}
return(tun_fd);
}

172
srsue/ue.conf.example Normal file
View File

@ -0,0 +1,172 @@
#####################################################################
# srsUE configuration file
#####################################################################
# RF configuration
#
# dl_freq: Downlink centre frequency (Hz).
# ul_freq: Uplink centre frequency (Hz).
# tx_gain: Transmit gain (dB).
# rx_gain: Optional receive gain (dB). If disabled, AGC if enabled
#
# Optional parameters:
# nof_rx_ant: Number of RX antennas (Default 1, supported 1 or 2)
# device_name: Device driver family. Supported options: "auto" (uses first found), "UHD" or "bladeRF"
# device_args: Arguments for the device driver. Options are "auto" or any string.
# Default for UHD: "recv_frame_size=9232,send_frame_size=9232"
# Default for bladeRF: ""
# #time_adv_nsamples: Transmission time advance (in number of samples) to compensate for RF delay
# from antenna to timestamp insertion.
# Default "auto". B210 USRP: 100 samples, bladeRF: 27.
# burst_preamble_us: Preamble length to transmit before start of burst.
# Default "auto". B210 USRP: 400 us, bladeRF: 0 us.
#####################################################################
[rf]
dl_freq = 2680000000
ul_freq = 2560000000
tx_gain = 60
rx_gain = 50
#nof_rx_ant = 1
#device_name = auto
#device_args = auto
#time_adv_nsamples = auto
#burst_preamble_us = auto
#####################################################################
# MAC-layer packet capture configuration
#
# Packets are captured to file in the compact format decoded by
# the Wireshark mac-lte-framed dissector and with DLT 147.
# To use the dissector, edit the preferences for DLT_USER to
# add an entry with DLT=147, Payload Protocol=mac-lte-framed.
# For more information see: https://wiki.wireshark.org/MAC-LTE
#
# enable: Enable MAC layer packet captures (true/false)
# filename: File path to use for packet captures
#####################################################################
[pcap]
enable = false
filename = /tmp/ue.pcap
#####################################################################
# Log configuration
#
# Log levels can be set for individual layers. "all_level" sets log
# level for all layers unless otherwise configured.
# Format: e.g. phy_level = info
#
# In the same way, packet hex dumps can be limited for each level.
# "all_hex_limit" sets the hex limit for all layers unless otherwise
# configured.
# Format: e.g. phy_hex_limit = 32
#
# Logging layers: phy, mac, rlc, pdcp, rrc, nas, gw, usim, all
# Logging levels: debug, info, warning, error, none
#
# filename: File path to use for log output
#####################################################################
[log]
all_level = info
all_hex_limit = 32
filename = /tmp/ue.log
#####################################################################
# USIM configuration
#
# algo: Authentication algorithm (xor/milenage)
# op: 128-bit Operator Variant Algorithm Configuration Field (hex)
# amf: 16-bit Authentication Management Field (hex)
# k: 128-bit subscriber key (hex)
# imsi: 15 digit International Mobile Subscriber Identity
# imei: 15 digit International Mobile Station Equipment Identity
#####################################################################
[usim]
algo = milenage
op = 63BFA50EE6523365FF14C1F45F88737D
amf = 8000
k = 00112233445566778899aabbccddeeff
imsi = 001010123456789
imei = 353490069873319
[gui]
enable = false
#####################################################################
# Expert configuration options
#
# ue_category: Sets UE category (range 1-5). Default: 4
#
# prach_gain: PRACH gain (dB). If defined, forces a gain for the tranmsission of PRACH only.,
# Default is to use tx_gain in [rf] section.
# cqi_max: Upper bound on the maximum CQI to be reported. Default 15.
# cqi_fixed: Fixes the reported CQI to a constant value. Default disabled.
# snr_ema_coeff: Sets the SNR exponential moving average coefficient (Default 0.1)
# snr_estim_alg: Sets the noise estimation algorithm. (Default refs)
# Options: pss: use difference between received and known pss signal,
# refs: use difference between noise references and noiseless (after filtering)
# empty: use empty subcarriers in the boarder of pss/sss signal
# pdsch_max_its: Maximum number of turbo decoder iterations (Default 4)
# attach_enable_64qam: Enables PUSCH 64QAM modulation before attachment (Necessary for old
# Amarisoft LTE 100 eNodeB, disabled by default)
# nof_phy_threads: Selects the number of PHY threads (maximum 4, minimum 1, default 2)
# equalizer_mode: Selects equalizer mode. Valid modes are: "mmse", "zf" or any
# non-negative real number to indicate a regularized zf coefficient.
# Default is MMSE.
# cfo_integer_enabled: Enables integer CFO estimation and correction. This needs improvement
# and may lead to incorrect synchronization. Use with caution.
# cfo_correct_tol_hz: Tolerance (in Hz) for digial CFO compensation. Lower tolerance means that
# a new table will be generated more often.
# time_correct_period: Period for sampling time offset correction. Default is 10 (ue_sync.c),
# good for long channels. For best performance at highest SNR reduce it to 1.
# sfo_correct_disable: Disables phase correction before channel estimation to compensate for
# sampling frequency offset. Default is enabled.
# sss_algorithm: Selects the SSS estimation algorithm. Can choose between
# {full, partial, diff}.
# estimator_fil_w: Chooses the coefficients for the 3-tap channel estimator centered filter.
# The taps are [w, 1-2w, w]
# metrics_period_secs: Sets the period at which metrics are requested from the UE.
#
# pregenerate_signals: Pregenerate uplink signals after attach. Improves CPU performance.
#
#####################################################################
[expert]
#ue_category = 4
#prach_gain = 30
#cqi_max = 15
#cqi_offset = 0
#cqi_fixed = 10
#cqi_random_ms = 0
#cqi_period_ms = 0
#cqi_period_duty = 0.5
#snr_ema_coeff = 0.1
#snr_estim_alg = refs
#pdsch_max_its = 4
#attach_enable_64qam = false
#nof_phy_threads = 2
#equalizer_mode = mmse
#cfo_integer_enabled = false
#cfo_correct_tol_hz = 50
#time_correct_period = 5
#sfo_correct_disable = false
#sss_algorithm = full
#estimator_fil_w = 0.1
#pregenerate_signals = false
#####################################################################
# Manual RF calibration
#
# Applies DC offset and IQ imbalance to TX and RX modules.
# Currently this configuration is only used if the detected device is a bladeRF
#
# tx_corr_dc_gain: TX DC offset gain correction
# tx_corr_dc_phase: TX DC offset phase correction
# tx_corr_iq_i: TX IQ imbalance inphase correction
# tx_corr_iq_q: TX IQ imbalance quadrature correction
# same can be configured for rx_*
#####################################################################
[rf_calibration]
tx_corr_dc_gain = 20
tx_corr_dc_phase = 184
tx_corr_iq_i = 19
tx_corr_iq_q = 97