diff --git a/CMakeLists.txt b/CMakeLists.txt index c677c9f9e..143fd68ac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,42 +1,156 @@ +# +# Copyright 2012-2013 The libLTE Developers. See the +# COPYRIGHT file at the top-level directory of this distribution. +# +# This file is part of the libLTE library. +# +# libLTE is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# libLTE is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# A copy of the GNU Lesser 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/. +# + + +######################################################################## +# Prevent in-tree builds +######################################################################## + if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) message(FATAL_ERROR "Prevented in-tree build. This is bad practice.") endif(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) -cmake_minimum_required (VERSION 2.6) -project (osldlib) -# The version number. -set (OSLDLIB_VERSION_MAJOR 0) -set (OSLDLIB_VERSION_MINOR 0) +######################################################################## +# Project setup +######################################################################## +CMAKE_MINIMUM_REQUIRED (VERSION 2.6) +PROJECT (LIBLTE) + +LIST(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/modules") + +INCLUDE(libLTEPackage) #setup cpack + +include(CTest) +set( CTEST_MEMORYCHECK_COMMAND valgrind ) +CONFIGURE_FILE( + "${CMAKE_CURRENT_SOURCE_DIR}/CTestCustom.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/CTestCustom.cmake" + IMMEDIATE @ONLY) + +######################################################################## +# Install Dirs +######################################################################## +SET(RUNTIME_DIR bin) +SET(LIBRARY_DIR lib) +SET(INCLUDE_DIR include) +SET(DOC_DIR "share/doc/${CPACK_PACKAGE_NAME}") +SET(DATA_DIR share/${CPACK_PACKAGE_NAME}) + + +IF(NOT CMAKE_BUILD_TYPE) + SET(CMAKE_BUILD_TYPE Release) + MESSAGE(STATUS "Build type not specified: defaulting to Release.") +ENDIF(NOT CMAKE_BUILD_TYPE) +SET(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "") + +######################################################################## +# Compiler specific setup +######################################################################## +IF(CMAKE_COMPILER_IS_GNUCXX) +# do something +ENDIF(CMAKE_COMPILER_IS_GNUCXX) + +IF(CMAKE_COMPILER_IS_GNUCC) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-format-extra-args -Winline -Wno-unused-result -Wno-format -std=c99 -D_GNU_SOURCE") +ENDIF(CMAKE_COMPILER_IS_GNUCC) + +IF(MSVC) + INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/msvc) #missing headers + ADD_DEFINITIONS(-D_WIN32_WINNT=0x0501) #minimum version required is windows xp + ADD_DEFINITIONS(-DNOMINMAX) #disables stupidity and enables std::min and std::max + ADD_DEFINITIONS( #stop all kinds of compatibility warnings + -D_SCL_SECURE_NO_WARNINGS + -D_CRT_SECURE_NO_WARNINGS + -D_CRT_SECURE_NO_DEPRECATE + -D_CRT_NONSTDC_NO_DEPRECATE + ) + ADD_DEFINITIONS(/MP) #build with multiple processors +ENDIF(MSVC) + +IF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + # The following is needed for weak linking to work under OS X + SET(CMAKE_SHARED_LINKER_FLAGS "-undefined dynamic_lookup") +ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + + + +######################################################################## +# Create uninstall targets +######################################################################## +CONFIGURE_FILE( + "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" + IMMEDIATE @ONLY) + +ADD_CUSTOM_TARGET(uninstall + COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) + + +######################################################################## +# Macro to add -fPIC property to static libs +######################################################################## +MACRO(LIBLTE_SET_PIC) + IF( CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" ) + SET_TARGET_PROPERTIES(${ARGV} PROPERTIES COMPILE_FLAGS -fPIC) + ENDIF( CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" ) +ENDMACRO(LIBLTE_SET_PIC) + +######################################################################## +# A macro for passing lists between different directories +# through an internal cache variable. +######################################################################## +MACRO (APPEND_INTERNAL_LIST LIST_NAME VALUE) + # If the list in not in the cache, create it. + IF (${LIST_NAME}) + SET (${LIST_NAME} "${${LIST_NAME}};${VALUE}" CACHE INTERNAL "Internal +variable") + ELSE (${LIST_NAME}) + SET (${LIST_NAME} "${VALUE}" CACHE INTERNAL "Internal variable") + ENDIF (${LIST_NAME}) -set(CPACK_PACKAGE_VERSION_MAJOR ${OSLDLIB_VERSION_MAJOR}) -set(CPACK_PACKAGE_VERSION_MINOR ${OSLDLIB_VERSION_MINOR}) -set(CPACK_PACKAGE_VERSION_PATCH "1") -set(CPACK_SOURCE_GENERATOR "TBZ2") -set(CPACK_SOURCE_PACKAGE_FILE_NAME - "${CMAKE_PROJECT_NAME}-${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}") -set(CPACK_SOURCE_IGNORE_FILES - "${CMAKE_CURRENT_BINARY_DIR};/.bzr/;~$;${CPACK_SOURCE_IGNORE_FILES}") -include(CPack) -add_custom_target(dist COMMAND ${CMAKE_MAKE_PROGRAM} package_source) +ENDMACRO (APPEND_INTERNAL_LIST) -option(DEBUG "Compiles with debugging symbols and no optimizations" OFF) -if(DEBUG) - message("-- Configuring debugging CFLAGS") - set(CFDEB "-O0 -g -rdynamic") -else() - set(CFDEB "-O2") -endif() +######################################################################## +# Print summary +######################################################################## +MESSAGE(STATUS "Using install prefix: ${CMAKE_INSTALL_PREFIX}") +MESSAGE(STATUS "Building for version: ${VERSION}") -set(CMAKE_C_FLAGS "${CFDEB} -Wall -Wno-format-extra-args -Winline -Wno-unused-result -Wno-format -std=c99 -D_GNU_SOURCE") -set(CMAKE_BINARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) +######################################################################## +# Add general includes and dependencies +######################################################################## +INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/lte/include) +INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/cuhd/include) +INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/graphics/include) -### INCLUDES -include_directories("{CMAKE_CURRENT_SOURCE_DIR}/include") +######################################################################## +# Add the subdirectories +######################################################################## -add_subdirectory(examples) -add_subdirectory(lib) +ADD_SUBDIRECTORY(lte) +ADD_SUBDIRECTORY(cuhd) +ADD_SUBDIRECTORY(graphics) +ADD_SUBDIRECTORY(examples) diff --git a/COPYRIGHT b/COPYRIGHT new file mode 100644 index 000000000..6b399f6a5 --- /dev/null +++ b/COPYRIGHT @@ -0,0 +1,542 @@ +Copyright (C) 2013-2014 Ismael Gomez Miguelez, . All rights reserved. + +The following copyright notices are for libraries used within libLTE: + + +----------------------------------------------------------- +CLibrary.py +----------------------------------------------------------- + +Copyright (c) 2003-2011 Paul T. McGuire + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +----------------------------------------------------------- +FEC Library - Version 3.0.1 - August 7th, 2007 +----------------------------------------------------------- + +COPYRIGHT + +This package is copyright 2006 by Phil Karn, KA9Q. It may be used +under the terms of the GNU Lesser General Public License (LGPL). + + +GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! \ No newline at end of file diff --git a/CTestConfig.cmake b/CTestConfig.cmake new file mode 100644 index 000000000..32743e0ba --- /dev/null +++ b/CTestConfig.cmake @@ -0,0 +1,13 @@ +## This file should be placed in the root directory of your project. +## Then modify the CMakeLists.txt file in the root directory of your +## project to incorporate the testing dashboard. +## # The following are required to uses Dart and the Cdash dashboard +## ENABLE_TESTING() +## INCLUDE(CTest) +set(CTEST_PROJECT_NAME "libLTE") +set(CTEST_NIGHTLY_START_TIME "00:00:00 GMT") + +set(CTEST_DROP_METHOD "http") +set(CTEST_DROP_SITE "my.cdash.org") +set(CTEST_DROP_LOCATION "/submit.php?project=libLTE") +set(CTEST_DROP_SITE_CDASH TRUE) diff --git a/CTestCustom.cmake.in b/CTestCustom.cmake.in new file mode 100644 index 000000000..a66fe53e2 --- /dev/null +++ b/CTestCustom.cmake.in @@ -0,0 +1,15 @@ +SET(CTEST_CUSTOM_MEMCHECK_IGNORE + +# Ignore memcheck for plots. QT errors + + waterfallplot_test + scatterplot_test + realplot_test + complexplot_test + +# Ignore these to, they take too lonk + fft_normal + fft_extened + chest_test_all_cellids +) + diff --git a/README.md b/README.md index 539310895..b7a2d5dd3 100644 --- a/README.md +++ b/README.md @@ -7,15 +7,30 @@ The license is LGPLv3. The project contains a set of Python tools for the automatic code generation of modules for popular SDR frameworks, including GNURadio, ALOE++, IRIS, and OSSIE. These tools are easy to use and adapt for generating targets for specific platforms or frameworks. -Support +Current Status +=============== + +The following parts are available: + * Physical Broadcast channel (PBCH) eNodeB and UE part. The UE supports multi-antenna transmitters + * Synchronization and CFO estimation/correction + * Equalization + * UE receiver verified with live LTE signals + +Hardware ======== -Mailing list: https://lists.sourceforge.net/lists/listinfo/liblte-users +The library currently uses Ettus Universal Hardware Driver (UHD). Thus, any hardware supported by UHD 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. Download & Install Instructions ================================= +* Requirements: Currently, the library requires libfftw, although we plan make this dependency optional in the future. Also, QT4 is needed for graphics visualization. Compilation is possible without QT4, although graphics will be disabled. + +To install QT4 and libfftw use your distribution packet management system, for instance in ubuntu you can run: `sudo apt-get install libfftw3-dev libqt4-dev` to install all requirements. + + +Finally, to download and build libLTE, just run: ``` git clone https://github.com/ismagom/libLTE.git cd libLTE @@ -23,42 +38,61 @@ mkdir build cd build cmake ../ make -sudo make install ``` -Cell Search Example -==================== +The library can also be installed using the command ```sudo make install```. -This program uses any hardware supported by the UHD driver to scan an LTE band for active cells. See http://niviuk.free.fr/lte_band.php for a list of available bands. The program first obtains a power spectral density of the entire band. For all frequencies with an RSSI higher than a threshold, it tries to find the LTE Primary Synchronization Signal (PSS) and then identifies the CELL ID using the Secondary Synchronization Signal (SSS). Finally, it estimates the Carrier Frequency Offset (CFO) and Sampling Frequency Offset (SFO). +Examples +========== -For instance, the command: +* eNodeB and UE PBCH example + +Setup one or two computers connected to two USRP or UHD-compatible hardware. From the eNodeB, type + +``` +examples/pbch_enodeb -f [frequency_in_Hz] -c [cell_id] [-a [UHD args]] [-h for more commands] +``` + +From the UE, type +``` +examples/pbch_ue -f [frequency_in_Hz] -c [cell_id] [-a [UHD args]] [-h for more commands] +``` + +And the output should look something like the following video. In this example, we removed the transmitter and receiver antennas in the middle of the demonstration, showing how reception is still possible (despite with some erros). + +https://www.dropbox.com/s/txh1nuzdb0igq5n/demo_pbch.ogv -``` pss_scan_usrp -b 3 ``` +![Screenshopt of the PBCH example output](pbch_capture.png "Screenshopt of the PBCH example output") -Scans the LTE band 3 (1805 to 1880 MHz). Note that you need a hardware supporting these frequencies (e.g. SBX daughterboard for USRP). The program outputs the following: +If you don't have a pair of USRP, you can also test the demo by writing the samples to a file and then reading them: +From the eNodeB, type + +``` +examples/pbch_enodeb -o [output_file] -c [cell_id] [-h for more commands] +``` + +From the UE, type ``` -Opening UHD device... --- Opening a USRP2/N-Series device... --- Current recv frame size: 1472 bytes --- Current send frame size: 1472 bytes -RSSI scan: 749 freqs in band 3, RSSI threshold -30.00 dBm -Freq 1879.0 Mhz - RSSI: -43.96 dBm -Done. Starting PSS search on 75 channels - -UHD Warning: - The hardware does not support the requested RX sample rate: - Target sample rate: 1.920000 MSps - Actual sample rate: 1.923077 MSps -[199/749]: EARFCN 1399 Freq. 1824.90 MHz No PSS found -[200/749]: FOUND EARFCN 1400 Freq. 1825.00 MHz, RSSI -22.43 dBm, PAR 15.86 dB, CFO=-0.25 KHz, SFO=+3.099 KHz, CELL_ID=150 -[433/749]: EARFCN 1633 Freq. 1848.30 MHz No PSS found - -Done +examples/pbch_ue -i [input_file] -c [cell_id] [-h for more commands] ``` -indicating that a Cell with ID 150 has been found at 1825.0 MHz. PAR indicates the peak-to-average ratio (in dB) at the output of the PSS correlator. -For more command arguments, type ``` pss_scan_usrp --help ``` +* Cell Search Example + +This program uses any hardware supported by the UHD driver to scan an LTE band for active cells. See http://niviuk.free.fr/lte_band.php for a list of available bands. The program first obtains a power spectral density of the entire band. For all frequencies with an RSSI higher than a threshold, it tries to find the LTE Primary Synchronization Signal (PSS) and then identifies the CELL ID using the Secondary Synchronization Signal (SSS). Finally, it estimates the Carrier Frequency Offset (CFO) and Sampling Frequency Offset (SFO) and decodes the Master Information Block (MIB) from the PBCH. + +For instance, the command: + +``` examples/scan_mib -b 3 ``` + + +Scans the LTE band 3 (1805 to 1880 MHz). Note that you need a hardware supporting these frequencies (e.g. SBX daughterboard for USRP). For more command arguments, type ``` examples/mib_scan_usrp -h ``` + + +Support +======== + +Mailing list: https://lists.sourceforge.net/lists/listinfo/liblte-users diff --git a/cmake/FindFFTWS.cmake b/cmake/FindFFTWS.cmake deleted file mode 100644 index ff28c85a7..000000000 --- a/cmake/FindFFTWS.cmake +++ /dev/null @@ -1,22 +0,0 @@ -# - Find FFTW -# Find the native FFTW includes and library -# -# FFTW_INCLUDES - where to find fftw3.h -# FFTW_LIBRARIES - List of libraries when using FFTW. -# FFTW_FOUND - True if FFTW found. - -if (FFTWS_INCLUDES) - # Already in cache, be silent - set (FFTWS_FIND_QUIETLY TRUE) -endif (FFTWS_INCLUDES) - -find_path (FFTWS_INCLUDES fftw3.h) -SET(CMAKE_FIND_LIBRARY_SUFFIXES .a) -find_library (FFTWfS_LIBRARIES NAMES fftw3f) -find_library (FFTWnS_LIBRARIES NAMES fftw3) -set(FFTWS_LIBRARIES ${FFTWfS_LIBRARIES} ${FFTWnS_LIBRARIES}) - -include (FindPackageHandleStandardArgs) -find_package_handle_standard_args (FFTWS DEFAULT_MSG FFTWS_LIBRARIES FFTWS_INCLUDES) - -mark_as_advanced (FFTWS_LIBRARIES FFTWS_INCLUDES) diff --git a/cmake/modules/FindFFTW3F.cmake b/cmake/modules/FindFFTW3F.cmake new file mode 100644 index 000000000..7487eac8c --- /dev/null +++ b/cmake/modules/FindFFTW3F.cmake @@ -0,0 +1,55 @@ +# +# Copyright 2012-2013 The Iris Project Developers. See the +# COPYRIGHT file at the top-level directory of this distribution +# and at http://www.softwareradiosystems.com/iris/copyright.html. +# +# This file is part of the Iris Project. +# +# Iris is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# Iris is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# A copy of the GNU Lesser 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/. +# + +# - Try to find fftw3f - the single-precision version of FFTW3 +# Once done this will define +# FFTW3F_FOUND - System has fftw3f +# FFTW3F_INCLUDE_DIRS - The fftw3f include directories +# FFTW3F_LIBRARIES - The libraries needed to use fftw3f +# FFTW3F_DEFINITIONS - Compiler switches required for using fftw3f + +find_package(PkgConfig) +pkg_check_modules(PC_FFTW3F "fftw3f >= 3.0") +set(FFTW3F_DEFINITIONS ${PC_FFTW3F_CFLAGS_OTHER}) + +find_path(FFTW3F_INCLUDE_DIR + NAMES fftw3.h + HINTS ${PC_FFTW3F_INCLUDEDIR} ${PC_FFTW3F_INCLUDE_DIRS} $ENV{FFTW3_DIR}/include + PATHS /usr/local/include + /usr/include ) + +find_library(FFTW3F_LIBRARY + NAMES fftw3f libfftw3f libfftw3f-3 + HINTS ${PC_FFTW3F_LIBDIR} ${PC_FFTW3F_LIBRARY_DIRS} $ENV{FFTW3_DIR}/lib + PATHS /usr/local/lib + /usr/lib) + +set(FFTW3F_LIBRARIES ${FFTW3F_LIBRARY} ) +set(FFTW3F_INCLUDE_DIRS ${FFTW3F_INCLUDE_DIR} ) + +include(FindPackageHandleStandardArgs) +# handle the QUIETLY and REQUIRED arguments and set FFTW3F_FOUND to TRUE +# if all listed variables are TRUE +find_package_handle_standard_args(fftw3f DEFAULT_MSG + FFTW3F_LIBRARY FFTW3F_INCLUDE_DIR) + +mark_as_advanced(FFTW3F_INCLUDE_DIR FFTW3F_LIBRARY ) diff --git a/cmake/modules/FindQwt.cmake b/cmake/modules/FindQwt.cmake new file mode 100644 index 000000000..e52243f38 --- /dev/null +++ b/cmake/modules/FindQwt.cmake @@ -0,0 +1,141 @@ +# +# Copyright 2012-2013 The Iris Project Developers. See the +# COPYRIGHT file at the top-level directory of this distribution +# and at http://www.softwareradiosystems.com/iris/copyright.html. +# +# This file is part of the Iris Project. +# +# Iris is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# Iris is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# A copy of the GNU Lesser 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/. +# + +# - Try to find the Qwt includes and library +# - Defines the following: +# +# QWT_FOUND - system has Qwt +# QWT_INCLUDE_DIR - where to find qwt.h +# QWT_INCLUDE_DIRS - the qwt include directories +# QWT_LIBRARY - where to find the Qwt library (not for general use) +# QWT_LIBRARIES - the libraries to link against to use Qwt +# QWT_MAJOR_VERSION - major version +# QWT_MINOR_VERSION - minor version +# QWT_PATCH_VERSION - patch version +# QWT_VERSION_STRING - version (ex. 5.2.1) + +SET(QWT_FOUND "NO") + +FIND_PATH(QWT_INCLUDE_DIR qwt.h + /usr/local/qwt/include + /usr/local/include + /usr/include/qwt + /usr/include/qwt-qt4 + /usr/include/qwt5 + /usr/include + /opt/local/include/qwt #macports path + $ENV{QWT_DIR}/include + $ENV{QWT_DIR}/src + $ENV{QWTDIR}/include + $ENV{QWTDIR}/src + $ENV{QWT_ROOT}/include + $ENV{QWT_ROOT}/src + $ENV{QWTROOT}/include + $ENV{QWTROOT}/src +) + +SET(QWT_INCLUDE_DIRS ${QWT_INCLUDE_DIR}) + +# version +SET(_VERSION_FILE ${QWT_INCLUDE_DIR}/qwt_global.h) +IF(EXISTS ${_VERSION_FILE} ) + FILE( STRINGS ${_VERSION_FILE} _VERSION_LINE REGEX "define[ ]+QWT_VERSION_STR") + IF( _VERSION_LINE ) + STRING( REGEX REPLACE ".*define[ ]+QWT_VERSION_STR[ ]+\"(.*)\".*" "\\1" QWT_VERSION_STRING "${_VERSION_LINE}" ) + STRING( REGEX REPLACE "([0-9]+)\\.([0-9]+)\\.([0-9]+)" "\\1" QWT_MAJOR_VERSION "${QWT_VERSION_STRING}" ) + STRING( REGEX REPLACE "([0-9]+)\\.([0-9]+)\\.([0-9]+)" "\\2" QWT_MINOR_VERSION "${QWT_VERSION_STRING}" ) + STRING( REGEX REPLACE "([0-9]+)\\.([0-9]+)\\.([0-9]+)" "\\3" QWT_PATCH_VERSION "${QWT_VERSION_STRING}" ) + ENDIF() +ENDIF() + + +# check version +SET( _QWT_VERSION_MATCH TRUE ) +IF( Qwt_FIND_VERSION AND QWT_VERSION_STRING ) + IF( Qwt_FIND_VERSION_EXACT ) + IF( NOT Qwt_FIND_VERSION VERSION_EQUAL QWT_VERSION_STRING ) + SET( _QWT_VERSION_MATCH FALSE ) + ENDIF() + ELSE() + IF( QWT_VERSION_STRING VERSION_LESS Qwt_FIND_VERSION ) + SET( _QWT_VERSION_MATCH FALSE ) + ENDIF() + ENDIF() +ENDIF() + +SET(POTENTIAL_LIBRARY_PATHS /usr/local/qwt/lib /usr/local/lib /usr/lib /opt/local/lib + $ENV{QWT_DIR}/lib $ENV{QWTDIR}/lib $ENV{QWT_ROOT}/lib $ENV{QWTROOT}/lib) + +SET(QWT_NAMES ${QWT_NAMES} qwt qwt-qt4 qwt5 ) +FIND_LIBRARY(QWT_LIBRARY + NAMES ${QWT_NAMES} + PATHS ${POTENTIAL_LIBRARY_PATHS} +) +MARK_AS_ADVANCED(QWT_LIBRARY) + +IF (QWT_LIBRARY) + + IF(WIN32 AND NOT CYGWIN) + + SET(QWT_NAMES_DEBUG qwtd qwtd-qt4 qwtd5 ) + FIND_LIBRARY(QWT_LIBRARY_DEBUG + NAMES ${QWT_NAMES_DEBUG} + PATHS ${POTENTIAL_LIBRARY_PATHS} + ) + MARK_AS_ADVANCED(QWT_LIBRARY_DEBUG) + + IF(QWT_LIBRARY_DEBUG) + SET(QWT_LIBRARIES optimized ${QWT_LIBRARY} debug ${QWT_LIBRARY_DEBUG} CACHE DOC "QWT library files") + ELSE(QWT_LIBRARY_DEBUG) + SET(QWT_LIBRARIES ${QWT_LIBRARY} CACHE DOC "QWT library files") + ENDIF(QWT_LIBRARY_DEBUG) + + ADD_DEFINITIONS(-DQWT_DLL) + + ELSE(WIN32 AND NOT CYGWIN) + + SET(QWT_LIBRARIES ${QWT_LIBRARY} CACHE DOC "QWT library files") + + ENDIF(WIN32 AND NOT CYGWIN) + + SET(QWT_FOUND "YES") + + IF (CYGWIN) + IF(BUILD_SHARED_LIBS) + # No need to define QWT_USE_DLL here, because it's default for Cygwin. + ELSE(BUILD_SHARED_LIBS) + SET (QWT_DEFINITIONS -DQWT_STATIC) + ENDIF(BUILD_SHARED_LIBS) + ENDIF (CYGWIN) + +ENDIF (QWT_LIBRARY) + +# handle the QUIETLY and REQUIRED arguments +INCLUDE( FindPackageHandleStandardArgs ) +IF( CMAKE_VERSION LESS 2.8.3 ) + FIND_PACKAGE_HANDLE_STANDARD_ARGS( Qwt DEFAULT_MSG QWT_LIBRARY QWT_INCLUDE_DIR _QWT_VERSION_MATCH ) +ELSE() + FIND_PACKAGE_HANDLE_STANDARD_ARGS( Qwt REQUIRED_VARS QWT_LIBRARY QWT_INCLUDE_DIR _QWT_VERSION_MATCH VERSION_VAR QWT_VERSION_STRING ) +ENDIF() + +MARK_AS_ADVANCED(QWT_INCLUDE_DIR QWT_LIBRARY) + diff --git a/cmake/FindUHD.cmake b/cmake/modules/FindUHD.cmake similarity index 100% rename from cmake/FindUHD.cmake rename to cmake/modules/FindUHD.cmake diff --git a/cmake/modules/FindVolk.cmake b/cmake/modules/FindVolk.cmake new file mode 100644 index 000000000..3da43592d --- /dev/null +++ b/cmake/modules/FindVolk.cmake @@ -0,0 +1,29 @@ +INCLUDE(FindPkgConfig) +PKG_CHECK_MODULES(PC_VOLK volk QUIET) + +FIND_PATH( + VOLK_INCLUDE_DIRS + NAMES volk.h + HINTS $ENV{VOLK_DIR}/include/volk + ${CMAKE_INSTALL_PREFIX}/include/volk + ${PC_VOLK_INCLUDE_DIR} + PATHS /usr/local/include/volk + /usr/include/volk +) + +FIND_LIBRARY( + VOLK_LIBRARIES + NAMES volk + HINTS $ENV{VOLK_DIR}/lib + ${CMAKE_INSTALL_PREFIX}/lib + ${CMAKE_INSTALL_PREFIX}/lib64 + ${PC_VOLK_LIBDIR} + PATHS /usr/local/lib + /usr/local/lib64 + /usr/lib + /usr/lib64 +) + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(VOLK DEFAULT_MSG VOLK_LIBRARIES VOLK_INCLUDE_DIRS) +MARK_AS_ADVANCED(VOLK_LIBRARIES VOLK_INCLUDE_DIRS) diff --git a/cmake/modules/libLTEPackage.cmake b/cmake/modules/libLTEPackage.cmake new file mode 100644 index 000000000..c164a469e --- /dev/null +++ b/cmake/modules/libLTEPackage.cmake @@ -0,0 +1,85 @@ +# +# Copyright 2012-2013 The Iris Project Developers. See the +# COPYRIGHT file at the top-level directory of this distribution +# and at http://www.softwareradiosystems.com/iris/copyright.html. +# +# This file is part of the Iris Project. +# +# Iris is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# Iris is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# A copy of the GNU Lesser 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/. +# + +SET(CPACK_PACKAGE_DESCRIPTION "libLTE") +SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "LTE library for SDR.") +SET(CPACK_PACKAGE_NAME "liblte") +SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.3.6), libgcc1 (>= 1:4.1), libboost-dev (>= 1.35)") + +SET(CPACK_PACKAGE_CONTACT "Ismael Gomez ") +SET(CPACK_PACKAGE_VENDOR "University of Dublin, Trinity College") +SET(CPACK_PACKAGE_VERSION_MAJOR "0") +SET(CPACK_PACKAGE_VERSION_MINOR "1") +SET(CPACK_PACKAGE_VERSION_PATCH "0") +SET(VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}") + +######################################################################## +# Setup additional defines for OS types +######################################################################## +IF(CMAKE_SYSTEM_NAME STREQUAL "Linux") + SET(LINUX TRUE) +ENDIF() + +IF(LINUX AND EXISTS "/etc/debian_version") + SET(DEBIAN TRUE) +ENDIF() + +IF(LINUX AND EXISTS "/etc/redhat-release") + SET(REDHAT TRUE) +ENDIF() + +######################################################################## +# Set generator type for recognized systems +######################################################################## +IF(CPACK_GENERATOR) + #already set +ELSEIF(APPLE) + SET(CPACK_GENERATOR PackageMaker) +ELSEIF(WIN32) + SET(CPACK_GENERATOR NSIS) +ELSEIF(DEBIAN) + SET(CPACK_GENERATOR DEB) +ELSEIF(REDHAT) + SET(CPACK_GENERATOR RPM) +ELSE() + SET(CPACK_GENERATOR TGZ) +ENDIF() + +######################################################################## +# Setup CPack Debian +######################################################################## +SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libboost-dev") + +######################################################################## +# Setup CPack RPM +######################################################################## +SET(CPACK_RPM_PACKAGE_REQUIRES "boost-devel") + +######################################################################## +# Setup CPack NSIS +######################################################################## +SET(CPACK_NSIS_MODIFY_PATH ON) + + +SET(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}-${CMAKE_SYSTEM_PROCESSOR}") +INCLUDE(CPack) + diff --git a/cmake_uninstall.cmake.in b/cmake_uninstall.cmake.in new file mode 100644 index 000000000..c869827cc --- /dev/null +++ b/cmake_uninstall.cmake.in @@ -0,0 +1,26 @@ +if(POLICY CMP0007) + cmake_policy(SET CMP0007 OLD) +endif(POLICY CMP0007) + +if (NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + message(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") +endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + +file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) +string(REGEX REPLACE "\n" ";" files "${files}") +list(REVERSE files) +foreach (file ${files}) + message(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") + if (EXISTS "$ENV{DESTDIR}${file}") + execute_process( + COMMAND @CMAKE_COMMAND@ -E remove "$ENV{DESTDIR}${file}" + OUTPUT_VARIABLE rm_out + RESULT_VARIABLE rm_retval + ) + if(NOT ${rm_retval} EQUAL 0) + message(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") + endif (NOT ${rm_retval} EQUAL 0) + else (EXISTS "$ENV{DESTDIR}${file}") + message(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") + endif (EXISTS "$ENV{DESTDIR}${file}") +endforeach(file) diff --git a/cuhd/CMakeLists.txt b/cuhd/CMakeLists.txt new file mode 100644 index 000000000..38d87ce55 --- /dev/null +++ b/cuhd/CMakeLists.txt @@ -0,0 +1,36 @@ +# +# Copyright 2012-2013 The libLTE Developers. See the +# COPYRIGHT file at the top-level directory of this distribution. +# +# This file is part of the libLTE library. +# +# libLTE is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# libLTE is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# A copy of the GNU Lesser 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/. +# + +######################################################################## +# Install headers +######################################################################## +INSTALL(DIRECTORY include/ DESTINATION "${INCLUDE_DIR}" + FILES_MATCHING PATTERN "*.h" + PATTERN ".svn" EXCLUDE +) + + +######################################################################## +# Add the subdirectories +######################################################################## + +ADD_SUBDIRECTORY(lib) + diff --git a/cuhd/include/cuhd.h b/cuhd/include/cuhd.h new file mode 100644 index 000000000..188f127c3 --- /dev/null +++ b/cuhd/include/cuhd.h @@ -0,0 +1,57 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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/. + * + */ + + + +#ifdef __cplusplus +extern "C" { +#endif +#include + +#include "cuhd/cuhd_utils.h" + +int cuhd_open(char *args, void **handler); +int cuhd_close(void *h); + +int cuhd_start_rx_stream(void *h); +int cuhd_start_rx_stream_nsamples(void *h, int nsamples); +int cuhd_stop_rx_stream(void *h); +bool cuhd_rx_wait_lo_locked(void *h); +double cuhd_set_rx_srate(void *h, double freq); +double cuhd_set_rx_gain(void *h, double gain); +double cuhd_set_rx_freq(void *h, double freq); +int cuhd_recv(void *h, void *data, int nsamples, int blocking); + +double cuhd_set_tx_srate(void *h, double freq); +double cuhd_set_tx_gain(void *h, double gain); +double cuhd_set_tx_freq(void *h, double freq); +int cuhd_send(void *h, void *data, int nsamples, int blocking); + + +#ifdef __cplusplus +} +#endif diff --git a/cuhd/include/cuhd/cuhd_utils.h b/cuhd/include/cuhd/cuhd_utils.h new file mode 100644 index 000000000..f872f830e --- /dev/null +++ b/cuhd/include/cuhd/cuhd_utils.h @@ -0,0 +1,30 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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/. + * + */ + + + +int cuhd_rssi_scan(void *uhd, float *freqs, float *rssi, int nof_bands, double fs, int nsamp); diff --git a/cuhd/lib/CMakeLists.txt b/cuhd/lib/CMakeLists.txt new file mode 100644 index 000000000..82ad6382c --- /dev/null +++ b/cuhd/lib/CMakeLists.txt @@ -0,0 +1,43 @@ +# +# Copyright 2012-2013 The libLTE Developers. See the +# COPYRIGHT file at the top-level directory of this distribution. +# +# This file is part of the libLTE library. +# +# libLTE is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# libLTE is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# A copy of the GNU Lesser 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_PACKAGE(UHD) + +IF(UHD_FOUND) + + ADD_LIBRARY(cuhd cuhd_imp.cpp cuhd_utils.c) + INCLUDE_DIRECTORIES(${UHD_INCLUDE_DIRS}) + TARGET_LINK_LIBRARIES(cuhd ${UHD_LIBRARIES}) + + LIBLTE_SET_PIC(cuhd) + APPEND_INTERNAL_LIST(OPTIONAL_LIBS cuhd) + INSTALL(TARGETS cuhd DESTINATION ${LIBRARY_DIR}) + + MESSAGE(STATUS " cuhd UHD C wrapper will be installed.") + +ELSE(UHD_FOUND) + + MESSAGE(STATUS " UHD driver not found. CUHD library is not generated") + +ENDIF(UHD_FOUND) + + + \ No newline at end of file diff --git a/cuhd/lib/cuhd_handler.hpp b/cuhd/lib/cuhd_handler.hpp new file mode 100644 index 000000000..349117a88 --- /dev/null +++ b/cuhd/lib/cuhd_handler.hpp @@ -0,0 +1,38 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 + +class cuhd_handler { +public: + uhd::usrp::multi_usrp::sptr usrp; + uhd::rx_streamer::sptr rx_stream; + bool rx_stream_enable; + uhd::tx_streamer::sptr tx_stream; + +}; diff --git a/cuhd/lib/cuhd_imp.cpp b/cuhd/lib/cuhd_imp.cpp new file mode 100644 index 000000000..88e1ce27f --- /dev/null +++ b/cuhd/lib/cuhd_imp.cpp @@ -0,0 +1,193 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 +#include +#include +#include +#include + +#include "cuhd_handler.hpp" +#include "cuhd.h" + + +void my_handler(uhd::msg::type_t type, const std::string &msg){ + //handle the message... +} + +typedef _Complex float complex_t; + +#define SAMPLE_SZ sizeof(complex_t) + +bool isLocked(void *h) +{ + cuhd_handler* handler = static_cast(h); + return handler->usrp->get_rx_sensor("lo_locked", 0).to_bool(); +} + +bool cuhd_rx_wait_lo_locked(void *h) +{ + + double report = 0.0; + while(isLocked(h) && report < 3.0) + { + report += 0.1; + usleep(1000); + } + return isLocked(h); +} + +int cuhd_start_rx_stream(void *h) { + cuhd_handler* handler = static_cast(h); + uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS); + cmd.time_spec = handler->usrp->get_time_now(); + cmd.stream_now = true; + handler->usrp->issue_stream_cmd(cmd); + return 0; +} + +int cuhd_stop_rx_stream(void *h) { + cuhd_handler* handler = static_cast(h); + uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS); + cmd.time_spec = handler->usrp->get_time_now(); + cmd.stream_now = true; + handler->usrp->issue_stream_cmd(cmd); + return 0; +} + +int cuhd_start_rx_stream_nsamples(void *h, int nsamples) { + cuhd_handler* handler = static_cast(h); + uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE); + cmd.time_spec = handler->usrp->get_time_now(); + cmd.stream_now = true; + cmd.num_samps = nsamples; + handler->usrp->issue_stream_cmd(cmd); + return 0; +} + + + +int cuhd_open(char *args, void **h) { + cuhd_handler* handler = new cuhd_handler(); + std::string _args=std::string(args); + handler->usrp = uhd::usrp::multi_usrp::make(_args); + handler->usrp->set_clock_source("internal"); + + std::string otw, cpu; + otw="sc16"; + cpu="fc32"; + uhd::stream_args_t stream_args(cpu, otw); + handler->rx_stream = handler->usrp->get_rx_stream(stream_args); + handler->tx_stream = handler->usrp->get_tx_stream(stream_args); + + *h = handler; + + return 0; +} + +int cuhd_close(void *h) { + cuhd_stop_rx_stream(h); + /** Something else to close the USRP?? */ + return 0; +} + + +double cuhd_set_rx_srate(void *h, double freq) { + cuhd_handler* handler = static_cast(h); + handler->usrp->set_rx_rate(freq); + double ret = handler->usrp->get_rx_rate(); + return ret; +} + +double cuhd_set_rx_gain(void *h, double gain) { + cuhd_handler* handler = static_cast(h); + handler->usrp->set_rx_gain(gain); + return handler->usrp->get_rx_gain(); +} + +double cuhd_set_rx_freq(void *h, double freq) { + cuhd_handler* handler = static_cast(h); + handler->usrp->set_rx_freq(freq); + return handler->usrp->get_rx_freq(); +} + +int cuhd_recv(void *h, void *data, int nsamples, int blocking) { + cuhd_handler* handler = static_cast(h); + uhd::rx_metadata_t md; + if (blocking) { + int n=0,p; + complex_t *data_c = (complex_t*) data; + do { + p=handler->rx_stream->recv(&data_c[n], nsamples-n, md); + if (p == -1) { + return -1; + } + n+=p; + } while(nrx_stream->recv(data, nsamples, md, 0.0); + } +} + +double cuhd_set_tx_gain(void *h, double gain) { + cuhd_handler* handler = static_cast(h); + handler->usrp->set_tx_gain(gain); + return handler->usrp->get_tx_gain(); +} + +double cuhd_set_tx_srate(void *h, double freq) { + cuhd_handler* handler = static_cast(h); + handler->usrp->set_tx_rate(freq); + return handler->usrp->get_tx_rate(); +} + +double cuhd_set_tx_freq(void *h, double freq) { + cuhd_handler* handler = static_cast(h); + handler->usrp->set_tx_freq(freq); + return handler->usrp->get_tx_freq(); +} + +int cuhd_send(void *h, void *data, int nsamples, int blocking) { + cuhd_handler* handler = static_cast(h); + uhd::tx_metadata_t md; + if (blocking) { + int n=0,p; + complex_t *data_c = (complex_t*) data; + do { + p=handler->tx_stream->send(&data_c[n], nsamples-n, md); + if (p == -1) { + return -1; + } + n+=p; + } while(ntx_stream->send(data, nsamples, md, 0.0); + } +} + diff --git a/cuhd/lib/cuhd_utils.c b/cuhd/lib/cuhd_utils.c new file mode 100644 index 000000000..f755f073f --- /dev/null +++ b/cuhd/lib/cuhd_utils.c @@ -0,0 +1,79 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 +#include +#include +#include + + +#include "cuhd.h" +#include "lte/utils/vector.h" +#include "lte/utils/debug.h" + +int cuhd_rssi_scan(void *uhd, float *freqs, float *rssi, int nof_bands, double fs, int nsamp) { + int i, j; + int ret = -1; + _Complex float *buffer; + double f; + + buffer = calloc(nsamp, sizeof(_Complex float)); + if (!buffer) { + goto free_and_exit; + } + + cuhd_set_rx_gain(uhd, 0.0); + cuhd_set_rx_srate(uhd, fs); + + for (i=0;i -#include -#include -#include -#include - -#include "lte.h" - -char *input_file_name = NULL; -int nof_slots=100; -float corr_peak_threshold=30; -int file_binary = 0; -int force_N_id_2=-1; -int nof_ports = 1; - - -#define FLEN 9600 - -filesource_t fsrc; -cf_t *input_buffer, *fft_buffer, *ce[MAX_PORTS]; -pbch_t pbch; -lte_fft_t fft; -chest_t chest; -sync_t synch; - -void usage(char *prog) { - printf("Usage: %s [onlt] -i input_file\n", prog); - printf("\t-n number of frames [Default %d]\n", nof_slots); - printf("\t-t correlation threshold [Default %g]\n", corr_peak_threshold); - printf("\t-v [set verbose to debug, default none]\n"); - printf("\t-b Input files is binary [Default %s]\n", file_binary?"yes":"no"); - printf("\t-f force_N_id_2 [Default %d]\n", force_N_id_2); -} - -void parse_args(int argc, char **argv) { - int opt; - while ((opt = getopt(argc, argv, "intvbf")) != -1) { - switch(opt) { - case 'i': - input_file_name = argv[optind]; - break; - case 'n': - nof_slots = atoi(argv[optind]); - break; - case 't': - corr_peak_threshold = atof(argv[optind]); - break; - case 'b': - file_binary = 1; - break; - case 'v': - verbose++; - break; - case 'f': - force_N_id_2 = atoi(argv[optind]); - break; - default: - usage(argv[0]); - exit(-1); - } - } - if (!input_file_name) { - usage(argv[0]); - exit(-1); - } -} - -int base_init() { - int i; - - file_data_type_t type = file_binary?COMPLEX_FLOAT_BIN:COMPLEX_FLOAT; - if (filesource_init(&fsrc, input_file_name, type)) { - fprintf(stderr, "Error opening file %s\n", input_file_name); - exit(-1); - } - - input_buffer = malloc(4 * FLEN * sizeof(cf_t)); - if (!input_buffer) { - perror("malloc"); - exit(-1); - } - - fft_buffer = malloc(CPNORM_NSYMB * 72 * sizeof(cf_t)); - if (!fft_buffer) { - perror("malloc"); - return -1; - } - - for (i=0;i= 4) { - state = SYNC; - } - } - mib_attempts++; - } - break; - case DONE: - INFO("State Done, Slot idx=%d\n", frame_idx); - pbch_mib_fprint(stdout, &mib); - printf("Done\n"); - break; - } - - if (read_length) { - frame_idx++; - if (frame_idx == 2) { - frame_idx = 0; - } - } - } - - sync_free(&synch); - filesource_close(&fsrc); - - free(input_buffer); - - printf("Done\n"); - exit(0); -} diff --git a/examples/cmake/Modules/FindFFTWS.cmake b/examples/cmake/Modules/FindFFTWS.cmake deleted file mode 100644 index ff28c85a7..000000000 --- a/examples/cmake/Modules/FindFFTWS.cmake +++ /dev/null @@ -1,22 +0,0 @@ -# - Find FFTW -# Find the native FFTW includes and library -# -# FFTW_INCLUDES - where to find fftw3.h -# FFTW_LIBRARIES - List of libraries when using FFTW. -# FFTW_FOUND - True if FFTW found. - -if (FFTWS_INCLUDES) - # Already in cache, be silent - set (FFTWS_FIND_QUIETLY TRUE) -endif (FFTWS_INCLUDES) - -find_path (FFTWS_INCLUDES fftw3.h) -SET(CMAKE_FIND_LIBRARY_SUFFIXES .a) -find_library (FFTWfS_LIBRARIES NAMES fftw3f) -find_library (FFTWnS_LIBRARIES NAMES fftw3) -set(FFTWS_LIBRARIES ${FFTWfS_LIBRARIES} ${FFTWnS_LIBRARIES}) - -include (FindPackageHandleStandardArgs) -find_package_handle_standard_args (FFTWS DEFAULT_MSG FFTWS_LIBRARIES FFTWS_INCLUDES) - -mark_as_advanced (FFTWS_LIBRARIES FFTWS_INCLUDES) diff --git a/examples/equalizer_test.c b/examples/equalizer_test.c deleted file mode 100644 index cd37ecdd3..000000000 --- a/examples/equalizer_test.c +++ /dev/null @@ -1,186 +0,0 @@ -#include -#include -#include -#include - -#include "lte.h" - -char *input_file_name; -int nof_slots=1; -int cell_id = 0; -int port_id = 0; -int nof_prb = 6; -lte_cp_t cp = CPNORM; -int file_binary = 0; - -int in_slot_length() { - if (CP_ISNORM(cp)) { - return SLOT_LEN_CPNORM(lte_symbol_sz(nof_prb)); - } else { - return SLOT_LEN_CPEXT(lte_symbol_sz(nof_prb)); - } -} - -int slot_length() { - return CP_NSYMB(cp)*lte_symbol_sz(nof_prb); -} - - -void usage(char *prog) { - printf("Usage: %s [bncprev] -i input_file\n", prog); - printf("\t-b input file is binary [Default no]\n"); - printf("\t-n number of slots [Default %d]\n", nof_slots); - printf("\t-c cell_id [Default %d]\n", cell_id); - printf("\t-p port_id [Default %d]\n", port_id); - printf("\t-r nof_prb [Default %d]\n", nof_prb); - printf("\t-e [extended cyclic prefix, Default normal]\n"); - printf("\t-v [set verbose to debug, default none]\n"); -} - -void parse_args(int argc, char **argv) { - int opt; - while ((opt = getopt(argc, argv, "bincprev")) != -1) { - switch(opt) { - case 'b': - file_binary = 1; - break; - case 'i': - input_file_name = argv[optind]; - break; - case 'n': - nof_slots = atoi(argv[optind]); - break; - case 'c': - cell_id = atoi(argv[optind]); - break; - case 'p': - port_id = atoi(argv[optind]); - break; - case 'r': - nof_prb = atoi(argv[optind]); - break; - case 'e': - cp = CPEXT; - break; - case 'v': - PRINT_DEBUG; - break; - default: - usage(argv[0]); - exit(-1); - } - } - if (!input_file_name) { - usage(argv[0]); - exit(-1); - } -} - -int main(int argc, char **argv) { - filesource_t fsrc; - lte_fft_t fft; - FILE *f = NULL; - chest_t eq; - int slot_cnt; - cf_t *input = NULL; - cf_t *outfft = NULL; - cf_t *ce = NULL; - int i; - - if (argc < 3) { - usage(argv[0]); - exit(-1); - } - - parse_args(argc,argv); - - if (filesource_init(&fsrc, input_file_name, file_binary?COMPLEX_FLOAT_BIN:COMPLEX_FLOAT)) { - fprintf(stderr, "Error opening file %s\n", input_file_name); - goto do_exit; - } - f = fopen("output.m", "w"); - if (!f) { - perror("fopen"); - goto do_exit; - } - - input = malloc(in_slot_length()*sizeof(cf_t)); - if (!input) { - perror("malloc"); - goto do_exit; - } - outfft = malloc(slot_length()*sizeof(cf_t)); - if (!outfft) { - perror("malloc"); - goto do_exit; - } - ce = malloc(nof_prb * RE_X_RB * CP_NSYMB(cp) * sizeof(cf_t)); - if (!ce) { - perror("malloc"); - goto do_exit; - } - - if (lte_fft_init(&fft, cp, nof_prb)) { - fprintf(stderr, "Error: initializing FFT\n"); - goto do_exit; - } - if (chest_init(&eq, LINEAR, cp, nof_prb, 1)) { - fprintf(stderr, "Error initializing equalizer\n"); - goto do_exit; - } - if (chest_ref_LTEDL(&eq, cell_id)) { - fprintf(stderr, "Error initializing reference signal\n"); - goto do_exit; - } - - bzero(input, sizeof(cf_t) * in_slot_length()); - bzero(outfft, sizeof(cf_t) * slot_length()); - - fprintf(f, "ce=zeros(%d, %d);\n", nof_slots * CP_NSYMB(cp), nof_prb * RE_X_RB); - /* read all file or nof_slots */ - slot_cnt = 0; - while (in_slot_length() == filesource_read(&fsrc, input, in_slot_length()) - && (slot_cnt < nof_slots || nof_slots == -1)) { - - fprintf(f, "infft="); - vec_fprint_c(f, input, CP_NSYMB(cp) * 128); - fprintf(f, ";\n"); - - lte_fft_run(&fft, input, outfft); - - fprintf(f, "outfft="); - vec_fprint_c(f, outfft, CP_NSYMB(cp) * nof_prb * RE_X_RB); - fprintf(f, ";\n"); - - chest_ce_slot_port(&eq, outfft, ce, 0, 0); - - chest_fprint(&eq, f, slot_cnt%20, 0); - - for (i=0;i #include #include diff --git a/examples/ll_example.c b/examples/ll_example.c index edfc0068b..83f91b188 100644 --- a/examples/ll_example.c +++ b/examples/ll_example.c @@ -1,3 +1,31 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 #include diff --git a/examples/pbch_enodeb.c b/examples/pbch_enodeb.c new file mode 100644 index 000000000..be6dbbb11 --- /dev/null +++ b/examples/pbch_enodeb.c @@ -0,0 +1,283 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 +#include +#include +#include +#include + +#include "lte.h" + +#ifndef DISABLE_UHD + #include "cuhd.h" + void *uhd; +#endif + +char *output_file_name = NULL; +int nof_slots=-1; +int cell_id = 1; +int nof_prb = 6; +char *uhd_args = ""; + +float uhd_amp=0.25, uhd_gain=10.0, uhd_freq=2400000000; + +filesink_t fsink; +lte_fft_t ifft; +pbch_t pbch; + +cf_t *slot_buffer = NULL, *output_buffer = NULL; +int slot_n_re, slot_n_samples; + +#define UHD_SAMP_FREQ 1920000 + +void usage(char *prog) { + printf("Usage: %s [agmfoncvp]\n", prog); +#ifndef DISABLE_UHD + printf("\t-a UHD args [Default %s]\n", uhd_args); + printf("\t-g UHD TX gain [Default %.2f dB]\n", uhd_gain); + printf("\t-m UHD signal amplitude [Default %.2f]\n", uhd_amp); + printf("\t-f UHD TX frequency [Default %.1f MHz]\n", uhd_freq/1000000); +#else + printf("\t UHD is disabled. CUHD library not available\n"); +#endif + printf("\t-o output_file [Default USRP]\n"); + printf("\t-n number of frames [Default %d]\n", nof_slots); + printf("\t-c cell id [Default %d]\n", cell_id); + printf("\t-p nof_prb [Default %d]\n", nof_prb); + printf("\t-v [set verbose to debug, default none]\n"); +} + +void parse_args(int argc, char **argv) { + int opt; + while ((opt = getopt(argc, argv, "agfmoncpv")) != -1) { + switch(opt) { + case 'a': + uhd_args = argv[optind]; + break; + case 'g': + uhd_gain = atof(argv[optind]); + break; + case 'm': + uhd_amp = atof(argv[optind]); + break; + case 'f': + uhd_freq = atof(argv[optind]); + break; + case 'o': + output_file_name = argv[optind]; + break; + case 'n': + nof_slots = atoi(argv[optind]); + break; + case 'p': + nof_prb = atoi(argv[optind]); + break; + case 'c': + cell_id = atoi(argv[optind]); + break; + case 'v': + verbose++; + break; + default: + usage(argv[0]); + exit(-1); + } + } +#ifdef DISABLE_UHD + if (!output_file_name) { + usage(argv[0]); + exit(-1); + } +#endif +} + +void base_init() { + /* init memory */ + slot_buffer = malloc(sizeof(cf_t) * slot_n_re); + if (!slot_buffer) { + perror("malloc"); + exit(-1); + } + output_buffer = malloc(sizeof(cf_t) * slot_n_samples); + if (!output_buffer) { + perror("malloc"); + exit(-1); + } + /* open file or USRP */ + if (output_file_name) { + if (filesink_init(&fsink, output_file_name, COMPLEX_FLOAT_BIN)) { + fprintf(stderr, "Error opening file %s\n", output_file_name); + exit(-1); + } + } else { +#ifndef DISABLE_UHD + printf("Opening UHD device...\n"); + if (cuhd_open(uhd_args,&uhd)) { + fprintf(stderr, "Error opening uhd\n"); + exit(-1); + } +#else + printf("Error UHD not available. Select an output file\n"); + exit(-1); +#endif + } + + /* create ifft object */ + if (lte_ifft_init(&ifft, CPNORM, nof_prb)) { + fprintf(stderr, "Error creating iFFT object\n"); + exit(-1); + } + if (pbch_init(&pbch, cell_id, CPNORM)) { + fprintf(stderr, "Error creating PBCH object\n"); + exit(-1); + } +} + +void base_free() { + + pbch_free(&pbch); + + lte_ifft_free(&ifft); + + if (slot_buffer) { + free(slot_buffer); + } + if (output_buffer) { + free(output_buffer); + } + if (output_file_name) { + filesink_free(&fsink); + } else { +#ifndef DISABLE_UHD + cuhd_close(&uhd); +#endif + } +} + +int main(int argc, char **argv) { + int nf, ns, N_id_2; + cf_t pss_signal[PSS_LEN]; + float sss_signal0[SSS_LEN]; // for subframe 0 + float sss_signal5[SSS_LEN]; // for subframe 5 + pbch_mib_t mib; + refsignal_t refs[NSLOTS_X_FRAME]; + int i; + cf_t *slot1_symbols[MAX_PORTS_CTRL]; + + +#ifdef DISABLE_UHD + if (argc < 3) { + usage(argv[0]); + exit(-1); + } +#endif + + parse_args(argc,argv); + + N_id_2 = cell_id%3; + slot_n_re = CPNORM_NSYMB * nof_prb * RE_X_RB; + slot_n_samples = SLOT_LEN_CPNORM(lte_symbol_sz(nof_prb)); + + /* this *must* be called after setting slot_len_* */ + base_init(); + + /* Generate PSS/SSS signals */ + pss_generate(pss_signal, N_id_2); + sss_generate(sss_signal0, sss_signal5, cell_id); + + /* Generate CRS signals */ + for (i=0;i +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lte.h" + +#ifndef DISABLE_UHD + #include "cuhd.h" + void *uhd; +#endif + +#ifndef DISABLE_GRAPHICS + #include "plot.h" + plot_real_t poutfft; + plot_complex_t pce; + plot_scatter_t pscatrecv, pscatequal; +#endif + +#define MHZ 1000000 +#define SAMP_FREQ 1920000 +#define FLEN 9600 +#define FLEN_PERIOD 0.005 + +#define NOF_PORTS 2 + +float find_threshold = 30.0, track_threshold = 10.0; +int max_track_lost = 20, nof_slots = -1; +int track_len=300; +char *input_file_name = NULL; +int disable_plots = 0; + +int go_exit=0; + +float uhd_freq = 2600000000.0, uhd_gain = 20.0; +char *uhd_args = ""; + +filesource_t fsrc; +cf_t *input_buffer, *fft_buffer, *ce[MAX_PORTS_CTRL]; +pbch_t pbch; +lte_fft_t fft; +chest_t chest; +sync_t sfind, strack; +cfo_t cfocorr; + + +enum sync_state {FIND, TRACK}; + +void usage(char *prog) { + printf("Usage: %s [iagfndvp]\n", prog); + printf("\t-i input_file [Default use USRP]\n"); +#ifndef DISABLE_UHD + printf("\t-a UHD args [Default %s]\n", uhd_args); + printf("\t-g UHD RX gain [Default %.2f dB]\n", uhd_gain); + printf("\t-f UHD RX frequency [Default %.1f MHz]\n", uhd_freq/1000000); +#else + printf("\t UHD is disabled. CUHD library not available\n"); +#endif + printf("\t-n nof_frames [Default %d]\n", nof_slots); + printf("\t-p PSS threshold [Default %f]\n", find_threshold); +#ifndef DISABLE_GRAPHICS + printf("\t-d disable plots [Default enabled]\n"); +#else + printf("\t plots are disabled. Graphics library not available\n"); +#endif + printf("\t-v [set verbose to debug, default none]\n"); +} + +void parse_args(int argc, char **argv) { + int opt; + while ((opt = getopt(argc, argv, "iagfndvp")) != -1) { + switch(opt) { + case 'i': + input_file_name = argv[optind]; + break; + case 'a': + uhd_args = argv[optind]; + break; + case 'g': + uhd_gain = atof(argv[optind]); + break; + case 'f': + uhd_freq = atof(argv[optind]); + break; + case 'p': + find_threshold = atof(argv[optind]); + break; + case 'n': + nof_slots = atoi(argv[optind]); + break; + case 'd': + disable_plots = 1; + break; + case 'v': + verbose++; + break; + default: + usage(argv[0]); + exit(-1); + } + } +} + +#ifndef DISABLE_GRAPHICS + +void init_plots() { + plot_init(); + plot_real_init(&poutfft); + plot_real_setTitle(&poutfft, "Output FFT - Magnitude"); + plot_real_setLabels(&poutfft, "Index", "dB"); + plot_real_setYAxisScale(&poutfft, -60, 0); + plot_real_setXAxisScale(&poutfft, 1, 504); + + plot_complex_init(&pce); + plot_complex_setTitle(&pce, "Channel Estimates"); + plot_complex_setYAxisScale(&pce, Ip, -0.01, 0.01); + plot_complex_setYAxisScale(&pce, Q, -0.01, 0.01); + plot_complex_setYAxisScale(&pce, Magnitude, 0, 0.01); + plot_complex_setYAxisScale(&pce, Phase, -M_PI, M_PI); + + plot_scatter_init(&pscatrecv); + plot_scatter_setTitle(&pscatrecv, "Received Symbols"); + plot_scatter_setXAxisScale(&pscatrecv, -0.01, 0.01); + plot_scatter_setYAxisScale(&pscatrecv, -0.01, 0.01); + + plot_scatter_init(&pscatequal); + plot_scatter_setTitle(&pscatequal, "Equalized Symbols"); + plot_scatter_setXAxisScale(&pscatequal, -1, 1); + plot_scatter_setYAxisScale(&pscatequal, -1, 1); +} + +#endif + +int base_init(int frame_length) { + int i; + +#ifndef DISABLE_GRAPHICS + if (!disable_plots) { + init_plots(); + } +#else + printf("-- PLOTS are disabled. Graphics library not available --\n\n"); +#endif + + if (input_file_name) { + if (filesource_init(&fsrc, input_file_name, COMPLEX_FLOAT_BIN)) { + return -1; + } + } else { + /* open UHD device */ + #ifndef DISABLE_UHD + printf("Opening UHD device...\n"); + if (cuhd_open(uhd_args,&uhd)) { + fprintf(stderr, "Error opening uhd\n"); + return -1; + } + #else + printf("Error UHD not available. Select an input file\n"); + return -1; + #endif + } + + input_buffer = (cf_t*) malloc(frame_length * sizeof(cf_t)); + if (!input_buffer) { + perror("malloc"); + return -1; + } + + fft_buffer = (cf_t*) malloc(CPNORM_NSYMB * 72 * sizeof(cf_t)); + if (!fft_buffer) { + perror("malloc"); + return -1; + } + + for (i=0;i max_track_lost) { + INFO("%d frames lost. Going back to FIND", frame_cnt - last_found); + printf("\r\n"); + fflush(stdout); + printf("\r\n"); + state = FIND; + } + + // Correct CFO + INFO("Correcting CFO=%.4f\n", cfo); + + cfo_correct(&cfocorr, input_buffer, -cfo/128); + + if (nslot == 0 && find_idx + 960 < FLEN) { + INFO("Finding MIB at idx %d\n", find_idx); + if (mib_decoder_run(&input_buffer[find_idx], &mib)) { + INFO("MIB detected attempt=%d\n", frame_cnt); + if (verbose == VERBOSE_NONE) { + if (!nof_found_mib) { + printf("\r\n"); + fflush(stdout); + printf("\r\n"); + printf(" - Phy. CellId:\t%d\n", cell_id); + pbch_mib_fprint(stdout, &mib); + } + } + nof_found_mib++; + } else { + INFO("MIB not found attempt %d\n",frame_cnt); + } + if (frame_cnt) { + printf("SFN: %4d, CFO: %+.4f KHz, SFO: %+.4f Khz, TimeOffset: %4d, Errors: %4d/%4d, ErrorRate: %.1e\r", mib.sfn, + cfo*15, timeoffset/5, find_idx, frame_cnt-2*(nof_found_mib-1), frame_cnt, + (float) (frame_cnt-2*(nof_found_mib-1))/frame_cnt); + fflush(stdout); + } + } + if (input_file_name) { + usleep(5000); + } + nslot = (nslot+10)%20; + break; + } + frame_cnt++; + } + + base_free(); + + printf("\nBye\n"); + exit(0); +} + diff --git a/examples/mib_scan_usrp.c b/examples/scan_mib.c similarity index 74% rename from examples/mib_scan_usrp.c rename to examples/scan_mib.c index 15805a1d8..e94ad6c18 100644 --- a/examples/mib_scan_usrp.c +++ b/examples/scan_mib.c @@ -1,3 +1,30 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 #include #include @@ -9,11 +36,10 @@ #include "lte.h" -#define DISABLE_UHD +//#define DISABLE_UHD #ifndef DISABLE_UHD -#include "uhd.h" -#include "uhd_utils.h" +#include "cuhd.h" #endif #define MHZ 1000000 @@ -26,28 +52,27 @@ #define IS_SIGNAL(i) (10*log10f(rssi[i]) + 30 > rssi_threshold) - int band, earfcn=-1; -float find_threshold = 40.0, track_threshold = 8.0; +float find_threshold = 10.0, track_threshold = 8.0; int earfcn_start=-1, earfcn_end = -1; -float rssi_threshold = -30.0; +float rssi_threshold = -45.0; int max_track_lost=9; -int nof_frames_find=8, nof_frames_track=100, nof_samples_rssi=50000; +int nof_frames_find=20, nof_frames_track=100, nof_samples_rssi=50000; int track_len=500; -int nof_ports; cf_t *input_buffer, *fft_buffer, *ce[MAX_PORTS]; pbch_t pbch; lte_fft_t fft; chest_t chest; sync_t sfind, strack; +cfo_t cfocorr; float *cfo_v; int *idx_v, *idx_valid, *t; float *p2a_v; void *uhd; int nof_bands; -float gain = 20.0; +float uhd_gain = 20.0; #define MAX_EARFCN 1000 lte_earfcn_t channels[MAX_EARFCN]; @@ -59,7 +84,6 @@ float p2a[MAX_EARFCN]; enum sync_state {INIT, FIND, TRACK, MIB, DONE}; -void print_to_matlab(); void usage(char *prog) { printf("Usage: %s [seRrFfTtgv] -b band\n", prog); @@ -72,7 +96,7 @@ void usage(char *prog) { printf("\t-T pss_track_nof_frames [Default %d]\n", nof_frames_track); printf("\t-t pss_track_threshold [Default %.2f]\n", track_threshold); printf("\t-l pss_track_len [Default %d]\n", track_len); - printf("\t-g gain [Default %.2f dB]\n", gain); + printf("\t-g gain [Default %.2f dB]\n", uhd_gain); printf("\t-v [set verbose to debug, default none]\n"); } @@ -108,7 +132,7 @@ void parse_args(int argc, char **argv) { track_threshold = atof(argv[optind]); break; case 'g': - gain = atof(argv[optind]); + uhd_gain = atof(argv[optind]); break; case 'v': verbose++; @@ -135,7 +159,7 @@ int base_init(int frame_length) { return -1; } - for (i=0;i= nof_frames_track) { + mib_decoder_init(cell_id); + + cfo[freq] = mean_valid(idx_v, cfo_v, frame_cnt); + p2a[freq] = mean_valid(idx_v, p2a_v, frame_cnt); + valid_frames = preprocess_idx(idx_v, idx_valid, t, frame_cnt); + sfo = sfo_estimate_period(idx_valid, t, valid_frames, FLEN_PERIOD); + state = MIB; nslot=(nslot+10)%20; } break; case MIB: - INFO("Finding MIB at freq %.2f Mhz\n", channels[freq].fd); - cfo[freq] = mean_valid(idx_v, cfo_v, frame_cnt); - p2a[freq] = mean_valid(idx_v, p2a_v, frame_cnt); - valid_frames = preprocess_idx(idx_v, idx_valid, t, frame_cnt); - sfo = sfo_estimate_period(idx_valid, t, valid_frames, FLEN_PERIOD); + INFO("Finding MIB at freq %.2f Mhz offset=%d, cell_id=%d, slot_idx=%d\n", channels[freq].fd, find_idx, cell_id, nslot); // TODO: Correct SFO // Correct CFO INFO("Correcting CFO=%.4f\n", cfo[freq]); - nco_cexp_f_direct(&input_buffer[FLEN], -cfo[freq]/128, FLEN); + cfo_correct(&cfocorr, &input_buffer[FLEN], (-cfo[freq])/128); - if (nslot == 10) { - if (mib_decoder_run(&input_buffer[FLEN+find_idx+FLEN/10], &mib)) { + if (nslot == 0) { + if (mib_decoder_run(&input_buffer[FLEN+find_idx], &mib)) { INFO("MIB detected attempt=%d\n", mib_attempts); state = DONE; } else { INFO("MIB not detected attempt=%d\n", mib_attempts); - if (mib_attempts >= 20) { + if (mib_attempts == 0) { freq++; state = INIT; } } mib_attempts++; - } else { - nslot = (nslot+10)%20; } + nslot = (nslot+10)%20; + break; case DONE: @@ -509,84 +544,16 @@ int main(int argc, char **argv) { } /** FIXME: This is not necessary at all */ - if (state == TRACK || (state == FIND && frame_cnt)) { + if (state == TRACK || state == FIND) { memcpy(input_buffer, &input_buffer[FLEN], FLEN * sizeof(cf_t)); } frame_cnt++; } } - print_to_matlab(); - base_free(); printf("\n\nDone\n"); exit(0); } -void print_to_matlab() { - int i; - - FILE *f = fopen("output.m", "w"); - if (!f) { - perror("fopen"); - exit(-1); - } - fprintf(f, "fd=["); - for (i=0;i #include #include @@ -8,9 +35,7 @@ #include #include "lte.h" - -#include "uhd.h" -#include "uhd_utils.h" +#include "cuhd.h" #define MHZ 1000000 #define SAMP_FREQ 1920000 @@ -24,11 +49,11 @@ int band, earfcn=-1; -float find_threshold = 40.0, track_threshold = 8.0; +float find_threshold = 10.0, track_threshold = 8.0; int earfcn_start=-1, earfcn_end = -1; -float rssi_threshold = -30.0; +float rssi_threshold = -45.0; int max_track_lost=9; -int nof_frames_find=8, nof_frames_track=100, nof_samples_rssi=50000; +int nof_frames_find=20, nof_frames_track=100, nof_samples_rssi=50000; int track_len=500; cf_t *input_buffer; @@ -37,7 +62,7 @@ int *idx_v, *idx_valid, *t; float *p2a_v; void *uhd; int nof_bands; -float gain = 20.0; +float uhd_gain = 20.0; #define MAX_EARFCN 1000 lte_earfcn_t channels[MAX_EARFCN]; @@ -62,7 +87,7 @@ void usage(char *prog) { printf("\t-T pss_track_nof_frames [Default %d]\n", nof_frames_track); printf("\t-t pss_track_threshold [Default %.2f]\n", track_threshold); printf("\t-l pss_track_len [Default %d]\n", track_len); - printf("\t-g gain [Default %.2f dB]\n", gain); + printf("\t-g gain [Default %.2f dB]\n", uhd_gain); printf("\t-v [set verbose to debug, default none]\n"); } @@ -98,7 +123,7 @@ void parse_args(int argc, char **argv) { track_threshold = atof(argv[optind]); break; case 'g': - gain = atof(argv[optind]); + uhd_gain = atof(argv[optind]); break; case 'v': verbose++; @@ -149,7 +174,7 @@ int base_init(int frame_length) { /* open UHD device */ printf("Opening UHD device...\n"); - if (uhd_open("",&uhd)) { + if (cuhd_open("",&uhd)) { fprintf(stderr, "Error opening uhd\n"); exit(-1); } @@ -159,7 +184,7 @@ int base_init(int frame_length) { void base_free() { - uhd_close(&uhd); + cuhd_close(uhd); free(input_buffer); free(idx_v); free(idx_valid); @@ -208,7 +233,7 @@ int rssi_scan() { freqs[n] = channels[i].fd * MHZ; n++; } - if (uhd_rssi_scan(uhd, freqs, rssi_d, n, (double) RSSI_FS, nof_samples_rssi)) { + if (cuhd_rssi_scan(uhd, freqs, rssi_d, n, (double) RSSI_FS, nof_samples_rssi)) { fprintf(stderr, "Error while doing RSSI scan\n"); return -1; } @@ -218,7 +243,7 @@ int rssi_scan() { for (i=0;i #include #include @@ -6,7 +33,7 @@ #include #include "lte.h" -#include "uhd.h" +#include "cuhd.h" int nof_slots=1000; int band; @@ -65,16 +92,16 @@ int base_init() { /* open UHD device */ printf("Opening UHD device...\n"); - if (uhd_open("",&uhd)) { + if (cuhd_open("",&uhd)) { fprintf(stderr, "Error opening uhd\n"); exit(-1); } printf("Setting sampling frequency %.2f MHz\n", (float) SAMP_FREQ/MHZ); - uhd_set_rx_srate(uhd, SAMP_FREQ); + cuhd_set_rx_srate(uhd, SAMP_FREQ); printf("Starting receiver...\n"); - uhd_start_rx_stream(uhd); + cuhd_start_rx_stream(uhd); return 0; } @@ -101,12 +128,12 @@ int main(int argc, char **argv) { int nof_bands = lte_band_get_fd_band(band, channels, earfcn_start, earfcn_end, MAX_EARFCN); printf("Scanning %d freqs in band %d\n", nof_bands, band); for (i=0;i #include #include @@ -10,28 +37,27 @@ char *input_file_name; char *output_file_name="abs_corr.txt"; int nof_slots=100, frame_length=9600, symbol_sz=128; float corr_peak_threshold=25.0; -int file_binary = 0; int out_N_id_2 = 0, force_N_id_2=-1; #define CFO_AUTO -9999.0 float force_cfo = CFO_AUTO; void usage(char *prog) { - printf("Usage: %s [onlt] -i input_file\n", prog); + printf("Usage: %s [olntsNfcv] -i input_file\n", prog); printf("\t-o output_file [Default %s]\n", output_file_name); printf("\t-l frame_length [Default %d]\n", frame_length); printf("\t-n number of frames [Default %d]\n", nof_slots); printf("\t-t correlation threshold [Default %g]\n", corr_peak_threshold); printf("\t-s symbol_sz [Default %d]\n", symbol_sz); - printf("\t-b Input files is binary [Default %s]\n", file_binary?"yes":"no"); printf("\t-N out_N_id_2 [Default %d]\n", out_N_id_2); printf("\t-f force_N_id_2 [Default %d]\n", force_N_id_2); printf("\t-c force_cfo [Default disabled]\n"); + printf("\t-v verbose\n"); } void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "ionltsbNfc")) != -1) { + while ((opt = getopt(argc, argv, "ionltsNfcv")) != -1) { switch(opt) { case 'i': input_file_name = argv[optind]; @@ -51,9 +77,6 @@ void parse_args(int argc, char **argv) { case 's': symbol_sz = atof(argv[optind]); break; - case 'b': - file_binary = 1; - break; case 'N': out_N_id_2 = atoi(argv[optind]); break; @@ -63,6 +86,9 @@ void parse_args(int argc, char **argv) { case 'c': force_cfo = atof(argv[optind]); break; + case 'v': + verbose++; + break; default: usage(argv[0]); exit(-1); @@ -79,6 +105,7 @@ int main(int argc, char **argv) { filesink_t fsink; pss_synch_t pss[3]; // One for each N_id_2 sss_synch_t sss[3]; // One for each N_id_2 + cfo_t cfocorr; int peak_pos[3]; float *cfo; float peak_value[3]; @@ -102,12 +129,11 @@ int main(int argc, char **argv) { gettimeofday(&tdata[1], NULL); printf("Initializing...");fflush(stdout); - file_data_type_t type = file_binary?COMPLEX_FLOAT_BIN:COMPLEX_FLOAT; - if (filesource_init(&fsrc, input_file_name, type)) { + if (filesource_init(&fsrc, input_file_name, COMPLEX_FLOAT_BIN)) { fprintf(stderr, "Error opening file %s\n", input_file_name); exit(-1); } - if (filesink_init(&fsink, output_file_name, type)) { + if (filesink_init(&fsink, output_file_name, COMPLEX_FLOAT_BIN)) { fprintf(stderr, "Error opening file %s\n", output_file_name); exit(-1); } @@ -128,6 +154,11 @@ int main(int argc, char **argv) { exit(-1); } + if (cfo_init(&cfocorr, frame_length)) { + fprintf(stderr, "Error initiating CFO\n"); + return -1; + } + /* We have 2 options here: * a) We create 3 pss objects, each initialized with a different N_id_2 * b) We create 1 pss object which scans for each N_id_2 one after another. @@ -165,7 +196,7 @@ int main(int argc, char **argv) { gettimeofday(&tdata[1], NULL); if (force_cfo != CFO_AUTO) { - nco_cexp_f_direct(input, -force_cfo/128, frame_length); + cfo_correct(&cfocorr, input, -force_cfo/128); } if (force_N_id_2 != -1) { @@ -229,8 +260,8 @@ int main(int argc, char **argv) { sss_synch_free(&sss[N_id_2]); } - filesource_close(&fsrc); - filesink_close(&fsink); + filesource_free(&fsrc); + filesink_free(&fsink); free(input); free(cfo); diff --git a/examples/viterbi_test.c b/examples/viterbi_test.c deleted file mode 100644 index b1d53994c..000000000 --- a/examples/viterbi_test.c +++ /dev/null @@ -1,168 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include "lte.h" - -typedef _Complex float cf_t; - -int frame_length=1000, nof_slots=128; -float ebno_db = 5.0; -unsigned int seed=0; -bool tail_biting = false; - -char message[40] = {0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,1,0,0,1,1,0,1,0,0,0,0,1}; - -void usage(char *prog) { - printf("Usage: %s [nl]\n", prog); - printf("\t-n nof_frames [Default %d]\n", nof_slots); - printf("\t-l frame_length [Default %d]\n", frame_length); - printf("\t-e ebno in dB [Default %.2f dB]\n", ebno_db); - printf("\t-s seed [Default 0=time]\n"); - printf("\t-t tail_bitting [Default %s]\n", tail_biting?"yes":"no"); -} - -void parse_args(int argc, char **argv) { - int opt; - while ((opt = getopt(argc, argv, "nlste")) != -1) { - switch(opt) { - case 'n': - nof_slots = atoi(argv[optind]); - break; - case 'l': - frame_length = atoi(argv[optind]); - break; - case 'e': - ebno_db = atof(argv[optind]); - break; - case 's': - seed = atoi(argv[optind]); - break; - case 't': - tail_biting = true; - break; - default: - usage(argv[0]); - exit(-1); - } - } -} - -int main(int argc, char **argv) { - viterbi_t dec; - convcoder_t cod; - modem_table_t modem; - demod_soft_t demod; - int frame_cnt; - float *llr; - char *data_tx, *data_rx, *symbols; - cf_t *iq; - int i; - - parse_args(argc,argv); - - if (!seed) { - seed = time(NULL); - } - srand(seed); - - int coded_length = 3 * (frame_length + ((tail_biting)?0:6)); - - printf("Convolutional Code 1/3 K=7 Test\n"); - printf(" Frame length: %d\n", frame_length); - printf(" Codeword length: %d\n", coded_length); - printf(" Tail bitting: %s\n", tail_biting?"yes":"no"); - printf(" EbNo: %.2f\n", ebno_db); - - data_tx = malloc(frame_length * sizeof(char)); - if (!data_tx) { - perror("malloc"); - exit(-1); - } - - data_rx = malloc(frame_length * sizeof(char)); - if (!data_rx) { - perror("malloc"); - exit(-1); - } - - symbols = malloc(coded_length * sizeof(char)); - if (!symbols) { - perror("malloc"); - exit(-1); - } - llr = malloc(coded_length * sizeof(float)); - if (!llr) { - perror("malloc"); - exit(-1); - } - - iq = malloc(coded_length * sizeof(cf_t)); - if (!iq) { - perror("malloc"); - exit(-1); - } - - cod.K = 7; - cod.R = 3; - cod.tail_biting = tail_biting; - cod.framelength = frame_length; - cod.poly[0] = 0x6D; - cod.poly[1] = 0x4F; - cod.poly[2] = 0x57; - - float var = sqrt(pow(10,-ebno_db/10)); - - modem_table_init(&modem); - modem_table_std(&modem, LTE_QPSK, true); - demod_soft_init(&demod); - demod_soft_table_set(&demod, &modem); - demod_soft_alg_set(&demod, APPROX); - demod_soft_sigma_set(&demod, var); - - viterbi_init(&dec, viterbi_37, cod.poly, frame_length, tail_biting); - - /* read all file or nof_frames */ - frame_cnt = 0; - unsigned int errors=0; - while (frame_cnt < nof_slots) { - - /* generate data_tx */ - for (i=0;i + +typedef enum { + Ip, Q, Magnitude, Phase +} plot_complex_id_t; + +typedef void* plot_complex_t; + +int plot_complex_init(plot_complex_t *h); +void plot_complex_setTitle(plot_complex_t *h, char *title); +void plot_complex_setNewData(plot_complex_t *h, _Complex float *data, + int num_points); +void plot_complex_setXAxisAutoScale(plot_complex_t *h, plot_complex_id_t id, bool on); +void plot_complex_setYAxisAutoScale(plot_complex_t *h, plot_complex_id_t id, bool on); +void plot_complex_setXAxisScale(plot_complex_t *h, plot_complex_id_t id, double xMin, double xMax); +void plot_complex_setYAxisScale(plot_complex_t *h, plot_complex_id_t id, double yMin, double yMax); +void plot_complex_setXAxisRange(plot_complex_t *h, double xMin, double xMax); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/graphics/include/plot/plot_real.h b/graphics/include/plot/plot_real.h new file mode 100644 index 000000000..bd8fe58d7 --- /dev/null +++ b/graphics/include/plot/plot_real.h @@ -0,0 +1,55 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 _plot_real_h +#define _plot_real_h + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +typedef void* plot_real_t; + +int plot_real_init(plot_real_t *h); +void plot_real_setTitle(plot_real_t *h, char *title); +void plot_real_setNewData(plot_real_t *h, float *data, + int num_points); +void plot_real_setXAxisAutoScale(plot_real_t *h, bool on); +void plot_real_setYAxisAutoScale(plot_real_t *h, bool on); +void plot_real_setXAxisScale(plot_real_t *h, double xMin, double xMax); +void plot_real_setYAxisScale(plot_real_t *h, double yMin, double yMax); +void plot_real_setXAxisRange(plot_real_t *h, double xMin, double xMax); +void plot_real_setLabels(plot_real_t *h, char *xLabel, char *yLabel); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/graphics/include/plot/plot_scatter.h b/graphics/include/plot/plot_scatter.h new file mode 100644 index 000000000..bd9536903 --- /dev/null +++ b/graphics/include/plot/plot_scatter.h @@ -0,0 +1,54 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 _plot_scatter_h +#define _plot_scatter_h + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +typedef void* plot_scatter_t; + +int plot_scatter_init(plot_scatter_t *h); +void plot_scatter_setTitle(plot_scatter_t *h, char *title); +void plot_scatter_setNewData(plot_scatter_t *h, _Complex float *data, + int num_points); +void plot_scatter_setXAxisAutoScale(plot_scatter_t *h, bool on); +void plot_scatter_setYAxisAutoScale(plot_scatter_t *h, bool on); +void plot_scatter_setXAxisScale(plot_scatter_t *h, double xMin, double xMax); +void plot_scatter_setYAxisScale(plot_scatter_t *h, double yMin, double yMax); +void plot_scatter_setAxisLabels(plot_scatter_t *h, char *xLabel, char *yLabel); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/graphics/include/plot/plot_waterfall.h b/graphics/include/plot/plot_waterfall.h new file mode 100644 index 000000000..341b7d9d1 --- /dev/null +++ b/graphics/include/plot/plot_waterfall.h @@ -0,0 +1,61 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 _plot_waterfall_h +#define _plot_waterfall_h + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +typedef void* plot_waterfall_t; + +int plot_waterfall_init(plot_waterfall_t *h); +void plot_waterfall_setTitle(plot_waterfall_t *h, char *title); +void plot_waterfall_appendNewData(plot_waterfall_t *h, float *data, + int num_points); +void plot_complex_setPlotXLabel(plot_waterfall_t *h, char *xLabel); +void plot_complex_setPlotYLabel(plot_waterfall_t *h, char *yLabel); +void plot_waterfall_setPlotXAxisRange(plot_waterfall_t *h, double xMin, double xMax); +void plot_waterfall_setPlotXAxisScale(plot_waterfall_t *h, double xMin, double xMax); +void plot_waterfall_setPlotYAxisScale(plot_waterfall_t *h, double yMin, double yMax); + +void plot_waterfall_setSpectrogramXLabel(plot_waterfall_t *h, char* xLabel); +void plot_waterfall_setSpectrogramYLabel(plot_waterfall_t *h, char* yLabel); +void plot_waterfall_setSpectrogramXAxisRange(plot_waterfall_t *h, double xMin, double xMax); +void plot_waterfall_setSpectrogramYAxisRange(plot_waterfall_t *h, double yMin, double yMax); +void plot_waterfall_setSpectrogramZAxisScale(plot_waterfall_t *h, double zMin, double zMax); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/graphics/lib/CMakeLists.txt b/graphics/lib/CMakeLists.txt new file mode 100644 index 000000000..a7ba627de --- /dev/null +++ b/graphics/lib/CMakeLists.txt @@ -0,0 +1,94 @@ +# +# Copyright 2012-2013 The libLTE Developers. See the +# COPYRIGHT file at the top-level directory of this distribution. +# +# This file is part of the libLTE library. +# +# libLTE is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# libLTE is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# A copy of the GNU Lesser 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/. +# + + +######################################################################## +# Setup Qt and Qwt +######################################################################## + +FIND_PACKAGE(Qt4) +IF(QT4_FOUND) + INCLUDE(${QT_USE_FILE}) +ENDIF(QT4_FOUND) + +FIND_PACKAGE(Qwt) +IF(QT4_FOUND AND QWT_FOUND) + INCLUDE_DIRECTORIES(${QWT_INCLUDE_DIRS}) +ENDIF(QT4_FOUND AND QWT_FOUND) + + + +######################################################################## +# Build the graphics library +######################################################################## + +file(GLOB modules *) + +SET(SOURCES_ALL "") +FOREACH (_module ${modules}) + IF(IS_DIRECTORY ${_module}) + FILE(GLOB tmp "${_module}/*.cpp") + LIST(APPEND SOURCES_ALL ${tmp}) + ENDIF(IS_DIRECTORY ${_module}) +ENDFOREACH(_module ${modules}) + +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../../) + +IF(QWT_MAJOR_VERSION LESS 6) + MESSAGE(STATUS "QWT6 is required.") +ENDIF(QWT_MAJOR_VERSION LESS 6) + +IF(QT4_FOUND AND QWT_FOUND AND QWT_MAJOR_VERSION EQUAL 6) + QT4_WRAP_CPP(lineplotwraps common/Lineplot.h) + QT4_WRAP_CPP(pointplotwraps common/Pointplot.h) + QT4_WRAP_CPP(spectrogramplotwraps common/Spectrogramplot.h) + QT4_WRAP_CPP(complex complexplot/ComplexWidget.h complexplot/ComplexplotWrapper.h) + QT4_WRAP_CPP(real realplot/RealWidget.h realplot/RealplotWrapper.h) + QT4_WRAP_CPP(scatter scatterplot/ScatterWidget.h scatterplot/ScatterplotWrapper.h) + QT4_WRAP_CPP(waterfall waterfallplot/WaterfallWidget.h waterfallplot/WaterfallplotWrapper.h) + + INCLUDE_DIRECTORIES(common complexplot realplot scatterplot waterfallplot ${Boost_INCLUDE_DIRS}) + + ADD_LIBRARY(graphics ${eventwraps} ${lineplotwraps} ${pointplotwraps} ${spectrogramplotwraps} ${complex} ${real} ${scatter} ${waterfall} ${SOURCES_ALL} ) + TARGET_LINK_LIBRARIES(graphics pthread ${QT_LIBRARIES} ${QWT_LIBRARIES}) + INSTALL(TARGETS graphics DESTINATION ${LIBRARY_DIR}) + LIBLTE_SET_PIC(graphics) + + APPEND_INTERNAL_LIST(OPTIONAL_LIBS graphics) + + + ADD_SUBDIRECTORY(complexplot/test) + ADD_SUBDIRECTORY(realplot/test) + ADD_SUBDIRECTORY(scatterplot/test) + ADD_SUBDIRECTORY(waterfallplot/test) + + MESSAGE(STATUS " GRAPHICS library will be installed.") + + +ELSE(QT4_FOUND AND QWT_FOUND AND AND QWT_MAJOR_VERSION EQUAL 6) + + MESSAGE(STATUS " QT4 or Qwt6 not found. GRAPHICS library is not generated") + +ENDIF(QT4_FOUND AND QWT_FOUND AND QWT_MAJOR_VERSION EQUAL 6) + + + + diff --git a/graphics/lib/common/Events.cpp b/graphics/lib/common/Events.cpp new file mode 100644 index 000000000..9276e346a --- /dev/null +++ b/graphics/lib/common/Events.cpp @@ -0,0 +1,94 @@ +/** + * \file lib/generic/graphics/qt/common/Events.cpp + * \version 1.0 + * + * \section COPYRIGHT + * + * Copyright 2012-2013 The Iris Project Developers. See the + * COPYRIGHT file at the top-level directory of this distribution + * and at http://www.softwareradiosystems.com/iris/copyright.html. + * + * \section LICENSE + * + * This file is part of the Iris Project. + * + * Iris is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * Iris is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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/. + * + * \section DESCRIPTION + * + * Implementation of events used to pass data to Qt-based classes. + */ + +#include "Events.h" + +using namespace std; + +const QEvent::Type RealDataEvent::type = static_cast(10000); + +RealDataEvent::RealDataEvent(double* dataPoints, int numPoints) + : QEvent(QEvent::Type(type)) +{ + dataPoints_ = new double[numPoints]; + numPoints_ = numPoints; + memcpy(dataPoints_, dataPoints, numPoints*sizeof(double)); +} + +RealDataEvent::RealDataEvent(float* dataPoints, int numPoints) + : QEvent(QEvent::Type(type)) +{ + dataPoints_ = new double[numPoints]; + numPoints_ = numPoints; + + for(int i=0;i(10001); + +ComplexDataEvent::ComplexDataEvent(complex* dataPoints, + int numPoints) + : QEvent(QEvent::Type(type)) +{ + dataPoints_ = new complex[numPoints]; + numPoints_ = numPoints; + memcpy(dataPoints_, dataPoints, numPoints*sizeof(complex)); +} + +ComplexDataEvent::ComplexDataEvent(complex* dataPoints, + int numPoints) + : QEvent(QEvent::Type(type)) +{ + dataPoints_ = new complex[numPoints]; + numPoints_ = numPoints; + + for(int i=0;i(dataPoints[i].real(), + dataPoints[i].imag()); + } +} + +ComplexDataEvent::~ComplexDataEvent() +{ + delete[] dataPoints_; +} diff --git a/graphics/lib/common/Events.h b/graphics/lib/common/Events.h new file mode 100644 index 000000000..c7a8b9c6c --- /dev/null +++ b/graphics/lib/common/Events.h @@ -0,0 +1,72 @@ +/** + * \file lib/generic/graphics/qt/common/Events.h + * \version 1.0 + * + * \section COPYRIGHT + * + * Copyright 2012-2013 The Iris Project Developers. See the + * COPYRIGHT file at the top-level directory of this distribution + * and at http://www.softwareradiosystems.com/iris/copyright.html. + * + * \section LICENSE + * + * This file is part of the Iris Project. + * + * Iris is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * Iris is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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/. + * + * \section DESCRIPTION + * + * Events used to pass data to Qt-based classes. + */ + +#ifndef EVENTS_H +#define EVENTS_H + +#include +#include + +class RealDataEvent + : public QEvent +{ +public: + const static QEvent::Type type; + + RealDataEvent(double* dataPoints, + int numPoints); + RealDataEvent(float* dataPoints, + int numPoints); + virtual ~RealDataEvent(); + + double* dataPoints_; + int numPoints_; +}; + +class ComplexDataEvent + : public QEvent +{ +public: + const static QEvent::Type type; + + ComplexDataEvent(std::complex* dataPoints, + int numPoints); + ComplexDataEvent(std::complex* dataPoints, + int numPoints); + virtual ~ComplexDataEvent(); + + std::complex* dataPoints_; + int numPoints_; +}; + +#endif // EVENTS_H diff --git a/graphics/lib/common/Lineplot.cpp b/graphics/lib/common/Lineplot.cpp new file mode 100644 index 000000000..0f0c298ce --- /dev/null +++ b/graphics/lib/common/Lineplot.cpp @@ -0,0 +1,164 @@ +/** + * \file lib/generic/graphics/qt/common/Lineplot.cpp + * \version 1.0 + * + * \section COPYRIGHT + * + * Copyright 2012-2013 The Iris Project Developers. See the + * COPYRIGHT file at the top-level directory of this distribution + * and at http://www.softwareradiosystems.com/iris/copyright.html. + * + * \section LICENSE + * + * This file is part of the Iris Project. + * + * Iris is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * Iris is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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/. + * + * \section DESCRIPTION + * + * Implementation of a simple line plotted using a QwtPlot. + */ + +#include "Lineplot.h" + +#include + +class MyZoomer: public QwtPlotZoomer +{ +public: + MyZoomer(QwtPlotCanvas *canvas): + QwtPlotZoomer(canvas) + { + setTrackerMode(AlwaysOn); + } + + virtual QwtText trackerTextF(const QPointF &pos) const + { + QColor bg(Qt::white); + bg.setAlpha(200); + + QwtText text = QwtPlotZoomer::trackerTextF(pos); + text.setBackgroundBrush( QBrush( bg )); + return text; + } +}; + +Lineplot::Lineplot(QWidget *parent) + :QwtPlot(parent) + ,xMin_(0) + ,xMax_(0) +{ + counter_ = 0; + numPoints_ = 1; + indexPoints_ = new double[numPoints_]; + dataPoints_ = new double[numPoints_]; + + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + + QPalette palette; + palette.setColor(canvas()->backgroundRole(), QColor("white")); + canvas()->setPalette(palette); + + curve_ = new QwtPlotCurve("Curve"); + curve_->setPen(QPen(Qt::blue, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); + curve_->setStyle(QwtPlotCurve::Lines); + curve_->setRawSamples(indexPoints_, dataPoints_, numPoints_); + curve_->setYAxis(QwtPlot::yLeft); + curve_->attach(this); + + memset(dataPoints_, 0x0, numPoints_*sizeof(double)); + for(int i=0;isetAttribute(QwtScaleEngine::Floating,true); + axisScaleEngine(QwtPlot::yLeft)->setAttribute(QwtScaleEngine::Floating,true); + axisScaleEngine(QwtPlot::yRight)->setAttribute(QwtScaleEngine::Floating,true); + + zoomer_ = new MyZoomer(canvas()); + zoomer_->setMousePattern(QwtEventPattern::MouseSelect1, Qt::LeftButton); + zoomer_->setMousePattern(QwtEventPattern::MouseSelect2, Qt::LeftButton, + Qt::ControlModifier); + + panner_ = new QwtPlotPanner(canvas()); + panner_->setMouseButton(Qt::RightButton); + + magnifier_ = new QwtPlotMagnifier(canvas()); + magnifier_->setMouseButton(Qt::NoButton); + +} + +Lineplot::~Lineplot() +{ + delete[] indexPoints_; + delete[] dataPoints_; +} + +void Lineplot::setData(double* data, int n) +{ + if(numPoints_ != n) + { + numPoints_ = n; + delete[] indexPoints_; + delete[] dataPoints_; + indexPoints_ = new double[numPoints_]; + dataPoints_ = new double[numPoints_]; + if(xMin_==xMax_) + { + for(int i=0;isetRawSamples(indexPoints_, dataPoints_, numPoints_); + resetZoom(); +} + +void Lineplot::setXAxisRange(double xMin, double xMax) +{ + xMin_ = xMin; + xMax_ = xMax; + double step = (xMax_-xMin_)/numPoints_; + double val = xMin_; + for(int i=0;isetRawSamples(indexPoints_, dataPoints_, numPoints_); +} + +void Lineplot::resetZoom() +{ + zoomer_->setZoomBase(curve_->boundingRect()); +} + +void Lineplot::linkScales() +{ + setAxisScaleDiv(QwtPlot::yRight, *axisScaleDiv(QwtPlot::yLeft)); +} diff --git a/graphics/lib/common/Lineplot.h b/graphics/lib/common/Lineplot.h new file mode 100644 index 000000000..745fae126 --- /dev/null +++ b/graphics/lib/common/Lineplot.h @@ -0,0 +1,80 @@ +/** + * \file lib/generic/graphics/qt/common/Lineplot.h + * \version 1.0 + * + * \section COPYRIGHT + * + * Copyright 2012-2013 The Iris Project Developers. See the + * COPYRIGHT file at the top-level directory of this distribution + * and at http://www.softwareradiosystems.com/iris/copyright.html. + * + * \section LICENSE + * + * This file is part of the Iris Project. + * + * Iris is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * Iris is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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/. + * + * \section DESCRIPTION + * + * A simple line plotted using a QwtPlot. + */ + +#ifndef LINEPLOT_H +#define LINEPLOT_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class Lineplot + : public QwtPlot +{ + Q_OBJECT + +public: + Lineplot(QWidget* parent = 0); + virtual ~Lineplot(); + + void setData(double* data, int n); + void setXAxisRange(double xMin, double xMax); + void resetZoom(); + +public slots: + void linkScales(); + +private: + QwtPlotCurve* curve_; + + QwtPlotPanner* panner_; + QwtPlotZoomer* zoomer_; + QwtPlotMagnifier* magnifier_; + + double* indexPoints_; + double* dataPoints_; + + int numPoints_; + int counter_; + double xMin_; + double xMax_; +}; + +#endif // LINEPLOT_H diff --git a/graphics/lib/common/Pointplot.cpp b/graphics/lib/common/Pointplot.cpp new file mode 100644 index 000000000..b706851d1 --- /dev/null +++ b/graphics/lib/common/Pointplot.cpp @@ -0,0 +1,121 @@ +/** + * \file lib/generic/graphics/qt/common/Pointplot.h + * \version 1.0 + * + * \section COPYRIGHT + * + * Copyright 2012-2013 The Iris Project Developers. See the + * COPYRIGHT file at the top-level directory of this distribution + * and at http://www.softwareradiosystems.com/iris/copyright.html. + * + * \section LICENSE + * + * This file is part of the Iris Project. + * + * Iris is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * Iris is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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/. + * + * \section DESCRIPTION + * + * Implementation of a plot of complex data values as points on an IQ axis. + */ + +#include "Pointplot.h" +#include + +using namespace std; + +class MyZoomer: public QwtPlotZoomer +{ +public: + MyZoomer(QwtPlotCanvas *canvas): + QwtPlotZoomer(canvas) + { + setTrackerMode(AlwaysOn); + } + + virtual QwtText trackerTextF(const QPointF &pos) const + { + QColor bg(Qt::white); + bg.setAlpha(200); + + QwtText text = QwtPlotZoomer::trackerTextF(pos); + text.setBackgroundBrush( QBrush( bg )); + return text; + } +}; + +Pointplot::Pointplot(QWidget *parent) + :QwtPlot(parent) +{ + counter_ = 0; + numPoints_ = 1; + realPoints_ = new double[numPoints_]; + imagPoints_ = new double[numPoints_]; + + QPalette palette; + palette.setColor(canvas()->backgroundRole(), QColor("white")); + canvas()->setPalette(palette); + + setAxisScaleEngine(QwtPlot::xBottom, new QwtLinearScaleEngine); + setAxisTitle(QwtPlot::xBottom, "In-phase"); + + setAxisScaleEngine(QwtPlot::yLeft, new QwtLinearScaleEngine); + setAxisTitle(QwtPlot::yLeft, "Quadrature"); + + curve_ = new QwtPlotCurve("Constellation Points"); + curve_->attach(this); + curve_->setPen(QPen(Qt::blue, 5, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); + curve_->setStyle(QwtPlotCurve::Dots); + curve_->setRawSamples(realPoints_, imagPoints_, numPoints_); + + memset(realPoints_, 0x0, numPoints_*sizeof(double)); + memset(imagPoints_, 0x0, numPoints_*sizeof(double)); + + zoomer_ = new MyZoomer(canvas()); + zoomer_->setMousePattern(QwtEventPattern::MouseSelect1, Qt::LeftButton); + zoomer_->setMousePattern(QwtEventPattern::MouseSelect2, Qt::LeftButton, + Qt::ControlModifier); + + panner_ = new QwtPlotPanner(canvas()); + panner_->setMouseButton(Qt::RightButton); + + magnifier_ = new QwtPlotMagnifier(canvas()); + magnifier_->setMouseButton(Qt::NoButton); + +} + +Pointplot::~Pointplot() +{ + delete[] realPoints_; + delete[] imagPoints_; +} + +void Pointplot::setData(double* iData, double* qData, int n) +{ + if(numPoints_ != n) + { + numPoints_ = n; + delete[] realPoints_; + delete[] imagPoints_; + realPoints_ = new double[numPoints_]; + imagPoints_ = new double[numPoints_]; + } + + copy(iData, iData+n, realPoints_); + copy(qData, qData+n, imagPoints_); + //Need to setRawSamples again for autoscaling to work + curve_->setRawSamples(realPoints_, imagPoints_, numPoints_); + zoomer_->setZoomBase(curve_->boundingRect()); +} diff --git a/graphics/lib/common/Pointplot.h b/graphics/lib/common/Pointplot.h new file mode 100644 index 000000000..42ed25fb8 --- /dev/null +++ b/graphics/lib/common/Pointplot.h @@ -0,0 +1,76 @@ +/** + * \file lib/generic/graphics/qt/common/Pointplot.h + * \version 1.0 + * + * \section COPYRIGHT + * + * Copyright 2012-2013 The Iris Project Developers. See the + * COPYRIGHT file at the top-level directory of this distribution + * and at http://www.softwareradiosystems.com/iris/copyright.html. + * + * \section LICENSE + * + * This file is part of the Iris Project. + * + * Iris is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * Iris is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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/. + * + * \section DESCRIPTION + * + * A plot of complex data values as points on an IQ axis. + */ + +#ifndef POINTPLOT_H +#define POINTPLOT_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class Pointplot + : public QwtPlot +{ + Q_OBJECT + +public: + Pointplot(QWidget* parent = 0); + virtual ~Pointplot(); + void setData(double* iData, double* qData, int n); + +private: + QwtPlotCurve* curve_; + + QwtPlotPanner* panner_; + QwtPlotZoomer* zoomer_; + QwtPlotMagnifier* magnifier_; + + struct opReal{double operator()(std::complex i) const{return real(i);}}; + struct opImag{double operator()(std::complex i) const{return imag(i);}}; + + double* realPoints_; + double* imagPoints_; + + int numPoints_; + int counter_; +}; + +#endif // POINTPLOT_H diff --git a/graphics/lib/common/Spectrogramplot.cpp b/graphics/lib/common/Spectrogramplot.cpp new file mode 100644 index 000000000..6a6433dba --- /dev/null +++ b/graphics/lib/common/Spectrogramplot.cpp @@ -0,0 +1,198 @@ +/** + * \file lib/generic/graphics/qt/common/Spectrogramplot.cpp + * \version 1.0 + * + * \section COPYRIGHT + * + * Copyright 2012-2013 The Iris Project Developers. See the + * COPYRIGHT file at the top-level directory of this distribution + * and at http://www.softwareradiosystems.com/iris/copyright.html. + * + * \section LICENSE + * + * This file is part of the Iris Project. + * + * Iris is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * Iris is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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/. + * + * \section DESCRIPTION + * + * A spectrogram plot which acts as a waterfall. New data is plotted + * at the top row of the spectrogram and all old data is shifted + * downwards. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "Spectrogramplot.h" + +class MyZoomer: public QwtPlotZoomer +{ +public: + MyZoomer(QwtPlotCanvas *canvas): + QwtPlotZoomer(canvas) + { + setTrackerMode(AlwaysOn); + } + + virtual QwtText trackerTextF(const QPointF &pos) const + { + QColor bg(Qt::white); + bg.setAlpha(200); + + QwtText text = QwtPlotZoomer::trackerTextF(pos); + text.setBackgroundBrush( QBrush( bg )); + return text; + } +}; + +//Set up a colormap to use the "jet" colormap from matlab +class ColorMap + :public QwtLinearColorMap +{ +public: + ColorMap() + :QwtLinearColorMap(QColor(0,0,189), QColor(132,0,0)) + { + double pos; + pos = 1.0/13.0*1.0; addColorStop(pos, QColor(0,0,255)); + pos = 1.0/13.0*2.0; addColorStop(pos, QColor(0,66,255)); + pos = 1.0/13.0*3.0; addColorStop(pos, QColor(0,132,255)); + pos = 1.0/13.0*4.0; addColorStop(pos, QColor(0,189,255)); + pos = 1.0/13.0*5.0; addColorStop(pos, QColor(0,255,255)); + pos = 1.0/13.0*6.0; addColorStop(pos, QColor(66,255,189)); + pos = 1.0/13.0*7.0; addColorStop(pos, QColor(132,255,132)); + pos = 1.0/13.0*8.0; addColorStop(pos, QColor(189,255,66)); + pos = 1.0/13.0*9.0; addColorStop(pos, QColor(255,255,0)); + pos = 1.0/13.0*10.0; addColorStop(pos, QColor(255,189,0)); + pos = 1.0/13.0*12.0; addColorStop(pos, QColor(255,66,0)); + pos = 1.0/13.0*13.0; addColorStop(pos, QColor(189,0,0)); + } +}; + +Spectrogramplot::Spectrogramplot(int numDataPoints, int numRows, QWidget *parent) + :QwtPlot(parent) + ,nData_(numDataPoints) + ,nRows_(numRows) +{ + spectrogram_ = new QwtPlotSpectrogram(); + spectrogram_->setRenderThreadCount(0); // set system specific thread count + data_ = new WaterfallData(nData_, nRows_); + spectrogram_->attach(this); + + setAxisScaleEngine(QwtPlot::xBottom, new QwtLinearScaleEngine); + setAxisScaleEngine(QwtPlot::yLeft, new QwtLinearScaleEngine); + + axisScaleEngine(QwtPlot::xBottom)->setAttribute(QwtScaleEngine::Floating,true); + axisScaleEngine(QwtPlot::yLeft)->setAttribute(QwtScaleEngine::Floating,true); + + spectrogram_->setColorMap(new ColorMap()); + spectrogram_->setData(data_); + + setXAxisRange(0, nData_); + setYAxisRange(0, nRows_); + setZAxisScale(-1,1); + + // LeftButton for the zooming + // MidButton for the panning + // RightButton: zoom out by 1 + // Ctrl+RighButton: zoom out to full size + + zoomer_ = new MyZoomer(canvas()); + zoomer_->setMousePattern(QwtEventPattern::MouseSelect1, + Qt::LeftButton); + zoomer_->setMousePattern(QwtEventPattern::MouseSelect2, + Qt::LeftButton, Qt::ControlModifier); + + panner_ = new QwtPlotPanner(canvas()); + panner_->setAxisEnabled(QwtPlot::yRight, false); + panner_->setMouseButton(Qt::RightButton); + + magnifier_ = new QwtPlotMagnifier(canvas()); + magnifier_->setMouseButton(Qt::NoButton); + + // Avoid jumping when labels with more/less digits + // appear/disappear when scrolling vertically + + const QFontMetrics fm(axisWidget(QwtPlot::yLeft)->font()); + QwtScaleDraw *sd = axisScaleDraw(QwtPlot::yLeft); + sd->setMinimumExtent( fm.width("100.00") ); + + const QColor c(Qt::darkBlue); + zoomer_->setRubberBandPen(c); + zoomer_->setTrackerPen(c); +} + +void Spectrogramplot::appendData(double* data, int n) +{ + data_->appendData(data, n); +} + +void Spectrogramplot::setXAxisRange(double xMin, double xMax) +{ + xMin_ = xMin; + xMax_ = xMax; + data_->setInterval( Qt::XAxis, QwtInterval( xMin_, xMax_ ) ); + plotLayout()->setAlignCanvasToScales(true); + replot(); +} + +void Spectrogramplot::setYAxisRange(double yMin, double yMax) +{ + yMin_ = yMin; + yMax_ = yMax; + data_->setInterval( Qt::YAxis, QwtInterval( yMin_, yMax_ ) ); + plotLayout()->setAlignCanvasToScales(true); + replot(); +} + +void Spectrogramplot::setZAxisScale(double zMin, double zMax) +{ + zMin_ = zMin; + zMax_ = zMax; + data_->setInterval( Qt::ZAxis, QwtInterval( zMin_, zMax_ ) ); + + //Set up the intensity bar on the right + const QwtInterval zInterval = spectrogram_->data()->interval( Qt::ZAxis ); + QwtScaleWidget *rightAxis = axisWidget(QwtPlot::yRight); + rightAxis->setColorBarEnabled(true); + rightAxis->setColorMap( zInterval, new ColorMap()); + setAxisScale(QwtPlot::yRight, zInterval.minValue(), zInterval.maxValue() ); + enableAxis(QwtPlot::yRight); + + plotLayout()->setAlignCanvasToScales(true); + replot(); +} + +double Spectrogramplot::min() +{ + return data_->min(); +} + +double Spectrogramplot::max() +{ + return data_->max(); +} + +void Spectrogramplot::autoscale() +{ + setZAxisScale(min(),max()); +} diff --git a/graphics/lib/common/Spectrogramplot.h b/graphics/lib/common/Spectrogramplot.h new file mode 100644 index 000000000..157461070 --- /dev/null +++ b/graphics/lib/common/Spectrogramplot.h @@ -0,0 +1,79 @@ +/** + * \file lib/generic/graphics/qt/common/Spectrogramplot.h + * \version 1.0 + * + * \section COPYRIGHT + * + * Copyright 2012-2013 The Iris Project Developers. See the + * COPYRIGHT file at the top-level directory of this distribution + * and at http://www.softwareradiosystems.com/iris/copyright.html. + * + * \section LICENSE + * + * This file is part of the Iris Project. + * + * Iris is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * Iris is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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/. + * + * \section DESCRIPTION + * + * A spectrogram plot which acts as a waterfall. New data is plotted + * at the top row of the spectrogram and all old data is shifted + * downwards. + */ + +#ifndef SPECTROGRAMPLOT_H +#define SPECTROGRAMPLOT_H + +#include +#include +#include +#include +#include +#include +#include +#include "WaterfallData.h" + +class Spectrogramplot + :public QwtPlot +{ + Q_OBJECT + +public: + Spectrogramplot(int numDataPoints, int numRows, QWidget * = NULL); + void appendData(double* data, int n); + void setXAxisRange(double xMin, double xMax); + void setYAxisRange(double yMin, double yMax); + void setZAxisScale(double zMin, double zMax); + double min(); + double max(); + void autoscale(); + +private: + QwtPlotZoomer* zoomer_; + QwtPlotPanner *panner_; + QwtPlotMagnifier *magnifier_; + QwtPlotSpectrogram *spectrogram_; + WaterfallData* data_; + int nData_; + int nRows_; + double xMin_; + double xMax_; + double yMin_; + double yMax_; + double zMin_; + double zMax_; +}; + +#endif // SPECTROGRAMPLOT_H diff --git a/graphics/lib/common/WaterfallData.h b/graphics/lib/common/WaterfallData.h new file mode 100644 index 000000000..5f7ff613a --- /dev/null +++ b/graphics/lib/common/WaterfallData.h @@ -0,0 +1,90 @@ +#ifndef WATERFALLDATA_H +#define WATERFALLDATA_H + +#include +#include +#include +#include +#include +#include +#include + +class WaterfallData + :public QwtRasterData +{ +public: + typedef std::vector Vec; + typedef boost::shared_ptr< std::vector > VecPtr; + typedef boost::circular_buffer< VecPtr > VecPtrBuf; + typedef VecPtrBuf::iterator VecPtrBufIt; + + WaterfallData(int numDataPoints, int numRows) + :QwtRasterData() + ,nData_(numDataPoints) + ,nRows_(numRows) + ,data_(numRows) + { + for(int i=0;i(nData_))); + data_[0]->assign(nData_, 0.0); + } + } + + void appendData(double* data, int n) + { + assert(n == nData_); + + VecPtr v = data_.front(); + v->assign(data, data+n); + data_.push_back(v); + } + + double max() + { + Vec maxVec; + for(int i=0;ibegin(),v->end()))); + } + return *(std::max_element(maxVec.begin(),maxVec.end())); + } + + double min() + { + Vec minVec; + for(int i=0;ibegin(),v->end()))); + } + return *(std::min_element(minVec.begin(),minVec.end())); + } + + double value(double x, double y) const + { + double bottom = interval(Qt::YAxis).minValue(); + double top = interval(Qt::YAxis).maxValue(); + double left = interval(Qt::XAxis).minValue(); + double right = interval(Qt::XAxis).maxValue(); + double xStep = std::abs(right-left)/nData_; + double yStep = std::abs(top-bottom)/nRows_; + + int ix = (x-left) / xStep; + int iy = (y-bottom) / yStep; + if(ix >= nData_) + ix = nData_-1; + if(iy >= nRows_) + iy = nRows_-1; + double ret = (*data_[iy])[ix]; + return ret; + } + +private: + VecPtrBuf data_; + int nData_; + int nRows_; +}; + +#endif // WATERFALLDATA_H diff --git a/graphics/lib/common/plot.cpp b/graphics/lib/common/plot.cpp new file mode 100644 index 000000000..08e2faae3 --- /dev/null +++ b/graphics/lib/common/plot.cpp @@ -0,0 +1,65 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 "plot.h" +#include +#include +#include +#include + +pthread_t thread; +static int plot_initiated=0; + +void *qt_thread(void *arg) +{ + int argc = 1; + char* argv[] = { const_cast("libLTE Visualizer"), NULL }; + QApplication app(argc, argv); + app.exec(); + pthread_exit(NULL); +} + +int plot_init() { + if (!plot_initiated) { + /** FIXME: Set attributes to detachable */ + if (pthread_create(&thread, NULL, qt_thread, NULL)) { + perror("phtread_create"); + return -1; + } + usleep(100000); + plot_initiated=1; + } + return 0; +} + +void plot_exit() { + if (plot_initiated) { + pthread_cancel(thread); + } +} + diff --git a/graphics/lib/complexplot/ComplexWidget.cpp b/graphics/lib/complexplot/ComplexWidget.cpp new file mode 100644 index 000000000..39646fc37 --- /dev/null +++ b/graphics/lib/complexplot/ComplexWidget.cpp @@ -0,0 +1,195 @@ +#include "ComplexWidget.h" +#include "Lineplot.h" +#include "Events.h" + +#include +#include + +using namespace std; + +ComplexWidget::ComplexWidget(QWidget *parent) + :QWidget(parent) +{ + i_ = new Lineplot(); + q_ = new Lineplot(); + m_ = new Lineplot(); + p_ = new Lineplot(); + + i_->setAxisTitle(QwtPlot::xBottom, "In-phase"); + q_->setAxisTitle(QwtPlot::xBottom, "Quadrature"); + m_->setAxisTitle(QwtPlot::xBottom, "Magnitude"); + p_->setAxisTitle(QwtPlot::xBottom, "Phase"); + + QVBoxLayout* vLayout1 = new QVBoxLayout(this); + vLayout1->addWidget(i_); + vLayout1->addWidget(q_); + vLayout1->addWidget(m_); + vLayout1->addWidget(p_); + + numPoints_ = 16; + iData_ = new double[numPoints_]; + qData_ = new double[numPoints_]; + mData_ = new double[numPoints_]; + pData_ = new double[numPoints_]; + timerId_ = startTimer(10); + haveNewData_ = false; +} + +ComplexWidget::~ComplexWidget() +{ + delete i_; + delete q_; + delete m_; + delete p_; +} + +void ComplexWidget::customEvent( QEvent * e ) +{ + if(e->type() == ComplexDataEvent::type) + { + ComplexDataEvent* dataEvent = (ComplexDataEvent*)e; + setData(dataEvent); + } +} + +void ComplexWidget::timerEvent(QTimerEvent *event) +{ + if(event->timerId() == timerId_) + { + if(haveNewData_) + { + i_->replot(); + q_->replot(); + m_->replot(); + p_->replot(); + haveNewData_ = false; + } + return; + } + QWidget::timerEvent(event); +} + +void ComplexWidget::setData(ComplexDataEvent* e) +{ + if(e->numPoints_ != numPoints_) + { + numPoints_ = e->numPoints_; + delete [] iData_; + delete [] qData_; + delete [] mData_; + delete [] pData_; + + iData_ = new double[numPoints_]; + qData_ = new double[numPoints_]; + mData_ = new double[numPoints_]; + pData_ = new double[numPoints_]; + } + + transform(e->dataPoints_, &e->dataPoints_[numPoints_], iData_, opReal()); + transform(e->dataPoints_, &e->dataPoints_[numPoints_], qData_, opImag()); + transform(e->dataPoints_, &e->dataPoints_[numPoints_], mData_, opAbs()); + transform(e->dataPoints_, &e->dataPoints_[numPoints_], pData_, opArg()); + + i_->setData(iData_, numPoints_); + q_->setData(qData_, numPoints_); + m_->setData(mData_, numPoints_); + p_->setData(pData_, numPoints_); + haveNewData_ = true; +} + +void ComplexWidget::setWidgetTitle(QString title) +{ + setWindowTitle(title); +} + +void ComplexWidget::setWidgetXAxisScale(int id, double xMin, double xMax) +{ + switch(id) + { + case 0: + i_->setAxisScale(QwtPlot::xBottom, xMin, xMax); + break; + case 1: + q_->setAxisScale(QwtPlot::xBottom, xMin, xMax); + break; + case 2: + m_->setAxisScale(QwtPlot::xBottom, xMin, xMax); + break; + case 3: + p_->setAxisScale(QwtPlot::xBottom, xMin, xMax); + break; + default: + break; + } +} + +void ComplexWidget::setWidgetYAxisScale(int id, double yMin, double yMax) +{ + switch(id) + { + case 0: + i_->setAxisScale(QwtPlot::yLeft, yMin, yMax); + break; + case 1: + q_->setAxisScale(QwtPlot::yLeft, yMin, yMax); + break; + case 2: + m_->setAxisScale(QwtPlot::yLeft, yMin, yMax); + break; + case 3: + p_->setAxisScale(QwtPlot::yLeft, yMin, yMax); + break; + default: + break; + } +} + +void ComplexWidget::setWidgetXAxisAutoScale(int id, bool on=true) +{ + switch(id) + { + case 0: + i_->setAxisAutoScale(QwtPlot::xBottom, on); + break; + case 1: + q_->setAxisAutoScale(QwtPlot::xBottom, on); + break; + case 2: + m_->setAxisAutoScale(QwtPlot::xBottom, on); + break; + case 3: + p_->setAxisAutoScale(QwtPlot::xBottom, on); + break; + default: + break; + } +} + +void ComplexWidget::setWidgetYAxisAutoScale(int id, bool on=true) +{ + switch(id) + { + case 0: + i_->setAxisAutoScale(QwtPlot::yLeft, on); + break; + case 1: + q_->setAxisAutoScale(QwtPlot::yLeft, on); + break; + case 2: + m_->setAxisAutoScale(QwtPlot::yLeft, on); + break; + case 3: + p_->setAxisAutoScale(QwtPlot::yLeft, on); + break; + default: + break; + } +} + +void ComplexWidget::setWidgetXAxisRange(double xMin, double xMax) +{ + i_->setXAxisRange(xMin, xMax); + q_->setXAxisRange(xMin, xMax); + m_->setXAxisRange(xMin, xMax); + p_->setXAxisRange(xMin, xMax); +} diff --git a/graphics/lib/complexplot/ComplexWidget.h b/graphics/lib/complexplot/ComplexWidget.h new file mode 100644 index 000000000..e50dcff76 --- /dev/null +++ b/graphics/lib/complexplot/ComplexWidget.h @@ -0,0 +1,53 @@ +#ifndef COMPLEXWIDGET_H +#define COMPLEXWIDGET_H + +#include +#include +#include + +class ComplexDataEvent; +class Lineplot; + +class ComplexWidget + : public QWidget +{ + Q_OBJECT + +public: + ComplexWidget(QWidget* parent = 0); + virtual ~ComplexWidget(); + +public slots: + void customEvent( QEvent * e ); + void setWidgetTitle(QString title); + void setWidgetXAxisScale(int id, double xMin, double xMax); + void setWidgetYAxisScale(int id, double yMin, double yMax); + void setWidgetXAxisAutoScale(int id, bool on); + void setWidgetYAxisAutoScale(int id, bool on); + void setWidgetXAxisRange(double xMin, double xMax); + +protected: + virtual void timerEvent(QTimerEvent *event); + +private: + void setData(ComplexDataEvent* e); + Lineplot* i_; //In-phase plot + Lineplot* q_; //Quadrature plot + Lineplot* m_; //Magnitude plot + Lineplot* p_; //Phase plot + + struct opReal{double operator()(std::complex i) const{return real(i);}}; + struct opImag{double operator()(std::complex i) const{return imag(i);}}; + struct opAbs{double operator()(std::complex i) const{return abs(i);}}; + struct opArg{double operator()(std::complex i) const{return arg(i);}}; + + double* iData_; + double* qData_; + double* mData_; + double* pData_; + int numPoints_; + int timerId_; + bool haveNewData_; +}; + +#endif // COMPLEXWIDGET_H diff --git a/graphics/lib/complexplot/Complexplot.cpp b/graphics/lib/complexplot/Complexplot.cpp new file mode 100644 index 000000000..6e520214d --- /dev/null +++ b/graphics/lib/complexplot/Complexplot.cpp @@ -0,0 +1,55 @@ +#include "Complexplot.h" +#include "ComplexplotWrapper.h" + +using namespace std; + +Complexplot::Complexplot() +{ + plot_ = new ComplexplotWrapper; +} + +Complexplot::~Complexplot() +{ + delete plot_; +} + +void Complexplot::setNewData(complex* data, int numPoints) +{ + plot_->setNewData(data, numPoints); +} + +void Complexplot::setNewData(complex* data, int numPoints) +{ + plot_->setNewData(data, numPoints); +} + +void Complexplot::setTitle(std::string title) +{ + plot_->setTitle(title); +} + +void Complexplot::setXAxisAutoScale(PlotId id, bool on=true) +{ + plot_->setXAxisAutoScale(id, on); +} + +void Complexplot::setYAxisAutoScale(PlotId id, bool on=true) +{ + plot_->setYAxisAutoScale(id, on); +} + +void Complexplot::setXAxisScale(PlotId id, double xMin, double xMax) +{ + plot_->setXAxisScale(id, xMin, xMax); +} + +void Complexplot::setYAxisScale(PlotId id, double yMin, double yMax) +{ + plot_->setYAxisScale(id, yMin, yMax); +} + +void Complexplot::setXAxisRange(double xMin, double xMax) +{ + plot_->setXAxisRange(xMin, xMax); +} + diff --git a/graphics/lib/complexplot/Complexplot.h b/graphics/lib/complexplot/Complexplot.h new file mode 100644 index 000000000..19c1ccee0 --- /dev/null +++ b/graphics/lib/complexplot/Complexplot.h @@ -0,0 +1,53 @@ +#ifndef COMPLEXPLOT_H +#define COMPLEXPLOT_H + +#include +#include + +class ComplexplotWrapper; + +class Complexplot +{ +public: + enum PlotId + { + I, + Q, + Magnitude, + Phase + }; + Complexplot(); + ~Complexplot(); + + template + void setNewData(Iterator begin, Iterator end); + void setNewData(std::complex* data, int numPoints); + void setNewData(std::complex* data, int numPoints); + void setTitle(std::string title); + void setXAxisAutoScale(PlotId id, bool on); + void setYAxisAutoScale(PlotId id, bool on); + void setXAxisScale(PlotId id, double xMin, double xMax); + void setYAxisScale(PlotId id, double yMin, double yMax); + void setXAxisRange(double xMin, double xMax); + +private: + ComplexplotWrapper* plot_; +}; + +template +void Complexplot::setNewData(Iterator begin, Iterator end) +{ + int numPoints = end-begin; + std::complex* data = new std::complex[numPoints]; + + for(int i=0;begin!=end;begin++,i++) + { + data[i] = *begin; + } + + setNewData(data, numPoints); + + delete[] data; +} + +#endif // COMPLEXPLOT_H diff --git a/graphics/lib/complexplot/ComplexplotWrapper.cpp b/graphics/lib/complexplot/ComplexplotWrapper.cpp new file mode 100644 index 000000000..abfc819c2 --- /dev/null +++ b/graphics/lib/complexplot/ComplexplotWrapper.cpp @@ -0,0 +1,141 @@ +#include "ComplexplotWrapper.h" + +#include "ComplexWidget.h" +#include "Events.h" +#include +#include + +using namespace std; + + +ComplexplotWrapper::ComplexplotWrapper() + :widget_(NULL) + ,destroyed_(true) +{ + if(QCoreApplication::instance() == NULL) + return; //TODO: throw exception here in Iris + if(QCoreApplication::instance()->thread() == QThread::currentThread()) + { + connect( this, SIGNAL( createWidgetSignal() ), + this, SLOT(createWidgetSlot()) ); + connect( this, SIGNAL( destroyWidgetSignal() ), + this, SLOT(destroyWidgetSlot()) ); + connect( this, SIGNAL( destroyWidgetSignalBlocking() ), + this, SLOT(destroyWidgetSlot()) ); + } + else + { + connect( this, SIGNAL( createWidgetSignal() ), + this, SLOT(createWidgetSlot()), + Qt::BlockingQueuedConnection ); + connect( this, SIGNAL( destroyWidgetSignal() ), + this, SLOT(destroyWidgetSlot()) ); + connect( this, SIGNAL( destroyWidgetSignalBlocking() ), + this, SLOT(destroyWidgetSlot()), + Qt::BlockingQueuedConnection ); + moveToThread(QCoreApplication::instance()->thread()); + } + emit createWidgetSignal(); +} + +ComplexplotWrapper::~ComplexplotWrapper() +{ + if(destroyed_) + emit destroyWidgetSignal(); + else + emit destroyWidgetSignalBlocking(); +} + +void ComplexplotWrapper::createWidgetSlot() +{ + widget_ = new ComplexWidget; + destroyed_ = false; + widget_->setAttribute(Qt::WA_DeleteOnClose, true); + connect(widget_, SIGNAL( destroyed() ), + this, SLOT( widgetDestroyed() )); + connect(this, SIGNAL(setWidgetTitle(QString)), + widget_, SLOT(setWidgetTitle(QString))); + connect(this, SIGNAL(setWidgetXAxisScale(int,double,double)), + widget_, SLOT(setWidgetXAxisScale(int,double,double))); + connect(this, SIGNAL(setWidgetYAxisScale(int,double,double)), + widget_, SLOT(setWidgetYAxisScale(int,double,double))); + connect(this, SIGNAL(setWidgetXAxisAutoScale(int,bool)), + widget_, SLOT(setWidgetXAxisAutoScale(int,bool))); + connect(this, SIGNAL(setWidgetYAxisAutoScale(int,bool)), + widget_, SLOT(setWidgetYAxisAutoScale(int,bool))); + connect(this, SIGNAL(setWidgetXAxisRange(double,double)), + widget_, SLOT(setWidgetXAxisRange(double,double))); + + widget_->resize( 800, 600 ); + widget_->show(); +} + +void ComplexplotWrapper::destroyWidgetSlot() +{ + if(widget_) + delete widget_; + widget_ = NULL; +} + +void ComplexplotWrapper::widgetDestroyed() +{ + destroyed_ = true; +} + +void ComplexplotWrapper::setNewData(complex* data, int numPoints) +{ + if(destroyed_) + return; + qApp->postEvent(widget_, new ComplexDataEvent(data, numPoints)); +} + +void ComplexplotWrapper::setNewData(complex* data, int numPoints) +{ + if(destroyed_) + return; + qApp->postEvent(widget_, new ComplexDataEvent(data, numPoints)); +} + +void ComplexplotWrapper::setTitle(std::string title) +{ + if(destroyed_) + return; + QString str = QString::fromUtf8(title.c_str()); + emit setWidgetTitle(str); +} + +void ComplexplotWrapper::setXAxisAutoScale(int id, bool on=true) +{ + if(destroyed_) + return; + emit setWidgetXAxisAutoScale(id, on); +} + +void ComplexplotWrapper::setYAxisAutoScale(int id, bool on=true) +{ + if(destroyed_) + return; + emit setWidgetYAxisAutoScale(id, on); +} + +void ComplexplotWrapper::setXAxisScale(int id, double xMin, double xMax) +{ + if(destroyed_) + return; + emit setWidgetXAxisScale(id, xMin, xMax); +} + +void ComplexplotWrapper::setYAxisScale(int id, double yMin, double yMax) +{ + if(destroyed_) + return; + emit setWidgetYAxisScale(id, yMin, yMax); +} + +void ComplexplotWrapper::setXAxisRange(double xMin, double xMax) +{ + if(destroyed_) + return; + emit setWidgetXAxisRange(xMin, xMax); +} + diff --git a/graphics/lib/complexplot/ComplexplotWrapper.h b/graphics/lib/complexplot/ComplexplotWrapper.h new file mode 100644 index 000000000..2d64c1b11 --- /dev/null +++ b/graphics/lib/complexplot/ComplexplotWrapper.h @@ -0,0 +1,48 @@ +#ifndef COMPLEXPLOTWRAPPER_H +#define COMPLEXPLOTWRAPPER_H + +#include +#include + +class ComplexWidget; + +class ComplexplotWrapper + : QObject +{ + Q_OBJECT + +public: + ComplexplotWrapper(); + ~ComplexplotWrapper(); + + void setNewData(std::complex* data, int numPoints); + void setNewData(std::complex* data, int numPoints); + void setTitle(std::string title); + void setXAxisAutoScale(int id, bool on); + void setYAxisAutoScale(int id, bool on); + void setXAxisScale(int id, double xMin, double xMax); + void setYAxisScale(int id, double yMin, double yMax); + void setXAxisRange(double xMin, double xMax); + +public slots: + void createWidgetSlot(); + void destroyWidgetSlot(); + void widgetDestroyed(); + +signals: + void createWidgetSignal(); + void destroyWidgetSignal(); + void destroyWidgetSignalBlocking(); + void setWidgetTitle(QString title); + void setWidgetXAxisAutoScale(int id, bool on); + void setWidgetYAxisAutoScale(int id, bool on); + void setWidgetXAxisScale(int id, double xMin, double xMax); + void setWidgetYAxisScale(int id, double yMin, double yMax); + void setWidgetXAxisRange(double xMin, double xMax); + +private: + ComplexWidget* widget_; + bool destroyed_; +}; + +#endif // COMPLEXPLOTWRAPPER_H diff --git a/graphics/lib/complexplot/plot_complex.cpp b/graphics/lib/complexplot/plot_complex.cpp new file mode 100644 index 000000000..0f6b07c86 --- /dev/null +++ b/graphics/lib/complexplot/plot_complex.cpp @@ -0,0 +1,76 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 "plot/plot_complex.h" +#include "Complexplot.h" +#include + + +int plot_complex_init(plot_complex_t *h) { + *h = (void*) new Complexplot(); + return (*h != NULL)?0:-1; +} + +void plot_complex_setTitle(plot_complex_t *h, char *title) { + Complexplot *plot = static_cast(*h); + plot->setTitle(title); +} + +void plot_complex_setNewData(plot_complex_t *h, _Complex float *data, + int num_points) { + Complexplot *plot = static_cast(*h); + plot->setNewData(reinterpret_cast*> (data), num_points); +} + + +void plot_complex_setXAxisAutoScale(plot_complex_t *h, plot_complex_id_t id, bool on) { + Complexplot *plot = static_cast(*h); + plot->setXAxisAutoScale(static_cast (id), on); +} + +void plot_complex_setYAxisAutoScale(plot_complex_t *h, plot_complex_id_t id, bool on) { + Complexplot *plot = static_cast(*h); + plot->setYAxisAutoScale(static_cast (id), on); +} + +void plot_complex_setXAxisScale(plot_complex_t *h, plot_complex_id_t id, double xMin, double xMax) { + Complexplot *plot = static_cast(*h); + plot->setXAxisScale(static_cast (id), xMin, xMax); +} + +void plot_complex_setYAxisScale(plot_complex_t *h, plot_complex_id_t id, double yMin, double yMax) { + Complexplot *plot = static_cast(*h); + plot->setYAxisScale(static_cast (id), yMin, yMax); +} + +void plot_complex_setXAxisRange(plot_complex_t *h, double xMin, double xMax) { + Complexplot *plot = static_cast(*h); + plot->setXAxisRange(xMin, xMax); +} diff --git a/graphics/lib/complexplot/test/CMakeLists.txt b/graphics/lib/complexplot/test/CMakeLists.txt new file mode 100644 index 000000000..214a73f92 --- /dev/null +++ b/graphics/lib/complexplot/test/CMakeLists.txt @@ -0,0 +1,31 @@ +# +# Copyright 2012-2013 The Iris Project Developers. See the +# COPYRIGHT file at the top-level directory of this distribution +# and at http://www.softwareradiosystems.com/iris/copyright.html. +# +# This file is part of the Iris Project. +# +# Iris is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# Iris is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# A copy of the GNU Lesser 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/. +# + +######################################################################## +# Build tests +######################################################################## +#turn the test cpp file into an executable with an int main() function +INCLUDE_DIRECTORIES(..) +ADD_EXECUTABLE(complexplot_test complexplot_test.cpp) +TARGET_LINK_LIBRARIES(complexplot_test pthread graphics) +ADD_TEST(complexplot_test complexplot_test) + diff --git a/graphics/lib/complexplot/test/complexplot_test.cpp b/graphics/lib/complexplot/test/complexplot_test.cpp new file mode 100644 index 000000000..e3f7f93de --- /dev/null +++ b/graphics/lib/complexplot/test/complexplot_test.cpp @@ -0,0 +1,144 @@ +/** + * \file lib/generic/modulation/Crc_test.cpp + * \version 1.0 + * + * \section COPYRIGHT + * + * Copyright 2012-2013 The Iris Project Developers. See the + * COPYRIGHT file at the top-level directory of this distribution + * and at http://www.softwareradiosystems.com/iris/copyright.html. + * + * \section LICENSE + * + * This file is part of the Iris Project. + * + * Iris is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * Iris is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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/. + * + * \section DESCRIPTION + * + * Main test file for Complexplot class. + */ + +#include "Complexplot.h" + +#include +#include +#include +#include +#include +#include +#include + +#define PI 3.14159265358979323846 + +using namespace std; + +typedef vector > FloatVec; + +void *threadMain1(void *arg) { + Complexplot plot; + plot.setTitle("Float"); + plot.setXAxisRange(0, 2); + plot.setYAxisScale(Complexplot::Magnitude, 0.9, 1.1); + + int n = 1024; + float step = 2.0 * PI / n; + complex* data = new complex [n]; + for (int i = 0; i < n; i++) + data[i] = polar(1.0f, step * i); + + plot.setNewData(data, n); + + for (int i = 0; i < n; i++) { + rotate(data, data + 1, data + n); + plot.setNewData(data, n); + usleep(1000); + } + return NULL; +} + +void *threadMain2(void *arg) { + Complexplot plot; + plot.setTitle("Double"); + plot.setXAxisRange(0, 2); + plot.setYAxisScale(Complexplot::Magnitude, 0.9, 1.1); + + int n = 1024; + double step = 2.0 * PI / n; + complex* data = new complex [n]; + for (int i = 0; i < n; i++) + data[i] = polar(1.0, step * i); + + plot.setNewData(data, n); + + for (int i = 0; i < n; i++) { + rotate(data, data + 1, data + n); + plot.setNewData(data, n); + usleep(1000); + } + return NULL; +} + +void *threadMain3(void *arg) { + + Complexplot plot; + plot.setTitle("FloatVec"); + plot.setXAxisRange(0, 2); + plot.setYAxisScale(Complexplot::Magnitude, 0.9, 1.1); + + FloatVec data(1024); + int n = data.size(); + float step = 2.0 * PI / n; + for (int i = 0; i < n; i++) + data[i] = polar(1.0f, step * i); + + plot.setNewData(data.begin(), data.end()); + + for (int i = 0; i < n; i++) { + rotate(data.begin(), data.begin() + 1, data.end()); + plot.setNewData(data.begin(), data.end()); + usleep(1000); + } + return NULL; +} + +int main(int argc, char *argv[]) { + int argc2 = 1; + char* argv2[] = { const_cast("Compleplot_Basic_Test"), NULL }; + QApplication a(argc2, argv2); + pthread_t threads[3]; + int i; + + if (pthread_create(&threads[0], NULL, threadMain1, NULL)) { + perror("pthread_create"); + exit(-1); + } + if (pthread_create(&threads[1], NULL, threadMain2, NULL)) { + perror("pthread_create"); + exit(-1); + } + if (pthread_create(&threads[2], NULL, threadMain3, NULL)) { + perror("pthread_create"); + exit(-1); + } + + qApp->exec(); + + for (i=0;i<3;i++) { + pthread_join(threads[i], NULL); + } + exit(0); +} + diff --git a/graphics/lib/realplot/RealWidget.cpp b/graphics/lib/realplot/RealWidget.cpp new file mode 100644 index 000000000..85b10844d --- /dev/null +++ b/graphics/lib/realplot/RealWidget.cpp @@ -0,0 +1,100 @@ +#include "RealWidget.h" +#include "Lineplot.h" +#include "Events.h" + +#include +#include + +using namespace std; + +RealWidget::RealWidget(QWidget *parent) + :QWidget(parent) +{ + l_ = new Lineplot(); + QVBoxLayout* vLayout1 = new QVBoxLayout(this); + vLayout1->addWidget(l_); + + numPoints_ = 16; + dataPoints_ = new double[numPoints_]; + timerId_ = startTimer(10); + haveNewData_ = false; +} + +RealWidget::~RealWidget() +{ + delete l_; +} + +void RealWidget::customEvent( QEvent * e ) +{ + if(e->type() == RealDataEvent::type) + { + RealDataEvent* dataEvent = (RealDataEvent*)e; + setData(dataEvent); + } +} + +void RealWidget::timerEvent(QTimerEvent *event) +{ + if(event->timerId() == timerId_) + { + if(haveNewData_) + { + l_->replot(); + haveNewData_ = false; + } + return; + } + QWidget::timerEvent(event); +} + +void RealWidget::setData(RealDataEvent* e) +{ + if(e->numPoints_ != numPoints_) + { + numPoints_ = e->numPoints_; + delete [] dataPoints_; + dataPoints_ = new double[numPoints_]; + } + for(int i=0;idataPoints_[i]; + + l_->setData(dataPoints_, numPoints_); + haveNewData_ = true; +} + +void RealWidget::setWidgetTitle(QString title) +{ + l_->setTitle(title); +} + +void RealWidget::setWidgetAxisLabels(QString xLabel, QString yLabel) +{ + l_->setAxisTitle(QwtPlot::xBottom, xLabel); + l_->setAxisTitle(QwtPlot::yLeft, yLabel); +} + +void RealWidget::setWidgetXAxisScale(double xMin, double xMax) +{ + l_->setAxisScale(QwtPlot::xBottom, xMin, xMax); +} + +void RealWidget::setWidgetYAxisScale(double yMin, double yMax) +{ + l_->setAxisScale(QwtPlot::yLeft, yMin, yMax); +} + +void RealWidget::setWidgetXAxisAutoScale(bool on=true) +{ + l_->setAxisAutoScale(QwtPlot::xBottom, on); +} + +void RealWidget::setWidgetYAxisAutoScale(bool on=true) +{ + l_->setAxisAutoScale(QwtPlot::yLeft, on); +} + +void RealWidget::setWidgetXAxisRange(double xMin, double xMax) +{ + l_->setXAxisRange(xMin, xMax); +} diff --git a/graphics/lib/realplot/RealWidget.h b/graphics/lib/realplot/RealWidget.h new file mode 100644 index 000000000..b03183f20 --- /dev/null +++ b/graphics/lib/realplot/RealWidget.h @@ -0,0 +1,43 @@ +#ifndef REALWIDGET_H +#define REALWIDGET_H + +#include +#include +#include + +class RealDataEvent; +class Lineplot; + +class RealWidget + : public QWidget +{ + Q_OBJECT + +public: + RealWidget(QWidget* parent = 0); + virtual ~RealWidget(); + +public slots: + void customEvent( QEvent * e ); + void setWidgetTitle(QString title); + void setWidgetAxisLabels(QString xLabel, QString yLabel); + void setWidgetXAxisScale(double xMin, double xMax); + void setWidgetYAxisScale(double yMin, double yMax); + void setWidgetXAxisAutoScale(bool on); + void setWidgetYAxisAutoScale(bool on); + void setWidgetXAxisRange(double xMin, double xMax); + +protected: + virtual void timerEvent(QTimerEvent *event); + +private: + void setData(RealDataEvent* e); + Lineplot* l_; //The line plot + + double* dataPoints_; + int numPoints_; + int timerId_; + bool haveNewData_; +}; + +#endif // REALWIDGET_H diff --git a/graphics/lib/realplot/Realplot.cpp b/graphics/lib/realplot/Realplot.cpp new file mode 100644 index 000000000..561f71278 --- /dev/null +++ b/graphics/lib/realplot/Realplot.cpp @@ -0,0 +1,58 @@ +#include "Realplot.h" +#include "RealplotWrapper.h" + +Realplot::Realplot() +{ + plot_ = new RealplotWrapper; +} + +Realplot::~Realplot() +{ + delete plot_; +} + +void Realplot::setNewData(double* data, int numPoints) +{ + plot_->setNewData(data, numPoints); +} + +void Realplot::setNewData(float* data, int numPoints) +{ + plot_->setNewData(data, numPoints); +} + +void Realplot::setTitle(std::string title) +{ + plot_->setTitle(title); +} + +void Realplot::setXAxisScale(double xMin, double xMax) +{ + plot_->setXAxisScale(xMin, xMax); +} + +void Realplot::setYAxisScale(double yMin, double yMax) +{ + plot_->setYAxisScale(yMin, yMax); +} + +void Realplot::setXAxisAutoScale(bool on=true) +{ + plot_->setXAxisAutoScale(on); +} + +void Realplot::setYAxisAutoScale(bool on=true) +{ + plot_->setYAxisAutoScale(on); +} + +void Realplot::setXAxisRange(double xMin, double xMax) +{ + plot_->setXAxisRange(xMin, xMax); +} + +void Realplot::setLabels(std::string xLabel, std::string yLabel) +{ + plot_->setAxisLabels(xLabel, yLabel); +} + diff --git a/graphics/lib/realplot/Realplot.h b/graphics/lib/realplot/Realplot.h new file mode 100644 index 000000000..f495cd3c3 --- /dev/null +++ b/graphics/lib/realplot/Realplot.h @@ -0,0 +1,46 @@ +#ifndef REALPLOT_H +#define REALPLOT_H + +#include + +class RealplotWrapper; + +class Realplot +{ +public: + Realplot(); + ~Realplot(); + + template + void setNewData(Iterator begin, Iterator end); + void setNewData(float* data, int numPoints); + void setNewData(double* data, int numPoints); + void setTitle(std::string title); + void setXAxisScale(double xMin, double xMax); + void setYAxisScale(double yMin, double yMax); + void setXAxisAutoScale(bool on); + void setYAxisAutoScale(bool on); + void setXAxisRange(double xMin, double xMax); + void setLabels(std::string xLabel, std::string yLabel); + +private: + RealplotWrapper* plot_; +}; + +template +void Realplot::setNewData(Iterator begin, Iterator end) +{ + int numPoints = end-begin; + double* data = new double[numPoints]; + + for(int i=0;begin!=end;begin++,i++) + { + data[i] = *begin; + } + + setNewData(data, numPoints); + + delete[] data; +} + +#endif // REALPLOT_H diff --git a/graphics/lib/realplot/RealplotWrapper.cpp b/graphics/lib/realplot/RealplotWrapper.cpp new file mode 100644 index 000000000..975987621 --- /dev/null +++ b/graphics/lib/realplot/RealplotWrapper.cpp @@ -0,0 +1,147 @@ +#include "RealplotWrapper.h" + +#include "RealWidget.h" +#include "Events.h" +#include +#include + + +RealplotWrapper::RealplotWrapper() + :widget_(NULL) + ,destroyed_(true) +{ + if(QCoreApplication::instance() == NULL) + return; //TODO: throw exception here in Iris + if(QCoreApplication::instance()->thread() == QThread::currentThread()) + { + connect( this, SIGNAL( createWidgetSignal() ), + this, SLOT(createWidgetSlot()) ); + connect( this, SIGNAL( destroyWidgetSignal() ), + this, SLOT(destroyWidgetSlot()) ); + connect( this, SIGNAL( destroyWidgetSignalBlocking() ), + this, SLOT(destroyWidgetSlot()) ); + } + else + { + connect( this, SIGNAL( createWidgetSignal() ), + this, SLOT(createWidgetSlot()), + Qt::BlockingQueuedConnection ); + connect( this, SIGNAL( destroyWidgetSignal() ), + this, SLOT(destroyWidgetSlot()) ); + connect( this, SIGNAL( destroyWidgetSignalBlocking() ), + this, SLOT(destroyWidgetSlot()), + Qt::BlockingQueuedConnection ); + moveToThread(QCoreApplication::instance()->thread()); + } + emit createWidgetSignal(); +} + +RealplotWrapper::~RealplotWrapper() +{ + if(destroyed_) + emit destroyWidgetSignal(); + else + emit destroyWidgetSignalBlocking(); +} + +void RealplotWrapper::createWidgetSlot() +{ + widget_ = new RealWidget; + destroyed_ = false; + widget_->setAttribute(Qt::WA_DeleteOnClose, true); + connect(widget_, SIGNAL( destroyed() ), + this, SLOT( widgetDestroyed() )); + connect(this, SIGNAL(setWidgetTitle(QString)), + widget_, SLOT(setWidgetTitle(QString))); + connect(this, SIGNAL(setWidgetAxisLabels(QString, QString)), + widget_, SLOT(setWidgetAxisLabels(QString, QString))); + connect(this, SIGNAL(setWidgetXAxisScale(double,double)), + widget_, SLOT(setWidgetXAxisScale(double,double))); + connect(this, SIGNAL(setWidgetYAxisScale(double,double)), + widget_, SLOT(setWidgetYAxisScale(double,double))); + connect(this, SIGNAL(setWidgetXAxisAutoScale(bool)), + widget_, SLOT(setWidgetXAxisAutoScale(bool))); + connect(this, SIGNAL(setWidgetYAxisAutoScale(bool)), + widget_, SLOT(setWidgetYAxisAutoScale(bool))); + connect(this, SIGNAL(setWidgetXAxisRange(double,double)), + widget_, SLOT(setWidgetXAxisRange(double,double))); + + widget_->resize( 800, 600 ); + widget_->show(); +} + +void RealplotWrapper::destroyWidgetSlot() +{ + delete widget_; +} + +void RealplotWrapper::widgetDestroyed() +{ + destroyed_ = true; +} + +void RealplotWrapper::setNewData(double* data, int numPoints) +{ + if(destroyed_) + return; + qApp->postEvent(widget_, new RealDataEvent(data, numPoints)); +} + +void RealplotWrapper::setNewData(float* data, int numPoints) +{ + if(destroyed_) + return; + qApp->postEvent(widget_, new RealDataEvent(data, numPoints)); +} + +void RealplotWrapper::setTitle(std::string title) +{ + if(destroyed_) + return; + QString str = QString::fromUtf8(title.c_str()); + emit setWidgetTitle(str); +} + +void RealplotWrapper::setAxisLabels(std::string xLabel, std::string yLabel) +{ + if(destroyed_) + return; + QString xStr = QString::fromUtf8(xLabel.c_str()); + QString yStr = QString::fromUtf8(yLabel.c_str()); + emit setWidgetAxisLabels(xStr, yStr); +} + +void RealplotWrapper::setXAxisScale(double xMin, double xMax) +{ + if(destroyed_) + return; + emit setWidgetXAxisScale(xMin, xMax); +} + +void RealplotWrapper::setYAxisScale(double yMin, double yMax) +{ + if(destroyed_) + return; + emit setWidgetYAxisScale(yMin, yMax); +} + +void RealplotWrapper::setXAxisAutoScale(bool on=true) +{ + if(destroyed_) + return; + emit setWidgetXAxisAutoScale(on); +} + +void RealplotWrapper::setYAxisAutoScale(bool on=true) +{ + if(destroyed_) + return; + emit setWidgetYAxisAutoScale(on); +} + +void RealplotWrapper::setXAxisRange(double xMin, double xMax) +{ + if(destroyed_) + return; + emit setWidgetXAxisRange(xMin, xMax); +} diff --git a/graphics/lib/realplot/RealplotWrapper.h b/graphics/lib/realplot/RealplotWrapper.h new file mode 100644 index 000000000..b5750c609 --- /dev/null +++ b/graphics/lib/realplot/RealplotWrapper.h @@ -0,0 +1,49 @@ +#ifndef REALPLOTWRAPPER_H +#define REALPLOTWRAPPER_H + +#include + +class RealWidget; + +class RealplotWrapper + : QObject +{ + Q_OBJECT + +public: + RealplotWrapper(); + ~RealplotWrapper(); + + void setNewData(float* data, int numPoints); + void setNewData(double* data, int numPoints); + void setTitle(std::string title); + void setAxisLabels(std::string xLabel, std::string yLabel); + void setXAxisScale(double xMin, double xMax); + void setYAxisScale(double yMin, double yMax); + void setXAxisAutoScale(bool on); + void setYAxisAutoScale(bool on); + void setXAxisRange(double xMin, double xMax); + +public slots: + void createWidgetSlot(); + void destroyWidgetSlot(); + void widgetDestroyed(); + +signals: + void createWidgetSignal(); + void destroyWidgetSignal(); + void destroyWidgetSignalBlocking(); + void setWidgetTitle(QString title); + void setWidgetAxisLabels(QString xLabel, QString yLabel); + void setWidgetXAxisScale(double xMin, double xMax); + void setWidgetYAxisScale(double yMin, double yMax); + void setWidgetXAxisAutoScale(bool on); + void setWidgetYAxisAutoScale(bool on); + void setWidgetXAxisRange(double xMin, double xMax); + +private: + RealWidget* widget_; + bool destroyed_; +}; + +#endif // REALPLOTWRAPPER_H diff --git a/graphics/lib/realplot/plot_real.cpp b/graphics/lib/realplot/plot_real.cpp new file mode 100644 index 000000000..92fd745d3 --- /dev/null +++ b/graphics/lib/realplot/plot_real.cpp @@ -0,0 +1,79 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 "plot/plot_real.h" +#include "Realplot.h" +#include + + +int plot_real_init(plot_real_t *h) { + *h = (void*) new Realplot(); + return (*h != NULL)?0:-1; +} + +void plot_real_setTitle(plot_real_t *h, char *title) { + Realplot *plot = static_cast(*h); + plot->setTitle(title); +} +void plot_real_setNewData(plot_real_t *h, float *data, + int num_points) { + Realplot *plot = static_cast(*h); + plot->setNewData(data, num_points); + +} + +void plot_real_setXAxisAutoScale(plot_real_t *h, bool on) { + Realplot *plot = static_cast(*h); + plot->setXAxisAutoScale(on); +} + +void plot_real_setYAxisAutoScale(plot_real_t *h, bool on) { + Realplot *plot = static_cast(*h); + plot->setYAxisAutoScale(on); +} + +void plot_real_setXAxisScale(plot_real_t *h, double xMin, double xMax) { + Realplot *plot = static_cast(*h); + plot->setXAxisScale(xMin, xMax); +} + +void plot_real_setYAxisScale(plot_real_t *h, double yMin, double yMax) { + Realplot *plot = static_cast(*h); + plot->setYAxisScale(yMin, yMax); +} + +void plot_real_setXAxisRange(plot_real_t *h, double xMin, double xMax) { + Realplot *plot = static_cast(*h); + plot->setXAxisRange(xMin, xMax); +} + +void plot_real_setLabels(plot_real_t *h, char *xLabel, char *yLabel) { + Realplot *plot = static_cast(*h); + plot->setLabels(xLabel, yLabel); +} diff --git a/graphics/lib/realplot/test/CMakeLists.txt b/graphics/lib/realplot/test/CMakeLists.txt new file mode 100644 index 000000000..3168de705 --- /dev/null +++ b/graphics/lib/realplot/test/CMakeLists.txt @@ -0,0 +1,31 @@ +# +# Copyright 2012-2013 The Iris Project Developers. See the +# COPYRIGHT file at the top-level directory of this distribution +# and at http://www.softwareradiosystems.com/iris/copyright.html. +# +# This file is part of the Iris Project. +# +# Iris is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# Iris is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# A copy of the GNU Lesser 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/. +# + +######################################################################## +# Build tests +######################################################################## +#turn the test cpp file into an executable with an int main() function +INCLUDE_DIRECTORIES(..) +ADD_EXECUTABLE(realplot_test realplot_test.cpp) +TARGET_LINK_LIBRARIES(realplot_test pthread graphics) +ADD_TEST(realplot_test realplot_test) + diff --git a/graphics/lib/realplot/test/realplot_test.cpp b/graphics/lib/realplot/test/realplot_test.cpp new file mode 100644 index 000000000..111d07de6 --- /dev/null +++ b/graphics/lib/realplot/test/realplot_test.cpp @@ -0,0 +1,123 @@ +/** + * \file lib/generic/modulation/Crc_test.cpp + * \version 1.0 + * + * \section COPYRIGHT + * + * Copyright 2012-2013 The Iris Project Developers. See the + * COPYRIGHT file at the top-level directory of this distribution + * and at http://www.softwareradiosystems.com/iris/copyright.html. + * + * \section LICENSE + * + * This file is part of the Iris Project. + * + * Iris is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * Iris is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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/. + * + * \section DESCRIPTION + * + * Main test file for Realplot class. + */ + +#include "Realplot.h" + +#include +#include +#include +#include +#include +#include +#include + +typedef std::vector FloatVec; + +template +void getPoints(T* data, int numPoints) { + for (int i = 0; i < numPoints; i++) { + data[i] = 10 * ((T) rand() / RAND_MAX); + } +} + +template +void getPoints(Iterator begin, Iterator end) { + for (; begin != end; begin++) { + *begin = 10 * ((double) rand() / RAND_MAX); + } +} + +void *threadMain1(void *arg) { + Realplot plot; + + float data[1024]; + + for (int i = 0; i < 100; i++) { + getPoints(data, 504); + plot.setNewData(data, 504); + usleep(5000); + } + return NULL; +} + +void *threadMain2(void *arg) { + Realplot plot; + double data[1024]; + + for (int i = 0; i < 100; i++) { + getPoints(data, 504); + plot.setNewData(data, 504); + usleep(5000); + } + return NULL; +} + +void *threadMain3(void *arg) { + Realplot plot; + FloatVec v(1024); + + for (int i = 0; i < 100; i++) { + getPoints(v.begin(), v.end()); + plot.setNewData(v.begin(), v.end()); + usleep(5000); + } + return NULL; +} + +int main(int argc, char *argv[]) { + int argc2 = 1; + char* argv2[] = { const_cast("Realplot_Basic_Test"), NULL }; + QApplication a(argc2, argv2); + pthread_t threads[3]; + int i; + + if (pthread_create(&threads[0], NULL, threadMain1, NULL)) { + perror("pthread_create"); + exit(-1); + } + if (pthread_create(&threads[1], NULL, threadMain2, NULL)) { + perror("pthread_create"); + exit(-1); + } + if (pthread_create(&threads[2], NULL, threadMain3, NULL)) { + perror("pthread_create"); + exit(-1); + } + + qApp->exec(); + + for (i=0;i<3;i++) { + pthread_join(threads[i], NULL); + } + exit(0); +} diff --git a/graphics/lib/scatterplot/ScatterWidget.cpp b/graphics/lib/scatterplot/ScatterWidget.cpp new file mode 100644 index 000000000..f3f3542a6 --- /dev/null +++ b/graphics/lib/scatterplot/ScatterWidget.cpp @@ -0,0 +1,100 @@ +#include "ScatterWidget.h" +#include "Pointplot.h" +#include "Events.h" + +#include +#include + +using namespace std; + +ScatterWidget::ScatterWidget(QWidget *parent) + :QWidget(parent) +{ + plot_ = new Pointplot(); + QVBoxLayout* vLayout1 = new QVBoxLayout(this); + vLayout1->addWidget(plot_); + + numPoints_ = 16; + iData_ = new double[numPoints_]; + qData_ = new double[numPoints_]; + timerId_ = startTimer(10); + haveNewData_ = false; +} + +ScatterWidget::~ScatterWidget() +{ + delete iData_; + delete qData_; +} + +void ScatterWidget::customEvent( QEvent * e ) +{ + if(e->type() == ComplexDataEvent::type) + { + ComplexDataEvent* dataEvent = (ComplexDataEvent*)e; + setData(dataEvent); + } +} + +void ScatterWidget::timerEvent(QTimerEvent *event) +{ + if(event->timerId() == timerId_) + { + if(haveNewData_) + { + plot_->replot(); + haveNewData_ = false; + } + return; + } + QWidget::timerEvent(event); +} + +void ScatterWidget::setData(ComplexDataEvent* e) +{ + if(e->numPoints_ != numPoints_) + { + numPoints_ = e->numPoints_; + delete [] iData_; + delete [] qData_; + iData_ = new double[numPoints_]; + qData_ = new double[numPoints_]; + } + + transform(e->dataPoints_, &e->dataPoints_[numPoints_], iData_, opReal()); + transform(e->dataPoints_, &e->dataPoints_[numPoints_], qData_, opImag()); + + plot_->setData(iData_, qData_, numPoints_); + haveNewData_ = true; +} + +void ScatterWidget::setWidgetTitle(QString title) +{ + plot_->setTitle(title); +} + +void ScatterWidget::setWidgetAxisLabels(QString xLabel, QString yLabel) +{ + plot_->setAxisTitle(QwtPlot::xBottom, xLabel); + plot_->setAxisTitle(QwtPlot::yLeft, yLabel); +} + +void ScatterWidget::setWidgetXAxisScale(double xMin, double xMax) +{ + plot_->setAxisScale(QwtPlot::xBottom, xMin, xMax); +} + +void ScatterWidget::setWidgetYAxisScale(double yMin, double yMax) +{ + plot_->setAxisScale(QwtPlot::yLeft, yMin, yMax); +} + +void ScatterWidget::setWidgetXAxisAutoScale(bool on=true) +{ + plot_->setAxisAutoScale(QwtPlot::xBottom, on); +} + +void ScatterWidget::setWidgetYAxisAutoScale(bool on) +{ + plot_->setAxisAutoScale(QwtPlot::yLeft, on); +} diff --git a/graphics/lib/scatterplot/ScatterWidget.h b/graphics/lib/scatterplot/ScatterWidget.h new file mode 100644 index 000000000..1acc7904c --- /dev/null +++ b/graphics/lib/scatterplot/ScatterWidget.h @@ -0,0 +1,46 @@ +#ifndef SCATTERWIDGET_H +#define SCATTERWIDGET_H + +#include +#include +#include + +class ComplexDataEvent; +class Pointplot; + +class ScatterWidget + : public QWidget +{ + Q_OBJECT + +public: + ScatterWidget(QWidget* parent = 0); + virtual ~ScatterWidget(); + +public slots: + void customEvent( QEvent * e ); + void setWidgetTitle(QString title); + void setWidgetAxisLabels(QString xLabel, QString yLabel); + void setWidgetXAxisScale(double xMin, double xMax); + void setWidgetYAxisScale(double yMin, double yMax); + void setWidgetXAxisAutoScale(bool on); + void setWidgetYAxisAutoScale(bool on); + +protected: + virtual void timerEvent(QTimerEvent *event); + +private: + void setData(ComplexDataEvent* e); + Pointplot* plot_; + + struct opReal{double operator()(std::complex i) const{return real(i);}}; + struct opImag{double operator()(std::complex i) const{return imag(i);}}; + + double* iData_; + double* qData_; + int numPoints_; + int timerId_; + bool haveNewData_; +}; + +#endif // SCATTERWIDGET_H diff --git a/graphics/lib/scatterplot/Scatterplot.cpp b/graphics/lib/scatterplot/Scatterplot.cpp new file mode 100644 index 000000000..343435cc8 --- /dev/null +++ b/graphics/lib/scatterplot/Scatterplot.cpp @@ -0,0 +1,53 @@ +#include "Scatterplot.h" +#include "ScatterplotWrapper.h" + +Scatterplot::Scatterplot() +{ + plot_ = new ScatterplotWrapper; +} + +Scatterplot::~Scatterplot() +{ + delete plot_; +} + +void Scatterplot::setNewData(std::complex* data, int numPoints) +{ + plot_->setNewData(data, numPoints); +} + +void Scatterplot::setNewData(std::complex* data, int numPoints) +{ + plot_->setNewData(data, numPoints); +} + +void Scatterplot::setTitle(std::string title) +{ + plot_->setTitle(title); +} + +void Scatterplot::setXAxisScale(double xMin, double xMax) +{ + plot_->setXAxisScale(xMin, xMax); +} + +void Scatterplot::setYAxisScale(double yMin, double yMax) +{ + plot_->setYAxisScale(yMin, yMax); +} + +void Scatterplot::setXAxisAutoScale(bool on=true) +{ + plot_->setXAxisAutoScale(on); +} + +void Scatterplot::setYAxisAutoScale(bool on=true) +{ + plot_->setYAxisAutoScale(on); +} + +void Scatterplot::setAxisLabels(std::string xLabel, std::string yLabel) +{ + plot_->setAxisLabels(xLabel, yLabel); +} + diff --git a/graphics/lib/scatterplot/Scatterplot.h b/graphics/lib/scatterplot/Scatterplot.h new file mode 100644 index 000000000..19b340c43 --- /dev/null +++ b/graphics/lib/scatterplot/Scatterplot.h @@ -0,0 +1,46 @@ +#ifndef SCATTERPLOT_H +#define SCATTERPLOT_H + +#include +#include + +class ScatterplotWrapper; + +class Scatterplot +{ +public: + Scatterplot(); + ~Scatterplot(); + + template + void setNewData(Iterator begin, Iterator end); + void setNewData(std::complex* data, int numPoints); + void setNewData(std::complex* data, int numPoints); + void setTitle(std::string title); + void setXAxisScale(double xMin, double xMax); + void setYAxisScale(double yMin, double yMax); + void setXAxisAutoScale(bool on); + void setYAxisAutoScale(bool on); + void setAxisLabels(std::string xLabel, std::string yLabel); + +private: + ScatterplotWrapper* plot_; +}; + +template +void Scatterplot::setNewData(Iterator begin, Iterator end) +{ + int numPoints = end-begin; + std::complex* data = new std::complex[numPoints]; + + for(int i=0;begin!=end;begin++,i++) + { + data[i] = *begin; + } + + setNewData(data, numPoints); + + delete[] data; +} + +#endif // SCATTERPLOT_H diff --git a/graphics/lib/scatterplot/ScatterplotWrapper.cpp b/graphics/lib/scatterplot/ScatterplotWrapper.cpp new file mode 100644 index 000000000..35e7b8238 --- /dev/null +++ b/graphics/lib/scatterplot/ScatterplotWrapper.cpp @@ -0,0 +1,142 @@ +#include "ScatterplotWrapper.h" + +#include "ScatterWidget.h" +#include "Events.h" +#include +#include +#include + +using namespace std; + + +ScatterplotWrapper::ScatterplotWrapper() + :widget_(NULL) + ,destroyed_(true) +{ + if(QCoreApplication::instance() == NULL) + return; //TODO: throw exception here in Iris + if(QCoreApplication::instance()->thread() == QThread::currentThread()) + { + connect( this, SIGNAL(createWidgetSignal()), + this, SLOT(createWidgetSlot()) ); + connect( this, SIGNAL(destroyWidgetSignal()), + this, SLOT(destroyWidgetSlot()) ); + connect( this, SIGNAL( destroyWidgetSignalBlocking() ), + this, SLOT(destroyWidgetSlot()) ); + } + else + { + connect( this, SIGNAL(createWidgetSignal()), + this, SLOT(createWidgetSlot()), + Qt::BlockingQueuedConnection ); + connect( this, SIGNAL(destroyWidgetSignal()), + this, SLOT(destroyWidgetSlot()) ); + connect( this, SIGNAL( destroyWidgetSignalBlocking() ), + this, SLOT(destroyWidgetSlot()), + Qt::BlockingQueuedConnection ); + moveToThread(QCoreApplication::instance()->thread()); + } + emit createWidgetSignal(); +} + +ScatterplotWrapper::~ScatterplotWrapper() +{ + if(destroyed_) + emit destroyWidgetSignal(); + else + emit destroyWidgetSignalBlocking(); +} + +void ScatterplotWrapper::createWidgetSlot() +{ + widget_ = new ScatterWidget; + destroyed_ = false; + widget_->setAttribute(Qt::WA_DeleteOnClose, true); + connect(widget_, SIGNAL( destroyed() ), + this, SLOT( widgetDestroyed() )); + connect(this, SIGNAL(setWidgetXAxisScale(double,double)), + widget_, SLOT(setWidgetXAxisScale(double,double))); + connect(this, SIGNAL(setWidgetYAxisScale(double,double)), + widget_, SLOT(setWidgetYAxisScale(double,double))); + connect(this, SIGNAL(setWidgetXAxisAutoScale(bool)), + widget_, SLOT(setWidgetXAxisAutoScale(bool))); + connect(this, SIGNAL(setWidgetYAxisAutoScale(bool)), + widget_, SLOT(setWidgetYAxisAutoScale(bool))); + connect(this, SIGNAL(setWidgetTitle(QString)), + widget_, SLOT(setWidgetTitle(QString))); + connect(this, SIGNAL(setWidgetAxisLabels(QString, QString)), + widget_, SLOT(setWidgetAxisLabels(QString, QString))); + + widget_->resize( 800, 600 ); + widget_->show(); +} + +void ScatterplotWrapper::destroyWidgetSlot() +{ + delete widget_; +} + +void ScatterplotWrapper::widgetDestroyed() +{ + destroyed_ = true; +} + +void ScatterplotWrapper::setNewData(complex* data, int numPoints) +{ + if(destroyed_) + return; + qApp->postEvent(widget_, new ComplexDataEvent(data, numPoints)); +} + +void ScatterplotWrapper::setNewData(complex* data, int numPoints) +{ + if(destroyed_) + return; + qApp->postEvent(widget_, new ComplexDataEvent(data, numPoints)); +} + +void ScatterplotWrapper::setTitle(std::string title) +{ + if(destroyed_) + return; + QString str = QString::fromUtf8(title.c_str()); + emit setWidgetTitle(str); +} + +void ScatterplotWrapper::setXAxisScale(double xMin, double xMax) +{ + if(destroyed_) + return; + emit setWidgetXAxisScale(xMin, xMax); +} + +void ScatterplotWrapper::setYAxisScale(double yMin, double yMax) +{ + if(destroyed_) + return; + emit setWidgetYAxisScale(yMin, yMax); +} + +void ScatterplotWrapper::setXAxisAutoScale(bool on=true) +{ + if(destroyed_) + return; + emit setWidgetXAxisAutoScale(on); +} + +void ScatterplotWrapper::setYAxisAutoScale(bool on=true) +{ + if(destroyed_) + return; + emit setWidgetYAxisAutoScale(on); +} + +void ScatterplotWrapper::setAxisLabels(std::string xLabel, std::string yLabel) +{ + if(destroyed_) + return; + QString xStr = QString::fromUtf8(xLabel.c_str()); + QString yStr = QString::fromUtf8(yLabel.c_str()); + emit setWidgetAxisLabels(xStr, yStr); +} + diff --git a/graphics/lib/scatterplot/ScatterplotWrapper.h b/graphics/lib/scatterplot/ScatterplotWrapper.h new file mode 100644 index 000000000..e8b72a936 --- /dev/null +++ b/graphics/lib/scatterplot/ScatterplotWrapper.h @@ -0,0 +1,48 @@ +#ifndef SCATTERPLOTWRAPPER_H +#define SCATTERPLOTWRAPPER_H + +#include +#include + +class ScatterWidget; + +class ScatterplotWrapper + : QObject +{ + Q_OBJECT + +public: + ScatterplotWrapper(); + ~ScatterplotWrapper(); + + void setNewData(std::complex* data, int numPoints); + void setNewData(std::complex* data, int numPoints); + void setTitle(std::string title); + void setXAxisScale(double xMin, double xMax); + void setYAxisScale(double yMin, double yMax); + void setXAxisAutoScale(bool on); + void setYAxisAutoScale(bool on); + void setAxisLabels(std::string xLabel, std::string yLabel); + +public slots: + void createWidgetSlot(); + void destroyWidgetSlot(); + void widgetDestroyed(); + +signals: + void createWidgetSignal(); + void destroyWidgetSignal(); + void destroyWidgetSignalBlocking(); + void setWidgetTitle(QString title); + void setWidgetAxisLabels(QString xLabel, QString yLabel); + void setWidgetXAxisScale(double xMin, double xMax); + void setWidgetYAxisScale(double yMin, double yMax); + void setWidgetXAxisAutoScale(bool on); + void setWidgetYAxisAutoScale(bool on); + +private: + ScatterWidget* widget_; + bool destroyed_; +}; + +#endif // SCATTERPLOTWRAPPER_H diff --git a/graphics/lib/scatterplot/plot_scatter.cpp b/graphics/lib/scatterplot/plot_scatter.cpp new file mode 100644 index 000000000..b3d36986f --- /dev/null +++ b/graphics/lib/scatterplot/plot_scatter.cpp @@ -0,0 +1,75 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 "plot/plot_scatter.h" +#include "Scatterplot.h" +#include + + + +int plot_scatter_init(plot_scatter_t *h) { + *h = (void*) new Scatterplot(); + return (*h != NULL)?0:-1; +} + +void plot_scatter_setTitle(plot_scatter_t *h, char *title) { + Scatterplot *plot = static_cast(*h); + plot->setTitle(title); +} +void plot_scatter_setNewData(plot_scatter_t *h, _Complex float *data, + int num_points) { + Scatterplot *plot = static_cast(*h); + plot->setNewData(reinterpret_cast*> (data), num_points); + +} + +void plot_scatter_setXAxisAutoScale(plot_scatter_t *h, bool on) { + Scatterplot *plot = static_cast(*h); + plot->setXAxisAutoScale(on); +} + +void plot_scatter_setYAxisAutoScale(plot_scatter_t *h, bool on) { + Scatterplot *plot = static_cast(*h); + plot->setYAxisAutoScale(on); +} + +void plot_scatter_setXAxisScale(plot_scatter_t *h, double xMin, double xMax) { + Scatterplot *plot = static_cast(*h); + plot->setXAxisScale(xMin, xMax); +} + +void plot_scatter_setYAxisScale(plot_scatter_t *h, double yMin, double yMax) { + Scatterplot *plot = static_cast(*h); + plot->setYAxisScale(yMin, yMax); +} + +void plot_scatter_setAxisLabels(plot_scatter_t *h, char *xLabel, char *yLabel) { + Scatterplot *plot = static_cast(*h); + plot->setAxisLabels(xLabel, yLabel); +} diff --git a/graphics/lib/scatterplot/test/CMakeLists.txt b/graphics/lib/scatterplot/test/CMakeLists.txt new file mode 100644 index 000000000..9b373bca8 --- /dev/null +++ b/graphics/lib/scatterplot/test/CMakeLists.txt @@ -0,0 +1,30 @@ +# +# Copyright 2012-2013 The Iris Project Developers. See the +# COPYRIGHT file at the top-level directory of this distribution +# and at http://www.softwareradiosystems.com/iris/copyright.html. +# +# This file is part of the Iris Project. +# +# Iris is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# Iris is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# A copy of the GNU Lesser 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/. +# + +######################################################################## +# Build tests +######################################################################## +INCLUDE_DIRECTORIES(..) +ADD_EXECUTABLE(scatterplot_test scatterplot_test.cpp) +TARGET_LINK_LIBRARIES(scatterplot_test pthread graphics) +ADD_TEST(scatterplot_test scatterplot_test) + diff --git a/graphics/lib/scatterplot/test/scatterplot_test.cpp b/graphics/lib/scatterplot/test/scatterplot_test.cpp new file mode 100644 index 000000000..fcc104b7c --- /dev/null +++ b/graphics/lib/scatterplot/test/scatterplot_test.cpp @@ -0,0 +1,126 @@ +/** + * \file lib/generic/modulation/Crc_test.cpp + * \version 1.0 + * + * \section COPYRIGHT + * + * Copyright 2012-2013 The Iris Project Developers. See the + * COPYRIGHT file at the top-level directory of this distribution + * and at http://www.softwareradiosystems.com/iris/copyright.html. + * + * \section LICENSE + * + * This file is part of the Iris Project. + * + * Iris is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * Iris is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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/. + * + * \section DESCRIPTION + * + * Main test file for scatterplot class. + */ + +#include "Scatterplot.h" + +#include +#include +#include +#include +#include +#include +#include + +typedef std::complex Cplx; +typedef std::vector CplxVec; + +template +void getPoints(std::complex* data, int numPoints) { + for (int i = 0; i < numPoints; i++) { + data[i] = std::complex(2 * ((T) rand() / RAND_MAX) - 1, + 2 * ((T) rand() / RAND_MAX) - 1); + } +} + +template +void getPoints(Iterator begin, Iterator end) { + for (; begin != end; begin++) { + float r = 2 * ((double) rand() / RAND_MAX) - 1; + float i = 2 * ((double) rand() / RAND_MAX) - 1; + *begin = Cplx(r, i); + } +} + +void *threadMain1(void *arg) { + Scatterplot plot; + std::complex data[1024]; + + for (int i = 0; i < 10; i++) { + getPoints(data, 1024); + plot.setNewData(data, 1024); + usleep(100000); + } + return NULL; +} + +void *threadMain2(void *arg) { + Scatterplot plot; + std::complex data[1024]; + + for (int i = 0; i < 10; i++) { + getPoints(data, 1024); + plot.setNewData(data, 1024); + usleep(100000); + } + return NULL; +} + +void *threadMain3(void *arg) { + Scatterplot plot; + CplxVec v(1024); + + for (int i = 0; i < 10; i++) { + getPoints(v.begin(), v.end()); + plot.setNewData(v.begin(), v.end()); + usleep(100000); + } + return NULL; +} + +int main(int argc, char *argv[]) { + int argc2 = 1; + char* argv2[] = { const_cast("Scatterplot_Basic_Test"), NULL }; + QApplication a(argc2, argv2); + pthread_t threads[3]; + int i; + + if (pthread_create(&threads[0], NULL, threadMain1, NULL)) { + perror("pthread_create"); + exit(-1); + } + if (pthread_create(&threads[1], NULL, threadMain2, NULL)) { + perror("pthread_create"); + exit(-1); + } + if (pthread_create(&threads[2], NULL, threadMain3, NULL)) { + perror("pthread_create"); + exit(-1); + } + + qApp->exec(); + + for (i=0;i<3;i++) { + pthread_join(threads[i], NULL); + } + exit(0); +} diff --git a/graphics/lib/waterfallplot/WaterfallWidget.cpp b/graphics/lib/waterfallplot/WaterfallWidget.cpp new file mode 100644 index 000000000..89846f04b --- /dev/null +++ b/graphics/lib/waterfallplot/WaterfallWidget.cpp @@ -0,0 +1,141 @@ +#include "WaterfallWidget.h" +#include "Spectrogramplot.h" +#include "Lineplot.h" +#include "Events.h" + +#include +#include +#include + +using namespace std; + + +WaterfallWidget::WaterfallWidget(int numDataPoints, int numRows, QWidget *parent) + :QWidget(parent) +{ + p_ = new Lineplot(); + s_ = new Spectrogramplot(numDataPoints, numRows); + b_ = new QPushButton("Autoscale"); + + connect(b_, SIGNAL(clicked()), this, SLOT(autoscale())); + + QVBoxLayout* vLayout1 = new QVBoxLayout(this); + vLayout1->addWidget(p_);vLayout1->setStretch(0,1); + vLayout1->addWidget(s_);vLayout1->setStretch(1,3); + vLayout1->addWidget(b_); + + numPoints_ = numDataPoints; + data_ = new double[numPoints_]; + timerId_ = startTimer(10); + haveNewData_ = false; +} + +WaterfallWidget::~WaterfallWidget() +{ + delete p_; + delete s_; +} + +void WaterfallWidget::customEvent( QEvent * e ) +{ + if(e->type() == RealDataEvent::type) + { + RealDataEvent* dataEvent = (RealDataEvent*)e; + appendData(dataEvent); + } +} + +void WaterfallWidget::setWidgetTitle(QString title) +{ + setWindowTitle(title); +} + +void WaterfallWidget::setPlotXLabel(QString xLabel) +{ + p_->setAxisTitle(QwtPlot::xBottom, xLabel); +} + +void WaterfallWidget::setPlotYLabel(QString yLabel) +{ + p_->setAxisTitle(QwtPlot::yLeft, yLabel); +} + +void WaterfallWidget::setPlotXAxisRange(double xMin, double xMax) +{ + p_->setXAxisRange(xMin, xMax); +} + +void WaterfallWidget::setPlotXAxisScale(double xMin, double xMax) +{ + p_->setAxisScale(QwtPlot::xBottom, xMin, xMax); +} + +void WaterfallWidget::setPlotYAxisScale(double yMin, double yMax) +{ + p_->setAxisScale(QwtPlot::yLeft, yMin, yMax); +} + +void WaterfallWidget::setSpectrogramXLabel(QString xLabel) +{ + s_->setAxisTitle(QwtPlot::xBottom, xLabel); +} + +void WaterfallWidget::setSpectrogramYLabel(QString yLabel) +{ + s_->setAxisTitle(QwtPlot::yLeft, yLabel); +} + +void WaterfallWidget::setSpectrogramXAxisRange(double xMin, double xMax) +{ + s_->setXAxisRange(xMin, xMax); +} + +void WaterfallWidget::setSpectrogramYAxisRange(double yMin, double yMax) +{ + s_->setYAxisRange(yMin, yMax); +} + +void WaterfallWidget::setSpectrogramZAxisScale(double zMin, double zMax) +{ + s_->setZAxisScale(zMin, zMax); +} + +void WaterfallWidget::autoscale() +{ + double min = s_->min(); + double max = s_->max(); + s_->setZAxisScale(min, max); + p_->setAxisAutoScale(QwtPlot::yLeft, false); + p_->setAxisScale(QwtPlot::yLeft, min, max); +} + +void WaterfallWidget::timerEvent(QTimerEvent *event) +{ + if(event->timerId() == timerId_) + { + if(haveNewData_) + { + p_->replot(); + s_->replot(); + haveNewData_ = false; + } + return; + } + QWidget::timerEvent(event); +} + +void WaterfallWidget::appendData(RealDataEvent* e) +{ + if(e->numPoints_ != numPoints_) + { + numPoints_ = e->numPoints_; + delete [] data_; + data_ = new double[numPoints_]; + } + + memcpy(data_, e->dataPoints_, numPoints_*sizeof(double)); + + p_->setData(data_, numPoints_); + s_->appendData(data_, numPoints_); + haveNewData_ = true; +} diff --git a/graphics/lib/waterfallplot/WaterfallWidget.h b/graphics/lib/waterfallplot/WaterfallWidget.h new file mode 100644 index 000000000..63f2c9a71 --- /dev/null +++ b/graphics/lib/waterfallplot/WaterfallWidget.h @@ -0,0 +1,52 @@ +#ifndef WATERFALLWIDGET_H +#define WATERFALLWIDGET_H + +#include +#include +#include + +class RealDataEvent; +class Lineplot; +class Spectrogramplot; +class QPushButton; + +class WaterfallWidget + : public QWidget +{ + Q_OBJECT + +public: + WaterfallWidget(int numDataPoints, int numRows, QWidget* parent = 0); + virtual ~WaterfallWidget(); + +public slots: + void customEvent( QEvent * e ); + void setWidgetTitle(QString title); + void setPlotXLabel(QString xLabel); + void setPlotYLabel(QString yLabel); + void setPlotXAxisRange(double xMin, double xMax); + void setPlotXAxisScale(double xMin, double xMax); + void setPlotYAxisScale(double yMin, double yMax); + void setSpectrogramXLabel(QString xLabel); + void setSpectrogramYLabel(QString yLabel); + void setSpectrogramXAxisRange(double xMin, double xMax); + void setSpectrogramYAxisRange(double yMin, double yMax); + void setSpectrogramZAxisScale(double zMin, double zMax); + void autoscale(); + +protected: + virtual void timerEvent(QTimerEvent *event); + +private: + void appendData(RealDataEvent* e); + Lineplot* p_; + Spectrogramplot* s_; + QPushButton* b_; + + double* data_; + int numPoints_; + int timerId_; + bool haveNewData_; +}; + +#endif // WATERFALLWIDGET_H diff --git a/graphics/lib/waterfallplot/Waterfallplot.cpp b/graphics/lib/waterfallplot/Waterfallplot.cpp new file mode 100644 index 000000000..64c0d96e3 --- /dev/null +++ b/graphics/lib/waterfallplot/Waterfallplot.cpp @@ -0,0 +1,80 @@ +#include "Waterfallplot.h" +#include "WaterfallplotWrapper.h" + +using namespace std; + +Waterfallplot::Waterfallplot(int numDataPoints, int numRows) +{ + plot_ = new WaterfallplotWrapper(numDataPoints, numRows); +} + +Waterfallplot::~Waterfallplot() +{ + delete plot_; +} + +void Waterfallplot::appendNewData(float* data, int numPoints) +{ + plot_->appendNewData(data, numPoints); +} + +void Waterfallplot::appendNewData(double* data, int numPoints) +{ + plot_->appendNewData(data, numPoints); +} + +void Waterfallplot::setTitle(std::string title) +{ + plot_->setTitle(title); +} + +void Waterfallplot::setPlotXLabel(std::string xLabel) +{ + plot_->setPlotXLabel(xLabel); +} + +void Waterfallplot::setPlotYLabel(std::string yLabel) +{ + plot_->setPlotYLabel(yLabel); +} + +void Waterfallplot::setPlotXAxisRange(double xMin, double xMax) +{ + plot_->setPlotXAxisRange(xMin, xMax); +} + +void Waterfallplot::setPlotXAxisScale(double xMin, double xMax) +{ + plot_->setPlotXAxisScale(xMin, xMax); +} + +void Waterfallplot::setPlotYAxisScale(double yMin, double yMax) +{ + plot_->setPlotYAxisScale(yMin, yMax); +} + +void Waterfallplot::setSpectrogramXLabel(std::string xLabel) +{ + plot_->setSpectrogramXLabel(xLabel); +} + +void Waterfallplot::setSpectrogramYLabel(std::string yLabel) +{ + plot_->setSpectrogramYLabel(yLabel); +} + +void Waterfallplot::setSpectrogramXAxisRange(double xMin, double xMax) +{ + plot_->setSpectrogramXAxisRange(xMin, xMax); +} + +void Waterfallplot::setSpectrogramYAxisRange(double yMin, double yMax) +{ + plot_->setSpectrogramYAxisRange(yMin, yMax); +} + +void Waterfallplot::setSpectrogramZAxisScale(double zMin, double zMax) +{ + plot_->setSpectrogramZAxisScale(zMin, zMax); +} + diff --git a/graphics/lib/waterfallplot/Waterfallplot.h b/graphics/lib/waterfallplot/Waterfallplot.h new file mode 100644 index 000000000..f87bb84c0 --- /dev/null +++ b/graphics/lib/waterfallplot/Waterfallplot.h @@ -0,0 +1,49 @@ +#ifndef WATERFALLPLOT_H +#define WATERFALLPLOT_H + +#include + +class WaterfallplotWrapper; + +class Waterfallplot +{ +public: + Waterfallplot(int numDataPoints, int numRows); + ~Waterfallplot(); + + template + void appendNewData(Iterator begin, Iterator end); + void appendNewData(float* data, int numPoints); + void appendNewData(double* data, int numPoints); + void setTitle(std::string title); + void setPlotXLabel(std::string xLabel); + void setPlotYLabel(std::string yLabel); + void setPlotXAxisRange(double xMin, double xMax); + void setPlotXAxisScale(double xMin, double xMax); + void setPlotYAxisScale(double yMin, double yMax); + void setSpectrogramXLabel(std::string xLabel); + void setSpectrogramYLabel(std::string yLabel); + void setSpectrogramXAxisRange(double xMin, double xMax); + void setSpectrogramYAxisRange(double yMin, double yMax); + void setSpectrogramZAxisScale(double zMin, double zMax); + +private: + WaterfallplotWrapper* plot_; +}; + +template +void Waterfallplot::appendNewData(Iterator begin, Iterator end) +{ + int numPoints = end-begin; + double* data = new double[numPoints]; + + for(int i=0;begin!=end;begin++,i++) + { + data[i] = *begin; + } + + appendNewData(data, numPoints); + delete[] data; +} + +#endif // WATERFALLPLOT_H diff --git a/graphics/lib/waterfallplot/WaterfallplotWrapper.cpp b/graphics/lib/waterfallplot/WaterfallplotWrapper.cpp new file mode 100644 index 000000000..05b7281f0 --- /dev/null +++ b/graphics/lib/waterfallplot/WaterfallplotWrapper.cpp @@ -0,0 +1,187 @@ +#include "WaterfallplotWrapper.h" + +#include "WaterfallWidget.h" +#include "Events.h" +#include +#include + +using namespace std; + +WaterfallplotWrapper::WaterfallplotWrapper(int numDataPoints, int numRows) + :widget_(NULL) + ,destroyed_(true) +{ + if(QCoreApplication::instance() == NULL) + return; //TODO: throw exception here in Iris + if(QCoreApplication::instance()->thread() == QThread::currentThread()) + { + connect( this, SIGNAL( createWidgetSignal(int, int) ), + this, SLOT(createWidgetSlot(int, int)) ); + connect( this, SIGNAL( destroyWidgetSignal() ), + this, SLOT(destroyWidgetSlot()) ); + connect( this, SIGNAL( destroyWidgetSignalBlocking() ), + this, SLOT(destroyWidgetSlot()) ); + } + else + { + connect( this, SIGNAL( createWidgetSignal(int, int) ), + this, SLOT(createWidgetSlot(int, int)), + Qt::BlockingQueuedConnection ); + connect( this, SIGNAL( destroyWidgetSignal() ), + this, SLOT(destroyWidgetSlot()) ); + connect( this, SIGNAL( destroyWidgetSignalBlocking() ), + this, SLOT(destroyWidgetSlot()), + Qt::BlockingQueuedConnection ); + moveToThread(QCoreApplication::instance()->thread()); + } + emit createWidgetSignal(numDataPoints, numRows); +} + +WaterfallplotWrapper::~WaterfallplotWrapper() +{ + if(destroyed_) + emit destroyWidgetSignal(); + else + emit destroyWidgetSignalBlocking(); +} + +void WaterfallplotWrapper::createWidgetSlot(int numDataPoints, int numRows) +{ + widget_ = new WaterfallWidget(numDataPoints, numRows); + destroyed_ = false; + widget_->setAttribute(Qt::WA_DeleteOnClose, true); + connect(widget_, SIGNAL( destroyed() ), + this, SLOT( widgetDestroyed() )); + connect(this, SIGNAL(setWidgetTitle(QString)), + widget_, SLOT(setWidgetTitle(QString))); + connect(this, SIGNAL(setWidgetPXLabel(QString)), + widget_, SLOT(setPlotXLabel(QString))); + connect(this, SIGNAL(setWidgetPYLabel(QString)), + widget_, SLOT(setPlotYLabel(QString))); + connect(this, SIGNAL(setWidgetPXAxisRange(double, double)), + widget_, SLOT(setPlotXAxisRange(double, double))); + connect(this, SIGNAL(setWidgetPXAxisScale(double, double)), + widget_, SLOT(setPlotXAxisScale(double, double))); + connect(this, SIGNAL(setWidgetPYAxisScale(double, double)), + widget_, SLOT(setPlotYAxisScale(double, double))); + connect(this, SIGNAL(setWidgetSXLabel(QString)), + widget_, SLOT(setSpectrogramXLabel(QString))); + connect(this, SIGNAL(setWidgetSYLabel(QString)), + widget_, SLOT(setSpectrogramYLabel(QString))); + connect(this, SIGNAL(setWidgetSXAxisRange(double, double)), + widget_, SLOT(setSpectrogramXAxisRange(double, double))); + connect(this, SIGNAL(setWidgetSYAxisRange(double, double)), + widget_, SLOT(setSpectrogramYAxisRange(double, double))); + connect(this, SIGNAL(setWidgetSZAxisScale(double, double)), + widget_, SLOT(setSpectrogramZAxisScale(double, double))); + + widget_->resize( 800, 600 ); + widget_->show(); +} + +void WaterfallplotWrapper::destroyWidgetSlot() +{ + delete widget_; +} + +void WaterfallplotWrapper::widgetDestroyed() +{ + destroyed_ = true; +} + +void WaterfallplotWrapper::appendNewData(float* data, int numPoints) +{ + if(destroyed_) + return; + qApp->postEvent(widget_, new RealDataEvent(data, numPoints)); +} + +void WaterfallplotWrapper::appendNewData(double* data, int numPoints) +{ + if(destroyed_) + return; + qApp->postEvent(widget_, new RealDataEvent(data, numPoints)); +} + + +void WaterfallplotWrapper::setTitle(std::string title) +{ + if(destroyed_) + return; + QString str = QString::fromUtf8(title.c_str()); + emit setWidgetTitle(str); +} + +void WaterfallplotWrapper::setPlotXLabel(std::string xLabel) +{ + if(destroyed_) + return; + QString str = QString::fromUtf8(xLabel.c_str()); + emit setWidgetPXLabel(str); +} + +void WaterfallplotWrapper::setPlotYLabel(std::string yLabel) +{ + if(destroyed_) + return; + QString str = QString::fromUtf8(yLabel.c_str()); + emit setWidgetPYLabel(str); +} + +void WaterfallplotWrapper::setPlotXAxisRange(double xMin, double xMax) +{ + if(destroyed_) + return; + emit setWidgetPXAxisRange(xMin, xMax); +} + +void WaterfallplotWrapper::setPlotXAxisScale(double xMin, double xMax) +{ + if(destroyed_) + return; + emit setWidgetPXAxisScale(xMin, xMax); +} + +void WaterfallplotWrapper::setPlotYAxisScale(double yMin, double yMax) +{ + if(destroyed_) + return; + emit setWidgetPYAxisScale(yMin, yMax); +} + +void WaterfallplotWrapper::setSpectrogramXAxisRange(double xMin, double xMax) +{ + if(destroyed_) + return; + emit setWidgetSXAxisRange(xMin, xMax); +} + +void WaterfallplotWrapper::setSpectrogramXLabel(std::string xLabel) +{ + if(destroyed_) + return; + QString str = QString::fromUtf8(xLabel.c_str()); + emit setWidgetSXLabel(str); +} + +void WaterfallplotWrapper::setSpectrogramYLabel(std::string yLabel) +{ + if(destroyed_) + return; + QString str = QString::fromUtf8(yLabel.c_str()); + emit setWidgetSYLabel(str); +} + +void WaterfallplotWrapper::setSpectrogramYAxisRange(double yMin, double yMax) +{ + if(destroyed_) + return; + emit setWidgetSYAxisRange(yMin, yMax); +} + +void WaterfallplotWrapper::setSpectrogramZAxisScale(double zMin, double zMax) +{ + if(destroyed_) + return; + emit setWidgetSZAxisScale(zMin, zMax); +} diff --git a/graphics/lib/waterfallplot/WaterfallplotWrapper.h b/graphics/lib/waterfallplot/WaterfallplotWrapper.h new file mode 100644 index 000000000..119175047 --- /dev/null +++ b/graphics/lib/waterfallplot/WaterfallplotWrapper.h @@ -0,0 +1,57 @@ +#ifndef WATERFALLPLOTWRAPPER_H +#define WATERFALLPLOTWRAPPER_H + +#include + +class WaterfallWidget; + +class WaterfallplotWrapper + : QObject +{ + Q_OBJECT + +public: + WaterfallplotWrapper(int numDataPoints, int numRows); + ~WaterfallplotWrapper(); + + void appendNewData(float* data, int numPoints); + void appendNewData(double* data, int numPoints); + void setTitle(std::string title); + void setPlotXLabel(std::string xLabel); + void setPlotYLabel(std::string yLabel); + void setPlotXAxisRange(double xMin, double xMax); + void setPlotXAxisScale(double xMin, double xMax); + void setPlotYAxisScale(double yMin, double yMax); + void setSpectrogramXLabel(std::string xLabel); + void setSpectrogramYLabel(std::string yLabel); + void setSpectrogramXAxisRange(double xMin, double xMax); + void setSpectrogramYAxisRange(double yMin, double yMax); + void setSpectrogramZAxisScale(double zMin, double zMax); + +public slots: + void createWidgetSlot(int numDataPoints, int numRows); + void destroyWidgetSlot(); + void widgetDestroyed(); + +signals: + void createWidgetSignal(int numDataPoints, int numRows); + void destroyWidgetSignal(); + void destroyWidgetSignalBlocking(); + void setWidgetTitle(QString title); + void setWidgetPXLabel(QString xLabel); + void setWidgetPYLabel(QString yLabel); + void setWidgetPXAxisRange(double xMin, double xMax); + void setWidgetPXAxisScale(double xMin, double xMax); + void setWidgetPYAxisScale(double yMin, double yMax); + void setWidgetSXLabel(QString xLabel); + void setWidgetSYLabel(QString yLabel); + void setWidgetSXAxisRange(double xMin, double xMax); + void setWidgetSYAxisRange(double yMin, double yMax); + void setWidgetSZAxisScale(double zMin, double zMax); + +private: + WaterfallWidget* widget_; + bool destroyed_; +}; + +#endif // WATERFALLPLOTWRAPPER_H diff --git a/graphics/lib/waterfallplot/plot_waterfall.cpp b/graphics/lib/waterfallplot/plot_waterfall.cpp new file mode 100644 index 000000000..99b1cc568 --- /dev/null +++ b/graphics/lib/waterfallplot/plot_waterfall.cpp @@ -0,0 +1,102 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 "plot/plot_waterfall.h" +#include "Waterfallplot.h" +#include + + +int plot_waterfall_init(plot_waterfall_t *h, int numDataPoints, int numRows) { + *h = (void*) new Waterfallplot(numDataPoints, numRows); + return (*h != NULL)?0:-1; +} + +void plot_waterfall_setTitle(plot_waterfall_t *h, char *title) { + Waterfallplot *plot = static_cast(*h); + plot->setTitle(title); +} + +void plot_waterfall_appendNewData(plot_waterfall_t *h, float *data, + int num_points) { + Waterfallplot *plot = static_cast(*h); + plot->appendNewData(data, num_points); +} + +void plot_complex_setPlotXLabel(plot_waterfall_t *h, char *xLabel) { + Waterfallplot *plot = static_cast(*h); + plot->setPlotXLabel(xLabel); +} + +void plot_complex_setPlotYLabel(plot_waterfall_t *h, char *yLabel) { + Waterfallplot *plot = static_cast(*h); + plot->setPlotXLabel(yLabel); +} + +void plot_waterfall_setPlotXAxisRange(plot_waterfall_t *h, double xMin, double xMax) { + Waterfallplot *plot = static_cast(*h); + plot->setPlotXAxisRange(xMin, xMax); +} + +void plot_waterfall_setPlotXAxisScale(plot_waterfall_t *h, double xMin, double xMax) { + Waterfallplot *plot = static_cast(*h); + plot->setPlotXAxisScale(xMin, xMax); +} + +void plot_waterfall_setPlotYAxisScale(plot_waterfall_t *h, double yMin, double yMax) { + Waterfallplot *plot = static_cast(*h); + plot->setPlotYAxisScale(yMin, yMax); +} + + +void plot_waterfall_setSpectrogramXLabel(plot_waterfall_t *h, char* xLabel) { + Waterfallplot *plot = static_cast(*h); + plot->setSpectrogramXLabel(xLabel); +} + +void plot_waterfall_setSpectrogramYLabel(plot_waterfall_t *h, char* yLabel) { + Waterfallplot *plot = static_cast(*h); + plot->setSpectrogramYLabel(yLabel); +} + +void plot_waterfall_setSpectrogramXAxisRange(plot_waterfall_t *h, double xMin, double xMax) { + Waterfallplot *plot = static_cast(*h); + plot->setSpectrogramXAxisRange(xMin, xMax); +} + +void plot_waterfall_setSpectrogramYAxisRange(plot_waterfall_t *h, double yMin, double yMax) { + Waterfallplot *plot = static_cast(*h); + plot->setSpectrogramYAxisRange(yMin, yMax); +} + +void plot_waterfall_setSpectrogramZAxisScale(plot_waterfall_t *h, double zMin, double zMax) { + Waterfallplot *plot = static_cast(*h); + plot->setSpectrogramZAxisScale(zMin, zMax); +} + diff --git a/graphics/lib/waterfallplot/test/CMakeLists.txt b/graphics/lib/waterfallplot/test/CMakeLists.txt new file mode 100644 index 000000000..3f5a2dfe3 --- /dev/null +++ b/graphics/lib/waterfallplot/test/CMakeLists.txt @@ -0,0 +1,32 @@ +# +# Copyright 2012-2013 The Iris Project Developers. See the +# COPYRIGHT file at the top-level directory of this distribution +# and at http://www.softwareradiosystems.com/iris/copyright.html. +# +# This file is part of the Iris Project. +# +# Iris is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# Iris is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# A copy of the GNU Lesser 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/. +# + +######################################################################## +# Build tests +######################################################################## +#turn the test cpp file into an executable with an int main() function +ADD_DEFINITIONS(-DBOOST_TEST_DYN_LINK -DBOOST_TEST_MAIN) +INCLUDE_DIRECTORIES(..) +ADD_EXECUTABLE(waterfallplot_test Waterfallplot_test.cpp) +TARGET_LINK_LIBRARIES(waterfallplot_test ${Boost_LIBRARIES} graphics) +ADD_TEST(waterfallplot_test waterfallplot_test) + diff --git a/graphics/lib/waterfallplot/test/Waterfallplot_test.cpp b/graphics/lib/waterfallplot/test/Waterfallplot_test.cpp new file mode 100644 index 000000000..6be65f77a --- /dev/null +++ b/graphics/lib/waterfallplot/test/Waterfallplot_test.cpp @@ -0,0 +1,127 @@ +/** + * \file lib/generic/modulation/Crc_test.cpp + * \version 1.0 + * + * \section COPYRIGHT + * + * Copyright 2012-2013 The Iris Project Developers. See the + * COPYRIGHT file at the top-level directory of this distribution + * and at http://www.softwareradiosystems.com/iris/copyright.html. + * + * \section LICENSE + * + * This file is part of the Iris Project. + * + * Iris is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * Iris is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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/. + * + * \section DESCRIPTION + * + * Main test file for Waterfallplot class. + */ + +#include "Waterfallplot.h" + +#include +#include +#include +#include +#include +#include +#include + +#define PI 3.14159265358979323846 + +using namespace std; + +void *threadMain1(void *arg) { + int n = 2048; + Waterfallplot plot(n, n); + plot.setTitle("Float"); + + float step = 1.0 * PI / n; + float* data = new float[n * 2]; + for (int i = 0; i < n * 2; i++) + data[i] = sinf(step * i); + + for (int i = 0; i < n; i++) { + plot.appendNewData(data + i, n); + usleep(1000); + } + return NULL; +} + +void *threadMain2(void *arg) { + int n = 2048; + Waterfallplot plot(n, n); + plot.setTitle("Double"); + + double step = 2.0 * PI / n; + double* data = new double[n * 2]; + for (int i = 0; i < n * 2; i++) + data[i] = sin(step * i); + + for (int i = 0; i < n; i++) { + plot.appendNewData(data + i, n); + usleep(1000); + } + return NULL; +} + +void *threadMain3(void *arg) { + int n = 2048; + Waterfallplot plot(n, n); + plot.setTitle("FloatVec"); + + double step = 2.0 * PI / n; + std::vector data; + data.resize(n * 2); + for (int i = 0; i < n * 2; i++) + data[i] = sin(step * i); + + for (int i = 0; i < n; i++) { + plot.appendNewData(data.begin() + i, data.begin() + i + n); + usleep(1000); + } + return NULL; +} + +int main(int argc, char *argv[]) { + int argc2 = 1; + char* argv2[] = { const_cast("Waterfallplot_Init_Test"), NULL }; + QApplication a(argc2, argv2); + pthread_t threads[3]; + int i; + + if (pthread_create(&threads[0], NULL, threadMain1, NULL)) { + perror("pthread_create"); + exit(-1); + } + if (pthread_create(&threads[1], NULL, threadMain2, NULL)) { + perror("pthread_create"); + exit(-1); + } + if (pthread_create(&threads[2], NULL, threadMain3, NULL)) { + perror("pthread_create"); + exit(-1); + } + + qApp->exec(); + + for (i = 0; i < 3; i++) { + pthread_join(threads[i], NULL); + } + exit(0); + +} diff --git a/include/channel/ch_awgn.h b/include/channel/ch_awgn.h deleted file mode 100644 index c2358a637..000000000 --- a/include/channel/ch_awgn.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) - * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * OSLD-lib is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . - */ -#include - -#ifndef CH_AWGN_ -#define CH_AWGN_ - -typedef _Complex float cf; - -void ch_awgn(const cf* input, cf* output, float variance, int buff_sz); - -/* High-level API */ - -typedef struct { - const cf* input; - int in_len; - struct ch_awgn_ctrl_in { - float variance; // Noise variance - } ctrl_in; - - cf* output; - int out_len; -}ch_awgn_hl; - -int ch_awgn_initialize(ch_awgn_hl* hl); -int ch_awgn_work(ch_awgn_hl* hl); -int ch_awgn_stop(ch_awgn_hl* hl); - -#endif diff --git a/include/fec/crc.h b/include/fec/crc.h deleted file mode 100644 index da6216ae2..000000000 --- a/include/fec/crc.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) - * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * OSLD-lib is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . - */ - -#ifndef CRC_ -#define CRC_ - - -unsigned int crc(unsigned int crc, char *bufptr, int len, - int long_crc,unsigned int poly, int paste_word); - -#endif diff --git a/include/io/filesink.h b/include/io/filesink.h deleted file mode 100644 index 08acd6d7a..000000000 --- a/include/io/filesink.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) - * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * OSLD-lib is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . - */ - -#ifndef FILESINK_ -#define FILESINK_ - -#include -#include - -#include "io/format.h" - -/* Low-level API */ -typedef struct { - FILE *f; - file_data_type_t type; -}filesink_t; - -int filesink_init(filesink_t *q, char *filename, file_data_type_t type); -void filesink_close(filesink_t *q); - -int filesink_write(filesink_t *q, void *buffer, int nsamples); - - -/* High-level API */ -typedef struct { - filesink_t obj; - struct filesink_init { - char *file_name; - int block_length; - int data_type; - } init; - void* input; - int in_len; -}filesink_hl; - -int filesink_initialize(filesink_hl* h); -int filesink_work( filesink_hl* hl); -int filesink_stop(filesink_hl* h); - -#endif diff --git a/include/io/format.h b/include/io/format.h deleted file mode 100644 index caa0d516a..000000000 --- a/include/io/format.h +++ /dev/null @@ -1,7 +0,0 @@ - -#ifndef FORMAT_ -#define FORMAT_ - -typedef enum { FLOAT, COMPLEX_FLOAT, COMPLEX_SHORT, FLOAT_BIN, COMPLEX_FLOAT_BIN, COMPLEX_SHORT_BIN} file_data_type_t; - -#endif diff --git a/include/lte.h b/include/lte.h deleted file mode 100644 index 5870022ab..000000000 --- a/include/lte.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) - * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * OSLD-lib is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . - */ - -#include -#include - -#ifndef _LTE_ -#define _LTE_ - -#include "utils/bit.h" -#include "utils/convolution.h" -#include "utils/debug.h" -#include "utils/dft.h" -#include "utils/matrix.h" -#include "utils/mux.h" -#include "utils/nco.h" -#include "utils/pack.h" -#include "utils/vector.h" - -#include "lte/base.h" -#include "lte/fft.h" -#include "lte/sequence.h" - -#include "ch_estimation/chest.h" -#include "ch_estimation/refsignal.h" - -#include "channel/ch_awgn.h" - -#include "fec/viterbi.h" -#include "fec/convcoder.h" -#include "fec/crc.h" - -#include "filter/filter2d.h" - -#include "io/binsource.h" -#include "io/filesink.h" -#include "io/filesource.h" - -#include "modem/demod_hard.h" -#include "modem/demod_soft.h" -#include "modem/mod.h" -#include "modem/modem_table.h" - -#include "phch/pbch.h" - -#include "ratematching/rm_conv.h" - -#include "scrambling/scrambling.h" - -#include "resampling/interp.h" - -#include "sync/pss.h" -#include "sync/sfo.h" -#include "sync/sss.h" -#include "sync/sync.h" - - -#endif diff --git a/include/lte/sequence.h b/include/lte/sequence.h deleted file mode 100644 index 0b90b4518..000000000 --- a/include/lte/sequence.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) - * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * OSLD-lib is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . - */ - -#ifndef LTESEQ_ -#define LTESEQ_ - -#include "lte/base.h" - -typedef struct { - char *c; - int len; -}sequence_t; - -int sequence_init(sequence_t *q, int len); -void sequence_free(sequence_t *q); - -int sequence_LTEPRS(sequence_t *q, int len, int seed); - -int sequence_pbch(sequence_t *seq, lte_cp_t cp, int cell_id); -int sequence_pbch_crc(sequence_t *seq, int nof_ports); - -#endif diff --git a/include/modem/mod.h b/include/modem/mod.h deleted file mode 100644 index 198153b50..000000000 --- a/include/modem/mod.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) - * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * OSLD-lib is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . - */ - -#ifndef MOD_ -#define MOD_ - -#include -#include - -#include "modem_table.h" - -typedef _Complex float cf; - -int mod_modulate(modem_table_t* table, const char *bits, cf* symbols, int nbits); - -/* High-level API */ -typedef struct { - modem_table_t obj; - struct mod_init { - enum modem_std std; // symbol mapping standard (see modem_table.h) - } init; - - const char* input; - int in_len; - - cf* output; - int out_len; -}mod_hl; - -int mod_initialize(mod_hl* hl); -int mod_work(mod_hl* hl); -int mod_stop(mod_hl* hl); - -#endif diff --git a/include/phch/pbch.h b/include/phch/pbch.h deleted file mode 100644 index 97b4b00d8..000000000 --- a/include/phch/pbch.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) - * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * OSLD-lib is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . - */ - -#ifndef PBCH_ -#define PBCH_ - -#include "lte/base.h" -#include "modem/mod.h" -#include "modem/demod_soft.h" -#include "scrambling/scrambling.h" -#include "ratematching/rm_conv.h" -#include "fec/convcoder.h" -#include "fec/viterbi.h" -#include "fec/crc.h" - -#define PBCH_RE_CPNORM 240 -#define PBCH_RE_CPEXT 216 - -typedef _Complex float cf_t; - -enum phich_length { NORMAL, EXTENDED}; -enum phich_resources { R_1_6, R_1_2, R_1, R_2}; - -typedef struct { - int nof_ports; - int nof_prb; - int sfn; - enum phich_length phich_length; - int phich_resources; -}pbch_mib_t; - -/* PBCH receiver */ -typedef struct { - int cell_id; - lte_cp_t cp; - - /* buffers */ - cf_t *pbch_symbols; - float *pbch_llr; - float *temp; - float *pbch_rm; - char *data; - - int frame_idx; - - /* tx & rx objects */ - modem_table_t mod; - demod_soft_t demod; - sequence_t seq_pbch; - viterbi_t decoder; - -}pbch_t; - -int pbch_init(pbch_t *q, int cell_id, lte_cp_t cp); -void pbch_free(pbch_t *q); -int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t **ce, int nof_ports, int nof_prb, float ebno, pbch_mib_t *data); -void pbch_mib_fprint(FILE *stream, pbch_mib_t *mib); - - -bool pbch_exists(int nframe, int nslot); -int pbch_put(cf_t *pbch, cf_t *slot1_data, int nof_prb, lte_cp_t cp, int cell_id); -int pbch_get(cf_t *pbch, cf_t *slot1_data, int nof_prb, lte_cp_t cp, int cell_id); - -#endif diff --git a/include/resampling/interp.h b/include/resampling/interp.h deleted file mode 100644 index 207a39573..000000000 --- a/include/resampling/interp.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) - * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * OSLD-lib is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . - */ - -typedef _Complex float cf_t; - - -void interp_linear_offset(cf_t *input, cf_t *output, int M, int len, int off_st, int off_end); -void interp_linear(cf_t *input, cf_t *output, int M, int len); -void interp_linear_f(float *input, float *output, int M, int len); diff --git a/include/scrambling/scrambling.h b/include/scrambling/scrambling.h deleted file mode 100644 index b5990f030..000000000 --- a/include/scrambling/scrambling.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) - * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * OSLD-lib is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . - */ - -#ifndef SCRAMBLING_ -#define SCRAMBLING_ - -#include "lte/sequence.h" -#include "lte/base.h" - -/* Scrambling has no state */ -void scrambling_bit(sequence_t *s, char *data); -void scrambling_float(sequence_t *s, float *data); -int scrambling_float_offset(sequence_t *s, float *data, int offset, int len); - - -/* High-level API */ - -/* channel integer values */ -#define PDSCH 0 /* also PUSCH */ -#define PCFICH 1 -#define PDCCH 2 -#define PBCH 3 -#define PMCH 4 -#define PUCCH 5 - -typedef struct { - sequence_t seq[NSUBFRAMES_X_FRAME]; -}scrambling_t; - -typedef struct { - scrambling_t obj; - struct scrambling_init { - int hard; - int q; - int cell_id; - int nrnti; - int nMBSFN; - int channel; - int nof_symbols; // 7 normal 6 extended - } init; - void *input; // input type may be char or float depending on hard - int in_len; - struct scrambling_ctrl_in { - int subframe; - } ctrl_in; - void *output; - int out_len; -}scrambling_hl; - -#endif diff --git a/include/sync/sfo.h b/include/sync/sfo.h deleted file mode 100644 index a759184f1..000000000 --- a/include/sync/sfo.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) - * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * OSLD-lib is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . - */ - -#ifndef SFO_ -#define SFO_ - -float sfo_estimate(int *t0, int len, float period); -float sfo_estimate_period(int *t0, int *t, int len, float period); - -#endif diff --git a/include/sync/sync.h b/include/sync/sync.h deleted file mode 100644 index c3fc547fb..000000000 --- a/include/sync/sync.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) - * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * OSLD-lib is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . - */ - -#ifndef SYNC_ -#define SYNC_ - -#include "pss.h" -#include "sss.h" -#include "sfo.h" - -enum sync_pss_det { ABSOLUTE, PEAK_MEAN}; - -typedef struct { - pss_synch_t pss[3]; // One for each N_id_2 - sss_synch_t sss[3]; // One for each N_id_2 - enum sync_pss_det pss_mode; - float threshold; - float peak_to_avg; - int force_N_id_2; - int N_id_2; - int N_id_1; - int slot_id; - float cfo; -}sync_t; - -int sync_run(sync_t *q, cf_t *input, int read_offset); -float sync_get_cfo(sync_t *q); -void sync_pss_det_absolute(sync_t *q); -void sync_pss_det_peakmean(sync_t *q); -void sync_force_N_id_2(sync_t *q, int force_N_id_2); -int sync_get_slot_id(sync_t *q); -float sync_get_peak_to_avg(sync_t *q); -int sync_get_N_id_2(sync_t *q); -int sync_get_N_id_1(sync_t *q); -int sync_get_cell_id(sync_t *q); -void sync_set_threshold(sync_t *q, float threshold); -int sync_init(sync_t *q, int frame_size); -void sync_free(sync_t *q); - -#endif - diff --git a/include/utils/bit.h b/include/utils/bit.h deleted file mode 100644 index c6f59191b..000000000 --- a/include/utils/bit.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) - * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * OSLD-lib is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . - */ - -#ifndef BIT_ -#define BIT_ - -#include -#include - -uint32_t bit_unpack(char **bits, int nof_bits); -void bit_pack(uint32_t value, char **bits, int nof_bits); -void bit_fprint(FILE *stream, char *bits, int nof_bits); -unsigned int bit_diff(char *x, char *y, int nbits); - -#endif - diff --git a/include/utils/debug.h b/include/utils/debug.h deleted file mode 100644 index 20914eedc..000000000 --- a/include/utils/debug.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef DEBUG_H -#define DEBUG_H - -#include - -#define VERBOSE_DEBUG 2 -#define VERBOSE_INFO 1 -#define VERBOSE_NONE 0 - -#include -void get_time_interval(struct timeval * tdata); - -#ifndef DEBUG_DISABLED - -extern int verbose; - -#define VERBOSE_ISINFO() (verbose==VERBOSE_INFO) -#define VERBOSE_ISDEBUG() (verbose==VERBOSE_DEBUG) - -#define PRINT_DEBUG verbose=VERBOSE_DEBUG -#define PRINT_INFO verbose=VERBOSE_INFO -#define PRINT_NONE verbose=VERBOSE_NONE - -#define DEBUG(_fmt, ...) if (verbose >= VERBOSE_DEBUG) \ - fprintf(stdout, "[DEBUG]: " _fmt, __VA_ARGS__) - -#define INFO(_fmt, ...) if (verbose >= VERBOSE_INFO) \ - fprintf(stdout, "[INFO]: " _fmt, __VA_ARGS__) - -#else - -#define DEBUG -#define INFO - -#endif - -#endif diff --git a/include/utils/mux.h b/include/utils/mux.h deleted file mode 100644 index c96e29454..000000000 --- a/include/utils/mux.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) - * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * OSLD-lib is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . - */ - - -#ifndef MUX_ -#define MUX_ - -void mux(void **input, void *output, int *input_lengths, int *input_padding_pre, int nof_inputs, - int sample_sz); - -void demux(void *input, void **output, int *output_lengths, - int *output_padding_pre, int *output_padding_post, int nof_outputs, - int sample_sz); - -#endif diff --git a/include/utils/nco.h b/include/utils/nco.h deleted file mode 100644 index ae1cb912a..000000000 --- a/include/utils/nco.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) - * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * OSLD-lib is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . - */ - -#ifndef NCO_ -#define NCO_ - -#include - -typedef struct { - int size; - float *cost; - float *sint; -}nco_t; - -void nco_init(nco_t *nco, int size); -void nco_destroy(nco_t *nco); - -float nco_sin(nco_t *nco, float phase); -float nco_cos(nco_t *nco, float phase); -void nco_sincos(nco_t *nco, float phase, float *sin, float *cos); -_Complex float nco_cexp(nco_t *nco, float arg); - -void nco_sin_f(nco_t *nco, float *x, float freq, int len); -void nco_cos_f(nco_t *nco, float *x, float freq, int len); -void nco_cexp_f(nco_t *nco, _Complex float *x, float freq, int len); -void nco_cexp_f_direct(_Complex float *x, float freq, int len); - -#endif diff --git a/include/utils/pack.h b/include/utils/pack.h deleted file mode 100644 index a7df1ec9a..000000000 --- a/include/utils/pack.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) - * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * OSLD-lib is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . - */ - -#ifndef PACK_ -#define PACK_ - -unsigned int unpack_bits(char **bits, int nof_bits); -void pack_bits(unsigned int value, char **bits, int nof_bits); - -#endif diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt deleted file mode 100644 index fb0c9f526..000000000 --- a/lib/CMakeLists.txt +++ /dev/null @@ -1,28 +0,0 @@ - - -file(GLOB modules *) - -SET(SOURCES_ALL "") -foreach (_module ${modules}) - if (IS_DIRECTORY ${_module}) - file(GLOB_RECURSE tmp "${_module}/src/*.c") - LIST(APPEND SOURCES_ALL ${tmp}) - endif() -endforeach() - - -include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../include) - - -add_library(osld ${SOURCES_ALL}) - - - - - - - - - - - diff --git a/lib/channel/src/ch_awgn.c b/lib/channel/src/ch_awgn.c deleted file mode 100644 index 003e6e3a7..000000000 --- a/lib/channel/src/ch_awgn.c +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) - * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * OSLD-lib is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . - */ - -#include -#include -#include - -#include "gauss.h" -#include "channel/ch_awgn.h" - -void ch_awgn(const cf* x, cf* y, float variance, int buff_sz) { - _Complex float tmp; - int i; - - for (i=0;iinput,hl->output,hl->ctrl_in.variance,hl->in_len); - hl->out_len = hl->in_len; - return 0; -} - -int ch_awgn_stop(ch_awgn_hl* hl) { - return 0; -} diff --git a/lib/channel/src/gauss.c b/lib/channel/src/gauss.c deleted file mode 100644 index efdd090c0..000000000 --- a/lib/channel/src/gauss.c +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) - * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * OSLD-lib is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . - */ - -#include -#include -#include - -float rand_gauss (void) { - float v1,v2,s; - - do { - v1 = 2.0 * ((float) rand()/RAND_MAX) - 1; - v2 = 2.0 * ((float) rand()/RAND_MAX) - 1; - - s = v1*v1 + v2*v2; - } while ( s >= 1.0 ); - - if (s == 0.0) - return 0.0; - else - return (v1*sqrt(-2.0 * log(s) / s)); -} diff --git a/lib/channel/src/gauss.h b/lib/channel/src/gauss.h deleted file mode 100644 index 2cb14b179..000000000 --- a/lib/channel/src/gauss.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) - * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * OSLD-lib is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . - */ - -float rand_gauss (void); diff --git a/lib/fec/src/viterbi.c b/lib/fec/src/viterbi.c deleted file mode 100644 index 074d2db7e..000000000 --- a/lib/fec/src/viterbi.c +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) - * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * OSLD-lib is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . - */ - -/**@TODO frontend to FEC library if installed - */ - -#include -#include -#include - -#include "fec/viterbi.h" -#include "parity.h" -#include "viterbi37.h" - -#define DEB 0 - -int decode37(void *o, float *symbols, char *data) { - viterbi_t *q = o; - int i; - int len = q->tail_biting ? q->framebits : (q->framebits + q->K - 1); - float amp = 0; - - for (i=0;i<3*len;i++) { - if (fabsf(symbols[i] > amp)) { - amp = symbols[i]; - } - } - - /* Decode it and make sure we get the right answer */ - /* Initialize Viterbi decoder */ - init_viterbi37_port(q->ptr, q->tail_biting?-1:0); - - /* Decode block */ - update_viterbi37_blk_port(q->ptr, symbols,q->framebits + q->K - 1, amp, len); - - /* Do Viterbi chainback */ - chainback_viterbi37_port(q->ptr, data, q->framebits, 0); - - return q->framebits; -} - -void free37(void *o) { - viterbi_t *q = o; - delete_viterbi37_port(q->ptr); -} - -int init37(viterbi_t *q, int poly[3], int framebits, bool tail_biting) { - q->K = 7; - q->R = 3; - q->framebits = framebits; - q->tail_biting = tail_biting; - q->decode = decode37; - q->free = free37; - - if ((q->ptr = create_viterbi37_port(poly, framebits, tail_biting)) == NULL) { - fprintf(stderr, "create_viterbi37 failed\n"); - return -1; - } else { - return 0; - } -} - -int viterbi_init(viterbi_t *q, viterbi_type_t type, int poly[3], int framebits, bool tail_bitting) { - switch(type) { - case viterbi_37: - return init37(q, poly, framebits, tail_bitting); - default: - fprintf(stderr, "Decoder not implemented\n"); - return -1; - } -} - -void viterbi_free(viterbi_t *q) { - q->free(q); -} - -/* symbols are real-valued */ -int viterbi_decode(viterbi_t *q, float *symbols, char *data) { - return q->decode(q, symbols, data); -} - - -int viterbi_initialize(viterbi_hl* h) { - int poly[3]; - viterbi_type_t type; - if (h->init.rate == 2) { - if (h->init.constraint_length == 7) { - type = viterbi_27; - } else if (h->init.constraint_length == 9) { - type = viterbi_29; - } else { - fprintf(stderr, "Unsupported decoder %d/%d\n", h->init.rate, - h->init.constraint_length); - return -1; - } - } else if (h->init.rate == 3) { - if (h->init.constraint_length == 7) { - type = viterbi_37; - } else if (h->init.constraint_length == 9) { - type = viterbi_39; - } else { - fprintf(stderr, "Unsupported decoder %d/%d\n", h->init.rate, - h->init.constraint_length); - return -1; - } - } else { - fprintf(stderr, "Unsupported decoder %d/%d\n", h->init.rate, - h->init.constraint_length); - return -1; - } - poly[0] = h->init.generator_0; - poly[1] = h->init.generator_1; - poly[2] = h->init.generator_2; - return viterbi_init(&h->obj, type, poly, h->init.frame_length, - h->init.tail_bitting?true:false); -} - -int viterbi_work(viterbi_hl* hl) { - if (hl->in_len != hl->init.frame_length) { - fprintf(stderr, "Expected input length %d but got %d\n", hl->init.frame_length, hl->in_len); - return -1; - } - return viterbi_decode(&hl->obj, hl->input, hl->output); -} - -int viterbi_stop(viterbi_hl* h) { - viterbi_free(&h->obj); - return 0; -} diff --git a/lib/fec/src/viterbi37.h b/lib/fec/src/viterbi37.h deleted file mode 100644 index c91d30e2a..000000000 --- a/lib/fec/src/viterbi37.h +++ /dev/null @@ -1,7 +0,0 @@ -#include - -void *create_viterbi37_port(int polys[3], int len, bool tail_biting); -int init_viterbi37_port(void *p, int starting_state); -int chainback_viterbi37_port(void *p, char *data, unsigned int nbits, unsigned int endstate); -void delete_viterbi37_port(void *p); -int update_viterbi37_blk_port(void *p, float *syms, int nbits, float amp, int framebits); diff --git a/lib/lte/src/phch_sequence.c b/lib/lte/src/phch_sequence.c deleted file mode 100644 index 281e8c6fa..000000000 --- a/lib/lte/src/phch_sequence.c +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) - * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * OSLD-lib is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . - */ - -#include "lte/base.h" -#include "lte/sequence.h" - -int sequence_pbch(sequence_t *seq, lte_cp_t cp, int cell_id) { - return sequence_LTEPRS(seq, CP_ISNORM(cp)?1920:1728, cell_id); -} diff --git a/lib/modem/src/hard_demod_lte.h b/lib/modem/src/hard_demod_lte.h deleted file mode 100644 index 5d73eb625..000000000 --- a/lib/modem/src/hard_demod_lte.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez , Vuk Marojevic . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) - * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * OSLD-lib is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . - */ - -/* Thresholds for Demodulation */ -/* Assume perfect amplitude and phase alignment. - * Check threshold values for real case - * or implement dynamic threshold adjustent as a function of received symbol amplitudes */ -#define QAM16_THRESHOLD 2/sqrt(10) -#define QAM64_THRESHOLD_1 2/sqrt(42) -#define QAM64_THRESHOLD_2 4/sqrt(42) -#define QAM64_THRESHOLD_3 6/sqrt(42) - -void hard_bpsk_demod(const cf* in, char* out, int N); -void hard_qpsk_demod(const cf* in, char* out, int N); -void hard_qam16_demod(const cf* in, char* out, int N); -void hard_qam64_demod(const cf* in, char* out, int N); diff --git a/lib/modem/src/lte_tables.h b/lib/modem/src/lte_tables.h deleted file mode 100644 index 49f259547..000000000 --- a/lib/modem/src/lte_tables.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez , Vuk Marojevic . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) - * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * OSLD-lib is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . - */ - - -#define BPSK_LEVEL 1/sqrt(2) - -#define QPSK_LEVEL 1/sqrt(2) - -#define QAM16_LEVEL_1 1/sqrt(10) -#define QAM16_LEVEL_2 3/sqrt(10) - -#define QAM64_LEVEL_1 1/sqrt(42) -#define QAM64_LEVEL_2 3/sqrt(42) -#define QAM64_LEVEL_3 5/sqrt(42) -#define QAM64_LEVEL_4 7/sqrt(42) - -#define QAM64_LEVEL_x 2/sqrt(42) -/* this is not an QAM64 level, but, rather, an auxiliary value that can be used for computing the - * symbol from the bit sequence */ - - - - -void set_BPSKtable(cf* table, soft_table_t *soft_table, bool compute_soft_demod); -void set_QPSKtable(cf* table, soft_table_t *soft_table, bool compute_soft_demod); -void set_16QAMtable(cf* table, soft_table_t *soft_table, bool compute_soft_demod); -void set_64QAMtable(cf* table, soft_table_t *soft_table, bool compute_soft_demod); diff --git a/lib/modem/src/soft_algs.h b/lib/modem/src/soft_algs.h deleted file mode 100644 index 963dd4cbb..000000000 --- a/lib/modem/src/soft_algs.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2013, Vuk Marojevic . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) - * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * OSLD-lib is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . - */ - -void llr_approx(const _Complex float *in, float *out, int N, int M, int B, - _Complex float *symbols, int (*S)[6][32], float sigma2); - -void llr_exact(const _Complex float *in, float *out, int N, int M, int B, - _Complex float *symbols, int (*S)[6][32], float sigma2); diff --git a/lib/phch/src/common.h b/lib/phch/src/common.h deleted file mode 100644 index 56774ecbb..000000000 --- a/lib/phch/src/common.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) - * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * OSLD-lib is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . - */ - -typedef _Complex float cf_t; - -void phch_cp_prb_ref(cf_t **input, cf_t **output, int offset, int nof_refs, - int nof_prb, bool advance_input); -void phch_cp_prb(cf_t **input, cf_t **output, int nof_prb); -void phch_put_prb_ref_(cf_t **input, cf_t **output, int offset, int nof_refs, - int nof_prb); -void phch_get_prb_ref(cf_t **input, cf_t **output, int offset, int nof_refs, - int nof_prb); diff --git a/lib/phch/src/pbch.c b/lib/phch/src/pbch.c deleted file mode 100644 index 0d57f37ad..000000000 --- a/lib/phch/src/pbch.c +++ /dev/null @@ -1,370 +0,0 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) - * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * OSLD-lib is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . - */ - -#include -#include -#include -#include -#include -#include - -#include "common.h" -#include "phch/pbch.h" -#include "lte/base.h" -#include "utils/bit.h" -#include "utils/vector.h" -#include "utils/debug.h" - -bool pbch_exists(int nframe, int nslot) { - return (!(nframe % 4) && nslot == 1); -} - -int pbch_cp(cf_t *input, cf_t *output, int nof_prb, lte_cp_t cp, int cell_id, bool put) { - int i; - cf_t *ptr; - if (put) { - ptr = input; - output += nof_prb * RE_X_RB / 2 - 36; - } else { - ptr = output; - input += nof_prb * RE_X_RB / 2 - 36; - } - - /* symbol 0 & 1 */ - for (i=0;i<2;i++) { - phch_cp_prb_ref(&input, &output, cell_id%3, 4, 6, put); - } - /* symbols 2 & 3 */ - if (CP_ISNORM(cp)) { - for (i=0;i<2;i++) { - phch_cp_prb(&input, &output, 6); - } - } else { - phch_cp_prb(&input, &output, 6); - phch_cp_prb_ref(&input, &output, cell_id%3, 4, 6, put); - } - if (put) { - return input - ptr; - } else { - return output - ptr; - } -} - -/** - * Puts PBCH in slot number 1 - * - * Returns the number of symbols written to slot1_data - * - * 36.211 10.3 section 6.6.4 - */ -int pbch_put(cf_t *pbch, cf_t *slot1_data, int nof_prb, lte_cp_t cp, int cell_id) { - return pbch_cp(pbch, slot1_data, nof_prb, cp, cell_id, true); -} - -/** - * Extracts PBCH from slot number 1 - * - * Returns the number of symbols written to pbch - * - * 36.211 10.3 section 6.6.4 - */ -int pbch_get(cf_t *slot1_data, cf_t *pbch, int nof_prb, lte_cp_t cp, int cell_id) { - return pbch_cp(slot1_data, pbch, nof_prb, cp, cell_id, false); -} - - -/* Checks CRC and blindly obtains the number of ports, which is saved in nof_ports. - * - * The bits buffer size must be at least 40 bytes. - * - * Returns 0 if the data is correct, -1 otherwise - */ -int pbch_crc_check(char *bits, int *nof_ports) { - int i, j; - const char crc_mask[3][16] = { - {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, - {0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1} - }; - const int ports[3] = {1, 2, 4}; - char data[40]; - - memcpy(data, bits, 24 * sizeof(char)); - - for (i=0;i<3;i++) { - for (j=0;j<16;j++) { - data[24+j] = (bits[24+j] + crc_mask[i][j]) % 2; - } - if (!crc(0, data, 40, 16, 0x11021, 0)) { - *nof_ports = ports[i]; - return 0; - } - } - *nof_ports = 0; - return -1; -} - - -/** Initializes the PBCH channel receiver */ -int pbch_init(pbch_t *q, int cell_id, lte_cp_t cp) { - int ret = -1; - bzero(q, sizeof(pbch_t)); - q->cell_id = cell_id; - q->cp = cp; - if (modem_table_std(&q->mod, LTE_QPSK, true)) { - goto clean; - } - demod_soft_init(&q->demod); - demod_soft_table_set(&q->demod, &q->mod); - demod_soft_alg_set(&q->demod, APPROX); - if (sequence_pbch(&q->seq_pbch, q->cp, q->cell_id)) { - goto clean; - } - - int poly[3] = {0x6D, 0x4F, 0x57}; - if (viterbi_init(&q->decoder, viterbi_37, poly, 40, true)) { - goto clean; - } - int nof_symbols = (CP_ISNORM(q->cp)) ? PBCH_RE_CPNORM: PBCH_RE_CPEXT; - - q->pbch_symbols = malloc(sizeof(cf_t) * nof_symbols); - if (!q->pbch_symbols) { - goto clean; - } - q->pbch_llr = malloc(sizeof(float) * nof_symbols * 4 * 2); - if (!q->pbch_llr) { - goto clean; - } - q->temp = malloc(sizeof(float) * nof_symbols * 4 * 2); - if (!q->temp) { - goto clean; - } - q->pbch_rm = malloc(sizeof(float) * 120); - if (!q->pbch_rm) { - goto clean; - } - q->data = malloc(sizeof(char) * 40); - if (!q->data) { - goto clean; - } - - ret = 0; -clean: - if (ret == -1) { - pbch_free(q); - } - return ret; -} - -void pbch_free(pbch_t *q) { - if (q->pbch_symbols) { - free(q->pbch_symbols); - } - if (q->pbch_llr) { - free(q->pbch_llr); - } - if (q->pbch_rm) { - free(q->pbch_rm); - } - if (q->data) { - free(q->data); - } - sequence_free(&q->seq_pbch); - modem_table_free(&q->mod); - viterbi_free(&q->decoder); -} - -/** Unpacks MIB from PBCH message. - * msg buffer must be 24 byte length at least - */ -void pbch_mib_unpack(char *msg, pbch_mib_t *mib) { - int bw, phich_res; - char *buffer; - - bw = 4*msg[0] + 2*msg[1] + msg[2]; - switch(bw) { - case 0: - mib->nof_prb = 6; - break; - case 1: - mib->nof_prb = 15; - break; - default: - mib->nof_prb = (bw-1)*25; - break; - } - if (msg[3]) { - mib->phich_length = EXTENDED; - } else { - mib->phich_length = NORMAL; - } - phich_res = 2*msg[4] + msg[5]; - switch(phich_res) { - case 0: - mib->phich_resources = R_1_6; - break; - case 1: - mib->phich_resources = R_1_2; - break; - case 2: - mib->phich_resources = R_1; - break; - case 3: - mib->phich_resources = R_2; - break; - } - buffer = &msg[6]; - mib->sfn = bit_unpack(&buffer, 8); -} - -void pbch_mib_fprint(FILE *stream, pbch_mib_t *mib) { - printf(" - Nof ports: %d\n", mib->nof_ports); - printf(" - PRB: %d\n", mib->nof_prb); - printf(" - PHICH Length: %s\n", mib->phich_length==EXTENDED?"Extended":"Normal"); - printf(" - PHICH Resources: "); - switch(mib->phich_resources) { - case R_1_6: - printf("1/6"); - break; - case R_1_2: - printf("1/2"); - break; - case R_1: - printf("1"); - break; - case R_2: - printf("2"); - break; - } - printf("\n"); - printf(" - SFN: %d\n", mib->sfn); -} - -void pbch_decode_reset(pbch_t *q) { - q->frame_idx = 0; -} - -int pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, int src, int dst, int n, int nof_bits) { - int j; - - memcpy(&q->temp[dst*nof_bits], &q->pbch_llr[src*nof_bits], n*nof_bits*sizeof(float)); - - /* descramble */ - scrambling_float_offset(&q->seq_pbch, &q->temp[dst*nof_bits], dst*nof_bits, n*nof_bits); - - for (j=0;jtemp[j] = RX_NULL; - } - for (j=(dst+n)*nof_bits;j<4*nof_bits;j++) { - q->temp[j] = RX_NULL; - } - - /* unrate matching */ - rm_conv_rx(q->temp, q->pbch_rm, 4 * nof_bits, 120); - - /* decode */ - viterbi_decode(&q->decoder, q->pbch_rm, q->data); - - /* check crc and get nof ports */ - if (pbch_crc_check(q->data, &mib->nof_ports)) { - - return 0; - } else { - - printf("BCH Decoded Correctly.\n"); - - /* unpack MIB */ - pbch_mib_unpack(q->data, mib); - - mib->sfn += dst-src; - - pbch_mib_fprint(stdout, mib); - - return 1; - } -} - -/* Decodes the PBCH channel - * - * The PBCH spans in 40 ms. This function is called every 10 ms. It tries to decode the MIB - * given the symbols of the slot #1 of each radio frame. Successive calls will use more frames - * to help the decoding process. - * - * Returns 1 if successfully decoded MIB, 0 if not and -1 on error - */ -int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t **ce, int nof_ports, - int nof_prb, float ebno, pbch_mib_t *mib) { - int src, dst, res, nb, nant; - - int nof_symbols = (CP_ISNORM(q->cp)) ? PBCH_RE_CPNORM: PBCH_RE_CPEXT; - int nof_bits = 2 * nof_symbols; - - /* extract symbols */ - if (nof_symbols != pbch_get(slot1_symbols, q->pbch_symbols, nof_prb, - q->cp, q->cell_id)) { - fprintf(stderr, "There was an error getting the PBCH symbols\n"); - return -1; - } - - /* Try decoding for 1 to nof_ports antennas */ - for (nant=0;nantpbch_symbols[i] /= ce[0][i]; - } - - /*@TODO: layer demapping */ - - /* demodulate symbols */ - demod_soft_sigma_set(&q->demod, ebno); - demod_soft_demodulate(&q->demod, q->pbch_symbols, - &q->pbch_llr[nof_bits * q->frame_idx], nof_symbols); - - q->frame_idx++; - - INFO("PBCH: %d frames in buffer\n", q->frame_idx); - - /* We don't know where the 40 ms begin, so we try all combinations. E.g. if we received - * 4 frames, try 1,2,3,4 individually, 12, 23, 34 in pairs, 123, 234 and finally 1234. - * We know they are ordered. - */ - res = 0; - for (nb=0;nbframe_idx && !res;nb++) { - for (dst=0;(dst<4-nb) && !res;dst++) { - for (src=0;srcframe_idx && !res;src++) { - DEBUG("Trying %d blocks at offset %d as subframe mod4 number %d\n", nb+1, src, dst); - res = pbch_decode_frame(q, mib, src, dst, nb+1, nof_bits); - } - } - } - - if (res) { - q->frame_idx = 0; - return 1; - } - } - - /* If not found, make room for the next packet of radio frame symbols */ - if (q->frame_idx == 4) { - memcpy(&q->pbch_llr[nof_bits], q->pbch_llr, nof_bits * 3 * sizeof(float)); - q->frame_idx = 3; - } - return 0; -} diff --git a/lib/scrambling/src/scrambling.c b/lib/scrambling/src/scrambling.c deleted file mode 100644 index 2b0a5cf8c..000000000 --- a/lib/scrambling/src/scrambling.c +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) - * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * OSLD-lib is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . - */ - -#include -#include -#include -#include "scrambling/scrambling.h" - -/** - * @ingroup Soft-bit Scrambling - * Scrambles the input softbit-sequence (floats) with the scrambling - * sequence (32-bit integers). - * - */ -void scrambling_float(sequence_t *s, float *data) { - scrambling_float_offset(s, data, 0, s->len); -} - -int scrambling_float_offset(sequence_t *s, float *data, int offset, int len) { - int i; - if (len + offset > s->len) { - return -1; - } - for (i = 0; i < len; i++) { - data[i] = data[i]*(1-2*s->c[i+offset]); - } - return 0; -} - -/** - * @ingroup Bit Scrambling - * Directly scrambles the input bit-sequence (char) with the scrambling - * sequence. - */ -void scrambling_bit(sequence_t *s, char *data) { - int i; - - for (i = 0; i < s->len; i++) { - data[i] = (data[i] + s->c[i]) % 2; - } -} - -/** High-level API */ - -int compute_sequences(scrambling_hl* h) { - - switch (h->init.channel) { - case PBCH: - return sequence_pbch(&h->obj.seq[0], h->init.nof_symbols == CPNORM_NSYMB, - h->init.cell_id); - case PDSCH: - case PCFICH: - case PDCCH: - case PMCH: - case PUCCH: - fprintf(stderr, "Not implemented\n"); - return -1; - default: - fprintf(stderr, "Invalid channel %d\n", h->init.channel); - return -1; - } -} - -int scrambling_initialize(scrambling_hl* h) { - - bzero(&h->obj, sizeof(scrambling_t)); - - return compute_sequences(h); -} - -/** This function can be called in a subframe (1ms) basis for LTE */ -int scrambling_work(scrambling_hl* hl) { - int sf; - if (hl->init.channel == PBCH) { - sf = 0; - } else { - sf = hl->ctrl_in.subframe; - } - sequence_t *seq = &hl->obj.seq[sf]; - - if (hl->init.hard) { - memcpy(hl->output, hl->input, sizeof(char) * hl->in_len); - scrambling_bit(seq, hl->output); - } else { - memcpy(hl->output, hl->input, sizeof(float) * hl->in_len); - scrambling_float(seq, hl->output); - } - hl->out_len = hl->in_len; - return 0; -} - -int scrambling_stop(scrambling_hl* hl) { - int i; - for (i=0;iobj.seq[i]); - } - return 0; -} - diff --git a/lib/sync/src/cp.c b/lib/sync/src/cp.c deleted file mode 100644 index 567267290..000000000 --- a/lib/sync/src/cp.c +++ /dev/null @@ -1,5 +0,0 @@ - - -/** TODO: Cyclic-prefix based synchronization - * - */ diff --git a/lib/sync/src/sync.c b/lib/sync/src/sync.c deleted file mode 100644 index bcb14ce9c..000000000 --- a/lib/sync/src/sync.c +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) - * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * OSLD-lib is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . - */ - - -#include - -#include "utils/debug.h" -#include "lte/base.h" -#include "sync/sync.h" - -int sync_init(sync_t *q, int frame_size) { - int N_id_2; - - bzero(q, sizeof(sync_t)); - q->force_N_id_2 = -1; - q->threshold = 1.5; - q->pss_mode = PEAK_MEAN; - - for (N_id_2=0;N_id_2<3;N_id_2++) { - if (pss_synch_init(&q->pss[N_id_2], frame_size)) { - fprintf(stderr, "Error initializing PSS object\n"); - return -1; - } - if (pss_synch_set_N_id_2(&q->pss[N_id_2], N_id_2)) { - fprintf(stderr, "Error initializing N_id_2\n"); - return -1; - } - if (sss_synch_init(&q->sss[N_id_2])) { - fprintf(stderr, "Error initializing SSS object\n"); - return -1; - } - if (sss_synch_set_N_id_2(&q->sss[N_id_2], N_id_2)) { - fprintf(stderr, "Error initializing N_id_2\n"); - return -1; - } - DEBUG("PSS and SSS initiated N_id_2=%d\n", N_id_2); - } - - return 0; -} - -void sync_free(sync_t *q) { - int N_id_2; - - for (N_id_2=0;N_id_2<3;N_id_2++) { - pss_synch_free(&q->pss[N_id_2]); - sss_synch_free(&q->sss[N_id_2]); - } -} - -void sync_pss_det_absolute(sync_t *q) { - q->pss_mode = ABSOLUTE; -} -void sync_pss_det_peakmean(sync_t *q) { - q->pss_mode = PEAK_MEAN; -} - -void sync_set_threshold(sync_t *q, float threshold) { - q->threshold = threshold; -} - -void sync_force_N_id_2(sync_t *q, int force_N_id_2) { - q->force_N_id_2 = force_N_id_2; -} - -int sync_get_cell_id(sync_t *q) { - if (q->N_id_1 >=0 && q->N_id_2 >= 0) { - return q->N_id_1*3 + q->N_id_2; - } else { - return -1; - } -} - -int sync_get_N_id_1(sync_t *q) { - return q->N_id_1; -} - -int sync_get_N_id_2(sync_t *q) { - return q->N_id_2; -} - -int sync_get_slot_id(sync_t *q) { - return q->slot_id; -} - -float sync_get_cfo(sync_t *q) { - return q->cfo; -} - -float sync_get_peak_to_avg(sync_t *q) { - return q->peak_to_avg; -} - -int sync_run(sync_t *q, cf_t *input, int read_offset) { - int N_id_2, peak_pos[3], sss_idx; - int m0, m1; - float m0_value, m1_value; - float peak_value[3]; - float mean_value[3]; - float max=-999; - int i; - int peak_detected; - - if (q->force_N_id_2 == -1) { - for (N_id_2=0;N_id_2<3;N_id_2++) { - peak_pos[N_id_2] = pss_synch_find_pss(&q->pss[N_id_2], &input[read_offset], - &peak_value[N_id_2], &mean_value[N_id_2]); - } - for (i=0;i<3;i++) { - if (peak_value[i] > max) { - max = peak_value[i]; - N_id_2 = i; - } - } - } else { - N_id_2 = q->force_N_id_2; - peak_pos[N_id_2] = pss_synch_find_pss(&q->pss[N_id_2], &input[read_offset], - &peak_value[N_id_2], &mean_value[N_id_2]); - } - - q->peak_to_avg = peak_value[N_id_2] / mean_value[N_id_2]; - - DEBUG("PSS possible peak N_id_2=%d, pos=%d peak=%.2f par=%.2f threshold=%.2f\n", - N_id_2, peak_pos[N_id_2], peak_value[N_id_2], q->peak_to_avg, q->threshold); - - /* If peak detected */ - peak_detected = 0; - if (peak_pos[N_id_2] + read_offset > 128) { - if (q->pss_mode == ABSOLUTE) { - if (peak_value[N_id_2] > q->threshold) { - peak_detected = 1; - } - } else { - if (q->peak_to_avg > q->threshold) { - peak_detected = 1; - } - } - } - if (peak_detected) { - - - q->cfo = pss_synch_cfo_compute(&q->pss[N_id_2], &input[read_offset + peak_pos[N_id_2]-128]); - - INFO("PSS peak detected N_id_2=%d, pos=%d peak=%.2f par=%.2f th=%.2f cfo=%.4f\n", N_id_2, - peak_pos[N_id_2], peak_value[N_id_2], q->peak_to_avg, q->threshold, q->cfo); - - sss_idx = read_offset + peak_pos[N_id_2]-2*(128+CP(128,CPNORM_LEN)); - if (sss_idx>= 0) { - sss_synch_m0m1(&q->sss[N_id_2], &input[sss_idx], - &m0, &m0_value, &m1, &m1_value); - - q->N_id_2 = N_id_2; - q->slot_id = 2 * sss_synch_subframe(m0, m1); - q->N_id_1 = sss_synch_N_id_1(&q->sss[N_id_2], m0, m1); - - INFO("SSS detected N_id_1=%d, slot_idx=%d, m0=%d, m1=%d\n", - q->N_id_1, q->slot_id, m0, m1); - - return peak_pos[N_id_2]; - } else { - return -1; - } - } else { - return -1; - } -} diff --git a/lib/utils/src/debug.c b/lib/utils/src/debug.c deleted file mode 100644 index c5a25548c..000000000 --- a/lib/utils/src/debug.c +++ /dev/null @@ -1,13 +0,0 @@ -#include "utils/debug.h" - -int verbose = 0; - -void get_time_interval(struct timeval * tdata) { - - tdata[0].tv_sec = tdata[2].tv_sec - tdata[1].tv_sec; - tdata[0].tv_usec = tdata[2].tv_usec - tdata[1].tv_usec; - if (tdata[0].tv_usec < 0) { - tdata[0].tv_sec--; - tdata[0].tv_usec += 1000000; - } -} diff --git a/lib/utils/src/nco.c b/lib/utils/src/nco.c deleted file mode 100644 index 874519a1c..000000000 --- a/lib/utils/src/nco.c +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) - * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * OSLD-lib is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . - */ - - - -#include -#include -#include -#include -#include - -#include "utils/nco.h" - -void nco_init(nco_t *nco, int size) { - int i; - - nco->size=size; - nco->cost=malloc(size*sizeof(float)); - nco->sint=malloc(size*sizeof(float)); - assert(nco->cost && nco->sint); - - for (i=0;icost[i] = cosf(2*M_PI*i/size); - nco->sint[i] = sinf(2*M_PI*i/size); - } -} - -void nco_destroy(nco_t *nco) { - if (nco->cost) { - free(nco->cost); - } - if (nco->sint) { - free(nco->sint); - } - nco->size=0; - bzero(nco, sizeof(nco_t)); -} - -unsigned int nco_idx(float phase, int size) { - while(phase>=2*M_PI) { - phase-=2*M_PI; - } - unsigned int idx = (unsigned int) (phase*size/(2*M_PI)); - return idx; -} - -inline float nco_sin(nco_t *nco, float phase) { - return nco->sint[nco_idx(phase,nco->size)]; -} -inline float nco_cos(nco_t *nco, float phase) { - return nco->cost[nco_idx(phase,nco->size)]; -} -inline void nco_sincos(nco_t *nco, float phase, float *sin, float *cos) { - unsigned int idx = nco_idx(phase,nco->size); - *sin = nco->sint[idx]; - *cos = nco->cost[idx]; -} - -inline _Complex float nco_cexp(nco_t *nco, float arg) { - float s,c; - nco_sincos(nco,arg,&s,&c); - return c+I*s; -} - -void nco_sin_f(nco_t *nco, float *x, float freq, int len) { - int i; - unsigned int idx; - - idx=0; - for (i=0;isize/len))%nco->size; - x[i] = nco->sint[idx]; - } -} - - -void nco_cos_f(nco_t *nco, float *x, float freq, int len) { - int i; - unsigned int idx; - - idx=0; - for (i=0;isize/len))%nco->size; - x[i] = nco->cost[idx]; - } -} - - -void nco_cexp_f(nco_t *nco, _Complex float *x, float freq, int len) { - int i; - unsigned int idx; - - idx=0; - for (i=0;isize/len))%nco->size; - x[i] = nco->cost[idx] + I*nco->sint[idx]; - } -} - -void nco_cexp_f_direct(_Complex float *x, float freq, int len) { - int i; - for (i=0;i +#include + +#ifndef _LTE_ +#define _LTE_ + +#include "lte/utils/bit.h" +#include "lte/utils/convolution.h" +#include "lte/utils/debug.h" +#include "lte/utils/dft.h" +#include "lte/utils/matrix.h" +#include "lte/utils/mux.h" +#include "lte/utils/cexptab.h" +#include "lte/utils/pack.h" +#include "lte/utils/vector.h" + +#include "lte/common/base.h" +#include "lte/common/fft.h" +#include "lte/common/sequence.h" + +#include "lte/ch_estimation/chest.h" +#include "lte/ch_estimation/refsignal.h" + +#include "lte/channel/ch_awgn.h" + +#include "lte/fec/viterbi.h" +#include "lte/fec/convcoder.h" +#include "lte/fec/crc.h" + +#include "lte/filter/filter2d.h" + +#include "lte/io/binsource.h" +#include "lte/io/filesink.h" +#include "lte/io/filesource.h" +#include "lte/io/udpsink.h" +#include "lte/io/udpsource.h" + +#include "lte/modem/demod_hard.h" +#include "lte/modem/demod_soft.h" +#include "lte/modem/mod.h" +#include "lte/modem/modem_table.h" + +#include "lte/mimo/precoding.h" +#include "lte/mimo/layermap.h" + +#include "lte/phch/regs.h" +#include "lte/phch/pbch.h" +#include "lte/phch/pcfich.h" +#include "lte/phch/phich.h" + +#include "lte/ratematching/rm_conv.h" + +#include "lte/scrambling/scrambling.h" + +#include "lte/resampling/interp.h" + +#include "lte/sync/pss.h" +#include "lte/sync/sfo.h" +#include "lte/sync/sss.h" +#include "lte/sync/sync.h" +#include "lte/sync/cfo.h" + +#endif diff --git a/include/ch_estimation/chest.h b/lte/include/lte/ch_estimation/chest.h similarity index 76% rename from include/ch_estimation/chest.h rename to lte/include/lte/ch_estimation/chest.h index 1d42687e3..0f55580de 100644 --- a/include/ch_estimation/chest.h +++ b/lte/include/lte/ch_estimation/chest.h @@ -1,29 +1,40 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * \section COPYRIGHT * - * OSLD-lib is distributed in the hope that it will be useful, + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 CHEST_ #define CHEST_ #include -#include "ch_estimation/refsignal.h" -#include "filter/filter2d.h" -#include "lte/base.h" +#include "lte/ch_estimation/refsignal.h" +#include "lte/filter/filter2d.h" +#include "lte/common/base.h" typedef _Complex float cf_t; /* this is only a shortcut */ diff --git a/include/ch_estimation/refsignal.h b/lte/include/lte/ch_estimation/refsignal.h similarity index 57% rename from include/ch_estimation/refsignal.h rename to lte/include/lte/ch_estimation/refsignal.h index 7fec166af..707788361 100644 --- a/include/ch_estimation/refsignal.h +++ b/lte/include/lte/ch_estimation/refsignal.h @@ -1,21 +1,32 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * \section COPYRIGHT * - * OSLD-lib is distributed in the hope that it will be useful, + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 REFSIGNAL_ #define REFSIGNAL_ @@ -26,7 +37,7 @@ * */ -#include "lte/base.h" +#include "lte/common/base.h" typedef _Complex float cf_t; @@ -42,13 +53,15 @@ typedef struct { int *symbols_ref; // symbols with at least one reference int nsymbols; // number of symbols with at least one reference int voffset; // offset of the first reference in the freq domain + int nof_prb; ref_t *refs; cf_t *ch_est; } refsignal_t; int refsignal_init_LTEDL(refsignal_t *q, int port_id, int nslot, int cell_id, lte_cp_t cp, int nof_prb); - void refsignal_free(refsignal_t *q); +void refsignal_put(refsignal_t *q, cf_t *slot_symbols); + #endif diff --git a/lte/include/lte/channel/ch_awgn.h b/lte/include/lte/channel/ch_awgn.h new file mode 100644 index 000000000..2e6ada48d --- /dev/null +++ b/lte/include/lte/channel/ch_awgn.h @@ -0,0 +1,56 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 + +#ifndef CH_AWGN_ +#define CH_AWGN_ + +typedef _Complex float cf_t; + +void ch_awgn_c(const cf_t* input, cf_t* output, float variance, int buff_sz); +void ch_awgn_f(const float* x, float* y, float variance, int buff_sz); + +/* High-level API */ + +typedef struct { + const cf_t* input; + int in_len; + struct ch_awgn_ctrl_in { + float variance; // Noise variance + } ctrl_in; + + cf_t* output; + int out_len; +}ch_awgn_hl; + +int ch_awgn_initialize(ch_awgn_hl* hl); +int ch_awgn_work(ch_awgn_hl* hl); +int ch_awgn_stop(ch_awgn_hl* hl); + +#endif diff --git a/include/lte/base.h b/lte/include/lte/common/base.h similarity index 60% rename from include/lte/base.h rename to lte/include/lte/common/base.h index b359833f6..5592c3d5b 100644 --- a/include/lte/base.h +++ b/lte/include/lte/common/base.h @@ -1,28 +1,41 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * \section COPYRIGHT * - * OSLD-lib is distributed in the hope that it will be useful, + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 _LTEBASE_ #define _LTEBASE_ #define NSUBFRAMES_X_FRAME 10 #define NSLOTS_X_FRAME (2*NSUBFRAMES_X_FRAME) -#define MAX_PORTS 4 +#define MAX_PORTS 4 +#define MAX_PORTS_CTRL 4 +#define MAX_LAYERS 8 +#define MAX_CODEWORDS 2 typedef enum {CPNORM, CPEXT} lte_cp_t; @@ -48,15 +61,14 @@ typedef enum {CPNORM, CPEXT} lte_cp_t; #define SLOT_LEN_CPNORM(symbol_sz) (symbol_sz+CP(symbol_sz,CPNORM_0_LEN)+(CPNORM_NSYMB-1)*(symbol_sz+CP(symbol_sz,CPNORM_LEN))) #define SLOT_LEN_CPEXT(symbol_sz) (CPEXT_NSYMB*(symbol_sz+CP(symbol_sz, CPEXT_LEN))) +#define SLOT_LEN(symbol_sz, cp) CP_ISNORM(cp)?SLOT_LEN_CPNORM(symbol_sz):SLOT_LEN_CPEXT(symbol_sz) #define SF_LEN_CPNORM(symbol_sz) 2*SLOT_LEN_CPNORM(symbol_sz) #define SF_LEN_CPEXT(symbol_sz) 2*SLOT_LEN_CPEXT(symbol_sz) +#define SF_LEN(symbol_sz, cp) 2*SLOT_LEN(cp, symbol_sz) -#define SF_IDX_CPNORM(idx, symbol_sz) (idx==0?(CP(symbol_sz, CPNORM_0_LEN)):(CP(symbol_sz, CPNORM_0_LEN)+idx*(symbol_sz+CP(symbol_sz, CPNORM_LEN)))) -#define SF_IDX_CPEXT(idx, symbol_sz) (idx*(symbol_sz+CP(symbol_sz, CPEXT_LEN))) - -#define SLOT_IDX_CPNORM(idx, symbol_sz) (idx==0?0:symbol_sz*CPNORM_NSYMB) -#define SLOT_IDX_CPEXT(idx, symbol_sz) (idx==0?0:symbol_sz*CPEXT_NSYMB) +#define SLOT_IDX_CPNORM(idx, symbol_sz) (idx==0?(CP(symbol_sz, CPNORM_0_LEN)):(CP(symbol_sz, CPNORM_0_LEN)+idx*(symbol_sz+CP(symbol_sz, CPNORM_LEN)))) +#define SLOT_IDX_CPEXT(idx, symbol_sz) (idx*(symbol_sz+CP(symbol_sz, CPEXT_LEN))) #define MAX_PRB 110 #define RE_X_RB 12 @@ -74,6 +86,14 @@ int lte_voffset(int symbol_id, int cell_id, int nof_ports); #define NOF_LTE_BANDS 29 +typedef enum { + SINGLE_ANTENNA,TX_DIVERSITY, SPATIAL_MULTIPLEX +} mimo_type_t; + +typedef enum { PHICH_NORM, PHICH_EXT} phich_length_t; +typedef enum { R_1_6, R_1_2, R_1, R_2} phich_resources_t; + + typedef struct { int id; float fd; @@ -88,6 +108,8 @@ int lte_band_get_fd_band(int band, lte_earfcn_t *earfcn, int earfcn_start, int e int lte_band_get_fd_band_all(int band, lte_earfcn_t *earfcn, int max_nelems); int lte_band_get_fd_region(enum band_geographical_area region, lte_earfcn_t *earfcn, int max_elems); +int lte_str2mimotype(char *mimo_type_str, mimo_type_t *type); +char *lte_mimotype2str(mimo_type_t type); #endif diff --git a/include/lte/fft.h b/lte/include/lte/common/fft.h similarity index 57% rename from include/lte/fft.h rename to lte/include/lte/common/fft.h index 9859c9df2..e84342f13 100644 --- a/include/lte/fft.h +++ b/lte/include/lte/common/fft.h @@ -1,21 +1,31 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * \section COPYRIGHT * - * OSLD-lib is distributed in the hope that it will be useful, + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 LTEFFT_ #define LTEFFT_ @@ -23,8 +33,8 @@ #include #include -#include "lte/base.h" -#include "utils/dft.h" +#include "lte/common/base.h" +#include "lte/utils/dft.h" typedef _Complex float cf_t; /* this is only a shortcut */ diff --git a/lte/include/lte/common/sequence.h b/lte/include/lte/common/sequence.h new file mode 100644 index 000000000..c52f44602 --- /dev/null +++ b/lte/include/lte/common/sequence.h @@ -0,0 +1,48 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 LTESEQ_ +#define LTESEQ_ + +#include "lte/common/base.h" + +typedef struct { + char *c; + int len; +}sequence_t; + +int sequence_init(sequence_t *q, int len); +void sequence_free(sequence_t *q); + +int sequence_LTEPRS(sequence_t *q, int len, int seed); + +int sequence_pbch(sequence_t *seq, lte_cp_t cp, int cell_id); +int sequence_pcfich(sequence_t *seq, int nslot, int cell_id); +int sequence_phich(sequence_t *seq, int nslot, int cell_id); + +#endif diff --git a/include/fec/convcoder.h b/lte/include/lte/fec/convcoder.h similarity index 58% rename from include/fec/convcoder.h rename to lte/include/lte/fec/convcoder.h index afec93790..ac62a358e 100644 --- a/include/fec/convcoder.h +++ b/lte/include/lte/fec/convcoder.h @@ -1,21 +1,32 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * \section COPYRIGHT * - * OSLD-lib is distributed in the hope that it will be useful, + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 CONVCODER_ #define CONVCODER_ diff --git a/lte/include/lte/fec/crc.h b/lte/include/lte/fec/crc.h new file mode 100644 index 000000000..dd29d8868 --- /dev/null +++ b/lte/include/lte/fec/crc.h @@ -0,0 +1,37 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 CRC_ +#define CRC_ + + +unsigned int crc(unsigned int crc, char *bufptr, int len, + int long_crc,unsigned int poly, int paste_word); + +#endif diff --git a/include/fec/viterbi.h b/lte/include/lte/fec/viterbi.h similarity index 54% rename from include/fec/viterbi.h rename to lte/include/lte/fec/viterbi.h index 63d192488..9cf2cbb88 100644 --- a/include/fec/viterbi.h +++ b/lte/include/lte/fec/viterbi.h @@ -1,21 +1,31 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * \section COPYRIGHT * - * OSLD-lib is distributed in the hope that it will be useful, + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 VITERBI_ #define VITERBI_ @@ -32,13 +42,16 @@ typedef struct { unsigned int framebits; bool tail_biting; int poly[3]; - int (*decode) (void*, float*, char*); + int (*decode) (void*, unsigned char*, char*); void (*free) (void*); + unsigned char *tmp; + unsigned char *symbols_uc; }viterbi_t; int viterbi_init(viterbi_t *q, viterbi_type_t type, int poly[3], int framebits, bool tail_bitting); void viterbi_free(viterbi_t *q); -int viterbi_decode(viterbi_t *q, float *symbols, char *data); +int viterbi_decode_f(viterbi_t *q, float *symbols, char *data); +int viterbi_decode_uc(viterbi_t *q, unsigned char *symbols, char *data); /* High-level API */ diff --git a/include/filter/filter2d.h b/lte/include/lte/filter/filter2d.h similarity index 60% rename from include/filter/filter2d.h rename to lte/include/lte/filter/filter2d.h index 73d51dbfa..44325c08d 100644 --- a/include/filter/filter2d.h +++ b/lte/include/lte/filter/filter2d.h @@ -1,21 +1,32 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * \section COPYRIGHT * - * OSLD-lib is distributed in the hope that it will be useful, + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 FILTER2D_ #define FILTER2D_ diff --git a/include/io/binsource.h b/lte/include/lte/io/binsource.h similarity index 67% rename from include/io/binsource.h rename to lte/include/lte/io/binsource.h index eb926cfb1..67e525bab 100644 --- a/include/io/binsource.h +++ b/lte/include/lte/io/binsource.h @@ -1,21 +1,31 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * \section COPYRIGHT * - * OSLD-lib is distributed in the hope that it will be useful, + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 BINSOURCE_ #define BINSOURCE_ diff --git a/lte/include/lte/io/filesink.h b/lte/include/lte/io/filesink.h new file mode 100644 index 000000000..2d0f2d99b --- /dev/null +++ b/lte/include/lte/io/filesink.h @@ -0,0 +1,65 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 FILESINK_ +#define FILESINK_ + +#include +#include + +#include "lte/io/format.h" + +/* Low-level API */ +typedef struct { + FILE *f; + data_type_t type; +}filesink_t; + +int filesink_init(filesink_t *q, char *filename, data_type_t type); +void filesink_free(filesink_t *q); + +int filesink_write(filesink_t *q, void *buffer, int nsamples); + + +/* High-level API */ +typedef struct { + filesink_t obj; + struct filesink_init { + char *file_name; + int block_length; + int data_type; + } init; + void* input; + int in_len; +}filesink_hl; + +int filesink_initialize(filesink_hl* h); +int filesink_work( filesink_hl* hl); +int filesink_stop(filesink_hl* h); + +#endif diff --git a/include/io/filesource.h b/lte/include/lte/io/filesource.h similarity index 51% rename from include/io/filesource.h rename to lte/include/lte/io/filesource.h index c574da05c..d8c787cc2 100644 --- a/include/io/filesource.h +++ b/lte/include/lte/io/filesource.h @@ -1,38 +1,49 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * \section COPYRIGHT * - * OSLD-lib is distributed in the hope that it will be useful, + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 FILESOURCE_ #define FILESOURCE_ #include #include -#include "io/format.h" +#include "lte/io/format.h" /* Low-level API */ typedef struct { FILE *f; - file_data_type_t type; + data_type_t type; }filesource_t; -int filesource_init(filesource_t *q, char *filename, file_data_type_t type); -void filesource_close(filesource_t *q); +int filesource_init(filesource_t *q, char *filename, data_type_t type); +void filesource_free(filesource_t *q); +void filesource_seek(filesource_t *q, int pos); int filesource_read(filesource_t *q, void *buffer, int nsamples); diff --git a/lte/include/lte/io/format.h b/lte/include/lte/io/format.h new file mode 100644 index 000000000..0c313a37f --- /dev/null +++ b/lte/include/lte/io/format.h @@ -0,0 +1,34 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 FORMAT_ +#define FORMAT_ + +typedef enum { FLOAT, COMPLEX_FLOAT, COMPLEX_SHORT, FLOAT_BIN, COMPLEX_FLOAT_BIN, COMPLEX_SHORT_BIN} data_type_t; + +#endif diff --git a/lte/include/lte/io/udpsink.h b/lte/include/lte/io/udpsink.h new file mode 100644 index 000000000..e0acd2c3a --- /dev/null +++ b/lte/include/lte/io/udpsink.h @@ -0,0 +1,70 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 udpsink_ +#define udpsink_ + +#include +#include +#include +#include +#include + +#include "lte/io/format.h" + +/* Low-level API */ +typedef struct { + int sockfd; + struct sockaddr_in servaddr; + data_type_t type; +}udpsink_t; + +int udpsink_init(udpsink_t *q, char *address, int port, data_type_t type); +void udpsink_free(udpsink_t *q); + +int udpsink_write(udpsink_t *q, void *buffer, int nsamples); + + +/* High-level API */ +typedef struct { + udpsink_t obj; + struct udpsink_init { + char *address; + int port; + int block_length; + int data_type; + } init; + void* input; + int in_len; +}udpsink_hl; + +int udpsink_initialize(udpsink_hl* h); +int udpsink_work( udpsink_hl* hl); +int udpsink_stop(udpsink_hl* h); + +#endif diff --git a/lte/include/lte/io/udpsource.h b/lte/include/lte/io/udpsource.h new file mode 100644 index 000000000..42d6839ae --- /dev/null +++ b/lte/include/lte/io/udpsource.h @@ -0,0 +1,73 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 udpsource_ +#define udpsource_ + + +#include +#include +#include +#include +#include + +#include "lte/io/format.h" + +/* Low-level API */ +typedef struct { + int sockfd; + struct sockaddr_in servaddr; + data_type_t type; +}udpsource_t; + +int udpsource_init(udpsource_t *q, char *address, int port, data_type_t type); +void udpsource_free(udpsource_t *q); + +int udpsource_read(udpsource_t *q, void *buffer, int nsamples); + + +/* High-level API */ +typedef struct { + udpsource_t obj; + struct udpsource_init { + char *address; + int port; + int data_type; + } init; + struct udpsource_ctrl_in { + int nsamples; // Number of samples to read + } ctrl_in; + void* output; + int out_len; +}udpsource_hl; + +int udpsource_initialize(udpsource_hl* h); +int udpsource_work( udpsource_hl* hl); +int udpsource_stop(udpsource_hl* h); + +#endif diff --git a/lte/include/lte/mimo/layermap.h b/lte/include/lte/mimo/layermap.h new file mode 100644 index 000000000..9a2f6f9bb --- /dev/null +++ b/lte/include/lte/mimo/layermap.h @@ -0,0 +1,53 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 LAYERMAP_H_ +#define LAYERMAP_H_ + +typedef _Complex float cf_t; + +/* Generates the vector of layer-mapped symbols "x" based on the vector of data symbols "d" + */ +int layermap_single(cf_t *d, cf_t *x, int nof_symbols); +int layermap_diversity(cf_t *d, cf_t *x[MAX_LAYERS], int nof_layers, int nof_symbols); +int layermap_multiplex(cf_t *d[MAX_CODEWORDS], cf_t *x[MAX_LAYERS], int nof_cw, int nof_layers, + int nof_symbols[MAX_CODEWORDS]); +int layermap_type(cf_t *d[MAX_CODEWORDS], cf_t *x[MAX_LAYERS], int nof_cw, int nof_layers, + int nof_symbols[MAX_CODEWORDS], mimo_type_t type); + + +/* Generates the vector of data symbols "d" based on the vector of layer-mapped symbols "x" + */ +int layerdemap_single(cf_t *x, cf_t *d, int nof_symbols); +int layerdemap_diversity(cf_t *x[MAX_LAYERS], cf_t *d, int nof_layers, int nof_layer_symbols); +int layerdemap_multiplex(cf_t *x[MAX_LAYERS], cf_t *d[MAX_CODEWORDS], int nof_layers, int nof_cw, + int nof_layer_symbols, int nof_symbols[MAX_CODEWORDS]); +int layerdemap_type(cf_t *x[MAX_LAYERS], cf_t *d[MAX_CODEWORDS], int nof_layers, int nof_cw, + int nof_layer_symbols, int nof_symbols[MAX_CODEWORDS], mimo_type_t type); + +#endif diff --git a/lte/include/lte/mimo/precoding.h b/lte/include/lte/mimo/precoding.h new file mode 100644 index 000000000..ea68c5496 --- /dev/null +++ b/lte/include/lte/mimo/precoding.h @@ -0,0 +1,56 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 PRECODING_H_ +#define PRECODING_H_ + +typedef _Complex float cf_t; + +/** The precoder takes as input nlayers vectors "x" from the + * layer mapping and generates nports vectors "y" to be mapped onto + * resources on each of the antenna ports. + */ + +/* Generates the vector "y" from the input vector "x" + */ +int precoding_single(cf_t *x, cf_t *y, int nof_symbols); +int precoding_diversity(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_ports, int nof_symbols); +int precoding_type(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_layers, int nof_ports, + int nof_symbols, mimo_type_t type); + + +/* Estimates the vector "x" based on the received signal "y" and the channel estimates "ce" + */ +int predecoding_single_zf(cf_t *y, cf_t *ce, cf_t *x, int nof_symbols); +int predecoding_diversity_zf(cf_t *y[MAX_PORTS], cf_t *ce[MAX_PORTS], + cf_t *x[MAX_LAYERS], int nof_ports, int nof_symbols); +int predecoding_type(cf_t *y[MAX_PORTS], cf_t *ce[MAX_PORTS], + cf_t *x[MAX_LAYERS], int nof_ports, int nof_layers, int nof_symbols, + mimo_type_t type); + +#endif /* PRECODING_H_ */ diff --git a/include/modem/demod_hard.h b/lte/include/lte/modem/demod_hard.h similarity index 51% rename from include/modem/demod_hard.h rename to lte/include/lte/modem/demod_hard.h index 2d0ab7238..c7608b5d8 100644 --- a/include/modem/demod_hard.h +++ b/lte/include/lte/modem/demod_hard.h @@ -1,21 +1,31 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * \section COPYRIGHT * - * OSLD-lib is distributed in the hope that it will be useful, + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 DEMOD_HARD_ #define DEMOD_HARD_ @@ -24,7 +34,7 @@ #include "modem_table.h" -typedef _Complex float cf; +typedef _Complex float cf_t; typedef struct { enum modem_std table; /* In this implementation, mapping table is hard-coded */ @@ -32,8 +42,8 @@ typedef struct { void demod_hard_init(demod_hard_t* q); -void demod_hard_table(demod_hard_t* q, enum modem_std table); -int demod_hard_demodulate(demod_hard_t* q, const cf* symbols, char *bits, int nsymbols); +void demod_hard_table_set(demod_hard_t* q, enum modem_std table); +int demod_hard_demodulate(demod_hard_t* q, cf_t* symbols, char *bits, int nsymbols); @@ -44,7 +54,7 @@ typedef struct { enum modem_std std; // Symbol mapping standard (see modem_table.h) } init; - const cf* input; + cf_t* input; int in_len; char* output; diff --git a/include/modem/demod_soft.h b/lte/include/lte/modem/demod_soft.h similarity index 64% rename from include/modem/demod_soft.h rename to lte/include/lte/modem/demod_soft.h index 917b432ae..39fa2c993 100644 --- a/include/modem/demod_soft.h +++ b/lte/include/lte/modem/demod_soft.h @@ -1,21 +1,31 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * \section COPYRIGHT * - * OSLD-lib is distributed in the hope that it will be useful, + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 DEMOD_SOFT_ #define DEMOD_SOFT_ @@ -36,7 +46,7 @@ void demod_soft_init(demod_soft_t *q); void demod_soft_table_set(demod_soft_t *q, modem_table_t *table); void demod_soft_alg_set(demod_soft_t *q, enum alg alg_type); void demod_soft_sigma_set(demod_soft_t *q, float sigma); -int demod_soft_demodulate(demod_soft_t *q, const cf* symbols, float* llr, int nsymbols); +int demod_soft_demodulate(demod_soft_t *q, const cf_t* symbols, float* llr, int nsymbols); /* High-level API */ @@ -48,7 +58,7 @@ typedef struct { enum modem_std std; // symbol mapping standard (see modem_table.h) } init; - const cf* input; + const cf_t* input; int in_len; struct demod_soft_ctrl_in { diff --git a/lte/include/lte/modem/mod.h b/lte/include/lte/modem/mod.h new file mode 100644 index 000000000..33df9cca1 --- /dev/null +++ b/lte/include/lte/modem/mod.h @@ -0,0 +1,59 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 MOD_ +#define MOD_ + +#include +#include + +#include "modem_table.h" + +typedef _Complex float cf_t; + +int mod_modulate(modem_table_t* table, const char *bits, cf_t* symbols, int nbits); + +/* High-level API */ +typedef struct { + modem_table_t obj; + struct mod_init { + enum modem_std std; // symbol mapping standard (see modem_table.h) + } init; + + const char* input; + int in_len; + + cf_t* output; + int out_len; +}mod_hl; + +int mod_initialize(mod_hl* hl); +int mod_work(mod_hl* hl); +int mod_stop(mod_hl* hl); + +#endif diff --git a/include/modem/modem_table.h b/lte/include/lte/modem/modem_table.h similarity index 52% rename from include/modem/modem_table.h rename to lte/include/lte/modem/modem_table.h index e99eea137..93a6aa230 100644 --- a/include/modem/modem_table.h +++ b/lte/include/lte/modem/modem_table.h @@ -1,22 +1,32 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * \section COPYRIGHT * - * OSLD-lib is distributed in the hope that it will be useful, + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 MODEM_TABLE_ #define MODEM_TABLE_ @@ -24,13 +34,13 @@ #include #include -typedef _Complex float cf; +typedef _Complex float cf_t; typedef struct { int idx[2][6][32]; }soft_table_t; typedef struct { - cf* symbol_table; // bit-to-symbol mapping + cf_t* symbol_table; // bit-to-symbol mapping soft_table_t soft_table; // symbol-to-bit mapping (used in soft demodulating) int nsymbols; // number of modulation symbols int nbits_x_symbol; // number of bits per symbol @@ -45,7 +55,7 @@ enum modem_std { void modem_table_init(modem_table_t* q); void modem_table_free(modem_table_t* q); void modem_table_reset(modem_table_t* q); -int modem_table_set(modem_table_t* q, cf* table, soft_table_t *soft_table, int nsymbols, int nbits_x_symbol); +int modem_table_set(modem_table_t* q, cf_t* table, soft_table_t *soft_table, int nsymbols, int nbits_x_symbol); int modem_table_std(modem_table_t* q, enum modem_std table, bool compute_soft_demod); #endif diff --git a/lte/include/lte/phch/pbch.h b/lte/include/lte/phch/pbch.h new file mode 100644 index 000000000..081388289 --- /dev/null +++ b/lte/include/lte/phch/pbch.h @@ -0,0 +1,97 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 PBCH_ +#define PBCH_ + +#include "lte/common/base.h" +#include "lte/mimo/precoding.h" +#include "lte/mimo/layermap.h" +#include "lte/modem/mod.h" +#include "lte/modem/demod_soft.h" +#include "lte/scrambling/scrambling.h" +#include "lte/ratematching/rm_conv.h" +#include "lte/fec/convcoder.h" +#include "lte/fec/viterbi.h" +#include "lte/fec/crc.h" + +#define PBCH_RE_CPNORM 240 +#define PBCH_RE_CPEXT 216 + +typedef _Complex float cf_t; + +typedef struct { + int nof_ports; + int nof_prb; + int sfn; + phich_length_t phich_length; + phich_resources_t phich_resources; +}pbch_mib_t; + +/* PBCH object */ +typedef struct { + int cell_id; + lte_cp_t cp; + int nof_symbols; + + /* buffers */ + cf_t *ce[MAX_PORTS_CTRL]; + cf_t *pbch_symbols[MAX_PORTS_CTRL]; + cf_t *pbch_x[MAX_PORTS_CTRL]; + cf_t *pbch_d; + float *pbch_llr; + float *temp; + float *pbch_rm_f; + char *pbch_rm_b; + char *data; + char *data_enc; + + int frame_idx; + + /* tx & rx objects */ + modem_table_t mod; + demod_soft_t demod; + sequence_t seq_pbch; + viterbi_t decoder; + convcoder_t encoder; + +}pbch_t; + +int pbch_init(pbch_t *q, int cell_id, lte_cp_t cp); +void pbch_free(pbch_t *q); +int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], int nof_prb, float ebno, pbch_mib_t *mib); +void pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *slot1_symbols[MAX_PORTS_CTRL], + int nof_prb, int nof_ports); +void pbch_decode_reset(pbch_t *q); + +void pbch_mib_fprint(FILE *stream, pbch_mib_t *mib); +bool pbch_exists(int nframe, int nslot); +int pbch_put(cf_t *pbch, cf_t *slot1_data, int nof_prb, lte_cp_t cp, int cell_id); +int pbch_get(cf_t *pbch, cf_t *slot1_data, int nof_prb, lte_cp_t cp, int cell_id); + +#endif diff --git a/lte/include/lte/phch/pcfich.h b/lte/include/lte/phch/pcfich.h new file mode 100644 index 000000000..df8d87e17 --- /dev/null +++ b/lte/include/lte/phch/pcfich.h @@ -0,0 +1,82 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 PCFICH_ +#define PCFICH_ + +#include "lte/common/base.h" +#include "lte/mimo/precoding.h" +#include "lte/mimo/layermap.h" +#include "lte/modem/mod.h" +#include "lte/modem/demod_hard.h" +#include "lte/scrambling/scrambling.h" +#include "lte/phch/regs.h" + +#define PCFICH_CFI_LEN 32 +#define PCFICH_RE PCFICH_CFI_LEN/2 +#define PCFICH_MAX_DISTANCE 5 + +typedef _Complex float cf_t; + +/* PCFICH object */ +typedef struct { + int cell_id; + lte_cp_t cp; + int nof_symbols; + int nof_prb; + int nof_tx_ports; + + /* handler to REGs resource mapper */ + regs_t *regs; + + /* buffers */ + cf_t ce[MAX_PORTS_CTRL][PCFICH_RE]; + cf_t pcfich_symbols[MAX_PORTS_CTRL][PCFICH_RE]; + cf_t pcfich_x[MAX_PORTS_CTRL][PCFICH_RE]; + cf_t pcfich_d[PCFICH_RE]; + + /* bit message */ + char data[PCFICH_CFI_LEN]; + + /* tx & rx objects */ + modem_table_t mod; + demod_hard_t demod; + sequence_t seq_pcfich[NSUBFRAMES_X_FRAME]; + +}pcfich_t; + +int pcfich_init(pcfich_t *q, regs_t *regs, int cell_id, int nof_prb, int nof_tx_ports, lte_cp_t cp); +void pcfich_free(pcfich_t *q); +int pcfich_decode(pcfich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], int nsubframe, int *cfi, int *distance); +int pcfich_encode(pcfich_t *q, int cfi, cf_t *slot_symbols[MAX_PORTS_CTRL], int nsubframe); + +bool pcfich_exists(int nframe, int nslot); +int pcfich_put(regs_t *h, cf_t *pcfich, cf_t *slot_data); +int pcfich_get(regs_t *h, cf_t *pcfich, cf_t *slot_data); + +#endif diff --git a/lte/include/lte/phch/phich.h b/lte/include/lte/phch/phich.h new file mode 100644 index 000000000..80028a785 --- /dev/null +++ b/lte/include/lte/phch/phich.h @@ -0,0 +1,96 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 PHICH_ +#define PHICH_ + +#include "lte/common/base.h" +#include "lte/mimo/precoding.h" +#include "lte/mimo/layermap.h" +#include "lte/modem/mod.h" +#include "lte/modem/demod_hard.h" +#include "lte/scrambling/scrambling.h" +#include "regs.h" + +typedef _Complex float cf_t; + +#define PHICH_NORM_NSEQUENCES 8 +#define PHICH_EXT_NSEQUENCES 4 +#define PHICH_MAX_SEQUENCES PHICH_NORM_NSEQUENCES +#define PHICH_NBITS 3 + +#define PHICH_NORM_MSYMB PHICH_NBITS * 4 +#define PHICH_EXT_MSYMB PHICH_NBITS * 2 +#define PHICH_MAX_NSYMB PHICH_NORM_MSYMB +#define PHICH_NORM_C 1 +#define PHICH_EXT_C 2 +#define PHICH_NORM_NSF 4 +#define PHICH_EXT_NSF 2 + +/* phich object */ +typedef struct { + lte_cp_t cp; + int nof_prb; + int nof_tx_ports; + + /* handler to REGs resource mapper */ + regs_t *regs; + + /* buffers */ + cf_t ce[MAX_PORTS_CTRL][PHICH_MAX_NSYMB]; + cf_t phich_symbols[MAX_PORTS_CTRL][PHICH_MAX_NSYMB]; + cf_t phich_x[MAX_PORTS_CTRL][PHICH_MAX_NSYMB]; + cf_t phich_d[PHICH_MAX_NSYMB]; + cf_t phich_d0[PHICH_MAX_NSYMB]; + cf_t phich_z[PHICH_NBITS]; + + /* bit message */ + char data[PHICH_NBITS]; + + /* tx & rx objects */ + modem_table_t mod; + demod_hard_t demod; + sequence_t seq_phich[NSUBFRAMES_X_FRAME]; + +}phich_t; + +int phich_init(phich_t *q, regs_t *regs, int cell_id, int nof_prb, int nof_tx_ports, lte_cp_t cp); +void phich_free(phich_t *q); +int phich_decode(phich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], + int ngroup, int nseq, int nsubframe, char *ack, int *distance); +int phich_encode(phich_t *q, char ack, int ngroup, int nseq, int nsubframe, + cf_t *slot_symbols[MAX_PORTS_CTRL]); + + +void phich_reset(phich_t *q, cf_t *slot_symbols[MAX_PORTS_CTRL]); +int phich_ngroups(phich_t *q); +bool phich_exists(int nframe, int nslot); +int phich_put(regs_t *h, cf_t *phich, cf_t *slot_data); +int phich_get(regs_t *h, cf_t *phich, cf_t *slot_data); + +#endif diff --git a/lte/include/lte/phch/regs.h b/lte/include/lte/phch/regs.h new file mode 100644 index 000000000..1f7eef0ff --- /dev/null +++ b/lte/include/lte/phch/regs.h @@ -0,0 +1,93 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 _REGS_H_ +#define _REGS_H_ + +#include +#include "lte/common/base.h" + +#define REGS_PHICH_NSYM 12 +#define REGS_PHICH_REGS_X_GROUP 3 + +#define REGS_PCFICH_NSYM 16 +#define REGS_PCFICH_NREGS 4 + +#define REGS_RE_X_REG 4 + + +typedef _Complex float cf_t; + +typedef struct { + int k[4]; + int k0; + int l; + bool assigned; +}regs_reg_t; + +typedef struct { + int nof_regs; + regs_reg_t **regs; +}regs_ch_t; + +typedef struct { + int cell_id; + int nof_prb; + int max_ctrl_symbols; + int ngroups_phich; + int refs_in_symbol1; + lte_cp_t cp; + phich_resources_t phich_res; + phich_length_t phich_len; + int nof_cce; + regs_ch_t pcfich; + regs_ch_t *phich; // there are several phich + regs_ch_t *pdcch; // there are several pdcch + int nof_regs; + regs_reg_t *regs; +}regs_t; + +int regs_init(regs_t *h, int cell_id, int nof_prb, int refs_in_symbol1, + phich_resources_t phich_res, phich_length_t phich_len, lte_cp_t cp); +void regs_free(regs_t *h); + +int regs_put_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_prb); +int regs_add_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_prb); +int regs_get_reg(regs_reg_t *reg, cf_t *slot_symbols, cf_t *reg_data, int nof_prb); +int regs_reset_reg(regs_reg_t *reg, cf_t *slot_symbols, int nof_prb); + +int regs_pcfich_put(regs_t *h, cf_t pcfich_symbols[REGS_PCFICH_NSYM], cf_t *slot_symbols); +int regs_pcfich_get(regs_t *h, cf_t *slot_symbols, cf_t ch_data[REGS_PCFICH_NSYM]); + +int regs_phich_add(regs_t *h, cf_t phich_symbols[REGS_PHICH_NSYM], int ngroup, cf_t *slot_symbols); +int regs_phich_get(regs_t *h, cf_t *slot_symbols, cf_t phich_symbols[REGS_PHICH_NSYM], int ngroup); +int regs_phich_ngroups(regs_t *h); +int regs_phich_reset(regs_t *h, cf_t *slot_symbols); + + +#endif diff --git a/include/ratematching/rm_conv.h b/lte/include/lte/ratematching/rm_conv.h similarity index 51% rename from include/ratematching/rm_conv.h rename to lte/include/lte/ratematching/rm_conv.h index d71f24adc..58d3e2eb5 100644 --- a/include/ratematching/rm_conv.h +++ b/lte/include/lte/ratematching/rm_conv.h @@ -1,26 +1,39 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * \section COPYRIGHT * - * OSLD-lib is distributed in the hope that it will be useful, + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 RM_CONV_ #define RM_CONV_ #define RX_NULL 10000 +#define TX_NULL 80 + +int rm_conv_tx(char *input, char *output, int in_len, int out_len); int rm_conv_rx(float *input, float *output, int in_len, int out_len); diff --git a/lte/include/lte/resampling/interp.h b/lte/include/lte/resampling/interp.h new file mode 100644 index 000000000..39267ca36 --- /dev/null +++ b/lte/include/lte/resampling/interp.h @@ -0,0 +1,34 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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/. + * + */ + + +typedef _Complex float cf_t; + + +void interp_linear_offset(cf_t *input, cf_t *output, int M, int len, int off_st, int off_end); +void interp_linear(cf_t *input, cf_t *output, int M, int len); +void interp_linear_f(float *input, float *output, int M, int len); diff --git a/lte/include/lte/scrambling/scrambling.h b/lte/include/lte/scrambling/scrambling.h new file mode 100644 index 000000000..65f12cfb4 --- /dev/null +++ b/lte/include/lte/scrambling/scrambling.h @@ -0,0 +1,82 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 SCRAMBLING_ +#define SCRAMBLING_ + +#include "lte/common/sequence.h" +#include "lte/common/base.h" + +typedef _Complex float cf_t; + +/* Scrambling has no state */ +void scrambling_b(sequence_t *s, char *data); +void scrambling_b_offset(sequence_t *s, char *data, int offset, int len); + +void scrambling_f(sequence_t *s, float *data); +void scrambling_f_offset(sequence_t *s, float *data, int offset, int len); + +void scrambling_c(sequence_t *s, cf_t *data); +void scrambling_c_offset(sequence_t *s, cf_t *data, int offset, int len); + + +/* High-level API */ + +/* channel integer values */ +#define SCRAMBLING_PDSCH 0 /* also PUSCH */ +#define SCRAMBLING_PCFICH 1 +#define SCRAMBLING_PDCCH 2 +#define SCRAMBLING_PBCH 3 +#define SCRAMBLING_PMCH 4 +#define SCRAMBLING_PUCCH 5 + +typedef struct { + sequence_t seq[NSUBFRAMES_X_FRAME]; +}scrambling_t; + +typedef struct { + scrambling_t obj; + struct scrambling_init { + int hard; + int q; + int cell_id; + int nrnti; + int nMBSFN; + int channel; + int nof_symbols; // 7 normal 6 extended + } init; + void *input; // input type may be char or float depending on hard + int in_len; + struct scrambling_ctrl_in { + int subframe; + } ctrl_in; + void *output; + int out_len; +}scrambling_hl; + +#endif diff --git a/lte/include/lte/sync/cfo.h b/lte/include/lte/sync/cfo.h new file mode 100644 index 000000000..76bc9aafa --- /dev/null +++ b/lte/include/lte/sync/cfo.h @@ -0,0 +1,55 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 _cfo_ +#define _cfo_ + +#include + +typedef _Complex float cf_t; + +/** If the frequency is changed more than the tolerance, a new table is generated */ +#define CFO_TOLERANCE 0.00001 + +#define CFO_CEXPTAB_SIZE 4096 + +typedef struct { + float last_freq; + float tol; + int nsamples; + cexptab_t tab; + cf_t *cur_cexp; +}cfo_t; + +int cfo_init(cfo_t *h, int nsamples); +void cfo_free(cfo_t *h); + +void cfo_set_tol(cfo_t *h, float tol); +void cfo_correct(cfo_t *h, cf_t *x, float freq); + +#endif diff --git a/include/sync/pss.h b/lte/include/lte/sync/pss.h similarity index 68% rename from include/sync/pss.h rename to lte/include/lte/sync/pss.h index f1ce7b7b5..f1329dd97 100644 --- a/include/sync/pss.h +++ b/lte/include/lte/sync/pss.h @@ -1,27 +1,39 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * \section COPYRIGHT * - * OSLD-lib is distributed in the hope that it will be useful, + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 PSS_ #define PSS_ #include #include -#include "utils/convolution.h" + +#include "lte/common/base.h" +#include "lte/utils/convolution.h" typedef _Complex float cf_t; /* this is only a shortcut */ @@ -35,10 +47,15 @@ typedef _Complex float cf_t; /* this is only a shortcut */ -/** The pss_synch_t object provides functions for fast computation of the crosscorrelation +/** + * The pss_synch_t object provides functions for fast computation of the crosscorrelation * between the PSS and received signal and CFO estimation. Also, the function pss_synch_periodic() is designed * to be called periodically every subframe, taking care of the correct data alignment with respect * to the PSS sequence. + * + * The object is designed to work with signals sampled at 1.92 Mhz centered at the carrier frequency. + * Thus, downsampling is required if the signal is sampled at higher frequencies. + * */ @@ -67,11 +84,14 @@ typedef struct { cf_t *tmp_nco; }pss_synch_t; +typedef enum { PSS_TX, PSS_RX } pss_direction_t; + /* Basic functionality */ int pss_synch_init(pss_synch_t *q, int frame_size); void pss_synch_free(pss_synch_t *q); -int pss_generate(cf_t *signal, int direction, int N_id_2); +int pss_generate(cf_t *signal, int N_id_2); +void pss_put_slot(cf_t *pss_signal, cf_t *slot, int nof_prb, lte_cp_t cp); int pss_synch_set_N_id_2(pss_synch_t *q, int N_id_2); int pss_synch_find_pss(pss_synch_t *q, cf_t *input, float *corr_peak_value, float *corr_mean_value); diff --git a/lte/include/lte/sync/sfo.h b/lte/include/lte/sync/sfo.h new file mode 100644 index 000000000..11b5ba02c --- /dev/null +++ b/lte/include/lte/sync/sfo.h @@ -0,0 +1,35 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 SFO_ +#define SFO_ + +float sfo_estimate(int *t0, int len, float period); +float sfo_estimate_period(int *t0, int *t, int len, float period); + +#endif diff --git a/include/sync/sss.h b/lte/include/lte/sync/sss.h similarity index 73% rename from include/sync/sss.h rename to lte/include/lte/sync/sss.h index 1cb1850a8..d7227a540 100644 --- a/include/sync/sss.h +++ b/lte/include/lte/sync/sss.h @@ -1,28 +1,39 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * \section COPYRIGHT * - * OSLD-lib is distributed in the hope that it will be useful, + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 SSS_ #define SSS_ #include #include -#include "utils/dft.h" +#include "lte/common/base.h" +#include "lte/utils/dft.h" typedef _Complex float cf_t; /* this is only a shortcut */ @@ -35,6 +46,7 @@ typedef _Complex float cf_t; /* this is only a shortcut */ #define SSS_DFT_LEN 128 #define N_SSS 31 +#define SSS_LEN 2*N_SSS struct sss_tables { int z1[N_SSS][N_SSS]; @@ -71,7 +83,8 @@ typedef struct { /* Basic functionality */ int sss_synch_init(sss_synch_t *q); void sss_synch_free(sss_synch_t *q); -void sss_generate(float *signal, int cell_id); +void sss_generate(float *signal0, float *signal5, int cell_id); +void sss_put_slot(float *sss, cf_t *symbol, int nof_prb, lte_cp_t cp); int sss_synch_set_N_id_2(sss_synch_t *q, int N_id_2); diff --git a/lte/include/lte/sync/sync.h b/lte/include/lte/sync/sync.h new file mode 100644 index 000000000..706c45fd2 --- /dev/null +++ b/lte/include/lte/sync/sync.h @@ -0,0 +1,105 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 SYNC_ +#define SYNC_ + +#include + +#include "pss.h" +#include "sss.h" +#include "sfo.h" + +/** + * + * This object performs time and frequency synchronization using the PSS and SSS signals. + * The object is designed to work with signals sampled at 1.92 Mhz centered at the carrier frequency. + * Thus, downsampling is required if the signal is sampled at higher frequencies. + * + * Correlation peak is detected comparing the maximum at the output of the correlator with a threshold. + * The comparison accepts two modes: absolute value or peak-to-mean ratio, which are configured with the + * functions sync_pss_det_absolute() and sync_pss_det_peakmean(). + */ + +enum sync_pss_det { ABSOLUTE, PEAK_MEAN}; + +typedef struct { + pss_synch_t pss[3]; // One for each N_id_2 + sss_synch_t sss[3]; // One for each N_id_2 + enum sync_pss_det pss_mode; + float threshold; + float peak_to_avg; + int force_N_id_2; + int N_id_2; + int N_id_1; + int slot_id; + float cfo; + lte_cp_t cp; + bool detect_cp; + bool sss_en; +}sync_t; + + +int sync_init(sync_t *q, int frame_size); +void sync_free(sync_t *q); + +/* Runs the synchronization algorithm. input signal must be sampled at 1.92 MHz and should be frame_size long at least */ +int sync_run(sync_t *q, cf_t *input); + +/* Sets the threshold for peak comparison */ +void sync_set_threshold(sync_t *q, float threshold); +/* Set peak comparison to absolute value */ +void sync_pss_det_absolute(sync_t *q); +/* Set peak comparison to relative to the mean */ +void sync_pss_det_peak_to_avg(sync_t *q); + +/* Forces the synchronizer to check one N_id_2 PSS sequence only (useful for tracking mode) */ +void sync_force_N_id_2(sync_t *q, int force_N_id_2); +/* Forces the synchronizer to skip CP detection (useful for tracking mode) */ +void sync_force_cp(sync_t *q, lte_cp_t cp); +/* Enables/Disables SSS detection (useful for tracking mode) */ +void sync_sss_en(sync_t *q, bool enabled); + + +/* Gets the slot id (0 or 10) */ +int sync_get_slot_id(sync_t *q); +/* Gets the last peak-to-average ratio */ +float sync_get_peak_to_avg(sync_t *q); +/* Gets the N_id_2 from the last call to synch_run() */ +int sync_get_N_id_2(sync_t *q); +/* Gets the N_id_1 from the last call to synch_run() */ +int sync_get_N_id_1(sync_t *q); +/* Gets the Physical CellId from the last call to synch_run() */ +int sync_get_cell_id(sync_t *q); +/* Gets the CFO estimation from the last call to synch_run() */ +float sync_get_cfo(sync_t *q); +/* Gets the CP length estimation from the last call to synch_run() */ +lte_cp_t sync_get_cp(sync_t *q); + +#endif + diff --git a/lte/include/lte/utils/bit.h b/lte/include/lte/utils/bit.h new file mode 100644 index 000000000..00e2523f1 --- /dev/null +++ b/lte/include/lte/utils/bit.h @@ -0,0 +1,41 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 BIT_ +#define BIT_ + +#include +#include + +uint32_t bit_unpack(char **bits, int nof_bits); +void bit_pack(uint32_t value, char **bits, int nof_bits); +void bit_fprint(FILE *stream, char *bits, int nof_bits); +unsigned int bit_diff(char *x, char *y, int nbits); + +#endif + diff --git a/lte/include/lte/utils/cexptab.h b/lte/include/lte/utils/cexptab.h new file mode 100644 index 000000000..2063eb0cd --- /dev/null +++ b/lte/include/lte/utils/cexptab.h @@ -0,0 +1,47 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 _cexptab_ +#define _cexptab_ + +#include + +typedef _Complex float cf_t; + +typedef struct { + int size; + cf_t *tab; +}cexptab_t; + +int cexptab_init(cexptab_t *nco, int size); +void cexptab_free(cexptab_t *nco); + +void cexptab_gen(cexptab_t *nco, cf_t *x, float freq, int len); +void cexptab_gen_direct(cf_t *x, float freq, int len); + +#endif diff --git a/include/utils/convolution.h b/lte/include/lte/utils/convolution.h similarity index 58% rename from include/utils/convolution.h rename to lte/include/lte/utils/convolution.h index c6f3fef35..403c2c44f 100644 --- a/include/utils/convolution.h +++ b/lte/include/lte/utils/convolution.h @@ -1,25 +1,35 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * \section COPYRIGHT * - * OSLD-lib is distributed in the hope that it will be useful, + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 CONVOLUTION_H_ #define CONVOLUTION_H_ -#include "utils/dft.h" +#include "lte/utils/dft.h" typedef struct { _Complex float *input_fft; diff --git a/lte/include/lte/utils/debug.h b/lte/include/lte/utils/debug.h new file mode 100644 index 000000000..f6f08d777 --- /dev/null +++ b/lte/include/lte/utils/debug.h @@ -0,0 +1,64 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 DEBUG_H +#define DEBUG_H + +#include + +#define VERBOSE_DEBUG 2 +#define VERBOSE_INFO 1 +#define VERBOSE_NONE 0 + +#include +void get_time_interval(struct timeval * tdata); + +#ifndef DEBUG_DISABLED + +extern int verbose; + +#define VERBOSE_ISINFO() (verbose==VERBOSE_INFO) +#define VERBOSE_ISDEBUG() (verbose==VERBOSE_DEBUG) + +#define PRINT_DEBUG verbose=VERBOSE_DEBUG +#define PRINT_INFO verbose=VERBOSE_INFO +#define PRINT_NONE verbose=VERBOSE_NONE + +#define DEBUG(_fmt, ...) if (verbose >= VERBOSE_DEBUG) \ + fprintf(stdout, "[DEBUG]: " _fmt, __VA_ARGS__) + +#define INFO(_fmt, ...) if (verbose >= VERBOSE_INFO) \ + fprintf(stdout, "[INFO]: " _fmt, __VA_ARGS__) + +#else + +#define DEBUG +#define INFO + +#endif + +#endif diff --git a/include/utils/dft.h b/lte/include/lte/utils/dft.h similarity index 77% rename from include/utils/dft.h rename to lte/include/lte/utils/dft.h index 8f6d55d4c..6833a7ff1 100644 --- a/include/utils/dft.h +++ b/lte/include/lte/utils/dft.h @@ -1,21 +1,31 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * \section COPYRIGHT * - * OSLD-lib is distributed in the hope that it will be useful, + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 DFT_H_ #define DFT_H_ diff --git a/include/utils/matrix.h b/lte/include/lte/utils/matrix.h similarity index 59% rename from include/utils/matrix.h rename to lte/include/lte/utils/matrix.h index 863ee8b01..a74884b77 100644 --- a/include/utils/matrix.h +++ b/lte/include/lte/utils/matrix.h @@ -1,22 +1,32 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * \section COPYRIGHT * - * OSLD-lib is distributed in the hope that it will be useful, + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 #ifndef MATRIX_ diff --git a/lte/include/lte/utils/mux.h b/lte/include/lte/utils/mux.h new file mode 100644 index 000000000..8d01e8c74 --- /dev/null +++ b/lte/include/lte/utils/mux.h @@ -0,0 +1,40 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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_ +#define MUX_ + +void mux(void **input, void *output, int *input_lengths, int *input_padding_pre, int nof_inputs, + int sample_sz); + +void demux(void *input, void **output, int *output_lengths, + int *output_padding_pre, int *output_padding_post, int nof_outputs, + int sample_sz); + +#endif diff --git a/lte/include/lte/utils/pack.h b/lte/include/lte/utils/pack.h new file mode 100644 index 000000000..ea64cfbef --- /dev/null +++ b/lte/include/lte/utils/pack.h @@ -0,0 +1,35 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 PACK_ +#define PACK_ + +unsigned int unpack_bits(char **bits, int nof_bits); +void pack_bits(unsigned int value, char **bits, int nof_bits); + +#endif diff --git a/include/utils/vector.h b/lte/include/lte/utils/vector.h similarity index 53% rename from include/utils/vector.h rename to lte/include/lte/utils/vector.h index 475937fab..806952896 100644 --- a/include/utils/vector.h +++ b/lte/include/lte/utils/vector.h @@ -1,21 +1,31 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * \section COPYRIGHT * - * OSLD-lib is distributed in the hope that it will be useful, + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 VECTOR_ #define VECTOR_ @@ -33,6 +43,7 @@ void *vec_malloc(int size); /* print vectors */ void vec_fprint_c(FILE *stream, cf_t *x, int len); void vec_fprint_f(FILE *stream, float *x, int len); +void vec_fprint_b(FILE *stream, char *x, int len); void vec_fprint_i(FILE *stream, int *x, int len); /* sum two vectors */ @@ -43,9 +54,12 @@ void vec_sum_ccc(cf_t *z, cf_t *x, cf_t *y, int len); void vec_sc_prod_cfc(cf_t *x, float h, cf_t *z, int len); void vec_sc_prod_ccc(cf_t *x, cf_t h, cf_t *z, int len); -/* dot product */ -void vec_dot_prod_ccc(cf_t *x, cf_t *y, cf_t *z, int len); -void vec_dot_prod_ccc_unalign(cf_t *x, cf_t *y, cf_t *z, int len); +/* vector product (element-wise) */ +void vec_prod_ccc(cf_t *x, cf_t *y, cf_t *z, int len); +void vec_prod_ccc_unalign(cf_t *x, cf_t *y, cf_t *z, int len); + +/* z=x/y vector division (element-wise) */ +void vec_div_ccc(cf_t *x, cf_t *y, cf_t *z, int len); /* conjugate */ void vec_conj_cc(cf_t *x, cf_t *y, int len); @@ -56,6 +70,9 @@ float vec_avg_power_cf(cf_t *x, int len); /* return the index of the maximum value in the vector */ int vec_max_fi(float *x, int len); +/* quantify vector of floats and convert to unsigned char */ +void vec_quant_fuc(float *in, unsigned char *out, float gain, float offset, float clip, int len); + /* magnitude of each vector element */ void vec_abs_cf(cf_t *x, float *abs, int len); diff --git a/lte/lib/CMakeLists.txt b/lte/lib/CMakeLists.txt new file mode 100644 index 000000000..f4d09f9a2 --- /dev/null +++ b/lte/lib/CMakeLists.txt @@ -0,0 +1,84 @@ +# +# Copyright 2012-2013 The libLTE Developers. See the +# COPYRIGHT file at the top-level directory of this distribution. +# +# This file is part of the libLTE library. +# +# libLTE is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# libLTE is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# A copy of the GNU Lesser 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 Dependencies +######################################################################## + +FIND_PACKAGE(FFTW3F REQUIRED) # TODO: distribute kissfft instead +INCLUDE_DIRECTORIES(${FFTW3F_INCLUDE_DIRS}) + +IF(${DISABLE_VOLK}) + IF(${DISABLE_VOLK} EQUAL 0) + FIND_PACKAGE(Volk) + ELSE(${DISABLE_VOLK} EQUAL 0) + MESSAGE(STATUS "VOLK library disabled (DISABLE_VOLK=1)") + ENDIF(${DISABLE_VOLK} EQUAL 0) +ELSE(${DISABLE_VOLK}) + FIND_PACKAGE(Volk) +ENDIF(${DISABLE_VOLK}) + +######################################################################## +# Recurse subdirectories and compile all source files into the same lib +######################################################################## + +FILE(GLOB modules *) +SET(SOURCES_ALL "") +FOREACH (_module ${modules}) + IF(IS_DIRECTORY ${_module}) + FILE(GLOB_RECURSE tmp "${_module}/src/*.c") + LIST(APPEND SOURCES_ALL ${tmp}) + ENDIF(IS_DIRECTORY ${_module}) +ENDFOREACH() + +ADD_LIBRARY(lte ${SOURCES_ALL}) +TARGET_LINK_LIBRARIES(lte m ${FFTW3F_LIBRARIES}) +INSTALL(TARGETS lte DESTINATION ${LIBRARY_DIR}) +LIBLTE_SET_PIC(lte) + +IF(VOLK_FOUND) + INCLUDE_DIRECTORIES(${VOLK_INCLUDE_DIRS}) + SET_TARGET_PROPERTIES(lte PROPERTIES COMPILE_DEFINITIONS "HAVE_VOLK") + TARGET_LINK_LIBRARIES(lte ${VOLK_LIBRARIES}) + MESSAGE(STATUS " Compiling with VOLK SIMD library.") +ELSE(VOLK_FOUND) + MESSAGE(STATUS " VOLK SIMD library NOT found. Using generic implementation.") +ENDIF(VOLK_FOUND) + + +######################################################################## +# Recurse subdirectories and find all directories with a CMakeLists.txt file in it +######################################################################## + +FILE(GLOB_RECURSE cmakefiles CMakeLists.txt) +FOREACH (_file ${cmakefiles}) + GET_FILENAME_COMPONENT(dir ${_file} PATH) + IF (NOT ${dir} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) + ADD_SUBDIRECTORY(${dir}) + ENDIF () +ENDFOREACH() + + + + + + diff --git a/lib/ch_estimation/src/chest.c b/lte/lib/ch_estimation/src/chest.c similarity index 83% rename from lib/ch_estimation/src/chest.c rename to lte/lib/ch_estimation/src/chest.c index f2cd2e57a..48faccdc4 100644 --- a/lib/ch_estimation/src/chest.c +++ b/lte/lib/ch_estimation/src/chest.c @@ -1,31 +1,41 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * \section COPYRIGHT * - * OSLD-lib is distributed in the hope that it will be useful, + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 #include #include #include #include -#include "ch_estimation/chest.h" -#include "resampling/interp.h" -#include "utils/vector.h" -#include "utils/debug.h" +#include "lte/ch_estimation/chest.h" +#include "lte/resampling/interp.h" +#include "lte/utils/vector.h" +#include "lte/utils/debug.h" #define SLOT_SZ(q) (q->nof_symbols * q->symbol_sz) #define SF_SZ(q) (2 * SLOT_SZ(q)) @@ -38,7 +48,7 @@ void chest_fprint(chest_t *q, FILE *stream, int nslot, int port_id) { void chest_ref_fprint(chest_t *q, FILE *stream, int nslot, int port_id) { int i; - fprintf(stream, "refs=["); + fprintf(stream, "refs%d=[",port_id); for (i=0;irefsignal[port_id][nslot].nof_refs;i++) { fprintf(stream, "%3.3f%+3.3fi, ", __real__ q->refsignal[port_id][nslot].refs[i].simbol, __imag__ q->refsignal[port_id][nslot].refs[i].simbol); @@ -48,7 +58,7 @@ void chest_ref_fprint(chest_t *q, FILE *stream, int nslot, int port_id) { void chest_recvsig_fprint(chest_t *q, FILE *stream, int nslot, int port_id) { int i; - fprintf(stream, "recvsig=["); + fprintf(stream, "recvsig%d=[",port_id); for (i=0;irefsignal[port_id][nslot].nof_refs;i++) { fprintf(stream, "%3.3f%+3.3fi, ", __real__ q->refsignal[port_id][nslot].refs[i].recv_simbol, __imag__ q->refsignal[port_id][nslot].refs[i].recv_simbol); @@ -58,11 +68,11 @@ void chest_recvsig_fprint(chest_t *q, FILE *stream, int nslot, int port_id) { void chest_ce_fprint(chest_t *q, FILE *stream, int nslot, int port_id) { int i; - fprintf(stream, "mag=["); + fprintf(stream, "mag%d=[",port_id); for (i=0;irefsignal[port_id][nslot].nof_refs;i++) { fprintf(stream, "%3.3f, ", cabsf(q->refsignal[port_id][nslot].ch_est[i])); } - fprintf(stream, "];\nphase=["); + fprintf(stream, "];\nphase%d=[",port_id); for (i=0;irefsignal[port_id][nslot].nof_refs;i++) { fprintf(stream, "%3.3f, ", atan2f(__imag__ q->refsignal[port_id][nslot].ch_est[i], __real__ q->refsignal[port_id][nslot].ch_est[i])); @@ -83,7 +93,8 @@ void chest_ce_ref(chest_t *q, cf_t *input, int nslot, int port_id, int nref) { DEBUG("Reference %2d pos (%2d,%2d)=%3d %.2f dB %.2f/%.2f=%.2f\n", nref, tidx, fidx, SAMPLE_IDX(q->nof_prb, tidx, fidx), 10*log10f(cabsf(channel_ref/known_ref)), cargf(channel_ref)/M_PI,cargf(known_ref)/M_PI,cargf(channel_ref/known_ref)/M_PI); - /* FIXME: compare with treshold */ + + /* FIXME: compare with threshold */ if (channel_ref != 0) { q->refsignal[port_id][nslot].ch_est[nref] = channel_ref/known_ref; } else { @@ -104,7 +115,8 @@ void chest_ce_slot_port(chest_t *q, cf_t *input, cf_t *ce, int nslot, int port_i refsignal_t *r = &q->refsignal[port_id][nslot]; - INFO("Estimating channel using %d reference signals\n", r->nof_refs); + INFO("Estimating channel slot=%d port=%d using %d reference signals\n", + nslot, port_id, r->nof_refs); for (i=0;inof_refs;i++) { chest_ce_ref(q, input, nslot, port_id, i); @@ -120,11 +132,17 @@ void chest_ce_slot_port(chest_t *q, cf_t *input, cf_t *ce, int nslot, int port_i } /* now interpolate in the time domain */ for (i=0;inof_prb * RE_X_RB; i++) { - for (j=0;jnsymbols;j++) { - x[j] = ce[r->symbols_ref[j] * q->nof_prb * RE_X_RB + i]; + if (r->nsymbols > 1) { + for (j=0;jnsymbols;j++) { + x[j] = ce[r->symbols_ref[j] * q->nof_prb * RE_X_RB + i]; + } + interp_linear_offset(x, y, r->symbols_ref[1]-r->symbols_ref[0], + 2, r->symbols_ref[0], 3); + } else { + for (j=0;jsymbols_ref[0] * q->nof_prb * RE_X_RB + i]; + } } - interp_linear_offset(x, y, r->symbols_ref[1]-r->symbols_ref[0], - 2, r->symbols_ref[0], 3); for (j=0;jnof_symbols;j++) { ce[j * q->nof_prb * RE_X_RB + i] = y[j]; } diff --git a/lib/ch_estimation/src/refsignal.c b/lte/lib/ch_estimation/src/refsignal.c similarity index 72% rename from lib/ch_estimation/src/refsignal.c rename to lte/lib/ch_estimation/src/refsignal.c index 8436f627f..5e1008846 100644 --- a/lib/ch_estimation/src/refsignal.c +++ b/lte/lib/ch_estimation/src/refsignal.c @@ -1,32 +1,42 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * \section COPYRIGHT * - * OSLD-lib is distributed in the hope that it will be useful, + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 #include #include #include #include -#include "lte/base.h" -#include "ch_estimation/refsignal.h" -#include "utils/vector.h" -#include "utils/debug.h" -#include "lte/sequence.h" +#include "lte/common/base.h" +#include "lte/ch_estimation/refsignal.h" +#include "lte/utils/vector.h" +#include "lte/utils/debug.h" +#include "lte/common/sequence.h" #define idx(x, y) (l*nof_refs_x_symbol+i) @@ -61,6 +71,16 @@ int refsignal_k(int m, int v, int cell_id) { return 6*m+((v+(cell_id%6))%6); } +void refsignal_put(refsignal_t *q, cf_t *slot_symbols) { + int i; + int fidx, tidx; + for (i=0;inof_refs;i++) { + fidx = q->refs[i].freq_idx; // reference frequency index + tidx = q->refs[i].time_idx; // reference time index + slot_symbols[SAMPLE_IDX(q->nof_prb, tidx, fidx)] = q->refs[i].simbol; + } +} + /** Initializes refsignal_t object according to 3GPP 36.211 6.10.1 * */ @@ -105,6 +125,7 @@ int refsignal_init_LTEDL(refsignal_t *q, int port_id, int nslot, q->nsymbols = nof_ref_symbols; q->symbols_ref = malloc(sizeof(int) * nof_ref_symbols); q->voffset = cell_id%6; + q->nof_prb = nof_prb; if (!q->symbols_ref) { return -1; } @@ -141,12 +162,6 @@ int refsignal_init_LTEDL(refsignal_t *q, int port_id, int nslot, /* mapping to resource elements */ q->refs[idx(l,i)].freq_idx = refsignal_k(i, v, cell_id); q->refs[idx(l,i)].time_idx = lp[l]; - - /* print only first slot */ - if (ns == 0) { - DEBUG("(%-2d,%2d) is mapped to (%-2d,%2d) (mp=%d, v=%d)\n", - l,i,q->refs[idx(l,i)].time_idx, q->refs[idx(l,i)].freq_idx, mp, v); - } } } diff --git a/lte/lib/ch_estimation/test/CMakeLists.txt b/lte/lib/ch_estimation/test/CMakeLists.txt new file mode 100644 index 000000000..9f4be5ea8 --- /dev/null +++ b/lte/lib/ch_estimation/test/CMakeLists.txt @@ -0,0 +1,32 @@ +# +# Copyright 2012-2013 The libLTE Developers. See the +# COPYRIGHT file at the top-level directory of this distribution. +# +# This file is part of the libLTE library. +# +# libLTE is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# libLTE is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# A copy of the GNU Lesser 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/. +# + +######################################################################## +# Channel Estimation TEST +######################################################################## + +ADD_EXECUTABLE(chest_test chest_test.c) +TARGET_LINK_LIBRARIES(chest_test lte) + +ADD_TEST(chest_test_all_cellids chest_test) +ADD_TEST(chest_test_cellid chest_test -c 1) + + diff --git a/lte/lib/ch_estimation/test/chest_test.c b/lte/lib/ch_estimation/test/chest_test.c new file mode 100644 index 000000000..16160e7d7 --- /dev/null +++ b/lte/lib/ch_estimation/test/chest_test.c @@ -0,0 +1,251 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 +#include +#include +#include +#include + +#include "lte.h" + +int cell_id = -1; +int nof_prb = 6; +lte_cp_t cp = CPNORM; + +char *output_matlab = NULL; + +void usage(char *prog) { + printf("Usage: %s [recov]\n", prog); + + printf("\t-r nof_prb [Default %d]\n", nof_prb); + printf("\t-e extended cyclic prefix [Default normal]\n"); + + printf("\t-c cell_id (-1 tests all). [Default %d]\n", cell_id); + + printf("\t-o output matlab file [Default %s]\n",output_matlab?output_matlab:"None"); + printf("\t-v increase verbosity\n"); +} + +void parse_args(int argc, char **argv) { + int opt; + while ((opt = getopt(argc, argv, "recov")) != -1) { + switch(opt) { + case 'r': + nof_prb = atoi(argv[optind]); + break; + case 'e': + cp = CPEXT; + break; + case 'c': + cell_id = atoi(argv[optind]); + break; + case 'o': + output_matlab = argv[optind]; + break; + case 'v': + verbose++; + break; + default: + usage(argv[0]); + exit(-1); + } + } +} + +int check_mse(float mod, float arg, int n_port) { + INFO("mod=%.4f, arg=%.4f, n_port=%d\n", mod, arg, n_port); + switch(n_port) { + case 0: + if (mod > 0.029) { + return -1; + } + if (arg > 0.029) { + return -1; + } + break; + case 1: + if (mod > 0.012) { + return -1; + } + if (arg > 0.012) { + return -1; + } + break; + case 2: + case 3: + if (mod > 3.33) { + return -1; + } + if (arg > 0.63) { + return -1; + } + break; + default: + return -1; + } + return 0; +} + +int main(int argc, char **argv) { + chest_t eq; + cf_t *input = NULL, *ce = NULL, *h = NULL; + refsignal_t refs; + int i, j, n_port, n_slot, cid, num_re; + int ret = -1; + int max_cid; + FILE *fmatlab = NULL; + float mse_mag, mse_phase; + + parse_args(argc,argv); + + if (output_matlab) { + fmatlab=fopen(output_matlab, "w"); + if (!fmatlab) { + perror("fopen"); + goto do_exit; + } + } + + num_re = nof_prb * RE_X_RB * CP_NSYMB(cp); + + input = malloc(num_re * sizeof(cf_t)); + if (!input) { + perror("malloc"); + goto do_exit; + } + h = malloc(num_re * sizeof(cf_t)); + if (!h) { + perror("malloc"); + goto do_exit; + } + ce = malloc(num_re * sizeof(cf_t)); + if (!ce) { + perror("malloc"); + goto do_exit; + } + + if (cell_id == -1) { + cid = 0; + max_cid = 504; + } else { + cid = cell_id; + max_cid = cell_id; + } + while(cid <= max_cid) { + if (chest_init(&eq, LINEAR, cp, nof_prb, MAX_PORTS)) { + fprintf(stderr, "Error initializing equalizer\n"); + goto do_exit; + } + + if (chest_ref_LTEDL(&eq, cid)) { + fprintf(stderr, "Error initializing reference signal\n"); + goto do_exit; + } + + for (n_slot=0;n_slot +#include +#include + +#include "gauss.h" +#include "lte/channel/ch_awgn.h" + +void ch_awgn_c(const cf_t* x, cf_t* y, float variance, int buff_sz) { + _Complex float tmp; + int i; + + for (i=0;iinput,hl->output,hl->ctrl_in.variance,hl->in_len); + hl->out_len = hl->in_len; + return 0; +} + +int ch_awgn_stop(ch_awgn_hl* hl) { + return 0; +} diff --git a/lte/lib/channel/src/gauss.c b/lte/lib/channel/src/gauss.c new file mode 100644 index 000000000..b2b23d96c --- /dev/null +++ b/lte/lib/channel/src/gauss.c @@ -0,0 +1,44 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 +#include +#include + +float rand_gauss (void) { + float v1,v2,s; + + do { + v1 = 2.0 * ((float) rand()/RAND_MAX) - 1; + v2 = 2.0 * ((float) rand()/RAND_MAX) - 1; + + s = v1*v1 + v2*v2; + } while ( s >= 1.0 || s == 0.0); + + return (v1*sqrt(-2.0 * log(s) / s)); +} diff --git a/lte/lib/channel/src/gauss.h b/lte/lib/channel/src/gauss.h new file mode 100644 index 000000000..a36fc04eb --- /dev/null +++ b/lte/lib/channel/src/gauss.h @@ -0,0 +1,29 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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/. + * + */ + + +float rand_gauss (void); diff --git a/lib/lte/src/fft.c b/lte/lib/common/src/fft.c similarity index 56% rename from lib/lte/src/fft.c rename to lte/lib/common/src/fft.c index 9f6f2f6b3..e6319a5aa 100644 --- a/lib/lte/src/fft.c +++ b/lte/lib/common/src/fft.c @@ -1,28 +1,39 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * \section COPYRIGHT * - * OSLD-lib is distributed in the hope that it will be useful, + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 #include #include -#include "lte/base.h" -#include "utils/dft.h" -#include "lte/fft.h" -#include "utils/debug.h" +#include "lte/common/base.h" +#include "lte/utils/dft.h" +#include "lte/common/fft.h" +#include "lte/utils/debug.h" +#include "lte/utils/vector.h" int lte_fft_init_(lte_fft_t *q, lte_cp_t cp_type, int nof_prb, dft_dir_t dir) { int symbol_sz = lte_symbol_sz(nof_prb); @@ -41,7 +52,12 @@ int lte_fft_init_(lte_fft_t *q, lte_cp_t cp_type, int nof_prb, dft_dir_t dir) { return -1; } - q->fft_plan.options = DFT_DC_OFFSET | DFT_MIRROR_POS | DFT_NORMALIZE; + q->fft_plan.options = DFT_NORMALIZE; + if (dir==FORWARD) { + q->fft_plan.options |= DFT_DC_OFFSET | DFT_MIRROR_POS; + } else { + q->fft_plan.options |= DFT_DC_OFFSET | DFT_MIRROR_PRE; + } q->symbol_sz = symbol_sz; q->nof_symbols = CP_NSYMB(cp_type); q->cp_type = cp_type; @@ -55,6 +71,9 @@ int lte_fft_init_(lte_fft_t *q, lte_cp_t cp_type, int nof_prb, dft_dir_t dir) { void lte_fft_free_(lte_fft_t *q) { dft_plan_free(&q->fft_plan); + if (q->tmp) { + free(q->tmp); + } bzero(q, sizeof(lte_fft_t)); } @@ -67,7 +86,16 @@ void lte_fft_free(lte_fft_t *q) { } int lte_ifft_init(lte_fft_t *q, lte_cp_t cp_type, int nof_prb) { - return lte_fft_init_(q, cp_type, nof_prb, BACKWARD); + int i; + if (lte_fft_init_(q, cp_type, nof_prb, BACKWARD)) { + return -1; + } + /* set now zeros at CP */ + for (i=0;inof_symbols;i++) { + bzero(q->tmp, q->nof_guards * sizeof(cf_t)); + bzero(&q->tmp[q->nof_re + q->nof_guards], q->nof_guards * sizeof(cf_t)); + } + return 0; } void lte_ifft_free(lte_fft_t *q) { @@ -92,6 +120,15 @@ void lte_fft_run(lte_fft_t *q, cf_t *input, cf_t *output) { * Performs FFT on a each symbol and adds CP. */ void lte_ifft_run(lte_fft_t *q, cf_t *input, cf_t *output) { - fprintf(stderr, "Error: Not implemented\n"); + int i, cp_len; + for (i=0;inof_symbols;i++) { + cp_len = CP_ISNORM(q->cp_type)?CP_NORM(i, q->symbol_sz):CP_EXT(q->symbol_sz); + memcpy(&q->tmp[q->nof_guards], input, q->nof_re * sizeof(cf_t)); + dft_run_c2c(&q->fft_plan, q->tmp, &output[cp_len]); + input += q->nof_re; + /* add CP */ + memcpy(output, &output[q->symbol_sz], cp_len * sizeof(cf_t)); + output += q->symbol_sz + cp_len; + } } diff --git a/lib/lte/src/lte.c b/lte/lib/common/src/lte.c similarity index 78% rename from lib/lte/src/lte.c rename to lte/lib/common/src/lte.c index a80914278..e475cf161 100644 --- a/lib/lte/src/lte.c +++ b/lte/lib/common/src/lte.c @@ -1,26 +1,38 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * \section COPYRIGHT * - * OSLD-lib is distributed in the hope that it will be useful, + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 #include +#include -#include "lte/base.h" +#include "lte/common/base.h" const int lte_symbol_sz(int nof_prb) { if (nof_prb<=0) { @@ -123,6 +135,31 @@ struct lte_band lte_bands[NOF_LTE_BANDS] = { }; #define EOF_BAND 9919 +int lte_str2mimotype(char *mimo_type_str, mimo_type_t *type) { + if (!strcmp(mimo_type_str, "single")) { + *type = SINGLE_ANTENNA; + } else if (!strcmp(mimo_type_str, "diversity")) { + *type = TX_DIVERSITY; + } else if (!strcmp(mimo_type_str, "multiplex")) { + *type = SPATIAL_MULTIPLEX; + } else { + return -1; + } + return 0; +} + +char *lte_mimotype2str(mimo_type_t type) { + switch(type) { + case SINGLE_ANTENNA: + return "single"; + case TX_DIVERSITY: + return "diversity"; + case SPATIAL_MULTIPLEX: + return "multiplex"; + } + return NULL; +} + float get_fd(struct lte_band *band, int earfcn) { return band->fd_low_mhz + 0.1*(earfcn - band->earfcn_offset); } diff --git a/lib/lte/src/sequence.c b/lte/lib/common/src/sequence.c similarity index 69% rename from lib/lte/src/sequence.c rename to lte/lib/common/src/sequence.c index ec1a04a97..32e00359b 100644 --- a/lib/lte/src/sequence.c +++ b/lte/lib/common/src/sequence.c @@ -1,22 +1,32 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This file is part of the libLTE library. * - * OSLD-lib is distributed in the hope that it will be useful, + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 "lte/sequence.h" + +#include "lte/common/sequence.h" #include #include diff --git a/lte/lib/common/test/CMakeLists.txt b/lte/lib/common/test/CMakeLists.txt new file mode 100644 index 000000000..18ed7f8fb --- /dev/null +++ b/lte/lib/common/test/CMakeLists.txt @@ -0,0 +1,34 @@ +# +# Copyright 2012-2013 The libLTE Developers. See the +# COPYRIGHT file at the top-level directory of this distribution. +# +# This file is part of the libLTE library. +# +# libLTE is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# libLTE is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# A copy of the GNU Lesser 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/. +# + +######################################################################## +# FFT TEST +######################################################################## + +ADD_EXECUTABLE(fft_test fft_test.c) +TARGET_LINK_LIBRARIES(fft_test lte) + +ADD_TEST(fft_normal fft_test) +ADD_TEST(fft_extended fft_test -e) + +ADD_TEST(fft_normal_single fft_test -n 6) +ADD_TEST(fft_extended_single fft_test -e -n 6) + diff --git a/lte/lib/common/test/fft_test.c b/lte/lib/common/test/fft_test.c new file mode 100644 index 000000000..e82206eb8 --- /dev/null +++ b/lte/lib/common/test/fft_test.c @@ -0,0 +1,141 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 +#include +#include +#include +#include +#include + +#include "lte.h" + +int nof_prb = -1; +lte_cp_t cp = CPNORM; + +void usage(char *prog) { + printf("Usage: %s\n", prog); + printf("\t-n nof_prb [Default All]\n"); + printf("\t-e extended cyclic prefix [Default Normal]\n"); +} + +void parse_args(int argc, char **argv) { + int opt; + while ((opt = getopt(argc, argv, "ne")) != -1) { + switch (opt) { + case 'n': + nof_prb = atoi(argv[optind]); + break; + case 'e': + cp = CPEXT; + break; + default: + usage(argv[0]); + exit(-1); + } + } +} + + +int main(int argc, char **argv) { + lte_fft_t fft, ifft; + cf_t *input, *outfft, *outifft; + float mse; + int n_prb, max_prb, n_re; + int i; + + parse_args(argc, argv); + + if (nof_prb == -1) { + n_prb = 6; + max_prb = 100; + } else { + n_prb = nof_prb; + max_prb = nof_prb; + } + while(n_prb <= max_prb) { + n_re = CP_NSYMB(cp) * n_prb * RE_X_RB; + + printf("Running test for %d PRB, %d RE... ", n_prb, n_re);fflush(stdout); + + input = malloc(sizeof(cf_t) * n_re); + if (!input) { + perror("malloc"); + exit(-1); + } + outfft = malloc(sizeof(cf_t) * SLOT_LEN_CPNORM(lte_symbol_sz(n_prb))); + if (!outfft) { + perror("malloc"); + exit(-1); + } + outifft = malloc(sizeof(cf_t) * n_re); + if (!outifft) { + perror("malloc"); + exit(-1); + } + + if (lte_fft_init(&fft, cp, n_prb)) { + fprintf(stderr, "Error initializing FFT\n"); + exit(-1); + } + if (lte_ifft_init(&ifft, cp, n_prb)) { + fprintf(stderr, "Error initializing iFFT\n"); + exit(-1); + } + + for (i=0;i= 0.05) { + printf("MSE too large\n"); + exit(-1); + } + + lte_fft_free(&fft); + lte_ifft_free(&ifft); + + free(input); + free(outfft); + free(outifft); + + n_prb++; + } + fftwf_cleanup(); + exit(0); +} diff --git a/lib/fec/src/convcoder.c b/lte/lib/fec/src/convcoder.c similarity index 65% rename from lib/fec/src/convcoder.c rename to lte/lib/fec/src/convcoder.c index ce60e7b45..183afeee3 100644 --- a/lib/fec/src/convcoder.c +++ b/lte/lib/fec/src/convcoder.c @@ -1,26 +1,36 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * \section COPYRIGHT * - * OSLD-lib is distributed in the hope that it will be useful, + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 #include #include -#include "fec/convcoder.h" +#include "lte/fec/convcoder.h" #include "parity.h" int convcoder_encode(convcoder_t *q, char *input, char *output) { @@ -36,13 +46,14 @@ int convcoder_encode(convcoder_t *q, char *input, char *output) { } else { sr = 0; } - + //printf("Start state %d\n", sr); for (i = 0; i < len; i++) { int bit = (i < q->framelength) ? (input[i] & 1) : 0; sr = (sr << 1) | bit; for (j=0;jR;j++) { output[q->R * i + j] = parity(sr & q->poly[j]); } + //printf("%3d - sr=%u\n", i, sr%64); } return q->R*len; diff --git a/lib/fec/src/crc.c b/lte/lib/fec/src/crc.c similarity index 66% rename from lib/fec/src/crc.c rename to lte/lib/fec/src/crc.c index a10475a78..6360d3537 100644 --- a/lib/fec/src/crc.c +++ b/lte/lib/fec/src/crc.c @@ -1,22 +1,34 @@ -/* - * Copyright (c) 2012, Ismael Gomez-Miguelez . - * This file is part of ALOE++ (http://flexnets.upc.edu/) +/** * - * ALOE++ is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * \section COPYRIGHT * - * ALOE++ is distributed in the hope that it will be useful, + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with ALOE++. If not, see . + * A copy of the GNU Lesser 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 +#include + unsigned int cword; unsigned int icrc1(unsigned int crc, unsigned short onech,int long_crc, diff --git a/lib/fec/src/parity.h b/lte/lib/fec/src/parity.h similarity index 95% rename from lib/fec/src/parity.h rename to lte/lib/fec/src/parity.h index 58cd67ab5..56689124b 100644 --- a/lib/fec/src/parity.h +++ b/lte/lib/fec/src/parity.h @@ -1,4 +1,4 @@ -/* User include file for libfec +/* * Copyright 2004, Phil Karn, KA9Q * May be used under the terms of the GNU Lesser General Public License (LGPL) */ diff --git a/lte/lib/fec/src/viterbi.c b/lte/lib/fec/src/viterbi.c new file mode 100644 index 000000000..0b7351a10 --- /dev/null +++ b/lte/lib/fec/src/viterbi.c @@ -0,0 +1,239 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 +#include +#include +#include + +#include "lte/utils/vector.h" +#include "lte/fec/viterbi.h" +#include "parity.h" +#include "viterbi37.h" +#include "viterbi39.h" + +#define DEB 0 + +int decode37(void *o, unsigned char *symbols, char *data) { + viterbi_t *q = o; + int i; + + int best_state; + + /* Initialize Viterbi decoder */ + init_viterbi37_port(q->ptr, q->tail_biting?-1:0); + + /* Decode block */ + if (q->tail_biting) { + memcpy(q->tmp, symbols, 3 * q->framebits * sizeof(char)); + for (i=0;i<3*(q->K-1);i++) { + q->tmp[i+3*q->framebits] = q->tmp[i]; + } + } else { + q->tmp = symbols; + } + + update_viterbi37_blk_port(q->ptr, q->tmp, q->framebits + q->K - 1, q->tail_biting?&best_state:NULL); + + /* Do Viterbi chainback */ + chainback_viterbi37_port(q->ptr, data, q->framebits, q->tail_biting?best_state:0); + + return q->framebits; +} + +int decode39(void *o, unsigned char *symbols, char *data) { + viterbi_t *q = o; + + /* Initialize Viterbi decoder */ + init_viterbi39_port(q->ptr, 0); + + /* Decode block */ + update_viterbi39_blk_port(q->ptr, symbols,q->framebits + q->K - 1); + + /* Do Viterbi chainback */ + chainback_viterbi39_port(q->ptr, data, q->framebits, 0); + + return q->framebits; +} + + +void free37(void *o) { + viterbi_t *q = o; + if (q->symbols_uc) { + free(q->symbols_uc); + } + if (q->tmp) { + free(q->tmp); + } + delete_viterbi37_port(q->ptr); +} + +void free39(void *o) { + viterbi_t *q = o; + if (q->symbols_uc) { + free(q->symbols_uc); + } + delete_viterbi39_port(q->ptr); +} + +int init37(viterbi_t *q, int poly[3], int framebits, bool tail_biting) { + q->K = 7; + q->R = 3; + q->framebits = framebits; + q->tail_biting = tail_biting; + q->decode = decode37; + q->free = free37; + q->symbols_uc = malloc(3 * (q->framebits + q->K -1) * sizeof(char)); + if (!q->symbols_uc) { + perror("malloc"); + return -1; + } + if (q->tail_biting) { + q->tmp = malloc(3 * (q->framebits + q->K -1) * sizeof(char)); + if (!q->tmp) { + perror("malloc"); + free37(q); + return -1; + } + } else { + q->tmp = NULL; + } + + if ((q->ptr = create_viterbi37_port(poly, framebits)) == NULL) { + fprintf(stderr, "create_viterbi37 failed\n"); + free37(q); + return -1; + } else { + return 0; + } +} + +int init39(viterbi_t *q, int poly[3], int framebits, bool tail_biting) { + q->K = 9; + q->R = 3; + q->framebits = framebits; + q->tail_biting = tail_biting; + q->decode = decode39; + q->free = free39; + if (q->tail_biting) { + fprintf(stderr, "Error: Tailbitting not supported in 1/3 K=9 decoder\n"); + return -1; + } + q->symbols_uc = malloc(3 * (q->framebits + q->K -1) * sizeof(char)); + if (!q->symbols_uc) { + perror("malloc"); + return -1; + } + if ((q->ptr = create_viterbi39_port(poly, framebits)) == NULL) { + fprintf(stderr, "create_viterbi37 failed\n"); + free39(q); + return -1; + } else { + return 0; + } +} + +int viterbi_init(viterbi_t *q, viterbi_type_t type, int poly[3], int framebits, bool tail_bitting) { + switch(type) { + case viterbi_37: + return init37(q, poly, framebits, tail_bitting); + case viterbi_39: + return init39(q, poly, framebits, tail_bitting); + default: + fprintf(stderr, "Decoder not implemented\n"); + return -1; + } +} + +void viterbi_free(viterbi_t *q) { + q->free(q); +} + +/* symbols are real-valued */ +int viterbi_decode_f(viterbi_t *q, float *symbols, char *data) { + int len; + if (q->tail_biting) { + len = 3 * q->framebits; + } else { + len = 3 * (q->framebits + q->K - 1); + } + vec_quant_fuc(symbols, q->symbols_uc, 32, 127.5, 255, len); + return q->decode(q, q->symbols_uc, data); +} + +int viterbi_decode_uc(viterbi_t *q, unsigned char *symbols, char *data) { + return q->decode(q, symbols, data); +} + + +int viterbi_initialize(viterbi_hl* h) { + int poly[3]; + viterbi_type_t type; + if (h->init.rate == 2) { + if (h->init.constraint_length == 7) { + type = viterbi_27; + } else if (h->init.constraint_length == 9) { + type = viterbi_29; + } else { + fprintf(stderr, "Unsupported decoder %d/%d\n", h->init.rate, + h->init.constraint_length); + return -1; + } + } else if (h->init.rate == 3) { + if (h->init.constraint_length == 7) { + type = viterbi_37; + } else if (h->init.constraint_length == 9) { + type = viterbi_39; + } else { + fprintf(stderr, "Unsupported decoder %d/%d\n", h->init.rate, + h->init.constraint_length); + return -1; + } + } else { + fprintf(stderr, "Unsupported decoder %d/%d\n", h->init.rate, + h->init.constraint_length); + return -1; + } + poly[0] = h->init.generator_0; + poly[1] = h->init.generator_1; + poly[2] = h->init.generator_2; + return viterbi_init(&h->obj, type, poly, h->init.frame_length, + h->init.tail_bitting?true:false); +} + +int viterbi_work(viterbi_hl* hl) { + if (hl->in_len != hl->init.frame_length) { + fprintf(stderr, "Expected input length %d but got %d\n", hl->init.frame_length, hl->in_len); + return -1; + } + return viterbi_decode_f(&hl->obj, hl->input, hl->output); +} + +int viterbi_stop(viterbi_hl* h) { + viterbi_free(&h->obj); + return 0; +} diff --git a/lte/lib/fec/src/viterbi37.h b/lte/lib/fec/src/viterbi37.h new file mode 100644 index 000000000..6afc563e8 --- /dev/null +++ b/lte/lib/fec/src/viterbi37.h @@ -0,0 +1,34 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 + +void *create_viterbi37_port(int polys[3], int len); +int init_viterbi37_port(void *p, int starting_state); +int chainback_viterbi37_port(void *p, char *data, unsigned int nbits, unsigned int endstate); +void delete_viterbi37_port(void *p); +int update_viterbi37_blk_port(void *p, unsigned char *syms, int nbits, int *best_state); diff --git a/lib/fec/src/viterbi37_port.c b/lte/lib/fec/src/viterbi37_port.c similarity index 75% rename from lib/fec/src/viterbi37_port.c rename to lte/lib/fec/src/viterbi37_port.c index e1467c3b6..56ee3645c 100644 --- a/lib/fec/src/viterbi37_port.c +++ b/lte/lib/fec/src/viterbi37_port.c @@ -5,10 +5,9 @@ #include #include #include - -#include "parity.h" #include "viterbi37.h" -#include "utils/debug.h" +#include "parity.h" +#include typedef union { unsigned int w[64]; @@ -18,11 +17,9 @@ typedef union { } decision_t; static union { - unsigned char c[32]; + unsigned char c[128]; } Branchtab37[3]; -#define DEB 0 - /* State info for instance of Viterbi decoder */ struct v37 { metric_t metrics1; /* path metric buffer 1 */ @@ -39,7 +36,6 @@ int init_viterbi37_port(void *p, int starting_state) { if (p == NULL) return -1; - for (i = 0; i < 64; i++) vp->metrics1.w[i] = 63; @@ -47,7 +43,7 @@ int init_viterbi37_port(void *p, int starting_state) { vp->new_metrics = &vp->metrics2; vp->dp = vp->decisions; if (starting_state != -1) { - vp->old_metrics->w[starting_state & 63] = 0; /* Bias known start state */ + vp->old_metrics->w[starting_state & 255] = 0; /* Bias known start state */ } return 0; } @@ -66,7 +62,7 @@ void set_viterbi37_polynomial_port(int polys[3]) { } /* Create a new instance of a Viterbi decoder */ -void *create_viterbi37_port(int polys[3], int len, bool tail_biting) { +void *create_viterbi37_port(int polys[3], int len) { struct v37 *vp; set_viterbi37_polynomial_port(polys); @@ -79,16 +75,15 @@ void *create_viterbi37_port(int polys[3], int len, bool tail_biting) { free(vp); return NULL ; } - init_viterbi37_port(vp, tail_biting?-1:0); + init_viterbi37_port(vp, 0); return vp; } /* Viterbi chainback */ int chainback_viterbi37_port(void *p, char *data, /* Decoded output data */ - unsigned int nbits, /* Number of data bits */ - unsigned int endstate) { /* Terminal encoder state */ - + unsigned int nbits, /* Number of data bits */ + unsigned int endstate) { /* Terminal encoder state */ struct v37 *vp = p; decision_t *d; @@ -100,8 +95,9 @@ int chainback_viterbi37_port(void *p, char *data, /* Decoded output data */ /* Make room beyond the end of the encoder register so we can * accumulate a full byte of decoded data */ + endstate %= 64; + endstate <<= 2; - endstate=0; /* The store into data[] only needs to be done every 8 bits. * But this avoids a conditional branch, and the writes will * combine in the cache anyway @@ -144,23 +140,12 @@ unsigned int metric,m0,m1,decision;\ d->w[i/16] |= decision << ((2*i+1)&31);\ } -unsigned char tochar_clip(float sym, float amp) { - float ret = sym * (127.5 / amp) + 127.5; - if (ret > 255) { - ret = 255; - } - if (ret < 0) { - ret = 0; - } - return (unsigned char) ret; -} - /* Update decoder with a block of demodulated symbols * Note that nbits is the number of decoded data bits, not the number * of symbols! */ -int update_viterbi37_blk_port(void *p, float *syms, int nbits, float amp, int framebits) { +int update_viterbi37_blk_port(void *p, unsigned char *syms, int nbits, int *best_state) { struct v37 *vp = p; decision_t *d; @@ -168,63 +153,37 @@ int update_viterbi37_blk_port(void *p, float *syms, int nbits, float amp, int fr return -1; int k=0; d = (decision_t *) vp->dp; - while (nbits--) { void *tmp; unsigned char sym0, sym1, sym2; + int i; d->w[0] = d->w[1] = 0; - k++; - - if (k < framebits) { - sym0 = tochar_clip(*syms++, amp); - sym1 = tochar_clip(*syms++, amp); - sym2 = tochar_clip(*syms++, amp); - } else { - sym0=255; - sym1=255; - sym2=255; - } + sym0 = *syms++; + sym1 = *syms++; + sym2 = *syms++; - BFLY(0); - BFLY(1); - BFLY(2); - BFLY(3); - BFLY(4); - BFLY(5); - BFLY(6); - BFLY(7); - BFLY(8); - BFLY(9); - BFLY(10); - BFLY(11); - BFLY(12); - BFLY(13); - BFLY(14); - BFLY(15); - BFLY(16); - BFLY(17); - BFLY(18); - BFLY(19); - BFLY(20); - BFLY(21); - BFLY(22); - BFLY(23); - BFLY(24); - BFLY(25); - BFLY(26); - BFLY(27); - BFLY(28); - BFLY(29); - BFLY(30); - BFLY(31); + k++; + for (i = 0; i < 32; i++) + BFLY(i); d++; tmp = vp->old_metrics; vp->old_metrics = vp->new_metrics; vp->new_metrics = tmp; } + if (best_state) { + int i, bst=0; + unsigned int minmetric=UINT_MAX; + for (i=0;i<64;i++) { + if (vp->old_metrics->w[i] < minmetric) { + bst = i; + minmetric = vp->old_metrics->w[i]; + } + } + *best_state = bst; + } vp->dp = d; return 0; } diff --git a/lte/lib/fec/src/viterbi39.h b/lte/lib/fec/src/viterbi39.h new file mode 100644 index 000000000..f9179d2bc --- /dev/null +++ b/lte/lib/fec/src/viterbi39.h @@ -0,0 +1,36 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 + +void *create_viterbi39_port(int polys[3], int len); +int init_viterbi39_port(void *p, int starting_state); +int chainback_viterbi39_port(void *p, char *data, /* Decoded output data */ + unsigned int nbits, /* Number of data bits */ + unsigned int endstate); +void delete_viterbi39_port(void *p); +int update_viterbi39_blk_port(void *p, unsigned char *syms, int nbits); diff --git a/lte/lib/fec/src/viterbi39_port.c b/lte/lib/fec/src/viterbi39_port.c new file mode 100644 index 000000000..0ed0e55c0 --- /dev/null +++ b/lte/lib/fec/src/viterbi39_port.c @@ -0,0 +1,172 @@ +/* K=9 r=1/3 Viterbi decoder in portable C + * Copyright Aug 2006, Phil Karn, KA9Q + * May be used under the terms of the GNU Lesser General Public License (LGPL) + */ +#include +#include +#include +#include "viterbi39.h" +#include "parity.h" + +typedef union { + unsigned int w[256]; +} metric_t; +typedef union { + unsigned long w[8]; +} decision_t; + +static union { + unsigned char c[128]; +} Branchtab39[3]; + +/* State info for instance of Viterbi decoder */ +struct v39 { + metric_t metrics1; /* path metric buffer 1 */ + metric_t metrics2; /* path metric buffer 2 */ + decision_t *dp; /* Pointer to current decision */ + metric_t *old_metrics, *new_metrics; /* Pointers to path metrics, swapped on every bit */ + decision_t *decisions; /* Beginning of decisions for block */ +}; + +/* Initialize Viterbi decoder for start of new frame */ +int init_viterbi39_port(void *p, int starting_state) { + struct v39 *vp = p; + int i; + + if (p == NULL) + return -1; + for (i = 0; i < 256; i++) + vp->metrics1.w[i] = 63; + + vp->old_metrics = &vp->metrics1; + vp->new_metrics = &vp->metrics2; + vp->dp = vp->decisions; + vp->old_metrics->w[starting_state & 255] = 0; /* Bias known start state */ + return 0; +} + +void set_viterbi39_polynomial_port(int polys[3]) { + int state; + + for (state = 0; state < 128; state++) { + Branchtab39[0].c[state] = + (polys[0] < 0) ^ parity((2 * state) & abs(polys[0])) ? 255 : 0; + Branchtab39[1].c[state] = + (polys[1] < 0) ^ parity((2 * state) & abs(polys[1])) ? 255 : 0; + Branchtab39[2].c[state] = + (polys[2] < 0) ^ parity((2 * state) & abs(polys[2])) ? 255 : 0; + } +} + +/* Create a new instance of a Viterbi decoder */ +void *create_viterbi39_port(int polys[3], int len) { + struct v39 *vp; + + set_viterbi39_polynomial_port(polys); + + if ((vp = (struct v39 *) malloc(sizeof(struct v39))) == NULL) + return NULL ; + + if ((vp->decisions = (decision_t *) malloc((len + 8) * sizeof(decision_t))) + == NULL) { + free(vp); + return NULL ; + } + init_viterbi39_port(vp, 0); + + return vp; +} + +/* Viterbi chainback */ +int chainback_viterbi39_port(void *p, char *data, /* Decoded output data */ + unsigned int nbits, /* Number of data bits */ + unsigned int endstate) { /* Terminal encoder state */ + struct v39 *vp = p; + decision_t *d; + + if (p == NULL) + return -1; + + d = vp->decisions; + /* Make room beyond the end of the encoder register so we can + * accumulate a full byte of decoded data + */ + endstate %= 256; + + /* The store into data[] only needs to be done every 8 bits. + * But this avoids a conditional branch, and the writes will + * combine in the cache anyway + */ + d += 8; /* Look past tail */ + while (nbits-- != 0) { + int k; + + k = (d[nbits].w[(endstate) / 32] >> (endstate % 32)) & 1; + endstate = (endstate >> 1) | (k << 7); + data[nbits] = k; + } + return 0; +} + +/* Delete instance of a Viterbi decoder */ +void delete_viterbi39_port(void *p) { + struct v39 *vp = p; + + if (vp != NULL) { + free(vp->decisions); + free(vp); + } +} + +/* C-language butterfly */ +#define BFLY(i) {\ +unsigned int metric,m0,m1,decision;\ + metric = (Branchtab39[0].c[i] ^ sym0) + (Branchtab39[1].c[i] ^ sym1) + \ + (Branchtab39[2].c[i] ^ sym2);\ + m0 = vp->old_metrics->w[i] + metric;\ + m1 = vp->old_metrics->w[i+128] + (765 - metric);\ + decision = (signed int)(m0-m1) > 0;\ + vp->new_metrics->w[2*i] = decision ? m1 : m0;\ + d->w[i/16] |= decision << ((2*i)&31);\ + m0 -= (metric+metric-765);\ + m1 += (metric+metric-765);\ + decision = (signed int)(m0-m1) > 0;\ + vp->new_metrics->w[2*i+1] = decision ? m1 : m0;\ + d->w[i/16] |= decision << ((2*i+1)&31);\ +} + +/* Update decoder with a block of demodulated symbols + * Note that nbits is the number of decoded data bits, not the number + * of symbols! + */ + +int update_viterbi39_blk_port(void *p, unsigned char *syms, int nbits) { + struct v39 *vp = p; + decision_t *d; + + if (p == NULL) + return -1; + + d = (decision_t *) vp->dp; + while (nbits--) { + void *tmp; + unsigned char sym0, sym1, sym2; + int i; + + for (i = 0; i < 8; i++) + d->w[i] = 0; + sym0 = *syms++; + sym1 = *syms++; + sym2 = *syms++; + + for (i = 0; i < 128; i++) + BFLY(i); + + d++; + tmp = vp->old_metrics; + vp->old_metrics = vp->new_metrics; + vp->new_metrics = tmp; + } + vp->dp = d; + return 0; +} diff --git a/lte/lib/fec/test/CMakeLists.txt b/lte/lib/fec/test/CMakeLists.txt new file mode 100644 index 000000000..72768b3b2 --- /dev/null +++ b/lte/lib/fec/test/CMakeLists.txt @@ -0,0 +1,51 @@ +# +# Copyright 2012-2013 The libLTE Developers. See the +# COPYRIGHT file at the top-level directory of this distribution. +# +# This file is part of the libLTE library. +# +# libLTE is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# libLTE is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# A copy of the GNU Lesser 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/. +# + +######################################################################## +# Viterbi TEST +######################################################################## + +ADD_EXECUTABLE(viterbi_test viterbi_test.c) +TARGET_LINK_LIBRARIES(viterbi_test lte) + +ADD_TEST(viterbi_40_0 viterbi_test -n 1000 -s 1 -l 40 -k 7 -t -e 0.0) +ADD_TEST(viterbi_40_2 viterbi_test -n 1000 -s 1 -l 40 -k 7 -t -e 2.0) +ADD_TEST(viterbi_40_3 viterbi_test -n 1000 -s 1 -l 40 -k 7 -t -e 3.0) +ADD_TEST(viterbi_40_4 viterbi_test -n 1000 -s 1 -l 40 -k 7 -t -e 4.5) + +ADD_TEST(viterbi_1000_0 viterbi_test -n 100 -s 1 -l 1000 -k 7 -t -e 0.0) +ADD_TEST(viterbi_1000_2 viterbi_test -n 100 -s 1 -l 1000 -k 7 -t -e 2.0) +ADD_TEST(viterbi_1000_3 viterbi_test -n 100 -s 1 -l 1000 -k 7 -t -e 3.0) +ADD_TEST(viterbi_1000_4 viterbi_test -n 100 -s 1 -l 1000 -k 7 -t -e 4.5) + +######################################################################## +# CRC TEST +######################################################################## + +ADD_EXECUTABLE(crc_test crc_test.c) +TARGET_LINK_LIBRARIES(crc_test lte) + +ADD_TEST(crc_24A crc_test -n 5000 -l 24 -p 0x1864CFB -s 1) +ADD_TEST(crc_24B crc_test -n 5000 -l 24 -p 0x1800063 -s 1) +ADD_TEST(crc_16 crc_test -n 5000 -l 16 -p 0x11021 -s 1) +ADD_TEST(crc_8 crc_test -n 5000 -l 8 -p 0x19B -s 1) + + diff --git a/lte/lib/fec/test/crc_test.c b/lte/lib/fec/test/crc_test.c new file mode 100644 index 000000000..da2f1dfb3 --- /dev/null +++ b/lte/lib/fec/test/crc_test.c @@ -0,0 +1,119 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 +#include +#include +#include +#include +#include +#include + +#include "lte.h" + +#include "crc_test.h" + +int num_bits = 1000, crc_length = 16; +unsigned int crc_poly = 0x11021; +unsigned int seed = 0; + + +void usage(char *prog) { + printf("Usage: %s [nlps]\n", prog); + printf("\t-n num_bits [Default %d]\n", num_bits); + printf("\t-l crc_length [Default %d]\n", crc_length); + printf("\t-p crc_poly (Hex) [Default 0x%x]\n", crc_poly); + printf("\t-s seed [Default 0=time]\n"); +} + +void parse_args(int argc, char **argv) { + int opt; + while ((opt = getopt(argc, argv, "nlps")) != -1) { + switch (opt) { + case 'n': + num_bits = atoi(argv[optind]); + break; + case 'l': + crc_length = atoi(argv[optind]); + break; + case 'p': + crc_poly = (unsigned int) strtoul(argv[optind], NULL, 16); + break; + case 's': + seed = (unsigned int) strtoul(argv[optind], NULL, 0); + break; + default: + usage(argv[0]); + exit(-1); + } + } +} + +int main(int argc, char **argv) { + int i; + char *data; + unsigned int crc_word, expected_word; + + parse_args(argc, argv); + + data = malloc(sizeof(char) * (num_bits+crc_length)); + if (!data) { + perror("malloc"); + exit(-1); + } + + if (!seed) { + seed = time(NULL); + } + srand(seed); + + // Generate data + for (i=0;i + +typedef struct { + int n; + int l; + unsigned int p; + unsigned int s; + unsigned int word; +}expected_word_t; + + +static expected_word_t expected_words[] = { + {5000, 24, 0x1864CFB, 1, 0x4D0836}, // LTE CRC24A (36.212 Sec 5.1.1) + {5000, 24, 0X1800063, 1, 0x9B68F8}, // LTE CRC24B + {5000, 16, 0x11021, 1, 0xBFFA}, // LTE CRC16 + {5000, 8, 0x19B, 1, 0xF8}, // LTE CRC8 + + {-1, -1, 0, 0, 0} +}; + +int get_expected_word(int n, int l, unsigned int p, unsigned int s, unsigned int *word) { + int i; + i=0; + while(expected_words[i].n != -1) { + if (expected_words[i].l == l + && expected_words[i].p == p + && expected_words[i].s == s) { + break; + } else { + i++; + } + } + if (expected_words[i].n == -1) { + return -1; + } else { + if (word) { + *word = expected_words[i].word; + } + return 0; + } +} diff --git a/lte/lib/fec/test/viterbi_test.c b/lte/lib/fec/test/viterbi_test.c new file mode 100644 index 000000000..43180f9e5 --- /dev/null +++ b/lte/lib/fec/test/viterbi_test.c @@ -0,0 +1,343 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 +#include +#include +#include +#include +#include +#include + +#include "lte.h" + +#include "viterbi_test.h" + +typedef _Complex float cf_t; + +int frame_length = 1000, nof_slots = 128; +float ebno_db = 100.0; +unsigned int seed = 0; +bool tail_biting = false; +int K = -1; + +#define SNR_POINTS 10 +#define SNR_MIN 0.0 +#define SNR_MAX 5.0 + +#define NCODS 3 +#define NTYPES 1+NCODS + +void usage(char *prog) { + printf("Usage: %s [nlestk]\n", prog); + printf("\t-n nof_frames [Default %d]\n", nof_slots); + printf("\t-l frame_length [Default %d]\n", frame_length); + printf("\t-e ebno in dB [Default scan]\n"); + printf("\t-s seed [Default 0=time]\n"); + printf("\t-t tail_bitting [Default %s]\n", tail_biting ? "yes" : "no"); + printf("\t-k constraint length [Default both]\n", K); +} + +void parse_args(int argc, char **argv) { + int opt; + while ((opt = getopt(argc, argv, "nlstek")) != -1) { + switch (opt) { + case 'n': + nof_slots = atoi(argv[optind]); + break; + case 'l': + frame_length = atoi(argv[optind]); + break; + case 'e': + ebno_db = atof(argv[optind]); + break; + case 's': + seed = (unsigned int) strtoul(argv[optind], NULL, 0); + break; + case 't': + tail_biting = true; + break; + case 'k': + K = atoi(argv[optind]); + break; + default: + usage(argv[0]); + exit(-1); + } + } +} + +void output_matlab(float ber[NTYPES][SNR_POINTS], int snr_points, + convcoder_t cod[NCODS], int ncods) { + int i, j, n; + FILE *f = fopen("viterbi_snr.m", "w"); + if (!f) { + perror("fopen"); + exit(-1); + } + fprintf(f, "ber=["); + for (j = 0; j < NTYPES; j++) { + for (i = 0; i < snr_points; i++) { + fprintf(f, "%g ", ber[j][i]); + } + fprintf(f, "; "); + } + fprintf(f, "];\n"); + fprintf(f, "snr=linspace(%g,%g-%g/%d,%d);\n", SNR_MIN, SNR_MAX, SNR_MAX, + snr_points, snr_points); + fprintf(f, "semilogy(snr,ber,snr,0.5*erfc(sqrt(10.^(snr/10))));\n"); + fprintf(f, "legend('uncoded',"); + for (n=0;n max_coded_length) { + max_coded_length = coded_length[i]; + } + viterbi_init(&dec[i], viterbi_type[i], cod[i].poly, frame_length, cod[i].tail_biting); + printf("Convolutional Code 1/3 K=%d Tail bitting: %s\n", cod[i].K, cod[i].tail_biting ? "yes" : "no"); + } + + printf(" Frame length: %d\n", frame_length); + if (ebno_db < 100.0) { + printf(" EbNo: %.2f\n", ebno_db); + } + + data_tx = malloc(frame_length * sizeof(char)); + if (!data_tx) { + perror("malloc"); + exit(-1); + } + + for (i = 0; i < NTYPES; i++) { + data_rx[i] = malloc(frame_length * sizeof(char)); + if (!data_rx[i]) { + perror("malloc"); + exit(-1); + } + } + + symbols = malloc(max_coded_length * sizeof(char)); + if (!symbols) { + perror("malloc"); + exit(-1); + } + llr = malloc(max_coded_length * sizeof(float)); + if (!llr) { + perror("malloc"); + exit(-1); + } + llr_c = malloc(2 * max_coded_length * sizeof(char)); + if (!llr_c) { + perror("malloc"); + exit(-1); + } + + float ebno_inc, esno_db; + ebno_inc = (SNR_MAX - SNR_MIN) / SNR_POINTS; + if (ebno_db == 100.0) { + snr_points = SNR_POINTS; + for (i = 0; i < snr_points; i++) { + ebno_db = SNR_MIN + i * ebno_inc; + esno_db = ebno_db + 10 * log10((double) 1 / 3); + var[i] = sqrt(1 / (pow(10, esno_db / 10))); + varunc[i] = sqrt(1 / (pow(10, ebno_db / 10))); + } + } else { + esno_db = ebno_db + 10 * log10((double) 1 / 3); + var[0] = sqrt(1 / (pow(10, esno_db / 10))); + varunc[0] = sqrt(1 / (pow(10, ebno_db / 10))); + snr_points = 1; + } + + float Gain = 32; + + for (i = 0; i < snr_points; i++) { + frame_cnt = 0; + for (j = 0; j < NTYPES; j++) { + errors[j] = 0; + } + while (frame_cnt < nof_slots) { + + /* generate data_tx */ + for (j = 0; j < frame_length; j++) { + data_tx[j] = rand() % 2; + } + + /* uncoded BER */ + for (j = 0; j < frame_length; j++) { + llr[j] = data_tx[j] ? sqrt(2) : -sqrt(2); + } + ch_awgn_f(llr, llr, varunc[i], frame_length); + for (j = 0; j < frame_length; j++) { + data_rx[0][j] = llr[j] > 0 ? 1 : 0; + } + + /* coded BER */ + for (n=0;n expected_errors); + } + } else { + printf("\n"); + output_matlab(ber, snr_points, cod, ncods); + printf("Done\n"); + exit(0); + } +} diff --git a/lte/lib/fec/test/viterbi_test.h b/lte/lib/fec/test/viterbi_test.h new file mode 100644 index 000000000..c0080b6ff --- /dev/null +++ b/lte/lib/fec/test/viterbi_test.h @@ -0,0 +1,71 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 + +typedef struct { + int n; + unsigned int s; + int len; + int k; + bool tail; + float ebno; + int errors; +}expected_errors_t; + + +static expected_errors_t expected_errors[] = { + {1000, 1, 40, 7, true, 0.0, 5363}, + {1000, 1, 40, 7, true, 2.0, 356}, + {1000, 1, 40, 7, true, 3.0, 48}, + {1000, 1, 40, 7, true, 4.5, 0}, + + {100, 1, 1000, 7, true, 0.0, 8753}, + {100, 1, 1000, 7, true, 2.0, 350}, + {100, 1, 1000, 7, true, 3.0, 33}, + {100, 1, 1000, 7, true, 4.5, 0}, + + {-1, -1, -1, -1, true, -1.0, -1} +}; + +int get_expected_errors(int n, unsigned int s, int len, int k, bool tail, float ebno) { + int i; + i=0; + while(expected_errors[i].n != -1) { + if (expected_errors[i].n == n + && expected_errors[i].s == s + && expected_errors[i].len == len + && expected_errors[i].k == k + && expected_errors[i].tail == tail + && expected_errors[i].ebno == ebno) { + break; + } else { + i++; + } + } + return expected_errors[i].errors; +} diff --git a/lib/filter/src/filter2d.c b/lte/lib/filter/src/filter2d.c similarity index 78% rename from lib/filter/src/filter2d.c rename to lte/lib/filter/src/filter2d.c index 8da3d4264..daf11742c 100644 --- a/lib/filter/src/filter2d.c +++ b/lte/lib/filter/src/filter2d.c @@ -1,31 +1,41 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * \section COPYRIGHT * - * OSLD-lib is distributed in the hope that it will be useful, + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 #include #include -#include "utils/debug.h" +#include "lte/utils/debug.h" -#include "filter/filter2d.h" -#include "utils/matrix.h" -#include "utils/vector.h" -#include "utils/debug.h" +#include "lte/filter/filter2d.h" +#include "lte/utils/matrix.h" +#include "lte/utils/vector.h" +#include "lte/utils/debug.h" /* Useful macros */ #define intceil(X, Y) ((X-1)/Y+1) diff --git a/lib/io/src/binsource.c b/lte/lib/io/src/binsource.c similarity index 81% rename from lib/io/src/binsource.c rename to lte/lib/io/src/binsource.c index a3093b22e..cea416d5f 100644 --- a/lib/io/src/binsource.c +++ b/lte/lib/io/src/binsource.c @@ -1,27 +1,37 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This file is part of the libLTE library. * - * OSLD-lib is distributed in the hope that it will be useful, + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 #include #include -#include "io/binsource.h" -#include "utils/bit.h" +#include "lte/io/binsource.h" +#include "lte/utils/bit.h" #define DIV(a,b) ((a-1)/b+1) diff --git a/lib/io/src/filesink.c b/lte/lib/io/src/filesink.c similarity index 62% rename from lib/io/src/filesink.c rename to lte/lib/io/src/filesink.c index ac128dfe1..c03feea3a 100644 --- a/lib/io/src/filesink.c +++ b/lte/lib/io/src/filesink.c @@ -1,3 +1,30 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 #include @@ -5,9 +32,9 @@ #include -#include "io/filesink.h" +#include "lte/io/filesink.h" -int filesink_init(filesink_t *q, char *filename, file_data_type_t type) { +int filesink_init(filesink_t *q, char *filename, data_type_t type) { bzero(q, sizeof(filesink_t)); q->f = fopen(filename, "w"); if (!q->f) { @@ -18,7 +45,7 @@ int filesink_init(filesink_t *q, char *filename, file_data_type_t type) { return 0; } -void filesink_close(filesink_t *q) { +void filesink_free(filesink_t *q) { if (q->f) { fclose(q->f); } @@ -87,6 +114,6 @@ int filesink_work(filesink_hl* h) { } int filesink_stop(filesink_hl* h) { - filesink_close(&h->obj); + filesink_free(&h->obj); return 0; } diff --git a/lib/io/src/filesource.c b/lte/lib/io/src/filesource.c similarity index 62% rename from lib/io/src/filesource.c rename to lte/lib/io/src/filesource.c index 80c28066b..d2dd1217b 100644 --- a/lib/io/src/filesource.c +++ b/lte/lib/io/src/filesource.c @@ -1,11 +1,38 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 #include #include -#include "io/filesource.h" +#include "lte/io/filesource.h" -int filesource_init(filesource_t *q, char *filename, file_data_type_t type) { +int filesource_init(filesource_t *q, char *filename, data_type_t type) { bzero(q, sizeof(filesource_t)); q->f = fopen(filename, "r"); if (!q->f) { @@ -16,13 +43,17 @@ int filesource_init(filesource_t *q, char *filename, file_data_type_t type) { return 0; } -void filesource_close(filesource_t *q) { +void filesource_free(filesource_t *q) { if (q->f) { fclose(q->f); } bzero(q, sizeof(filesource_t)); } +void filesource_seek(filesource_t *q, int pos) { + fseek(q->f, pos, SEEK_SET); +} + int read_complex_f(FILE *f, _Complex float *y) { char in_str[64]; _Complex float x; @@ -100,6 +131,6 @@ int filesource_work(filesource_hl* h) { } int filesource_stop(filesource_hl* h) { - filesource_close(&h->obj); + filesource_free(&h->obj); return 0; } diff --git a/lte/lib/io/src/udpsink.c b/lte/lib/io/src/udpsink.c new file mode 100644 index 000000000..52884407f --- /dev/null +++ b/lte/lib/io/src/udpsink.c @@ -0,0 +1,102 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 +#include +#include +#include +#include +#include +#include +#include + + +#include "lte/io/udpsink.h" + +int udpsink_init(udpsink_t *q, char *address, int port, data_type_t type) { + bzero(q, sizeof(udpsink_t)); + + q->sockfd=socket(AF_INET,SOCK_DGRAM,0); + + q->servaddr.sin_family = AF_INET; + q->servaddr.sin_addr.s_addr=inet_addr(address); + q->servaddr.sin_port=htons(port); + + q->type = type; + return 0; +} + +void udpsink_free(udpsink_t *q) { + if (q->sockfd) { + close(q->sockfd); + } + bzero(q, sizeof(udpsink_t)); +} + +int udpsink_write(udpsink_t *q, void *buffer, int nsamples) { + int size; + + switch(q->type) { + case FLOAT: + case COMPLEX_FLOAT: + case COMPLEX_SHORT: + fprintf(stderr, "Not implemented\n"); + return -1; + case FLOAT_BIN: + case COMPLEX_FLOAT_BIN: + case COMPLEX_SHORT_BIN: + if (q->type == FLOAT_BIN) { + size = sizeof(float); + } else if (q->type == COMPLEX_FLOAT_BIN) { + size = sizeof(_Complex float); + } else if (q->type == COMPLEX_SHORT_BIN) { + size = sizeof(_Complex short); + } + return sendto(q->sockfd, buffer, nsamples * size, 0, + &q->servaddr, sizeof(struct sockaddr_in)); + break; + } + return -1; +} + + + +int udpsink_initialize(udpsink_hl* h) { + return udpsink_init(&h->obj, h->init.address, h->init.port, h->init.data_type); +} + +int udpsink_work(udpsink_hl* h) { + if (udpsink_write(&h->obj, h->input, h->in_len)<0) { + return -1; + } + return 0; +} + +int udpsink_stop(udpsink_hl* h) { + udpsink_free(&h->obj); + return 0; +} diff --git a/lte/lib/io/src/udpsource.c b/lte/lib/io/src/udpsource.c new file mode 100644 index 000000000..846d08608 --- /dev/null +++ b/lte/lib/io/src/udpsource.c @@ -0,0 +1,100 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 +#include +#include +#include +#include +#include +#include + +#include "lte/io/udpsource.h" + +int udpsource_init(udpsource_t *q, char *address, int port, data_type_t type) { + bzero(q, sizeof(udpsource_t)); + + q->sockfd=socket(AF_INET,SOCK_DGRAM,0); + + q->servaddr.sin_family = AF_INET; + q->servaddr.sin_addr.s_addr=inet_addr(address); + q->servaddr.sin_port=htons(port); + bind(q->sockfd,(struct sockaddr *)&q->servaddr,sizeof(struct sockaddr_in)); + + q->type = type; + return 0; +} + +void udpsource_free(udpsource_t *q) { + if (q->sockfd) { + close(q->sockfd); + } + bzero(q, sizeof(udpsource_t)); +} + +int udpsource_read(udpsource_t *q, void *buffer, int nsamples) { + int size; + + switch(q->type) { + case FLOAT: + case COMPLEX_FLOAT: + case COMPLEX_SHORT: + fprintf(stderr, "Not implemented\n"); + return -1; + case FLOAT_BIN: + case COMPLEX_FLOAT_BIN: + case COMPLEX_SHORT_BIN: + if (q->type == FLOAT_BIN) { + size = sizeof(float); + } else if (q->type == COMPLEX_FLOAT_BIN) { + size = sizeof(_Complex float); + } else if (q->type == COMPLEX_SHORT_BIN) { + size = sizeof(_Complex short); + } + return recv(q->sockfd, buffer, size * nsamples, 0); + break; + } + return -1; +} + + +int udpsource_initialize(udpsource_hl* h) { + return udpsource_init(&h->obj, h->init.address, h->init.port, h->init.data_type); +} + +int udpsource_work(udpsource_hl* h) { + h->out_len = udpsource_read(&h->obj, h->output, h->ctrl_in.nsamples); + if (h->out_len < 0) { + return -1; + } + return 0; +} + +int udpsource_stop(udpsource_hl* h) { + udpsource_free(&h->obj); + return 0; +} diff --git a/lte/lib/mimo/src/layermap.c b/lte/lib/mimo/src/layermap.c new file mode 100644 index 000000000..cd685dcd0 --- /dev/null +++ b/lte/lib/mimo/src/layermap.c @@ -0,0 +1,214 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 +#include +#include + +#include "lte/common/base.h" +#include "lte/mimo/layermap.h" + + + +int layermap_single(cf_t *d, cf_t *x, int nof_symbols) { + memcpy(x, d, sizeof(cf_t) * nof_symbols); + return nof_symbols; +} + +int layermap_diversity(cf_t *d, cf_t *x[MAX_LAYERS], int nof_layers, int nof_symbols) { + int i, j; + for (i=0;i MAX_CODEWORDS) { + fprintf(stderr, "Maximum number of codewords is %d (nof_cw=%d)\n", MAX_CODEWORDS, nof_cw); + return -1; + } + if (nof_layers > MAX_LAYERS) { + fprintf(stderr, "Maximum number of layers is %d (nof_layers=%d)\n", MAX_LAYERS, nof_layers); + return -1; + } + if (nof_layers < nof_cw) { + fprintf(stderr, "Number of codewords must be lower or equal than number of layers\n"); + return -1; + } + + switch(type) { + case SINGLE_ANTENNA: + if (nof_cw == 1 && nof_layers == 1) { + return layermap_single(x[0], d[0], nof_symbols[0]); + } else { + fprintf(stderr, "Number of codewords and layers must be 1 for transmission on single antenna ports\n"); + return -1; + } + break; + case TX_DIVERSITY: + if (nof_cw == 1) { + if (nof_layers == 2 || nof_layers == 4) { + return layermap_diversity(d[0], x, nof_layers, nof_symbols[0]); + } else { + fprintf(stderr, "Number of layers must be 2 or 4 for transmit diversity\n"); + return -1; + } + } else { + fprintf(stderr, "Number of codewords must be 1 for transmit diversity\n"); + return -1; + } + break; + case SPATIAL_MULTIPLEX: + return layermap_multiplex(d, x, nof_cw, nof_layers, nof_symbols); + break; + } + return 0; +} + + + + + + + + + +int layerdemap_single(cf_t *x, cf_t *d, int nof_symbols) { + memcpy(d, x, sizeof(cf_t) * nof_symbols); + return nof_symbols; +} +int layerdemap_diversity(cf_t *x[MAX_LAYERS], cf_t *d, int nof_layers, int nof_layer_symbols) { + int i, j; + for (i=0;i MAX_CODEWORDS) { + fprintf(stderr, "Maximum number of codewords is %d (nof_cw=%d)\n", MAX_CODEWORDS, nof_cw); + return -1; + } + if (nof_layers > MAX_LAYERS) { + fprintf(stderr, "Maximum number of layers is %d (nof_layers=%d)\n", MAX_LAYERS, nof_layers); + return -1; + } + if (nof_layers < nof_cw) { + fprintf(stderr, "Number of codewords must be lower or equal than number of layers\n"); + return -1; + } + + switch(type) { + case SINGLE_ANTENNA: + if (nof_cw == 1 && nof_layers == 1) { + nof_symbols[0] = layerdemap_single(x[0], d[0], nof_layer_symbols); + nof_symbols[1] = 0; + } else { + fprintf(stderr, "Number of codewords and layers must be 1 for transmission on single antenna ports\n"); + return -1; + } + break; + case TX_DIVERSITY: + if (nof_cw == 1) { + if (nof_layers == 2 || nof_layers == 4) { + nof_symbols[0] = layerdemap_diversity(x, d[0], nof_layers, nof_layer_symbols); + nof_symbols[1] = 0; + } else { + fprintf(stderr, "Number of layers must be 2 or 4 for transmit diversity\n"); + return -1; + } + } else { + fprintf(stderr, "Number of codewords must be 1 for transmit diversity\n"); + return -1; + } + break; + case SPATIAL_MULTIPLEX: + return layerdemap_multiplex(x, d, nof_layers, nof_cw, nof_layer_symbols, nof_symbols); + break; + } + return 0; +} diff --git a/lte/lib/mimo/src/precoding.c b/lte/lib/mimo/src/precoding.c new file mode 100644 index 000000000..dd136a01a --- /dev/null +++ b/lte/lib/mimo/src/precoding.c @@ -0,0 +1,215 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 +#include +#include +#include +#include + +#include "lte/common/base.h" +#include "lte/mimo/precoding.h" +#include "lte/utils/vector.h" + +int precoding_single(cf_t *x, cf_t *y, int nof_symbols) { + memcpy(y, x, nof_symbols * sizeof(cf_t)); + return nof_symbols; +} +int precoding_diversity(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_ports, int nof_symbols) { + int i; + if (nof_ports == 2) { + /* FIXME: Use VOLK here */ + for (i=0;i MAX_PORTS) { + fprintf(stderr, "Maximum number of ports is %d (nof_ports=%d)\n", MAX_PORTS, nof_ports); + return -1; + } + if (nof_layers > MAX_LAYERS) { + fprintf(stderr, "Maximum number of layers is %d (nof_layers=%d)\n", MAX_LAYERS, nof_layers); + return -1; + } + + switch(type) { + case SINGLE_ANTENNA: + if (nof_ports == 1 && nof_layers == 1) { + return precoding_single(x[0], y[0], nof_symbols); + } else { + fprintf(stderr, "Number of ports and layers must be 1 for transmission on single antenna ports\n"); + return -1; + } + break; + case TX_DIVERSITY: + if (nof_ports == nof_layers) { + return precoding_diversity(x, y, nof_ports, nof_symbols); + } else { + fprintf(stderr, "Error number of layers must equal number of ports in transmit diversity\n"); + return -1; + } + case SPATIAL_MULTIPLEX: + fprintf(stderr, "Spatial multiplexing not supported\n"); + return -1; + } + return 0; +} + + +/* ZF detector */ +int predecoding_single_zf(cf_t *y, cf_t *ce, cf_t *x, int nof_symbols) { + vec_div_ccc(y, ce, x, nof_symbols); + return nof_symbols; +} + +/* ZF detector */ +int predecoding_diversity_zf(cf_t *y[MAX_PORTS], cf_t *ce[MAX_PORTS], + cf_t *x[MAX_LAYERS], int nof_ports, int nof_symbols) { + int i; + cf_t h0, h1, h2, h3, r0, r1, r2, r3; + float hh, hh02, hh13; + if (nof_ports == 2) { + /* TODO: Use VOLK here */ + for (i=0;i MAX_PORTS) { + fprintf(stderr, "Maximum number of ports is %d (nof_ports=%d)\n", MAX_PORTS, nof_ports); + return -1; + } + if (nof_layers > MAX_LAYERS) { + fprintf(stderr, "Maximum number of layers is %d (nof_layers=%d)\n", MAX_LAYERS, nof_layers); + return -1; + } + + + switch(type) { + case SINGLE_ANTENNA: + if (nof_ports == 1 && nof_layers == 1) { + return predecoding_single_zf(y[0], ce[0], x[0], nof_symbols); + } else{ + fprintf(stderr, "Number of ports and layers must be 1 for transmission on single antenna ports\n"); + return -1; + } + break; + case TX_DIVERSITY: + if (nof_ports == nof_layers) { + return predecoding_diversity_zf(y, ce, x, nof_ports, nof_symbols); + } else { + fprintf(stderr, "Error number of layers must equal number of ports in transmit diversity\n"); + return -1; + } + break; + case SPATIAL_MULTIPLEX: + fprintf(stderr, "Spatial multiplexing not supported\n"); + return -1; + } + return 0; +} + diff --git a/lte/lib/mimo/test/CMakeLists.txt b/lte/lib/mimo/test/CMakeLists.txt new file mode 100644 index 000000000..48f9e0353 --- /dev/null +++ b/lte/lib/mimo/test/CMakeLists.txt @@ -0,0 +1,68 @@ +# +# Copyright 2012-2013 The libLTE Developers. See the +# COPYRIGHT file at the top-level directory of this distribution. +# +# This file is part of the libLTE library. +# +# libLTE is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# libLTE is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# A copy of the GNU Lesser 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/. +# + +######################################################################## +# LAYER MAPPING TEST +######################################################################## + +ADD_EXECUTABLE(layermap_test layermap_test.c) +TARGET_LINK_LIBRARIES(layermap_test lte) + +ADD_TEST(layermap_single layermap_test -n 1000 -m single -c 1 -l 1) + +ADD_TEST(layermap_diversity_2 layermap_test -n 1000 -m diversity -c 1 -l 2) +ADD_TEST(layermap_diversity_4 layermap_test -n 1000 -m diversity -c 1 -l 4) + +ADD_TEST(layermap_multiplex_11 layermap_test -n 1000 -m multiplex -c 1 -l 1) +ADD_TEST(layermap_multiplex_12 layermap_test -n 1000 -m multiplex -c 1 -l 2) +ADD_TEST(layermap_multiplex_13 layermap_test -n 1002 -m multiplex -c 1 -l 3) +ADD_TEST(layermap_multiplex_14 layermap_test -n 1000 -m multiplex -c 1 -l 4) +ADD_TEST(layermap_multiplex_15 layermap_test -n 1000 -m multiplex -c 1 -l 5) +ADD_TEST(layermap_multiplex_16 layermap_test -n 1002 -m multiplex -c 1 -l 6) +ADD_TEST(layermap_multiplex_17 layermap_test -n 994 -m multiplex -c 1 -l 7) +ADD_TEST(layermap_multiplex_18 layermap_test -n 1000 -m multiplex -c 1 -l 8) + + +ADD_TEST(layermap_multiplex_22 layermap_test -n 1000 -m multiplex -c 2 -l 2) +ADD_TEST(layermap_multiplex_23 layermap_test -n 1002 -m multiplex -c 2 -l 3) +ADD_TEST(layermap_multiplex_24 layermap_test -n 1000 -m multiplex -c 2 -l 4) +ADD_TEST(layermap_multiplex_25 layermap_test -n 1002 -m multiplex -c 2 -l 5) +ADD_TEST(layermap_multiplex_26 layermap_test -n 1002 -m multiplex -c 2 -l 6) +ADD_TEST(layermap_multiplex_27 layermap_test -n 1000 -m multiplex -c 2 -l 7) +ADD_TEST(layermap_multiplex_28 layermap_test -n 1000 -m multiplex -c 2 -l 8) + + +######################################################################## +# LAYER MAPPING TEST +######################################################################## + +ADD_EXECUTABLE(precoding_test precoding_test.c) +TARGET_LINK_LIBRARIES(precoding_test lte) + +ADD_TEST(precoding_single precoding_test -n 1000 -m single) +ADD_TEST(precoding_diversity2 precoding_test -n 1000 -m diversity -l 2 -p 2) +ADD_TEST(precoding_diversity4 precoding_test -n 1024 -m diversity -l 4 -p 4) + + + + + + diff --git a/lte/lib/mimo/test/layermap_test.c b/lte/lib/mimo/test/layermap_test.c new file mode 100644 index 000000000..3e60737f0 --- /dev/null +++ b/lte/lib/mimo/test/layermap_test.c @@ -0,0 +1,163 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 +#include +#include +#include +#include +#include +#include +#include + +#include "lte.h" + +int nof_symbols = 1000; +int nof_cw = 1, nof_layers = 1; +char *mimo_type_name = NULL; + +void usage(char *prog) { + printf("Usage: %s -m [single|diversity|multiplex] -c [nof_cw] -l [nof_layers]\n", prog); + printf("\t-n num_symbols [Default %d]\n", nof_symbols); +} + +void parse_args(int argc, char **argv) { + int opt; + while ((opt = getopt(argc, argv, "mcln")) != -1) { + switch (opt) { + case 'n': + nof_symbols = atoi(argv[optind]); + break; + case 'c': + nof_cw = atoi(argv[optind]); + break; + case 'l': + nof_layers = atoi(argv[optind]); + break; + case 'm': + mimo_type_name = argv[optind]; + break; + default: + usage(argv[0]); + exit(-1); + } + } + if (!mimo_type_name) { + usage(argv[0]); + exit(-1); + } +} + +int main(int argc, char **argv) { + int i, j, num_errors, symbols_layer; + cf_t *d[MAX_CODEWORDS], *x[MAX_LAYERS], *dp[MAX_CODEWORDS]; + mimo_type_t type; + int nof_symb_cw[MAX_CODEWORDS]; + int n[2]; + + parse_args(argc, argv); + + if (lte_str2mimotype(mimo_type_name, &type)) { + fprintf(stderr, "Invalid MIMO type %s\n", mimo_type_name); + exit(-1); + } + + if (nof_cw > 1) { + n[0] = nof_layers / nof_cw; + n[1] = nof_layers - n[0]; + nof_symb_cw[0] = nof_symbols * n[0]; + nof_symb_cw[1] = nof_symbols * n[1]; + } else { + nof_symb_cw[0] = nof_symbols; + nof_symb_cw[1] = 0; + } + + for (i=0;i +#include +#include +#include +#include +#include +#include +#include + +#include "lte.h" + +#define MSE_THRESHOLD 0.00001 + +int nof_symbols = 1000; +int nof_layers = 1, nof_ports = 1; +char *mimo_type_name = NULL; + +void usage(char *prog) { + printf("Usage: %s -m [single|diversity|multiplex] -l [nof_layers] -p [nof_ports]\n", prog); + printf("\t-n num_symbols [Default %d]\n", nof_symbols); +} + +void parse_args(int argc, char **argv) { + int opt; + while ((opt = getopt(argc, argv, "mpln")) != -1) { + switch (opt) { + case 'n': + nof_symbols = atoi(argv[optind]); + break; + case 'p': + nof_ports = atoi(argv[optind]); + break; + case 'l': + nof_layers = atoi(argv[optind]); + break; + case 'm': + mimo_type_name = argv[optind]; + break; + default: + usage(argv[0]); + exit(-1); + } + } + if (!mimo_type_name) { + usage(argv[0]); + exit(-1); + } +} + +int main(int argc, char **argv) { + int i, j; + float mse; + cf_t *x[MAX_LAYERS], *r[MAX_PORTS], *y[MAX_PORTS], *h[MAX_PORTS], *xr[MAX_LAYERS]; + mimo_type_t type; + + parse_args(argc, argv); + + if (nof_ports > MAX_PORTS || nof_layers > MAX_LAYERS) { + fprintf(stderr, "Invalid number of layers or ports\n"); + exit(-1); + } + + if (lte_str2mimotype(mimo_type_name, &type)) { + fprintf(stderr, "Invalid MIMO type %s\n", mimo_type_name); + exit(-1); + } + + for (i=0;i MSE_THRESHOLD) { + printf("MSE: %f\n", mse); + exit(-1); + } else { + printf("Ok\n"); + exit(0); + } +} diff --git a/lib/modem/src/demod_hard.c b/lte/lib/modem/src/demod_hard.c similarity index 56% rename from lib/modem/src/demod_hard.c rename to lte/lib/modem/src/demod_hard.c index d694659a0..a251cdf39 100644 --- a/lib/modem/src/demod_hard.c +++ b/lte/lib/modem/src/demod_hard.c @@ -1,25 +1,35 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * \section COPYRIGHT * - * OSLD-lib is distributed in the hope that it will be useful, + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 #include -#include "modem/demod_hard.h" +#include "lte/modem/demod_hard.h" #include "hard_demod_lte.h" @@ -27,11 +37,11 @@ void demod_hard_init(demod_hard_t* q) { bzero((void*) q, sizeof(demod_hard_t)); } -void demod_hard_table(demod_hard_t* q, enum modem_std table) { +void demod_hard_table_set(demod_hard_t* q, enum modem_std table) { q->table = table; } -int demod_hard_demodulate(demod_hard_t* q, const cf* symbols, char *bits, int nsymbols) { +int demod_hard_demodulate(demod_hard_t* q, cf_t* symbols, char *bits, int nsymbols) { int nbits=-1; switch(q->table) { @@ -58,7 +68,7 @@ int demod_hard_demodulate(demod_hard_t* q, const cf* symbols, char *bits, int ns int demod_hard_initialize(demod_hard_hl* hl) { demod_hard_init(&hl->obj); - demod_hard_table(&hl->obj,hl->init.std); + demod_hard_table_set(&hl->obj,hl->init.std); return 0; } diff --git a/lib/modem/src/demod_soft.c b/lte/lib/modem/src/demod_soft.c similarity index 67% rename from lib/modem/src/demod_soft.c rename to lte/lib/modem/src/demod_soft.c index 3426132a6..3180ff114 100644 --- a/lib/modem/src/demod_soft.c +++ b/lte/lib/modem/src/demod_soft.c @@ -1,26 +1,36 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * \section COPYRIGHT * - * OSLD-lib is distributed in the hope that it will be useful, + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 #include -#include "utils/bit.h" -#include "modem/demod_soft.h" +#include "lte/utils/bit.h" +#include "lte/modem/demod_soft.h" #include "soft_algs.h" @@ -40,7 +50,7 @@ void demod_soft_sigma_set(demod_soft_t *q, float sigma) { q->sigma = sigma; } -int demod_soft_demodulate(demod_soft_t *q, const cf* symbols, float* llr, int nsymbols) { +int demod_soft_demodulate(demod_soft_t *q, const cf_t* symbols, float* llr, int nsymbols) { switch(q->alg_type) { case EXACT: llr_exact(symbols, llr, nsymbols, q->table->nsymbols, q->table->nbits_x_symbol, diff --git a/lib/modem/src/hard_demod_lte.c b/lte/lib/modem/src/hard_demod_lte.c similarity index 80% rename from lib/modem/src/hard_demod_lte.c rename to lte/lib/modem/src/hard_demod_lte.c index 282ccf36f..b726c6217 100644 --- a/lib/modem/src/hard_demod_lte.c +++ b/lte/lib/modem/src/hard_demod_lte.c @@ -1,26 +1,36 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez , Vuk Marojevic . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This file is part of the libLTE library. * - * OSLD-lib is distributed in the hope that it will be useful, + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 #include #include -#include "modem/demod_hard.h" +#include "lte/modem/demod_hard.h" #include "hard_demod_lte.h" /** @@ -36,7 +46,7 @@ * \param N Number of input symbols * \param modulation Modulation type */ -inline void hard_bpsk_demod(const cf* in, char* out, int N) +inline void hard_bpsk_demod(const cf_t* in, char* out, int N) { int s; @@ -71,7 +81,7 @@ inline void hard_bpsk_demod(const cf* in, char* out, int N) * \param N Number of input symbols * \param modulation Modulation type */ -inline void hard_qpsk_demod(const cf* in, char* out, int N) +inline void hard_qpsk_demod(const cf_t* in, char* out, int N) { int s; @@ -105,7 +115,7 @@ inline void hard_qpsk_demod(const cf* in, char* out, int N) * \param N Number of input symbols * \param modulation Modulation type */ -inline void hard_qam16_demod(const cf* in, char* out, int N) +inline void hard_qam16_demod(const cf_t* in, char* out, int N) { int s; @@ -147,7 +157,7 @@ inline void hard_qam16_demod(const cf* in, char* out, int N) * \param N Number of input symbols * \param modulation Modulation type */ -inline void hard_qam64_demod(const cf* in, char* out, int N) +inline void hard_qam64_demod(const cf_t* in, char* out, int N) { int s; diff --git a/lte/lib/modem/src/hard_demod_lte.h b/lte/lib/modem/src/hard_demod_lte.h new file mode 100644 index 000000000..be79212e8 --- /dev/null +++ b/lte/lib/modem/src/hard_demod_lte.h @@ -0,0 +1,41 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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/. + * + */ + + +/* Thresholds for Demodulation */ +/* Assume perfect amplitude and phase alignment. + * Check threshold values for real case + * or implement dynamic threshold adjustent as a function of received symbol amplitudes */ +#define QAM16_THRESHOLD 2/sqrt(10) +#define QAM64_THRESHOLD_1 2/sqrt(42) +#define QAM64_THRESHOLD_2 4/sqrt(42) +#define QAM64_THRESHOLD_3 6/sqrt(42) + +void hard_bpsk_demod(const cf_t* in, char* out, int N); +void hard_qpsk_demod(const cf_t* in, char* out, int N); +void hard_qam16_demod(const cf_t* in, char* out, int N); +void hard_qam64_demod(const cf_t* in, char* out, int N); diff --git a/lib/modem/src/lte_tables.c b/lte/lib/modem/src/lte_tables.c similarity index 89% rename from lib/modem/src/lte_tables.c rename to lte/lib/modem/src/lte_tables.c index a970e87d5..cc169fbf0 100644 --- a/lib/modem/src/lte_tables.c +++ b/lte/lib/modem/src/lte_tables.c @@ -1,32 +1,42 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez , Vuk Marojevic . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This file is part of the libLTE library. * - * OSLD-lib is distributed in the hope that it will be useful, + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 #include #include #include -#include "modem/modem_table.h" +#include "lte/modem/modem_table.h" #include "lte_tables.h" /** * Set the BPSK modulation table */ -void set_BPSKtable(cf* table, soft_table_t *soft_table, bool compute_soft_demod) +void set_BPSKtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demod) { // LTE-BPSK constellation: // Q @@ -47,7 +57,7 @@ void set_BPSKtable(cf* table, soft_table_t *soft_table, bool compute_soft_demod) /** * Set the QPSK modulation table */ -void set_QPSKtable(cf* table, soft_table_t *soft_table, bool compute_soft_demod) +void set_QPSKtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demod) { int i,j; @@ -85,7 +95,7 @@ void set_QPSKtable(cf* table, soft_table_t *soft_table, bool compute_soft_demod) /** * Set the 16QAM modulation table */ -void set_16QAMtable(cf* table, soft_table_t *soft_table, bool compute_soft_demod) +void set_16QAMtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demod) { int i,j; // LTE-16QAM constellation: @@ -150,7 +160,7 @@ void set_16QAMtable(cf* table, soft_table_t *soft_table, bool compute_soft_demod /** * Set the 64QAM modulation table */ -void set_64QAMtable(cf* table, soft_table_t *soft_table, bool compute_soft_demod) +void set_64QAMtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demod) { int i,j; // LTE-64QAM constellation: diff --git a/lte/lib/modem/src/lte_tables.h b/lte/lib/modem/src/lte_tables.h new file mode 100644 index 000000000..1e5280137 --- /dev/null +++ b/lte/lib/modem/src/lte_tables.h @@ -0,0 +1,51 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 BPSK_LEVEL 1/sqrt(2) + +#define QPSK_LEVEL 1/sqrt(2) + +#define QAM16_LEVEL_1 1/sqrt(10) +#define QAM16_LEVEL_2 3/sqrt(10) + +#define QAM64_LEVEL_1 1/sqrt(42) +#define QAM64_LEVEL_2 3/sqrt(42) +#define QAM64_LEVEL_3 5/sqrt(42) +#define QAM64_LEVEL_4 7/sqrt(42) + +#define QAM64_LEVEL_x 2/sqrt(42) +/* this is not an QAM64 level, but, rather, an auxiliary value that can be used for computing the + * symbol from the bit sequence */ + + + + +void set_BPSKtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demod); +void set_QPSKtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demod); +void set_16QAMtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demod); +void set_64QAMtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demod); diff --git a/lib/modem/src/mod.c b/lte/lib/modem/src/mod.c similarity index 51% rename from lib/modem/src/mod.c rename to lte/lib/modem/src/mod.c index 979139615..968f202ba 100644 --- a/lib/modem/src/mod.c +++ b/lte/lib/modem/src/mod.c @@ -1,35 +1,47 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * \section COPYRIGHT * - * OSLD-lib is distributed in the hope that it will be useful, + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 #include +#include -#include "utils/bit.h" -#include "modem/mod.h" +#include "lte/utils/bit.h" +#include "lte/modem/mod.h" /** Low-level API */ -int mod_modulate(modem_table_t* q, const char *bits, cf* symbols, int nbits) { +int mod_modulate(modem_table_t* q, const char *bits, cf_t* symbols, int nbits) { int i,j,idx; char *b_ptr=(char*) bits; j=0; for (i=0;inbits_x_symbol) { idx = bit_unpack(&b_ptr,q->nbits_x_symbol); + assert(idx >= 0 && idx < q->nsymbols); symbols[j] = q->symbol_table[idx]; j++; } diff --git a/lib/modem/src/modem_table.c b/lte/lib/modem/src/modem_table.c similarity index 67% rename from lib/modem/src/modem_table.c rename to lte/lib/modem/src/modem_table.c index 1877cb046..3ec2888c0 100644 --- a/lib/modem/src/modem_table.c +++ b/lte/lib/modem/src/modem_table.c @@ -1,21 +1,31 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * \section COPYRIGHT * - * OSLD-lib is distributed in the hope that it will be useful, + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 #include #include @@ -23,12 +33,12 @@ #include #include -#include "modem/modem_table.h" +#include "lte/modem/modem_table.h" #include "lte_tables.h" /** Internal functions */ static int table_create(modem_table_t* q) { - q->symbol_table = malloc(q->nsymbols*sizeof(cf)); + q->symbol_table = malloc(q->nsymbols*sizeof(cf_t)); return q->symbol_table==NULL; } @@ -46,7 +56,7 @@ void modem_table_reset(modem_table_t* q) { modem_table_init(q); } -int modem_table_set(modem_table_t* q, cf* table, soft_table_t *soft_table, int nsymbols, int nbits_x_symbol) { +int modem_table_set(modem_table_t* q, cf_t* table, soft_table_t *soft_table, int nsymbols, int nbits_x_symbol) { if (q->nsymbols) { return -1; } @@ -54,7 +64,7 @@ int modem_table_set(modem_table_t* q, cf* table, soft_table_t *soft_table, int n if (table_create(q)) { return -1; } - memcpy(q->symbol_table,table,q->nsymbols*sizeof(cf)); + memcpy(q->symbol_table,table,q->nsymbols*sizeof(cf_t)); memcpy(&q->soft_table,soft_table,sizeof(soft_table_t)); q->nbits_x_symbol = nbits_x_symbol; return 0; diff --git a/lib/modem/src/soft_algs.c b/lte/lib/modem/src/soft_algs.c similarity index 87% rename from lib/modem/src/soft_algs.c rename to lte/lib/modem/src/soft_algs.c index deca250eb..3180a117a 100644 --- a/lib/modem/src/soft_algs.c +++ b/lte/lib/modem/src/soft_algs.c @@ -1,22 +1,32 @@ -/* - * Copyright (c) 2013, Vuk Marojevic . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This file is part of the libLTE library. * - * OSLD-lib is distributed in the hope that it will be useful, + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 #include #include diff --git a/lte/lib/modem/src/soft_algs.h b/lte/lib/modem/src/soft_algs.h new file mode 100644 index 000000000..15b0caee5 --- /dev/null +++ b/lte/lib/modem/src/soft_algs.h @@ -0,0 +1,33 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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/. + * + */ + + +void llr_approx(const _Complex float *in, float *out, int N, int M, int B, + _Complex float *symbols, int (*S)[6][32], float sigma2); + +void llr_exact(const _Complex float *in, float *out, int N, int M, int B, + _Complex float *symbols, int (*S)[6][32], float sigma2); diff --git a/lte/lib/modem/test/CMakeLists.txt b/lte/lib/modem/test/CMakeLists.txt new file mode 100644 index 000000000..7b1689b17 --- /dev/null +++ b/lte/lib/modem/test/CMakeLists.txt @@ -0,0 +1,40 @@ +# +# Copyright 2012-2013 The libLTE Developers. See the +# COPYRIGHT file at the top-level directory of this distribution. +# +# This file is part of the libLTE library. +# +# libLTE is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# libLTE is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# A copy of the GNU Lesser 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/. +# + +######################################################################## +# MODEM TEST +######################################################################## + +ADD_EXECUTABLE(modem_test modem_test.c) +TARGET_LINK_LIBRARIES(modem_test lte) + +ADD_TEST(modem_bpsk modem_test -n 1020 -m 1) +ADD_TEST(modem_qpsk modem_test -n 1020 -m 2) +ADD_TEST(modem_qam16 modem_test -n 1020 -m 4) +ADD_TEST(modem_qam64 modem_test -n 1020 -m 6) + +ADD_TEST(modem_bpsk_soft modem_test -n 1020 -m 1 -s) +ADD_TEST(modem_qpsk_soft modem_test -n 1020 -m 2 -s) +ADD_TEST(modem_qam16_soft modem_test -n 1020 -m 4 -s) +ADD_TEST(modem_qam64_soft modem_test -n 1020 -m 6 -s) + + + diff --git a/lte/lib/modem/test/modem_test.c b/lte/lib/modem/test/modem_test.c new file mode 100644 index 000000000..1582b611a --- /dev/null +++ b/lte/lib/modem/test/modem_test.c @@ -0,0 +1,184 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 +#include +#include +#include +#include +#include +#include +#include + +#include "lte.h" + +int num_bits = 1000; +enum modem_std modulation; +bool soft_output = false, soft_exact = false; + +void usage(char *prog) { + printf("Usage: %s [nmse]\n", prog); + printf("\t-n num_bits [Default %d]\n", num_bits); + printf("\t-m modulation (1: BPSK, 2: QPSK, 3: QAM16, 4: QAM64) [Default BPSK]\n"); + printf("\t-s soft outputs [Default hard]\n"); + printf("\t-e soft outputs exact algorithm [Default approx]\n"); +} + +void parse_args(int argc, char **argv) { + int opt; + while ((opt = getopt(argc, argv, "nmse")) != -1) { + switch (opt) { + case 'n': + num_bits = atoi(argv[optind]); + break; + case 's': + soft_output = true; + break; + case 'e': + soft_exact = true; + break; + case 'm': + switch(atoi(argv[optind])) { + case 1: + modulation = LTE_BPSK; + break; + case 2: + modulation = LTE_QPSK; + break; + case 4: + modulation = LTE_QAM16; + break; + case 6: + modulation = LTE_QAM64; + break; + default: + fprintf(stderr, "Invalid modulation %d. Possible values: " + "(1: BPSK, 2: QPSK, 3: QAM16, 4: QAM64)\n", atoi(argv[optind])); + break; + } + break; + default: + usage(argv[0]); + exit(-1); + } + } +} + + +int main(int argc, char **argv) { + int i; + modem_table_t mod; + demod_hard_t demod_hard; + demod_soft_t demod_soft; + char *input, *output; + cf_t *symbols; + float *llr; + + parse_args(argc, argv); + + /* initialize objects */ + if (modem_table_std(&mod, modulation, soft_output)) { + fprintf(stderr, "Error initializing modem table\n"); + exit(-1); + } + + /* check that num_bits is multiple of num_bits x symbol */ + if (num_bits % mod.nbits_x_symbol) { + fprintf(stderr, "Error num_bits must be multiple of %d\n", mod.nbits_x_symbol); + exit(-1); + } + + if (soft_output) { + demod_soft_init(&demod_soft); + demod_soft_table_set(&demod_soft, &mod); + demod_soft_alg_set(&demod_soft, soft_exact?EXACT:APPROX); + } else { + demod_hard_init(&demod_hard); + demod_hard_table_set(&demod_hard, modulation); + } + + /* allocate buffers */ + input = malloc(sizeof(char) * num_bits); + if (!input) { + perror("malloc"); + exit(-1); + } + output = malloc(sizeof(char) * num_bits); + if (!output) { + perror("malloc"); + exit(-1); + } + symbols = malloc(sizeof(cf_t) * num_bits / mod.nbits_x_symbol); + if (!symbols) { + perror("malloc"); + exit(-1); + } + + llr = malloc(sizeof(float) * num_bits); + if (!llr) { + perror("malloc"); + exit(-1); + } + + + /* generate random data */ + srand(time(NULL)); + for (i=0;i=0 ? 1 : 0; + } + } else { + demod_hard_demodulate(&demod_hard, symbols, output, num_bits / mod.nbits_x_symbol); + } + + /* check errors */ + for (i=0;i +#include +#include +#include +#include +#include +#include +#include + +#include "prb.h" +#include "lte/phch/pbch.h" +#include "lte/common/base.h" +#include "lte/utils/bit.h" +#include "lte/utils/vector.h" +#include "lte/utils/debug.h" + +const char crc_mask[4][16] = { + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1} +}; + + +bool pbch_exists(int nframe, int nslot) { + return (!(nframe % 5) && nslot == 1); +} + +int pbch_cp(cf_t *input, cf_t *output, int nof_prb, lte_cp_t cp, int cell_id, bool put) { + int i; + cf_t *ptr; + assert(cell_id >= 0); + if (put) { + ptr = input; + output += nof_prb * RE_X_RB / 2 - 36; + } else { + ptr = output; + input += nof_prb * RE_X_RB / 2 - 36; + } + + /* symbol 0 & 1 */ + for (i=0;i<2;i++) { + prb_cp_ref(&input, &output, cell_id%3, 4, 6, put); + } + /* symbols 2 & 3 */ + if (CP_ISNORM(cp)) { + for (i=0;i<2;i++) { + prb_cp(&input, &output, 6); + } + } else { + prb_cp(&input, &output, 6); + prb_cp_ref(&input, &output, cell_id%3, 4, 6, put); + } + if (put) { + return input - ptr; + } else { + return output - ptr; + } +} + +/** + * Puts PBCH in slot number 1 + * + * Returns the number of symbols written to slot1_data + * + * 36.211 10.3 section 6.6.4 + */ +int pbch_put(cf_t *pbch, cf_t *slot1_data, int nof_prb, lte_cp_t cp, int cell_id) { + return pbch_cp(pbch, slot1_data, nof_prb, cp, cell_id, true); +} + +/** + * Extracts PBCH from slot number 1 + * + * Returns the number of symbols written to pbch + * + * 36.211 10.3 section 6.6.4 + */ +int pbch_get(cf_t *slot1_data, cf_t *pbch, int nof_prb, lte_cp_t cp, int cell_id) { + return pbch_cp(slot1_data, pbch, nof_prb, cp, cell_id, false); +} + +/** Initializes the PBCH transmitter and receiver */ +int pbch_init(pbch_t *q, int cell_id, lte_cp_t cp) { + int ret = -1; + if (cell_id < 0) { + return -1; + } + bzero(q, sizeof(pbch_t)); + q->cell_id = cell_id; + q->cp = cp; + + if (modem_table_std(&q->mod, LTE_QPSK, true)) { + goto clean; + } + demod_soft_init(&q->demod); + demod_soft_table_set(&q->demod, &q->mod); + demod_soft_alg_set(&q->demod, APPROX); + if (sequence_pbch(&q->seq_pbch, q->cp, q->cell_id)) { + goto clean; + } + + int poly[3] = {0x6D, 0x4F, 0x57}; + if (viterbi_init(&q->decoder, viterbi_37, poly, 40, true)) { + goto clean; + } + q->encoder.K = 7; + q->encoder.R = 3; + q->encoder.framelength = 40; + q->encoder.tail_biting = true; + memcpy(q->encoder.poly, poly, 3 * sizeof(int)); + + q->nof_symbols = (CP_ISNORM(q->cp)) ? PBCH_RE_CPNORM: PBCH_RE_CPEXT; + + q->pbch_d = malloc(sizeof(cf_t) * q->nof_symbols); + if (!q->pbch_d) { + goto clean; + } + int i; + for (i=0;ice[i] = malloc(sizeof(cf_t) * q->nof_symbols); + if (!q->ce[i]) { + goto clean; + } + q->pbch_x[i] = malloc(sizeof(cf_t) * q->nof_symbols); + if (!q->pbch_x[i]) { + goto clean; + } + q->pbch_symbols[i] = malloc(sizeof(cf_t) * q->nof_symbols); + if (!q->pbch_symbols[i]) { + goto clean; + } + } + q->pbch_llr = malloc(sizeof(float) * q->nof_symbols * 4 * 2); + if (!q->pbch_llr) { + goto clean; + } + q->temp = malloc(sizeof(float) * q->nof_symbols * 4 * 2); + if (!q->temp) { + goto clean; + } + q->pbch_rm_f = malloc(sizeof(float) * 120); + if (!q->pbch_rm_f) { + goto clean; + } + q->pbch_rm_b = malloc(sizeof(float) * q->nof_symbols * 4 * 2); + if (!q->pbch_rm_b) { + goto clean; + } + q->data = malloc(sizeof(char) * 40); + if (!q->data) { + goto clean; + } + q->data_enc = malloc(sizeof(char) * 120); + if (!q->data_enc) { + goto clean; + } + + ret = 0; +clean: + if (ret == -1) { + pbch_free(q); + } + return ret; +} + +void pbch_free(pbch_t *q) { + if (q->pbch_d) { + free(q->pbch_d); + } + int i; + for (i=0;ice[i]) { + free(q->ce[i]); + } + if (q->pbch_x[i]) { + free(q->pbch_x[i]); + } + if (q->pbch_symbols[i]) { + free(q->pbch_symbols[i]); + } + } + if (q->pbch_llr) { + free(q->pbch_llr); + } + if (q->temp) { + free(q->temp); + } + if (q->pbch_rm_f) { + free(q->pbch_rm_f); + } + if (q->pbch_rm_b) { + free(q->pbch_rm_b); + } + if (q->data_enc) { + free(q->data_enc); + } + if (q->data) { + free(q->data); + } + sequence_free(&q->seq_pbch); + modem_table_free(&q->mod); + viterbi_free(&q->decoder); +} + +/** Unpacks MIB from PBCH message. + * msg buffer must be 24 byte length at least + */ +void pbch_mib_unpack(char *msg, pbch_mib_t *mib) { + int bw, phich_res; + + bw = bit_unpack(&msg, 3); + switch(bw) { + case 0: + mib->nof_prb = 6; + break; + case 1: + mib->nof_prb = 15; + break; + default: + mib->nof_prb = (bw-1)*25; + break; + } + if (*msg) { + mib->phich_length = PHICH_EXT; + } else { + mib->phich_length = PHICH_NORM; + } + msg++; + + phich_res = bit_unpack(&msg, 2); + switch(phich_res) { + case 0: + mib->phich_resources = R_1_6; + break; + case 1: + mib->phich_resources = R_1_2; + break; + case 2: + mib->phich_resources = R_1; + break; + case 3: + mib->phich_resources = R_2; + break; + } + mib->sfn = bit_unpack(&msg, 8) << 2; +} + + +/** Unpacks MIB from PBCH message. + * msg buffer must be 24 byte length at least + */ +void pbch_mib_pack(pbch_mib_t *mib, char *msg) { + int bw, phich_res=0; + + bzero(msg, 24); + + if (mib->nof_prb<=6) { + bw = 0; + } else if (mib->nof_prb <= 15) { + bw = 1; + } else { + bw = 1 + mib->nof_prb/25; + } + bit_pack(bw, &msg, 3); + + *msg = mib->phich_length == PHICH_EXT; + msg++; + + switch(mib->phich_resources) { + case R_1_6: + phich_res = 0; + break; + case R_1_2: + phich_res = 1; + break; + case R_1: + phich_res = 2; + break; + case R_2: + phich_res = 3; + break; + } + bit_pack(phich_res, &msg, 2); + bit_pack(mib->sfn >> 2, &msg, 8); +} + +void pbch_mib_fprint(FILE *stream, pbch_mib_t *mib) { + printf(" - Nof ports: %d\n", mib->nof_ports); + printf(" - PRB: %d\n", mib->nof_prb); + printf(" - PHICH Length: %s\n", mib->phich_length==PHICH_EXT?"Extended":"Normal"); + printf(" - PHICH Resources: "); + switch(mib->phich_resources) { + case R_1_6: + printf("1/6"); + break; + case R_1_2: + printf("1/2"); + break; + case R_1: + printf("1"); + break; + case R_2: + printf("2"); + break; + } + printf("\n"); + printf(" - SFN: %d\n", mib->sfn); +} + +void pbch_decode_reset(pbch_t *q) { + q->frame_idx = 0; +} + + +void crc_set_mask(char *data, int nof_ports) { + int i; + for (i=0;i<16;i++) { + data[24+i] = (data[24+i] + crc_mask[nof_ports-1][i]) % 2; + } + +} + + +/* Checks CRC after applying the mask for the given number of ports. + * + * The bits buffer size must be at least 40 bytes. + * + * Returns 0 if the data is correct, -1 otherwise + */ +int pbch_crc_check(char *bits, int nof_ports) { + char data[40]; + memcpy(data, bits, 40 * sizeof(char)); + crc_set_mask(data, nof_ports); + return crc(0, data, 40, 16, 0x11021, 0); +} + +int pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, int src, int dst, int n, int nof_bits, int nof_ports) { + int j; + + memcpy(&q->temp[dst*nof_bits], &q->pbch_llr[src*nof_bits], n*nof_bits*sizeof(float)); + + /* descramble */ + scrambling_f_offset(&q->seq_pbch, &q->temp[dst*nof_bits], dst*nof_bits, n*nof_bits); + + for (j=0;jtemp[j] = RX_NULL; + } + for (j=(dst+n)*nof_bits;j<4*nof_bits;j++) { + q->temp[j] = RX_NULL; + } + + /* unrate matching */ + rm_conv_rx(q->temp, q->pbch_rm_f, 4 * nof_bits, 120); + + /* FIXME: If channel estimates are zero, received LLR are NaN. Check and return error */ + for (j=0;j<120;j++) { + if (isnan(q->pbch_rm_f[j]) || isinf(q->pbch_rm_f[j])) { + return 0; + } + } + + /* decode */ + viterbi_decode_f(&q->decoder, q->pbch_rm_f, q->data); + + int c=0; + for (j=0;j<40;j++) { + c+=q->data[j]; + } + if (!c) { + c=1; + } + + if (!pbch_crc_check(q->data, nof_ports)) { + /* unpack MIB */ + pbch_mib_unpack(q->data, mib); + + mib->nof_ports = nof_ports; + mib->sfn += dst-src; + + return 1; + } else { + return 0; + } +} + +/* Decodes the PBCH channel + * + * The PBCH spans in 40 ms. This function is called every 10 ms. It tries to decode the MIB + * given the symbols of the slot #1 of each radio frame. Successive calls will use more frames + * to help the decoding process. + * + * Returns 1 if successfully decoded MIB, 0 if not and -1 on error + */ +int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], int nof_prb, float ebno, pbch_mib_t *mib) { + int src, dst, res, nb; + int nant_[3] = {1, 2, 4}; + int na, nant; + + /* Set pointers for layermapping & precoding */ + int i; + int nof_bits = 2 * q->nof_symbols; + cf_t *x[MAX_LAYERS]; + + /* number of layers equals number of ports */ + for (i=0;ipbch_x[i]; + } + memset(&x[MAX_PORTS_CTRL], 0, sizeof(cf_t*) * (MAX_LAYERS - MAX_PORTS_CTRL)); + + /* extract symbols */ + if (q->nof_symbols != pbch_get(slot1_symbols, q->pbch_symbols[0], nof_prb, + q->cp, q->cell_id)) { + fprintf(stderr, "There was an error getting the PBCH symbols\n"); + return -1; + } + + /* extract channel estimates */ + for (i=0;inof_symbols != pbch_get(ce[i], q->ce[i], nof_prb, + q->cp, q->cell_id)) { + fprintf(stderr, "There was an error getting the PBCH symbols\n"); + return -1; + } + } + + q->frame_idx++; + res = 0; + + /* Try decoding for 1 to 4 antennas */ + for (na=0;na<3 && !res;na++) { + nant = nant_[na]; + + INFO("Trying %d TX antennas with %d frames\n", nant, q->frame_idx); + + /* in conctrol channels, only diversity is supported */ + if (nant == 1) { + /* no need for layer demapping */ + predecoding_single_zf(q->pbch_symbols[0], q->ce[0], q->pbch_d, q->nof_symbols); + } else { + predecoding_diversity_zf(q->pbch_symbols, q->ce, x, nant, q->nof_symbols); + layerdemap_diversity(x, q->pbch_d, nant, q->nof_symbols/nant); + } + + /* demodulate symbols */ + demod_soft_sigma_set(&q->demod, ebno); + demod_soft_demodulate(&q->demod, q->pbch_d, + &q->pbch_llr[nof_bits * (q->frame_idx - 1)], q->nof_symbols); + + /* We don't know where the 40 ms begin, so we try all combinations. E.g. if we received + * 4 frames, try 1,2,3,4 individually, 12, 23, 34 in pairs, 123, 234 and finally 1234. + * We know they are ordered. + * + * FIXME: There are unnecessary checks because 2,3,4 have already been processed in the previous + * calls. + */ + for (nb=0;nbframe_idx && !res;nb++) { + for (dst=0;(dst<4-nb) && !res;dst++) { + for (src=0;srcframe_idx-nb && !res;src++) { + DEBUG("Trying %d blocks at offset %d as subframe mod4 number %d\n", nb+1, src, dst); + res = pbch_decode_frame(q, mib, src, dst, nb+1, nof_bits, nant); + } + } + } + } + + /* If not found, make room for the next packet of radio frame symbols */ + if (q->frame_idx == 4) { + memmove(q->pbch_llr, &q->pbch_llr[nof_bits], nof_bits * 3 * sizeof(float)); + q->frame_idx = 3; + } + return res; +} + + +/** Converts the MIB message to symbols mapped to SLOT #1 ready for transmission + */ +void pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *slot1_symbols[MAX_PORTS_CTRL], + int nof_prb, int nof_ports) { + int i; + int nof_bits = 2 * q->nof_symbols; + + assert(nof_ports <= MAX_PORTS_CTRL); + + /* Set pointers for layermapping & precoding */ + cf_t *x[MAX_LAYERS]; + + /* number of layers equals number of ports */ + for (i=0;ipbch_x[i]; + } + memset(&x[nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - nof_ports)); + + if (q->frame_idx == 0) { + /* pack MIB */ + pbch_mib_pack(mib, q->data); + + /* encode & modulate */ + crc(0, q->data, 24, 16, 0x11021, 1); + crc_set_mask(q->data, nof_ports); + + convcoder_encode(&q->encoder, q->data, q->data_enc); + + rm_conv_tx(q->data_enc, q->pbch_rm_b, 120, 4 * nof_bits); + + } + + scrambling_b_offset(&q->seq_pbch, &q->pbch_rm_b[q->frame_idx * nof_bits], + q->frame_idx * nof_bits, nof_bits); + mod_modulate(&q->mod, &q->pbch_rm_b[q->frame_idx * nof_bits], q->pbch_d, nof_bits); + + + /* layer mapping & precoding */ + if (nof_ports > 1) { + layermap_diversity(q->pbch_d, x, nof_ports, q->nof_symbols); + precoding_diversity(x, q->pbch_symbols, nof_ports, q->nof_symbols/nof_ports); + } else { + memcpy(q->pbch_symbols[0], q->pbch_d, q->nof_symbols * sizeof(cf_t)); + } + + + /* mapping to resource elements */ + for (i=0;ipbch_symbols[i], slot1_symbols[i], nof_prb, q->cp, q->cell_id); + } + q->frame_idx++; + if (q->frame_idx == 4) { + q->frame_idx = 0; + } +} + + + diff --git a/lte/lib/phch/src/pcfich.c b/lte/lib/phch/src/pcfich.c new file mode 100644 index 000000000..5422cf54f --- /dev/null +++ b/lte/lib/phch/src/pcfich.c @@ -0,0 +1,261 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 +#include +#include +#include +#include +#include +#include +#include + +#include "lte/phch/regs.h" +#include "lte/phch/pcfich.h" +#include "lte/common/base.h" +#include "lte/utils/bit.h" +#include "lte/utils/vector.h" +#include "lte/utils/debug.h" + + +// Table 5.3.4-1 +static char cfi_table[4][PCFICH_CFI_LEN] = { + {0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1}, + {1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0}, + {1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} // reserved +}; + + + +bool pcfich_exists(int nframe, int nslot) { + return true; +} + +/** Initializes the pcfich channel receiver */ +int pcfich_init(pcfich_t *q, regs_t *regs, int cell_id, int nof_prb, int nof_tx_ports, lte_cp_t cp) { + int ret = -1; + if (cell_id < 0) { + return -1; + } + bzero(q, sizeof(pcfich_t)); + q->cell_id = cell_id; + q->cp = cp; + q->regs = regs; + q->nof_prb = nof_prb; + q->nof_tx_ports = nof_tx_ports; + + if (modem_table_std(&q->mod, LTE_QPSK, false)) { + goto clean; + } + + demod_hard_init(&q->demod); + demod_hard_table_set(&q->demod, LTE_QPSK); + + for (int nsf=0;nsfseq_pcfich[nsf], 2*nsf, q->cell_id)) { + goto clean; + } + } + + q->nof_symbols = PCFICH_RE; + + ret = 0; +clean: + if (ret == -1) { + pcfich_free(q); + } + return ret; +} + +void pcfich_free(pcfich_t *q) { + for (int ns=0;nsseq_pcfich[ns]); + } + modem_table_free(&q->mod); +} + +/** Finds the CFI with minimum distance with the vector of received 32 bits. + * Saves the CFI value in the cfi pointer and returns the distance. + */ +int pcfich_cfi_decode(char bits[PCFICH_CFI_LEN], int *cfi) { + int i, j; + int distance, index=-1; + int min = 32; + + for (i=0;i<3;i++) { + distance = 0; + for (j=0;j 3) { + fprintf(stderr, "Invalid CFI %d\n", cfi); + return -1; + } + memcpy(bits, cfi_table[cfi-1], PCFICH_CFI_LEN * sizeof(char)); + return 0; +} + + +/* Decodes the PCFICH channel and saves the CFI in the cfi pointer. + * + * Returns 1 if successfully decoded the CFI, 0 if not and -1 on error + */ +int pcfich_decode(pcfich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], int nsubframe, int *cfi, int *distance) { + int dist; + + /* Set pointers for layermapping & precoding */ + int i; + cf_t *x[MAX_LAYERS]; + cf_t *ce_precoding[MAX_PORTS]; + cf_t *symbols_precoding[MAX_PORTS]; + + if (nsubframe < 0 || nsubframe > NSUBFRAMES_X_FRAME) { + fprintf(stderr, "Invalid nslot %d\n", nsubframe); + return -1; + } + + /* number of layers equals number of ports */ + for (i=0;ipcfich_x[i]; + } + for (i=0;ice[i]; + symbols_precoding[i] = q->pcfich_symbols[i]; + } + + /* extract symbols */ + if (q->nof_symbols != regs_pcfich_get(q->regs, slot_symbols, q->pcfich_symbols[0])) { + fprintf(stderr, "There was an error getting the PCFICH symbols\n"); + return -1; + } + + /* extract channel estimates */ + for (i=0;inof_tx_ports;i++) { + if (q->nof_symbols != regs_pcfich_get(q->regs, ce[i], q->ce[i])) { + fprintf(stderr, "There was an error getting the PCFICH symbols\n"); + return -1; + } + } + + /* in control channels, only diversity is supported */ + if (q->nof_tx_ports == 1) { + /* no need for layer demapping */ + predecoding_single_zf(q->pcfich_symbols[0], q->ce[0], q->pcfich_d, q->nof_symbols); + } else { + predecoding_diversity_zf(symbols_precoding, ce_precoding, x, q->nof_tx_ports, q->nof_symbols); + layerdemap_diversity(x, q->pcfich_d, q->nof_tx_ports, q->nof_symbols/q->nof_tx_ports); + } + + /* demodulate symbols */ + demod_hard_demodulate(&q->demod, q->pcfich_d, q->data, q->nof_symbols); + + /* Scramble with the sequence for slot nslot */ + scrambling_b(&q->seq_pcfich[nsubframe], q->data); + + /* decode CFI */ + dist = pcfich_cfi_decode(q->data, cfi); + if (distance) { + *distance = dist; + } + if (dist < PCFICH_MAX_DISTANCE) { + return 1; + } else { + return 0; + } +} + + +/** Encodes CFI and maps symbols to the slot + */ +int pcfich_encode(pcfich_t *q, int cfi, cf_t *slot_symbols[MAX_PORTS_CTRL], int nsubframe) { + int i; + + if (nsubframe < 0 || nsubframe > NSUBFRAMES_X_FRAME) { + fprintf(stderr, "Invalid nslot %d\n", nsubframe); + return -1; + } + + /* Set pointers for layermapping & precoding */ + cf_t *x[MAX_LAYERS]; + cf_t *symbols_precoding[MAX_PORTS]; + + /* number of layers equals number of ports */ + for (i=0;inof_tx_ports;i++) { + x[i] = q->pcfich_x[i]; + } + for (i=0;ipcfich_symbols[i]; + } + + /* pack MIB */ + pcfich_cfi_encode(cfi, q->data); + + /* scramble for slot sequence nslot */ + scrambling_b(&q->seq_pcfich[nsubframe], q->data); + + mod_modulate(&q->mod, q->data, q->pcfich_d, PCFICH_CFI_LEN); + + /* layer mapping & precoding */ + if (q->nof_tx_ports > 1) { + layermap_diversity(q->pcfich_d, x, q->nof_tx_ports, q->nof_symbols); + precoding_diversity(x, symbols_precoding, q->nof_tx_ports, q->nof_symbols/q->nof_tx_ports); + } else { + memcpy(q->pcfich_symbols[0], q->pcfich_d, q->nof_symbols * sizeof(cf_t)); + } + + /* mapping to resource elements */ + for (i=0;inof_tx_ports;i++) { + if (regs_pcfich_put(q->regs, q->pcfich_symbols[i], slot_symbols[i]) < 0) { + fprintf(stderr, "Error putting PCHICH resource elements\n"); + return -1; + } + } + + return 0; +} + + diff --git a/lte/lib/phch/src/phich.c b/lte/lib/phch/src/phich.c new file mode 100644 index 000000000..d38c5ea67 --- /dev/null +++ b/lte/lib/phch/src/phich.c @@ -0,0 +1,376 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 +#include +#include +#include +#include +#include +#include +#include + +#include "prb.h" +#include "lte/phch/regs.h" +#include "lte/phch/phich.h" +#include "lte/common/base.h" +#include "lte/utils/bit.h" +#include "lte/utils/vector.h" +#include "lte/utils/debug.h" + +/** Table 6.9.1-2 */ +const cf_t w_normal[PHICH_NORM_NSEQUENCES][4] = { { 1, 1, 1, 1 }, + { 1, -1, 1, -1 }, { 1, 1, -1, -1 }, { 1, -1, -1, 1 }, { I, I, I, I }, { + I, -I, I, -I }, { I, I, -I, -I }, { I, -I, -I, I } }; +const cf_t w_ext[PHICH_EXT_NSEQUENCES][2] = { { 1, 1 }, { 1, -1 }, { I, I }, { +I, -I } }; + +bool phich_exists(int nframe, int nslot) { + return true; +} + +int phich_ngroups(phich_t *q) { + return regs_phich_ngroups(q->regs); +} + +void phich_reset(phich_t *q, cf_t *slot_symbols[MAX_PORTS_CTRL]) { + int i; + for (i=0;iregs, slot_symbols[i]); + } +} + +/** Initializes the phich channel receiver */ +int phich_init(phich_t *q, regs_t *regs, int cell_id, int nof_prb, + int nof_tx_ports, lte_cp_t cp) { + int ret = -1; + bzero(q, sizeof(phich_t)); + q->cp = cp; + q->regs = regs; + q->nof_prb = nof_prb; + q->nof_tx_ports = nof_tx_ports; + + if (modem_table_std(&q->mod, LTE_BPSK, false)) { + goto clean; + } + + demod_hard_init(&q->demod); + demod_hard_table_set(&q->demod, LTE_BPSK); + + for (int nsf = 0; nsf < NSUBFRAMES_X_FRAME; nsf++) { + if (sequence_phich(&q->seq_phich[nsf], 2 * nsf, cell_id)) { + goto clean; + } + } + + ret = 0; + clean: if (ret == -1) { + phich_free(q); + } + return ret; +} + +void phich_free(phich_t *q) { + for (int ns = 0; ns < NSUBFRAMES_X_FRAME; ns++) { + sequence_free(&q->seq_phich[ns]); + } + modem_table_free(&q->mod); +} + +/* Decodes ACK + * + */ +char phich_ack_decode(char bits[PHICH_NBITS], int *distance) { + int i, n; + + n = 0; + for (i = 0; i < PHICH_NBITS; i++) { + n += bits[i]; + } + INFO("PHICH decoder: %d, %d, %d\n", bits[0], bits[1], bits[2]); + if (n >= 2) { + if (distance) { + *distance = 3-n; + } + return 1; + } else { + if (distance) { + *distance = n; + } + return 0; + } +} + +/** Encodes the ACK + * 36.212 + */ +void phich_ack_encode(char ack, char bits[PHICH_NBITS]) { + memset(bits, ack, 3 * sizeof(char)); +} + +/* Decodes the phich channel and saves the CFI in the cfi pointer. + * + * Returns 1 if successfully decoded the CFI, 0 if not and -1 on error + */ +int phich_decode(phich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], + int ngroup, int nseq, int nsubframe, char *ack, int *distance) { + + /* Set pointers for layermapping & precoding */ + int i, j; + cf_t *x[MAX_LAYERS]; + cf_t *ce_precoding[MAX_PORTS]; + cf_t *symbols_precoding[MAX_PORTS]; + + DEBUG("Decoding PHICH Ngroup: %d, Nseq: %d\n", ngroup, nseq); + + if (nsubframe < 0 || nsubframe > NSUBFRAMES_X_FRAME) { + fprintf(stderr, "Invalid nslot %d\n", nsubframe); + return -1; + } + + if (CP_ISEXT(q->cp)) { + if (nseq < 0 || nseq > PHICH_EXT_NSEQUENCES) { + fprintf(stderr, "Invalid nseq %d\n", nseq); + return -1; + } + } else { + if (nseq < 0 || nseq > PHICH_NORM_NSEQUENCES) { + fprintf(stderr, "Invalid nseq %d\n", nseq); + return -1; + } + } + if (ngroup >= regs_phich_ngroups(q->regs)) { + fprintf(stderr, "Invalid ngroup %d\n", ngroup); + return -1; + } + + /* number of layers equals number of ports */ + for (i = 0; i < MAX_PORTS_CTRL; i++) { + x[i] = q->phich_x[i]; + } + for (i = 0; i < MAX_PORTS; i++) { + ce_precoding[i] = q->ce[i]; + symbols_precoding[i] = q->phich_symbols[i]; + } + + /* extract symbols */ + if (PHICH_MAX_NSYMB + != regs_phich_get(q->regs, slot_symbols, q->phich_symbols[0], + ngroup)) { + fprintf(stderr, "There was an error getting the phich symbols\n"); + return -1; + } + + /* extract channel estimates */ + for (i = 0; i < q->nof_tx_ports; i++) { + if (PHICH_MAX_NSYMB + != regs_phich_get(q->regs, ce[i], q->ce[i], ngroup)) { + fprintf(stderr, "There was an error getting the phich symbols\n"); + return -1; + } + } + + /* in control channels, only diversity is supported */ + if (q->nof_tx_ports == 1) { + /* no need for layer demapping */ + predecoding_single_zf(q->phich_symbols[0], q->ce[0], q->phich_d0, + PHICH_MAX_NSYMB); + } else { + predecoding_diversity_zf(symbols_precoding, ce_precoding, x, + q->nof_tx_ports, PHICH_MAX_NSYMB); + layerdemap_diversity(x, q->phich_d0, q->nof_tx_ports, + PHICH_MAX_NSYMB / q->nof_tx_ports); + } + DEBUG("Recv!!: \n",0); + DEBUG("d0: ",0); + if (VERBOSE_ISDEBUG()) vec_fprint_c(stdout, q->phich_d0, PHICH_MAX_NSYMB); + + if (CP_ISEXT(q->cp)) { + if (ngroup % 2) { + for (i = 0; i < PHICH_EXT_MSYMB / 2; i++) { + q->phich_d[2 * i + 0] = q->phich_d0[4 * i + 2]; + q->phich_d[2 * i + 1] = q->phich_d0[4 * i + 3]; + } + } else { + for (i = 0; i < PHICH_EXT_MSYMB / 2; i++) { + q->phich_d[2 * i + 0] = q->phich_d0[4 * i]; + q->phich_d[2 * i + 1] = q->phich_d0[4 * i + 1]; + } + } + } else { + memcpy(q->phich_d, q->phich_d0, PHICH_MAX_NSYMB * sizeof(cf_t)); + } + + DEBUG("d: ",0); + if (VERBOSE_ISDEBUG()) vec_fprint_c(stdout, q->phich_d, PHICH_EXT_MSYMB); + + scrambling_c(&q->seq_phich[nsubframe], q->phich_d); + + /* De-spreading */ + if (CP_ISEXT(q->cp)) { + for (i=0;iphich_z[i] = 0; + for (j=0;jphich_z[i] += conjf(w_ext[nseq][j]) * + q->phich_d[i*PHICH_EXT_NSF+j]/PHICH_EXT_NSF; + } + } + } else { + for (i=0;iphich_z[i] = 0; + for (j=0;jphich_z[i] += conjf(w_normal[nseq][j]) * + q->phich_d[i*PHICH_NORM_NSF+j]/PHICH_NORM_NSF; + } + } + } + + DEBUG("z: ",0); + if (VERBOSE_ISDEBUG()) vec_fprint_c(stdout, q->phich_z, PHICH_NBITS); + + demod_hard_demodulate(&q->demod, q->phich_z, q->data, PHICH_NBITS); + + if (ack) { + *ack = phich_ack_decode(q->data, distance); + } + + return 0; +} + +/** Encodes ACK/NACK bits, modulates and inserts into resource. + * The parameter ack is an array of phich_ngroups() pointers to buffers of nof_sequences chars + */ +int phich_encode(phich_t *q, char ack, int ngroup, int nseq, int nsubframe, + cf_t *slot_symbols[MAX_PORTS_CTRL]) { + int i; + + if (nsubframe < 0 || nsubframe > NSUBFRAMES_X_FRAME) { + fprintf(stderr, "Invalid nslot %d\n", nsubframe); + return -1; + } + + if (CP_ISEXT(q->cp)) { + if (nseq < 0 || nseq > PHICH_EXT_NSEQUENCES) { + fprintf(stderr, "Invalid nseq %d\n", nseq); + return -1; + } + } else { + if (nseq < 0 || nseq > PHICH_NORM_NSEQUENCES) { + fprintf(stderr, "Invalid nseq %d\n", nseq); + return -1; + } + } + if (ngroup >= regs_phich_ngroups(q->regs)) { + fprintf(stderr, "Invalid ngroup %d\n", ngroup); + return -1; + } + + /* Set pointers for layermapping & precoding */ + cf_t *x[MAX_LAYERS]; + cf_t *symbols_precoding[MAX_PORTS]; + + /* number of layers equals number of ports */ + for (i = 0; i < q->nof_tx_ports; i++) { + x[i] = q->phich_x[i]; + } + for (i = 0; i < MAX_PORTS; i++) { + symbols_precoding[i] = q->phich_symbols[i]; + } + + /* encode ACK/NACK bit */ + phich_ack_encode(ack, q->data); + + mod_modulate(&q->mod, q->data, q->phich_z, PHICH_NBITS); + + DEBUG("data: ",0); + if (VERBOSE_ISDEBUG()) vec_fprint_c(stdout, q->phich_z, PHICH_NBITS); + + /* Spread with w */ + if (CP_ISEXT(q->cp)) { + for (i = 0; i < PHICH_EXT_MSYMB; i++) { + q->phich_d[i] = w_ext[nseq][i % PHICH_EXT_NSF] + * q->phich_z[i / PHICH_EXT_NSF]; + } + } else { + for (i = 0; i < PHICH_NORM_MSYMB; i++) { + q->phich_d[i] = w_normal[nseq][i % PHICH_NORM_NSF] + * q->phich_z[i / PHICH_NORM_NSF]; + } + } + + DEBUG("d: ",0); + if (VERBOSE_ISDEBUG()) vec_fprint_c(stdout, q->phich_d, PHICH_EXT_MSYMB); + + scrambling_c(&q->seq_phich[nsubframe], q->phich_d); + + /* align to REG */ + if (CP_ISEXT(q->cp)) { + if (ngroup % 2) { + for (i = 0; i < PHICH_EXT_MSYMB / 2; i++) { + q->phich_d0[4 * i + 0] = 0; + q->phich_d0[4 * i + 1] = 0; + q->phich_d0[4 * i + 2] = q->phich_d[2 * i]; + q->phich_d0[4 * i + 3] = q->phich_d[2 * i + 1]; + } + } else { + for (i = 0; i < PHICH_EXT_MSYMB / 2; i++) { + q->phich_d0[4 * i + 0] = q->phich_d[2 * i]; + q->phich_d0[4 * i + 1] = q->phich_d[2 * i + 1]; + q->phich_d0[4 * i + 2] = 0; + q->phich_d0[4 * i + 3] = 0; + } + } + } else { + memcpy(q->phich_d0, q->phich_d, PHICH_MAX_NSYMB * sizeof(cf_t)); + } + + DEBUG("d0: ",0); + if (VERBOSE_ISDEBUG()) vec_fprint_c(stdout, q->phich_d0, PHICH_MAX_NSYMB); + + + /* layer mapping & precoding */ + if (q->nof_tx_ports > 1) { + layermap_diversity(q->phich_d0, x, q->nof_tx_ports, PHICH_MAX_NSYMB); + precoding_diversity(x, symbols_precoding, q->nof_tx_ports, + PHICH_MAX_NSYMB / q->nof_tx_ports); + /**FIXME: According to 6.9.2, Precoding for 4 tx ports is different! */ + } else { + memcpy(q->phich_symbols[0], q->phich_d0, PHICH_MAX_NSYMB * sizeof(cf_t)); + } + + /* mapping to resource elements */ + for (i = 0; i < q->nof_tx_ports; i++) { + if (regs_phich_add(q->regs, q->phich_symbols[i], ngroup, + slot_symbols[i]) < 0) { + fprintf(stderr, "Error putting PCHICH resource elements\n"); + return -1; + } + } + + return 0; +} + diff --git a/lib/phch/src/common.c b/lte/lib/phch/src/prb.c similarity index 50% rename from lib/phch/src/common.c rename to lte/lib/phch/src/prb.c index 0791b46f5..bf3651867 100644 --- a/lib/phch/src/common.c +++ b/lte/lib/phch/src/prb.c @@ -1,28 +1,38 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * \section COPYRIGHT * - * OSLD-lib is distributed in the hope that it will be useful, + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 #include -#include "common.h" -#include "lte/base.h" +#include "prb.h" +#include "lte/common/base.h" -void phch_cp_prb_ref(cf_t **input, cf_t **output, int offset, int nof_refs, +void prb_cp_ref(cf_t **input, cf_t **output, int offset, int nof_refs, int nof_prb, bool advance_output) { int i; @@ -52,19 +62,19 @@ void phch_cp_prb_ref(cf_t **input, cf_t **output, int offset, int nof_refs, } } -void phch_cp_prb(cf_t **input, cf_t **output, int nof_prb) { +void prb_cp(cf_t **input, cf_t **output, int nof_prb) { memcpy(*output, *input, sizeof(cf_t) * RE_X_RB * nof_prb); *input += nof_prb * RE_X_RB; *output += nof_prb * RE_X_RB; } -void phch_put_prb_ref_(cf_t **input, cf_t **output, int offset, int nof_refs, +void prb_put_ref_(cf_t **input, cf_t **output, int offset, int nof_refs, int nof_prb) { - phch_cp_prb_ref(input, output, offset, nof_refs, nof_prb, false); + prb_cp_ref(input, output, offset, nof_refs, nof_prb, false); } -void phch_get_prb_ref(cf_t **input, cf_t **output, int offset, int nof_refs, +void prb_get_ref_(cf_t **input, cf_t **output, int offset, int nof_refs, int nof_prb) { - phch_cp_prb_ref(input, output, offset, nof_refs, nof_prb, true); + prb_cp_ref(input, output, offset, nof_refs, nof_prb, true); } diff --git a/lte/lib/phch/src/prb.h b/lte/lib/phch/src/prb.h new file mode 100644 index 000000000..4adf29389 --- /dev/null +++ b/lte/lib/phch/src/prb.h @@ -0,0 +1,37 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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/. + * + */ + + +typedef _Complex float cf_t; + +void prb_cp_ref(cf_t **input, cf_t **output, int offset, int nof_refs, + int nof_prb, bool advance_input); +void prb_cp(cf_t **input, cf_t **output, int nof_prb); +void prb_put_ref_(cf_t **input, cf_t **output, int offset, int nof_refs, + int nof_prb); +void phch_get_prb_ref(cf_t **input, cf_t **output, int offset, int nof_refs, + int nof_prb); diff --git a/lte/lib/phch/src/regs.c b/lte/lib/phch/src/regs.c new file mode 100644 index 000000000..9d38f4549 --- /dev/null +++ b/lte/lib/phch/src/regs.c @@ -0,0 +1,625 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 +#include +#include +#include + +#include "lte/common/base.h" +#include "lte/phch/regs.h" +#include "lte/utils/debug.h" + +regs_reg_t *regs_find_reg(regs_t *h, int k, int l); + + + + +/*************************************************************** + * + * PDCCH REG ALLOCATION + * + ***************************************************************/ + +/** Initialize REGs for PDCCH + * 36.211 10.3 section 6.8.5 + */ +int regs_pdcch_init(regs_t *h) { + return 0; +} + +void regs_pdcch_free(regs_t *h) { + if (h->pdcch) { + free(h->pdcch); + } +} + + + + + +/*************************************************************** + * + * PHICH REG ALLOCATION + * + ***************************************************************/ + +/** Initialize REGs for PHICH + * 36.211 10.3 section 6.9.3 + */ +int regs_phich_init(regs_t *h) { + float ng; + int i,ni,li,n[3],nreg,mi; + regs_reg_t **regs_phich[3]; + int ret = -1; + + switch(h->phich_res) { + case R_1_6: + ng = (float) 1/6; + break; + case R_1_2: + ng = (float) 1/2; + break; + case R_1: + ng = 1; + break; + case R_2: + ng = 2; + break; + } + h->ngroups_phich = (int) ceilf(ng * ((float) h->nof_prb/8)); + h->phich = malloc(sizeof(regs_ch_t) * h->ngroups_phich); + if (!h->phich) { + perror("malloc"); + return -1; + } + INFO("Creating %d PHICH mapping units. %s length, Ng=%.2f\n",h->ngroups_phich, + h->phich_len==PHICH_EXT?"Extended":"Normal",ng); + for (i=0;ingroups_phich;i++) { + h->phich[i].nof_regs = REGS_PHICH_REGS_X_GROUP; + h->phich[i].regs = malloc(sizeof(regs_reg_t*) * REGS_PHICH_REGS_X_GROUP); + if (!h->phich[i].regs) { + perror("malloc"); + goto clean_and_exit; + } + } + + /** Here begins the mapping algorithm */ + + /* Step 2. Count REGs not assigned to PCFICH */ + bzero(n, 3*sizeof(int)); + for (i=0;inof_regs;i++) { + if (h->regs[i].l < 3 && !h->regs[i].assigned) { + n[h->regs[i].l]++; + } + } + + bzero(regs_phich, sizeof(regs_reg_t*) * 3); + for (i=0;i<3;i++) { + regs_phich[i] = malloc(n[i] * sizeof(regs_reg_t*)); + if (!regs_phich[i]) { + perror("malloc"); + goto clean_and_exit; + } + } + + bzero(n, 3 * sizeof(int)); + /* Step 3. Number REGs not assigned to PCFICH */ + for (i=0;inof_regs;i++) { + // they are already sorted starting from the REG with the lowest frequency-domain index + if (h->regs[i].l < 3 && !h->regs[i].assigned) { + regs_phich[h->regs[i].l][n[h->regs[i].l]++] = &h->regs[i]; + } + } + + nreg=0; + for (mi=0;mingroups_phich;mi++) { // here ngroups is the number of mapping units + for (i=0;i<3;i++) { + li=h->phich_len==PHICH_EXT?i:0; // Step 7 + ni=((h->cell_id*n[li]/n[0])+mi+i*n[li]/3) % n[li]; // Step 8 + h->phich[mi].regs[i] = regs_phich[li][ni]; + h->phich[mi].regs[i]->assigned = true; + INFO("Assigned PHICH REG#%d (%d,%d)\n",nreg,h->phich[mi].regs[i]->k0,li); + nreg++; + } + } + + // now the number of mapping units = number of groups for normal cp. For extended cp + // ngroups = 2 * number mapping units + if (CP_ISEXT(h->cp)) { + h->ngroups_phich *= 2; + } + ret = 0; + +clean_and_exit: + if (ret == -1) { + if (h->phich) { + for (i=0;ingroups_phich;i++) { + if (h->phich[i].regs) { + free(h->phich[i].regs); + } + } + free(h->phich); + } + } + for (i=0;i<3;i++) { + if (regs_phich[i]) { + free(regs_phich[i]); + } + } + return ret; +} + +void regs_phich_free(regs_t *h) { + int i; + if (h->phich) { + if (CP_ISEXT(h->cp)) { + h->ngroups_phich /= 2; + } + for (i=0;ingroups_phich;i++) { + if (h->phich[i].regs) { + free(h->phich[i].regs); + } + } + free(h->phich); + } +} + +int regs_phich_ngroups(regs_t *h) { + return h->ngroups_phich; +} + +/** + * Adds the PHICH symbols to the resource grid pointed by slot_symbols. + * + * Each subframe, the user shall call the regs_phich_reset function before adding PHICH symbols. + * + * Returns the number of written symbols, or -1 on error + */ +int regs_phich_add(regs_t *h, cf_t phich_symbols[REGS_PHICH_NSYM], int ngroup, cf_t *slot_symbols) { + int i; + if (ngroup < 0 || ngroup > h->ngroups_phich) { + fprintf(stderr, "Error invalid ngroup %d\n", ngroup); + return -1; + } + if (CP_ISEXT(h->cp)) { + ngroup /= 2; + } + regs_ch_t *rch = &h->phich[ngroup]; + for (i = 0; i < rch->nof_regs && i*REGS_RE_X_REG < REGS_PHICH_NSYM; i++) { + regs_add_reg(rch->regs[i], &phich_symbols[i*REGS_RE_X_REG], slot_symbols, h->nof_prb); + } + return i*REGS_RE_X_REG; +} + +/** + * Resets the PHICH symbols + * + * Returns the number of written symbols, or -1 on error + */ +int regs_phich_reset(regs_t *h, cf_t *slot_symbols) { + int i; + int ngroup, ng; + for (ngroup = 0;ngroup < h->ngroups_phich;CP_ISEXT(h->cp)?ngroup+=2:ngroup++) { + if (CP_ISEXT(h->cp)) { + ng = ngroup/2; + } else { + ng = ngroup; + } + regs_ch_t *rch = &h->phich[ng]; + for (i = 0; i < rch->nof_regs && i*REGS_RE_X_REG < REGS_PHICH_NSYM; i++) { + regs_reset_reg(rch->regs[i], slot_symbols, h->nof_prb); + } + } + return 0; +} + +/** + * Gets the PHICH symbols from the resource grid pointed by slot_symbols + * + * Returns the number of written symbols, or -1 on error + */ +int regs_phich_get(regs_t *h, cf_t *slot_symbols, cf_t phich_symbols[REGS_PHICH_NSYM], int ngroup) { + int i; + if (ngroup < 0 || ngroup > h->ngroups_phich) { + fprintf(stderr, "Error invalid ngroup %d\n", ngroup); + return -1; + } + if (CP_ISEXT(h->cp)) { + ngroup /= 2; + } + regs_ch_t *rch = &h->phich[ngroup]; + for (i = 0; i < rch->nof_regs && i*REGS_RE_X_REG < REGS_PHICH_NSYM; i++) { + regs_get_reg(rch->regs[i], slot_symbols, &phich_symbols[i*REGS_RE_X_REG], h->nof_prb); + } + return i*REGS_RE_X_REG; +} + + + + + + + + + + + + + + +/*************************************************************** + * + * PCFICH REG ALLOCATION + * + ***************************************************************/ + + +/** Initialize REGs for PCFICH + * 36.211 10.3 section 6.7.4 + */ +int regs_pcfich_init(regs_t *h) { + int i, k_hat, k; + regs_ch_t *ch = &h->pcfich; + + ch->regs = malloc(sizeof(regs_reg_t*) * REGS_PCFICH_NREGS); + if (!ch->regs) { + perror("malloc"); + return -1; + } + ch->nof_regs = REGS_PCFICH_NREGS; + + INFO("PCFICH allocating %d regs. CellID: %d, PRB: %d\n", ch->nof_regs, h->cell_id, h->nof_prb); + + k_hat = (RE_X_RB / 2) * (h->cell_id % (2 * h->nof_prb)); + for (i = 0; i < REGS_PCFICH_NREGS; i++) { + + k = (k_hat + (i * h->nof_prb / 2) * (RE_X_RB / 2)) + % (h->nof_prb * RE_X_RB); + ch->regs[i] = regs_find_reg(h, k, 0); + if (!ch->regs[i]) { + fprintf(stderr, "Error allocating PCFICH: REG (%d,0) not found\n", + k); + return -1; + } else if (ch->regs[i]->assigned) { + fprintf(stderr, + "Error allocating PCFICH: REG (%d,0) already allocated\n", + k); + return -1; + } else { + ch->regs[i]->assigned = true; + INFO("Assigned PCFICH REG#%d (%d,0)\n", i, k); + } + } + return 0; +} + +void regs_pcfich_free(regs_t *h) { + if (h->pcfich.regs) { + free(h->pcfich.regs); + } +} + +/** + * Maps the PCFICH symbols to the resource grid pointed by slot_symbols + * + * Returns the number of written symbols, or -1 on error + */ +int regs_pcfich_put(regs_t *h, cf_t pcfich_symbols[REGS_PCFICH_NSYM], cf_t *slot_symbols) { + regs_ch_t *rch = &h->pcfich; + + int i; + for (i = 0; i < rch->nof_regs && i*REGS_RE_X_REG < REGS_PCFICH_NSYM; i++) { + regs_put_reg(rch->regs[i], &pcfich_symbols[i*REGS_RE_X_REG], slot_symbols, h->nof_prb); + } + return i*REGS_RE_X_REG; +} + +/** + * Gets the PCFICH symbols from the resource grid pointed by slot_symbols + * + * Returns the number of written symbols, or -1 on error + */ +int regs_pcfich_get(regs_t *h, cf_t *slot_symbols, cf_t ch_data[REGS_PCFICH_NSYM]) { + regs_ch_t *rch = &h->pcfich; + int i; + for (i = 0; i < rch->nof_regs && i*REGS_RE_X_REG < REGS_PCFICH_NSYM; i++) { + regs_get_reg(rch->regs[i], slot_symbols, &ch_data[i*REGS_RE_X_REG], h->nof_prb); + } + return i*REGS_RE_X_REG; +} + + + + + + + + + + + + + + +/*************************************************************** + * + * COMMON FUNCTIONS + * + ***************************************************************/ + +regs_reg_t *regs_find_reg(regs_t *h, int k, int l) { + int i; + for (i=0;inof_regs;i++) { + if (h->regs[i].l == l && h->regs[i].k0 == k) { + return &h->regs[i]; + } + } + return NULL; +} + +/** + * Returns the number of REGs in a PRB + * 36.211 Section 6.2.4 + */ +int regs_num_x_symbol(int symbol, int refs_in_symbol1, lte_cp_t cp) { + + switch (symbol) { + case 0: + return 2; + case 1: + switch (refs_in_symbol1) { + case 1: + case 2: + return 3; + case 4: + return 2; + default: + return -1; + } + break; + case 2: + return 3; + case 3: + if (CP_ISNORM(cp)) { + return 3; + } else { + return 2; + } + default: + return -1; + } +} + +/** + * Initializes the indices of a REG + * 36.211 Section 6.2.4 + */ +int regs_reg_init(regs_reg_t *reg, int symbol, int nreg, int k0, int maxreg, int vo) { + int i, j, z; + + reg->l = symbol; + reg->assigned = false; + reg->k0 = k0 + nreg * 6; + + switch (maxreg) { + case 2: + /* there are two references in the middle */ + j = z = 0; + for (i = 0; i < vo; i++) { + reg->k[j] = k0 + nreg * 6 + i; + j++; + } + for (i = 0; i < 2; i++) { + reg->k[j] = k0 + nreg * 6 + i + vo + 1; + j++; + } + z = j; + for (i = 0; i < 4 - z; i++) { + reg->k[j] = k0 + nreg * 6 + vo + 3 + i + 1; + j++; + } + if (j != 4) { + fprintf(stderr, "Something went wrong: expected 2 references\n"); + return -1; + } + break; + + case 3: + /* there is no reference */ + for (i = 0; i < 4; i++) { + reg->k[i] = k0 + nreg * 4 + i; + } + break; + default: + fprintf(stderr, "Invalid number of REGs per PRB: %d\n", maxreg); + return -1; + } + return 0; +} + +void regs_free(regs_t *h) { + if (h->regs) { + free(h->regs); + } + regs_pcfich_free(h); + regs_phich_free(h); + regs_pdcch_free(h); + + bzero(h, sizeof(regs_t)); +} + +/** + * Initializes REGs structure. + * Sets all REG indices and initializes PCFICH, PHICH and PDCCH REGs + * Returns 0 if OK, -1 on error + */ +int regs_init(regs_t *h, int cell_id, int nof_prb, int refs_in_symbol1, + phich_resources_t phich_res, phich_length_t phich_len, lte_cp_t cp) { + int ret = -1; + int i, j, n, p, k; + int vo = cell_id % 3; + int max_ctrl_symbols = nof_prb<10?4:3; + + bzero(h, sizeof(regs_t)); + + h->cell_id = cell_id; + h->nof_prb = nof_prb; + h->max_ctrl_symbols = max_ctrl_symbols; + h->phich_res = phich_res; + h->phich_len = phich_len; + h->cp = cp; + h->refs_in_symbol1 = refs_in_symbol1; + + h->nof_regs = 0; + for (i = 0; i < max_ctrl_symbols; i++) { + n = regs_num_x_symbol(i, refs_in_symbol1, cp); + if (n == -1) { + return -1; + } + h->nof_regs += nof_prb * n; + } + INFO("Indexing %d REGs. CellId: %d, %d PRB, CP: %s\n", h->nof_regs, h->cell_id, h->nof_prb, + CP_ISNORM(cp)?"Normal":"Extended"); + h->regs = malloc(sizeof(regs_reg_t) * h->nof_regs); + if (!h->regs) { + perror("malloc"); + goto clean_and_exit; + } + + k = 0; + for (i = 0; i < max_ctrl_symbols; i++) { + n = regs_num_x_symbol(i, refs_in_symbol1, cp); + for (p = 0; p < nof_prb; p++) { + for (j = 0; j < n; j++) { + if (regs_reg_init(&h->regs[k], i, j, p * RE_X_RB, n, vo)) { + fprintf(stderr, "Error initializing REGs\n"); + goto clean_and_exit; + } + DEBUG("Available REG #%3d: %d:%d:%d (k0=%d)\n", k, i, p, j, + h->regs[k].k0); + k++; + } + } + } + + if (regs_pcfich_init(h)) { + fprintf(stderr, "Error initializing PCFICH REGs\n"); + goto clean_and_exit; + } + if (regs_phich_init(h)) { + fprintf(stderr, "Error initializing PHICH REGs\n"); + goto clean_and_exit; + } + if (regs_pdcch_init(h)) { + fprintf(stderr, "Error initializing PDCCH REGs\n"); + goto clean_and_exit; + } + + ret = 0; + + clean_and_exit: if (ret == -1) { + regs_free(h); + } + return ret; +} + +#define REG_IDX(r, i, n) r->k[i]+r->l*n*RE_X_RB + +/** + * Puts one REG data (4 symbols) in the slot symbols array + */ +int regs_put_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_prb) { + int i; + for (i = 0; i < REGS_RE_X_REG; i++) { + if (reg->assigned) { + DEBUG("PUT REG: i=%d, (k=%d,l=%d)\n", i, REG_IDX(reg, i, nof_prb),reg->l); + slot_symbols[REG_IDX(reg, i, nof_prb)] = reg_data[i]; + } else { + fprintf(stderr, "Error REG not assigned\n"); + return -1; + } + } + return REGS_RE_X_REG; +} + +/** + * Adds one REG data (4 symbols) in the slot symbols array + * Used by PHICH + */ +int regs_add_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_prb) { + int i; + for (i = 0; i < REGS_RE_X_REG; i++) { + if (reg->assigned) { + slot_symbols[REG_IDX(reg, i, nof_prb)] += reg_data[i]; + DEBUG("ADD REG: i=%d, (k=%d,l=%d): %.1f+%.1fi\n", i, REG_IDX(reg, i, nof_prb),reg->l, + __real__ slot_symbols[REG_IDX(reg, i, nof_prb)], + __imag__ slot_symbols[REG_IDX(reg, i, nof_prb)]); + } else { + fprintf(stderr, "Error REG not assigned\n"); + return -1; + } + } + return REGS_RE_X_REG; +} + + +/** + * Reset REG data (4 symbols) in the slot symbols array + */ +int regs_reset_reg(regs_reg_t *reg, cf_t *slot_symbols, int nof_prb) { + int i; + for (i = 0; i < REGS_RE_X_REG; i++) { + if (reg->assigned) { + DEBUG("RESET REG: i=%d, (k=%d,l=%d)\n", i, REG_IDX(reg, i, nof_prb),reg->l); + slot_symbols[REG_IDX(reg, i, nof_prb)] = 0; + } else { + fprintf(stderr, "Error REG not assigned\n"); + return -1; + } + } + return REGS_RE_X_REG; +} + +/** + * Gets one REG data (4 symbols) from the slot symbols array + */ +int regs_get_reg(regs_reg_t *reg, cf_t *slot_symbols, cf_t *reg_data, int nof_prb) { + int i; + for (i = 0; i < REGS_RE_X_REG; i++) { + if (reg->assigned) { + reg_data[i] = slot_symbols[REG_IDX(reg, i, nof_prb)]; + DEBUG("GET REG: i=%d, (k=%d,l=%d): %.1f+%.1fi\n", i, REG_IDX(reg, i, nof_prb),reg->l, + __real__ reg_data[i], __imag__ reg_data[i]); + } else { + fprintf(stderr, "Error REG not assigned\n"); + return -1; + } + } + return REGS_RE_X_REG; +} + diff --git a/lte/lib/phch/src/sequences.c b/lte/lib/phch/src/sequences.c new file mode 100644 index 000000000..566d2c589 --- /dev/null +++ b/lte/lib/phch/src/sequences.c @@ -0,0 +1,56 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 +#include "lte/common/base.h" +#include "lte/common/sequence.h" + +/** + * 36.211 6.6.1 + */ +int sequence_pbch(sequence_t *seq, lte_cp_t cp, int cell_id) { + bzero(seq, sizeof(sequence_t)); + return sequence_LTEPRS(seq, CP_ISNORM(cp)?1920:1728, cell_id); +} + +/** + * 36.211 6.7.1 + */ +int sequence_pcfich(sequence_t *seq, int nslot, int cell_id) { + bzero(seq, sizeof(sequence_t)); + return sequence_LTEPRS(seq, 32, (nslot/2+1) * (2*cell_id + 1) * 512 + cell_id); +} + + +/** + * 36.211 6.9.1 + */ +int sequence_phich(sequence_t *seq, int nslot, int cell_id) { + bzero(seq, sizeof(sequence_t)); + return sequence_LTEPRS(seq, 12, (nslot/2+1) * (2*cell_id + 1) * 512 + cell_id); +} diff --git a/lte/lib/phch/test/CMakeLists.txt b/lte/lib/phch/test/CMakeLists.txt new file mode 100644 index 000000000..e7f3a8fd5 --- /dev/null +++ b/lte/lib/phch/test/CMakeLists.txt @@ -0,0 +1,84 @@ +# +# Copyright 2012-2013 The libLTE Developers. See the +# COPYRIGHT file at the top-level directory of this distribution. +# +# This file is part of the libLTE library. +# +# libLTE is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# libLTE is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# A copy of the GNU Lesser 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/. +# + +######################################################################## +# PBCH TEST +######################################################################## + +ADD_EXECUTABLE(pbch_test pbch_test.c) +TARGET_LINK_LIBRARIES(pbch_test lte) + +ADD_TEST(pbch_test_6 pbch_test -p 1 -n 6 -c 100) +ADD_TEST(pbch_test_62 pbch_test -p 2 -n 6 -c 100) +ADD_TEST(pbch_test_64 pbch_test -p 4 -n 6 -c 100) +ADD_TEST(pbch_test_50 pbch_test -p 1 -n 50 -c 50) +ADD_TEST(pbch_test_502 pbch_test -p 2 -n 50 -c 50) +ADD_TEST(pbch_test_504 pbch_test -p 4 -n 50 -c 50) + + +######################################################################## +# PCFICH TEST +######################################################################## + +ADD_EXECUTABLE(pcfich_test pcfich_test.c) +TARGET_LINK_LIBRARIES(pcfich_test lte) + +ADD_TEST(pcfich_test_6 pcfich_test -p 1 -n 6) +ADD_TEST(pcfich_test_62 pcfich_test -p 2 -n 6) +ADD_TEST(pcfich_test_64 pcfich_test -p 4 -n 6) +ADD_TEST(pcfich_test_10 pcfich_test -p 1 -n 10) +ADD_TEST(pcfich_test_102 pcfich_test -p 2 -n 10) +ADD_TEST(pcfich_test_104 pcfich_test -p 4 -n 10) + +######################################################################## +# PHICH TEST +######################################################################## + +ADD_EXECUTABLE(phich_test phich_test.c) +TARGET_LINK_LIBRARIES(phich_test lte) + +ADD_TEST(phich_test_6 phich_test -p 1 -n 6) +ADD_TEST(phich_test_62 phich_test -p 2 -n 6) +ADD_TEST(phich_test_64 phich_test -p 4 -n 6 -g 1/6) + +ADD_TEST(phich_test_6e phich_test -p 1 -n 6 -e) +ADD_TEST(phich_test_62e phich_test -p 2 -n 6 -e -l) +ADD_TEST(phich_test_64e phich_test -p 4 -n 6 -e -l -g 2) + +ADD_TEST(phich_test_10 phich_test -p 1 -n 10 -e) +ADD_TEST(phich_test_102 phich_test -p 2 -n 10 -g 2) +ADD_TEST(phich_test_104 phich_test -p 4 -n 10 -e -l -g 1/2) + + + +######################################################################## +# FILE TEST +######################################################################## + +ADD_EXECUTABLE(pbch_file_test pbch_file_test.c) +TARGET_LINK_LIBRARIES(pbch_file_test lte) + +ADD_EXECUTABLE(pcfich_file_test pcfich_file_test.c) +TARGET_LINK_LIBRARIES(pcfich_file_test lte) + +ADD_TEST(pbch_file_test pbch_file_test -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.1.92M.dat) +ADD_TEST(pcfich_file_test pcfich_file_test -c 150 -n 50 -p 2 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.10M.dat) + \ No newline at end of file diff --git a/lte/lib/phch/test/pbch_file_test.c b/lte/lib/phch/test/pbch_file_test.c new file mode 100644 index 000000000..bc03a0b34 --- /dev/null +++ b/lte/lib/phch/test/pbch_file_test.c @@ -0,0 +1,234 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 +#include +#include +#include +#include + +#include "lte.h" + +char *input_file_name = NULL; +char *matlab_file_name = NULL; +int cell_id = 150; +lte_cp_t cp = CPNORM; +int nof_prb = 6; + +FILE *fmatlab = NULL; + +#define NOF_PORTS 2 +#define FLEN 9600 + +filesource_t fsrc; +cf_t *input_buffer, *fft_buffer, *ce[MAX_PORTS_CTRL]; +pbch_t pbch; +lte_fft_t fft; +chest_t chest; + +void usage(char *prog) { + printf("Usage: %s [vcoe] -i input_file\n", prog); + printf("\t-o output matlab file name [Default Disabled]\n"); + printf("\t-c cell_id [Default %d]\n", cell_id); + printf("\t-e Set extended prefix [Default Normal]\n"); + printf("\t-v [set verbose to debug, default none]\n"); +} + +void parse_args(int argc, char **argv) { + int opt; + while ((opt = getopt(argc, argv, "iovce")) != -1) { + switch(opt) { + case 'i': + input_file_name = argv[optind]; + break; + case 'c': + cell_id = atoi(argv[optind]); + break; + case 'o': + matlab_file_name = argv[optind]; + break; + case 'v': + verbose++; + break; + case 'e': + cp = CPEXT; + break; + default: + usage(argv[0]); + exit(-1); + } + } + if (!input_file_name) { + usage(argv[0]); + exit(-1); + } +} + +int base_init() { + int i; + + if (filesource_init(&fsrc, input_file_name, COMPLEX_FLOAT_BIN)) { + fprintf(stderr, "Error opening file %s\n", input_file_name); + exit(-1); + } + + if (matlab_file_name) { + fmatlab = fopen(matlab_file_name, "w"); + if (!fmatlab) { + perror("fopen"); + return -1; + } + } else { + fmatlab = NULL; + } + + input_buffer = malloc(FLEN * sizeof(cf_t)); + if (!input_buffer) { + perror("malloc"); + exit(-1); + } + + fft_buffer = malloc(CP_NSYMB(cp) * nof_prb * RE_X_RB * sizeof(cf_t)); + if (!fft_buffer) { + perror("malloc"); + return -1; + } + + for (i=0;i +#include +#include +#include +#include + +#include "lte.h" + +int cell_id = 1; +int nof_prb = 6; +int nof_ports = 1; + + +void usage(char *prog) { + printf("Usage: %s [cpv]\n", prog); + printf("\t-c cell id [Default %d]\n", cell_id); + printf("\t-p nof_ports [Default %d]\n", nof_ports); + printf("\t-n nof_prb [Default %d]\n", nof_prb); + printf("\t-v [set verbose to debug, default none]\n"); +} + +void parse_args(int argc, char **argv) { + int opt; + while ((opt = getopt(argc, argv, "cpnv")) != -1) { + switch(opt) { + case 'p': + nof_ports = atoi(argv[optind]); + break; + case 'n': + nof_prb = atoi(argv[optind]); + break; + case 'c': + cell_id = atoi(argv[optind]); + break; + case 'v': + verbose++; + break; + default: + usage(argv[0]); + exit(-1); + } + } +} + + +int main(int argc, char **argv) { + pbch_t pbch; + pbch_mib_t mib_tx, mib_rx; + int i, j; + cf_t *ce[MAX_PORTS_CTRL]; + int nof_re; + cf_t *slot1_symbols[MAX_PORTS_CTRL]; + + parse_args(argc,argv); + + nof_re = CPNORM_NSYMB * nof_prb * RE_X_RB; + + /* init memory */ + for (i=0;i +#include +#include +#include +#include + +#include "lte.h" + +char *input_file_name = NULL; +char *matlab_file_name = NULL; +int cell_id = 0; +lte_cp_t cp = CPNORM; +int nof_prb = 6; +int nof_ports = 1; +int flen; + +FILE *fmatlab = NULL; + +filesource_t fsrc; +cf_t *input_buffer, *fft_buffer, *ce[MAX_PORTS_CTRL]; +pcfich_t pcfich; +regs_t regs; +lte_fft_t fft; +chest_t chest; + +void usage(char *prog) { + printf("Usage: %s [vcoe] -i input_file\n", prog); + printf("\t-o output matlab file name [Default Disabled]\n"); + printf("\t-c cell_id [Default %d]\n", cell_id); + printf("\t-p nof_ports [Default %d]\n", nof_ports); + printf("\t-n nof_prb [Default %d]\n", nof_prb); + printf("\t-e Set extended prefix [Default Normal]\n"); + printf("\t-v [set verbose to debug, default none]\n"); +} + +void parse_args(int argc, char **argv) { + int opt; + while ((opt = getopt(argc, argv, "iovcenp")) != -1) { + switch(opt) { + case 'i': + input_file_name = argv[optind]; + break; + case 'c': + cell_id = atoi(argv[optind]); + break; + case 'n': + nof_prb = atoi(argv[optind]); + break; + case 'p': + nof_ports = atoi(argv[optind]); + break; + case 'o': + matlab_file_name = argv[optind]; + break; + case 'v': + verbose++; + break; + case 'e': + cp = CPEXT; + break; + default: + usage(argv[0]); + exit(-1); + } + } + if (!input_file_name) { + usage(argv[0]); + exit(-1); + } +} + +int base_init() { + int i; + + if (filesource_init(&fsrc, input_file_name, COMPLEX_FLOAT_BIN)) { + fprintf(stderr, "Error opening file %s\n", input_file_name); + exit(-1); + } + + if (matlab_file_name) { + fmatlab = fopen(matlab_file_name, "w"); + if (!fmatlab) { + perror("fopen"); + return -1; + } + } else { + fmatlab = NULL; + } + + flen = SLOT_LEN(lte_symbol_sz(nof_prb), cp); + + input_buffer = malloc(flen * sizeof(cf_t)); + if (!input_buffer) { + perror("malloc"); + exit(-1); + } + + fft_buffer = malloc(CP_NSYMB(cp) * nof_prb * RE_X_RB * sizeof(cf_t)); + if (!fft_buffer) { + perror("malloc"); + return -1; + } + + for (i=0;i +#include +#include +#include +#include + +#include "lte.h" + +int cell_id = -1; +int nof_prb = 6; +int nof_ports = 1; + +void usage(char *prog) { + printf("Usage: %s [cpv]\n", prog); + printf("\t-c cell id [Default %d]\n", cell_id); + printf("\t-p nof_ports [Default %d]\n", nof_ports); + printf("\t-n nof_prb [Default %d]\n", nof_prb); + printf("\t-v [set verbose to debug, default none]\n"); +} + +void parse_args(int argc, char **argv) { + int opt; + while ((opt = getopt(argc, argv, "cpnv")) != -1) { + switch(opt) { + case 'p': + nof_ports = atoi(argv[optind]); + break; + case 'n': + nof_prb = atoi(argv[optind]); + break; + case 'c': + cell_id = atoi(argv[optind]); + break; + case 'v': + verbose++; + break; + default: + usage(argv[0]); + exit(-1); + } + } +} + + +int main(int argc, char **argv) { + pcfich_t pcfich; + regs_t regs; + int i, j; + cf_t *ce[MAX_PORTS_CTRL]; + int nof_re; + cf_t *slot_symbols[MAX_PORTS_CTRL]; + int cfi, cfi_rx, nsf, distance; + int cid, max_cid; + + parse_args(argc,argv); + + nof_re = CPNORM_NSYMB * nof_prb * RE_X_RB; + + /* init memory */ + for (i=0;i +#include +#include +#include +#include + +#include "lte.h" + +int cell_id = -1; +int nof_prb = 6; +int nof_ports = 1; +lte_cp_t cp = CPNORM; +phich_resources_t phich_res = R_1; +phich_length_t phich_length = PHICH_NORM; + +void usage(char *prog) { + printf("Usage: %s [cpvgel]\n", prog); + printf("\t-c cell id [Default %d]\n", cell_id); + printf("\t-p nof_ports [Default %d]\n", nof_ports); + printf("\t-n nof_prb [Default %d]\n", nof_prb); + printf("\t-g phich ng factor: 1/6, 1/2, 1, 2 [Default 1]\n"); + printf("\t-e phich extended length [Default normal]\n"); + printf("\t-l extended cyclic prefix [Default normal]\n"); + printf("\t-v [set verbose to debug, default none]\n"); +} + +void parse_args(int argc, char **argv) { + int opt; + while ((opt = getopt(argc, argv, "cpnvgel")) != -1) { + switch(opt) { + case 'p': + nof_ports = atoi(argv[optind]); + break; + case 'n': + nof_prb = atoi(argv[optind]); + break; + case 'c': + cell_id = atoi(argv[optind]); + break; + case 'g': + if (!strcmp(argv[optind], "1/6")) { + phich_res = R_1_6; + } else if (!strcmp(argv[optind], "1/2")) { + phich_res = R_1_2; + } else if (!strcmp(argv[optind], "1")) { + phich_res = R_1; + } else if (!strcmp(argv[optind], "2")) { + phich_res = R_2; + } else { + fprintf(stderr, "Invalid phich ng factor %s. Setting to default.\n", argv[optind]); + } + break; + case 'e': + phich_length = PHICH_EXT; + break; + case 'l': + cp = CPEXT; + break; + case 'v': + verbose++; + break; + default: + usage(argv[0]); + exit(-1); + } + } +} + + +int main(int argc, char **argv) { + phich_t phich; + regs_t regs; + int i, j; + cf_t *ce[MAX_PORTS_CTRL]; + int nof_re; + cf_t *slot_symbols[MAX_PORTS_CTRL]; + char ack[50][PHICH_NORM_NSEQUENCES], ack_rx; + int nsf, distance; + int cid, max_cid; + int ngroup, nseq, max_nseq; + + parse_args(argc,argv); + + max_nseq = CP_ISNORM(cp)?PHICH_NORM_NSEQUENCES:PHICH_EXT_NSEQUENCES; + + nof_re = CPNORM_NSYMB * nof_prb * RE_X_RB; + + /* init memory */ + for (i=0;i. - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * \section COPYRIGHT * - * OSLD-lib is distributed in the hope that it will be useful, + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 #include -#include "ratematching/rm_conv.h" +#include "lte/ratematching/rm_conv.h" #define NCOLS 32 #define NROWS_MAX NCOLS @@ -30,6 +41,52 @@ unsigned char RM_PERM_CC_INV[NCOLS] = { 16, 0, 24, 8, 20, 4, 28, 12, 18, 2, 26, 10, 22, 6, 30, 14, 17, 1, 25, 9, 21, 5, 29, 13, 19, 3, 27, 11, 23, 7, 31, 15 }; +int rm_conv_tx(char *input, char *output, int in_len, int out_len) { + + char tmp[RATE * NCOLS * NROWS_MAX]; + int nrows, ndummy, K_p; + + int i, j, k, s; + + nrows = (int) (in_len / RATE - 1) / NCOLS + 1; + if (nrows > NROWS_MAX) { + fprintf(stderr, "Input too large. Max input length is %d\n", + RATE * NCOLS * NROWS_MAX); + return -1; + } + K_p = nrows * NCOLS; + ndummy = K_p - in_len / RATE; + if (ndummy < 0) { + ndummy = 0; + } + k=0; + for (s = 0; s < 3; s++) { + for (j = 0; j < NCOLS; j++) { + for (i = 0; i < nrows; i++) { + if (i*NCOLS + RM_PERM_CC[j] < ndummy) { + tmp[k] = TX_NULL; + } else { + tmp[k] = input[(i*NCOLS + RM_PERM_CC[j]-ndummy)*3+s]; + } + k++; + } + } + } + k = 0; + j = 0; + while (k < out_len) { + if (tmp[j] != TX_NULL) { + output[k] = tmp[j]; + k++; + } + j++; + if (j == RATE * K_p) { + j = 0; + } + } + return 0; +} + /* Undoes Convolutional Code Rate Matching. * 3GPP TS 36.212 v10.1.0 section 5.1.4.2 @@ -44,7 +101,8 @@ int rm_conv_rx(float *input, float *output, int in_len, int out_len) { nrows = (int) (out_len / RATE - 1) / NCOLS + 1; if (nrows > NROWS_MAX) { - fprintf(stderr, "Output too large. Max output length is %d\n", RATE * NCOLS * NROWS_MAX); + fprintf(stderr, "Output too large. Max output length is %d\n", + RATE * NCOLS * NROWS_MAX); return -1; } K_p = nrows * NCOLS; @@ -84,8 +142,8 @@ int rm_conv_rx(float *input, float *output, int in_len, int out_len) { d_i = (i + ndummy) / NCOLS; d_j = (i + ndummy) % NCOLS; for (j = 0; j < RATE; j++) { - output[i * RATE + j] = tmp[K_p * j - + RM_PERM_CC_INV[d_j] * nrows + d_i]; + output[i * RATE + j] = tmp[K_p * j + RM_PERM_CC_INV[d_j] * nrows + + d_i]; } } return 0; diff --git a/lte/lib/ratematching/test/CMakeLists.txt b/lte/lib/ratematching/test/CMakeLists.txt new file mode 100644 index 000000000..1c4ded6df --- /dev/null +++ b/lte/lib/ratematching/test/CMakeLists.txt @@ -0,0 +1,33 @@ +# +# Copyright 2012-2013 The libLTE Developers. See the +# COPYRIGHT file at the top-level directory of this distribution. +# +# This file is part of the libLTE library. +# +# libLTE is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# libLTE is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# A copy of the GNU Lesser 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/. +# + +######################################################################## +# RATEMATCHING TEST +######################################################################## + +ADD_EXECUTABLE(rm_conv_test rm_conv_test.c) +TARGET_LINK_LIBRARIES(rm_conv_test lte) + +ADD_TEST(rm_conv_test_1 rm_conv_test -t 480 -r 1920) +ADD_TEST(rm_conv_test_2 rm_conv_test -t 1920 -r 480) + + + diff --git a/lte/lib/ratematching/test/rm_conv_test.c b/lte/lib/ratematching/test/rm_conv_test.c new file mode 100644 index 000000000..dc79ecceb --- /dev/null +++ b/lte/lib/ratematching/test/rm_conv_test.c @@ -0,0 +1,135 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 +#include +#include +#include +#include +#include +#include +#include + +#include "lte.h" + +int nof_tx_bits=-1, nof_rx_bits=-1; + +void usage(char *prog) { + printf("Usage: %s -t nof_tx_bits -r nof_rx_bits\n", prog); +} + +void parse_args(int argc, char **argv) { + int opt; + while ((opt = getopt(argc, argv, "tr")) != -1) { + switch (opt) { + case 't': + nof_tx_bits = atoi(argv[optind]); + break; + case 'r': + nof_rx_bits = atoi(argv[optind]); + break; + default: + usage(argv[0]); + exit(-1); + } + } + if (nof_tx_bits == -1) { + usage(argv[0]); + exit(-1); + } + if (nof_rx_bits == -1) { + usage(argv[0]); + exit(-1); + } +} + +int main(int argc, char **argv) { + int i; + char *bits, *rm_bits; + float *rm_symbols, *unrm_symbols; + int nof_errors; + + parse_args(argc, argv); + + bits = malloc(sizeof(char) * nof_tx_bits); + if (!bits) { + perror("malloc"); + exit(-1); + } + rm_bits = malloc(sizeof(char) * nof_rx_bits); + if (!rm_bits) { + perror("malloc"); + exit(-1); + } + rm_symbols = malloc(sizeof(float) * nof_rx_bits); + if (!rm_symbols) { + perror("malloc"); + exit(-1); + } + unrm_symbols = malloc(sizeof(float) * nof_tx_bits); + if (!unrm_symbols) { + perror("malloc"); + exit(-1); + } + + for (i=0;i 0) != bits[i]) { + nof_errors++; + } + } + if (nof_rx_bits > nof_tx_bits) { + if (nof_errors) { + printf("nof_errors=%d\n", nof_errors); + exit(-1); + } + } + + free(bits); + free(rm_bits); + free(rm_symbols); + free(unrm_symbols); + + printf("Ok\n"); + exit(0); +} diff --git a/lib/resampling/src/interp.c b/lte/lib/resampling/src/interp.c similarity index 66% rename from lib/resampling/src/interp.c rename to lte/lib/resampling/src/interp.c index 068495e3f..05a6960f9 100644 --- a/lib/resampling/src/interp.c +++ b/lte/lib/resampling/src/interp.c @@ -1,29 +1,39 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * \section COPYRIGHT * - * OSLD-lib is distributed in the hope that it will be useful, + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 #include -#include "resampling/interp.h" -#include "utils/debug.h" +#include "lte/resampling/interp.h" +#include "lte/utils/debug.h" /* Performs 1st order linear interpolation with out-of-bound interpolation */ void interp_linear_offset(cf_t *input, cf_t *output, int M, int len, int off_st, int off_end) { int i, j; - float mag0, mag1, arg0, arg1, mag, arg; + float mag0=0, mag1=0, arg0=0, arg1=0, mag=0, arg=0; for (i=0;i +#include +#include +#include +#include "lte/scrambling/scrambling.h" + +void scrambling_f(sequence_t *s, float *data) { + scrambling_f_offset(s, data, 0, s->len); +} + +void scrambling_f_offset(sequence_t *s, float *data, int offset, int len) { + int i; + assert (len + offset <= s->len); + + for (i = 0; i < len; i++) { + data[i] = data[i]*(1-2*s->c[i+offset]); + } +} + +void scrambling_c(sequence_t *s, cf_t *data) { + scrambling_c_offset(s, data, 0, s->len); +} + +void scrambling_c_offset(sequence_t *s, cf_t *data, int offset, int len) { + int i; + assert (len + offset <= s->len); + + for (i = 0; i < len; i++) { + data[i] = data[i]*(1-2*s->c[i+offset]); + } +} + +void scrambling_b(sequence_t *s, char *data) { + int i; + + for (i = 0; i < s->len; i++) { + data[i] = (data[i] + s->c[i]) % 2; + } +} + +void scrambling_b_offset(sequence_t *s, char *data, int offset, int len) { + int i; + assert (len + offset <= s->len); + for (i = 0; i < len; i++) { + data[i] = (data[i] + s->c[i+offset]) % 2; + } +} + +/** High-level API */ + +int compute_sequences(scrambling_hl* h) { + + switch (h->init.channel) { + case SCRAMBLING_PBCH: + return sequence_pbch(&h->obj.seq[0], h->init.nof_symbols == CPNORM_NSYMB?CPNORM:CPEXT, + h->init.cell_id); + case SCRAMBLING_PDSCH: + case SCRAMBLING_PCFICH: + for (int ns=0;nsobj.seq[ns], 2*ns, h->init.cell_id); + } + return 0; + case SCRAMBLING_PDCCH: + case SCRAMBLING_PMCH: + case SCRAMBLING_PUCCH: + fprintf(stderr, "Not implemented\n"); + return -1; + default: + fprintf(stderr, "Invalid channel %d\n", h->init.channel); + return -1; + } +} + +int scrambling_initialize(scrambling_hl* h) { + + bzero(&h->obj, sizeof(scrambling_t)); + + return compute_sequences(h); +} + +/** This function can be called in a subframe (1ms) basis for LTE */ +int scrambling_work(scrambling_hl* hl) { + int sf; + if (hl->init.channel == SCRAMBLING_PBCH) { + sf = 0; + } else { + sf = hl->ctrl_in.subframe; + } + sequence_t *seq = &hl->obj.seq[sf]; + + if (hl->init.hard) { + memcpy(hl->output, hl->input, sizeof(char) * hl->in_len); + scrambling_b(seq, hl->output); + } else { + memcpy(hl->output, hl->input, sizeof(float) * hl->in_len); + scrambling_f(seq, hl->output); + } + hl->out_len = hl->in_len; + return 0; +} + +int scrambling_stop(scrambling_hl* hl) { + int i; + for (i=0;iobj.seq[i]); + } + return 0; +} + diff --git a/lte/lib/scrambling/test/CMakeLists.txt b/lte/lib/scrambling/test/CMakeLists.txt new file mode 100644 index 000000000..bf9709cc5 --- /dev/null +++ b/lte/lib/scrambling/test/CMakeLists.txt @@ -0,0 +1,35 @@ +# +# Copyright 2012-2013 The libLTE Developers. See the +# COPYRIGHT file at the top-level directory of this distribution. +# +# This file is part of the libLTE library. +# +# libLTE is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# libLTE is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# A copy of the GNU Lesser 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/. +# + +######################################################################## +# SCRAMBLING TEST +######################################################################## + +ADD_EXECUTABLE(scrambling_test scrambling_test.c) +TARGET_LINK_LIBRARIES(scrambling_test lte) + +ADD_TEST(scrambling_pbch_bit scrambling_test -s PBCH -c 50) +ADD_TEST(scrambling_pbch_float scrambling_test -s PBCH -c 50 -f) +ADD_TEST(scrambling_pbch_e_bit scrambling_test -s PBCH -c 50 -e) +ADD_TEST(scrambling_pbch_e_float scrambling_test -s PBCH -c 50 -f -e) + + + diff --git a/lte/lib/scrambling/test/scrambling_test.c b/lte/lib/scrambling/test/scrambling_test.c new file mode 100644 index 000000000..b246c4a84 --- /dev/null +++ b/lte/lib/scrambling/test/scrambling_test.c @@ -0,0 +1,165 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 +#include +#include +#include +#include +#include +#include +#include + +#include "lte.h" + +char *sequence_name = NULL; +bool do_floats = false; +lte_cp_t cp = CPNORM; +int cell_id = -1; + +void usage(char *prog) { + printf("Usage: %s [ef] -c cell_id -s [PBCH, PDSCH, PDCCH, PMCH, PUCCH]\n", prog); + printf("\t -e CP extended [Default CP Normal]\n"); + printf("\t -f scramble floats [Default bits]\n"); +} + +void parse_args(int argc, char **argv) { + int opt; + while ((opt = getopt(argc, argv, "csef")) != -1) { + switch (opt) { + case 'c': + cell_id = atoi(argv[optind]); + break; + case 'e': + cp = CPEXT; + break; + case 'f': + do_floats = true; + break; + case 's': + sequence_name = argv[optind]; + break; + default: + usage(argv[0]); + exit(-1); + } + } + if (cell_id == -1) { + usage(argv[0]); + exit(-1); + } + if (!sequence_name) { + usage(argv[0]); + exit(-1); + } +} + +int init_sequence(sequence_t *seq, char *name) { + if (!strcmp(name, "PBCH")) { + return sequence_pbch(seq, cp, cell_id); + } else { + fprintf(stderr, "Unsupported sequence name %s\n", name); + return -1; + } +} + + +int main(int argc, char **argv) { + int i; + sequence_t seq; + char *input_b, *scrambled_b; + float *input_f, *scrambled_f; + + parse_args(argc, argv); + + if (init_sequence(&seq, sequence_name) == -1) { + fprintf(stderr, "Error initiating sequence %s\n", sequence_name); + exit(-1); + } + + if (!do_floats) { + input_b = malloc(sizeof(char) * seq.len); + if (!input_b) { + perror("malloc"); + exit(-1); + } + scrambled_b = malloc(sizeof(char) * seq.len); + if (!scrambled_b) { + perror("malloc"); + exit(-1); + } + + for (i=0;i +#include +#include + +#include "lte/utils/cexptab.h" +#include "lte/sync/cfo.h" +#include "lte/utils/vector.h" +#include "lte/utils/debug.h" + +int cfo_init(cfo_t *h, int nsamples) { + int ret = -1; + bzero(h, sizeof(cfo_t)); + + if (cexptab_init(&h->tab, CFO_CEXPTAB_SIZE)) { + goto clean; + } + h->cur_cexp = malloc(sizeof(cf_t) * nsamples); + if (!h->cur_cexp) { + goto clean; + } + h->tol = CFO_TOLERANCE; + h->last_freq = 0; + h->nsamples = nsamples; + cexptab_gen(&h->tab, h->cur_cexp, h->last_freq, h->nsamples); + + ret = 0; +clean: + if (ret == -1) { + cfo_free(h); + } + return ret; +} + +void cfo_free(cfo_t *h) { + cexptab_free(&h->tab); + if (h->cur_cexp) { + free(h->cur_cexp); + } + bzero(h, sizeof(cf_t)); +} + +void cfo_set_tol(cfo_t *h, float tol) { + h->tol = tol; +} + +void cfo_correct(cfo_t *h, cf_t *x, float freq) { + if (fabs(h->last_freq - freq) > h->tol) { + h->last_freq = freq; + cexptab_gen(&h->tab, h->cur_cexp, h->last_freq, h->nsamples); + INFO("CFO generating new table for frequency %.4f\n", freq); + } + vec_prod_ccc(h->cur_cexp, x, x, h->nsamples); +} diff --git a/lte/lib/sync/src/cp.c b/lte/lib/sync/src/cp.c new file mode 100644 index 000000000..da62c450f --- /dev/null +++ b/lte/lib/sync/src/cp.c @@ -0,0 +1,32 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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/. + * + */ + + + +/** TODO: Cyclic-prefix based synchronization + * + */ diff --git a/lib/sync/src/find_sss.c b/lte/lib/sync/src/find_sss.c similarity index 71% rename from lib/sync/src/find_sss.c rename to lte/lib/sync/src/find_sss.c index 7b4a08ac3..b6e6d06e8 100644 --- a/lib/sync/src/find_sss.c +++ b/lte/lib/sync/src/find_sss.c @@ -1,30 +1,40 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * \section COPYRIGHT * - * OSLD-lib is distributed in the hope that it will be useful, + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 -#include "utils/vector.h" -#include "sync/sss.h" +#include "lte/utils/vector.h" +#include "lte/sync/sss.h" cf_t corr_sz(cf_t *z, cf_t *s) { cf_t sum; cf_t zsprod[32]; - vec_dot_prod_ccc(z, s, zsprod, N_SSS - 1); + vec_prod_ccc(z, s, zsprod, N_SSS - 1); sum = vec_acc_cc(zsprod, N_SSS - 1); return sum; @@ -66,10 +76,10 @@ void sss_synch_m0m1(sss_synch_t *q, cf_t *input, int *m0, float *m0_value, y[1][i] = input_fft[SSS_POS_SYMBOL + 2 * i + 1]; } - vec_dot_prod_ccc(y[0], q->fc_tables.c[0], z, N_SSS); + vec_prod_ccc(y[0], q->fc_tables.c[0], z, N_SSS); memcpy(zdelay, &z[1], (N_SSS - 1) * sizeof(cf_t)); vec_conj_cc(z, zconj, N_SSS - 1); - vec_dot_prod_ccc(zdelay, zconj, zprod, N_SSS - 1); + vec_prod_ccc(zdelay, zconj, zprod, N_SSS - 1); corr_all_zs(zprod, q->fc_tables.s, tmp); vec_abs_cf(tmp, tmp_real, N_SSS); @@ -78,11 +88,11 @@ void sss_synch_m0m1(sss_synch_t *q, cf_t *input, int *m0, float *m0_value, *m0_value = tmp_real[*m0]; } - vec_dot_prod_ccc(y[1], q->fc_tables.c[1], tmp, N_SSS); - vec_dot_prod_ccc(tmp, q->fc_tables.z1[*m0], z, N_SSS); + vec_prod_ccc(y[1], q->fc_tables.c[1], tmp, N_SSS); + vec_prod_ccc(tmp, q->fc_tables.z1[*m0], z, N_SSS); memcpy(zdelay, &z[1], (N_SSS - 1) * sizeof(cf_t)); vec_conj_cc(z, zconj, N_SSS - 1); - vec_dot_prod_ccc(zdelay, zconj, zprod, N_SSS - 1); + vec_prod_ccc(zdelay, zconj, zprod, N_SSS - 1); corr_all_zs(zprod, q->fc_tables.s, tmp); vec_abs_cf(tmp, tmp_real, N_SSS); diff --git a/lib/sync/src/gen_sss.c b/lte/lib/sync/src/gen_sss.c similarity index 77% rename from lib/sync/src/gen_sss.c rename to lte/lib/sync/src/gen_sss.c index ca9c8da3c..de75c189b 100644 --- a/lib/sync/src/gen_sss.c +++ b/lte/lib/sync/src/gen_sss.c @@ -1,24 +1,34 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This file is part of the libLTE library. * - * OSLD-lib is distributed in the hope that it will be useful, + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 -#include "sync/sss.h" +#include "lte/sync/sss.h" /** * @brief Function documentation: initSSStables() @@ -116,7 +126,7 @@ void generate_sss_all_tables(struct sss_tables *tables, int N_id_2) { tables->N_id_2 = N_id_2; } -void generate_sss(float *signal, int cell_id) { +void sss_generate(float *signal0, float *signal5, int cell_id) { int i; int id1 = cell_id / 3; @@ -140,15 +150,15 @@ void generate_sss(float *signal, int cell_id) { for (i = 0; i < N_SSS; i++) { /** Even Resource Elements: Sub-frame 0*/ - signal[2 * i] = (float) (s0[i] * c0[i]); + signal0[2 * i] = (float) (s0[i] * c0[i]); /** Odd Resource Elements: Sub-frame 0*/ - signal[2 * i + 1] = (float) (s1[i] * c1[i] * z1_0[i]); + signal0[2 * i + 1] = (float) (s1[i] * c1[i] * z1_0[i]); } for (i = 0; i < N_SSS; i++) { /** Even Resource Elements: Sub-frame 5*/ - signal[2 * i + N_SSS * 2] = (float) (s1[i] * c0[i]); + signal5[2 * i] = (float) (s1[i] * c0[i]); /** Odd Resource Elements: Sub-frame 5*/ - signal[2 * i + 1 + N_SSS * 2] = (float) (s0[i] * c1[i] * z1_1[i]); + signal5[2 * i + 1] = (float) (s0[i] * c1[i] * z1_1[i]); } } diff --git a/lib/sync/src/pss.c b/lte/lib/sync/src/pss.c similarity index 79% rename from lib/sync/src/pss.c rename to lte/lib/sync/src/pss.c index 8d339f123..70cb0741e 100644 --- a/lib/sync/src/pss.c +++ b/lte/lib/sync/src/pss.c @@ -1,31 +1,41 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This file is part of the libLTE library. * - * OSLD-lib is distributed in the hope that it will be useful, + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 #include #include #include #include -#include "sync/pss.h" -#include "utils/dft.h" -#include "utils/vector.h" -#include "utils/convolution.h" +#include "lte/sync/pss.h" +#include "lte/utils/dft.h" +#include "lte/utils/vector.h" +#include "lte/utils/convolution.h" #define NOT_SYNC 0xF0F0F0F0 @@ -36,27 +46,27 @@ int pss_synch_init(pss_synch_t *q, int frame_size) { int ret = -1; bzero(q, sizeof(pss_synch_t)); - q->pss_signal_freq = vec_malloc((PSS_LEN_FREQ+frame_size) * sizeof(cf_t)); + q->pss_signal_freq = vec_malloc((PSS_LEN_FREQ + frame_size) * sizeof(cf_t)); if (!q->pss_signal_freq) { fprintf(stderr, "Error allocating memory\n"); goto clean_and_exit; } - q->conv_abs = vec_malloc((PSS_LEN_FREQ+frame_size) * sizeof(float)); + q->conv_abs = vec_malloc((PSS_LEN_FREQ + frame_size) * sizeof(float)); if (!q->conv_abs) { fprintf(stderr, "Error allocating memory\n"); goto clean_and_exit; } - q->tmp_input = vec_malloc((PSS_LEN_FREQ+frame_size) * sizeof(cf_t)); + q->tmp_input = vec_malloc((PSS_LEN_FREQ + frame_size) * sizeof(cf_t)); if (!q->tmp_input) { fprintf(stderr, "Error allocating memory\n"); goto clean_and_exit; } - q->frame_buffer = vec_malloc(4*frame_size * sizeof(cf_t)); + q->frame_buffer = vec_malloc(4 * frame_size * sizeof(cf_t)); if (!q->frame_buffer) { fprintf(stderr, "Error allocating memory\n"); goto clean_and_exit; } - q->conv_output = vec_malloc((PSS_LEN_FREQ+frame_size) * sizeof(cf_t)); + q->conv_output = vec_malloc((PSS_LEN_FREQ + frame_size) * sizeof(cf_t)); if (!q->conv_output) { fprintf(stderr, "Error allocating memory\n"); goto clean_and_exit; @@ -78,8 +88,7 @@ int pss_synch_init(pss_synch_t *q, int frame_size) { q->fb_wp = 0; ret = 0; -clean_and_exit: - if (ret == -1) { + clean_and_exit: if (ret == -1) { pss_synch_free(q); } return ret; @@ -112,15 +121,14 @@ void pss_synch_free(pss_synch_t *q) { /** * This function calculates the Zadoff-Chu sequence. * @param signal Output array. - * @param direction 0 for tx, 1 for rx */ -int pss_generate(cf_t *signal, int direction, int N_id_2) { +int pss_generate(cf_t *signal, int N_id_2) { int i; float arg; - const float root_value[] = {25.0,29.0,34.0}; + const float root_value[] = { 25.0, 29.0, 34.0 }; int root_idx; - int sign = direction ? 1 : -1; + int sign = -1; if (N_id_2 < 0 || N_id_2 > 2) { fprintf(stderr, "Invalid N_id_2 %d\n", N_id_2); @@ -144,7 +152,15 @@ int pss_generate(cf_t *signal, int direction, int N_id_2) { return 0; } - +/** 36.211 10.3 section 6.11.1.2 + */ +void pss_put_slot(cf_t *pss_signal, cf_t *slot, int nof_prb, lte_cp_t cp) { + int k; + k = (CP_NSYMB(cp) - 1) * nof_prb * RE_X_RB + nof_prb * RE_X_RB / 2 - 31; + memset(&slot[k - 5], 0, 5 * sizeof(cf_t)); + memcpy(&slot[k], pss_signal, PSS_LEN * sizeof(cf_t)); + memset(&slot[k + PSS_LEN], 0, 5 * sizeof(cf_t)); +} /** Sets the current N_id_2 value. Initializes the object for this PSS sequence * Returns -1 on error, 0 otherwise @@ -161,7 +177,7 @@ int pss_synch_set_N_id_2(pss_synch_t *q, int N_id_2) { return -1; } - pss_generate(pss_signal_time, 0, N_id_2); + pss_generate(pss_signal_time, N_id_2); memset(pss_signal_pad, 0, PSS_LEN_FREQ * sizeof(cf_t)); memset(q->pss_signal_freq, 0, PSS_LEN_FREQ * sizeof(cf_t)); @@ -192,7 +208,8 @@ int pss_synch_set_N_id_2(pss_synch_t *q, int N_id_2) { * * Input buffer must be subframe_size long. */ -int pss_synch_find_pss(pss_synch_t *q, cf_t *input, float *corr_peak_value, float *corr_mean_value) { +int pss_synch_find_pss(pss_synch_t *q, cf_t *input, float *corr_peak_value, + float *corr_mean_value) { int corr_peak_pos; int conv_output_len; @@ -201,7 +218,8 @@ int pss_synch_find_pss(pss_synch_t *q, cf_t *input, float *corr_peak_value, floa memset(&q->tmp_input[q->frame_size], 0, PSS_LEN_FREQ * sizeof(cf_t)); #ifdef CONVOLUTION_FFT - conv_output_len = conv_fft_cc_run(&q->conv_fft, q->tmp_input, q->pss_signal_freq, q->conv_output); + conv_output_len = conv_fft_cc_run(&q->conv_fft, q->tmp_input, + q->pss_signal_freq, q->conv_output); #else conv_output_len = conv_cc(input, q->pss_signal_freq, q->conv_output, q->frame_size, PSS_LEN_FREQ); #endif @@ -212,7 +230,8 @@ int pss_synch_find_pss(pss_synch_t *q, cf_t *input, float *corr_peak_value, floa *corr_peak_value = q->conv_abs[corr_peak_pos]; } if (corr_mean_value) { - *corr_mean_value = vec_acc_ff(q->conv_abs, conv_output_len) / conv_output_len; + *corr_mean_value = vec_acc_ff(q->conv_abs, conv_output_len) + / conv_output_len; } return (int) corr_peak_pos; @@ -225,26 +244,17 @@ int pss_synch_find_pss(pss_synch_t *q, cf_t *input, float *corr_peak_value, floa */ float pss_synch_cfo_compute(pss_synch_t* q, cf_t *pss_recv) { cf_t y0, y1, yr; - cf_t y[PSS_LEN_FREQ-1]; + cf_t y[PSS_LEN_FREQ - 1]; - vec_dot_prod_ccc_unalign(q->pss_signal_freq, pss_recv, y, PSS_LEN_FREQ - 1); + vec_prod_ccc_unalign(q->pss_signal_freq, pss_recv, y, PSS_LEN_FREQ - 1); - y0 = vec_acc_cc(y, (PSS_LEN_FREQ - 1)/2); - y1 = vec_acc_cc(&y[(PSS_LEN_FREQ - 1)/2], (PSS_LEN_FREQ - 1)/2); + y0 = vec_acc_cc(y, (PSS_LEN_FREQ - 1) / 2); + y1 = vec_acc_cc(&y[(PSS_LEN_FREQ - 1) / 2], (PSS_LEN_FREQ - 1) / 2); yr = conjf(y0) * y1; return atan2f(__imag__ yr, __real__ yr) / M_PI; } - - - - - - - - - /** This function is designed to be called periodically on a subframe basis. * The function finds the PSS correlation peak and computes (does not adjust) CFO automatically as defined by * pss_synch_set_cfo_mode(). @@ -320,13 +330,13 @@ int pss_synch_frame(pss_synch_t *q, cf_t *input, cf_t *output, int nsamples) { } if (q->frame_start_idx != NOT_SYNC && q->cfo_auto && retval) { - q->current_cfo = pss_synch_cfo_compute(q, &output[q->frame_size/2 - PSS_LEN_FREQ + 1]); + q->current_cfo = pss_synch_cfo_compute(q, + &output[q->frame_size / 2 - PSS_LEN_FREQ + 1]); } return retval; } - void pss_synch_set_timeout(pss_synch_t *q, int nof_frames) { q->nosync_timeout_frames = nof_frames; } @@ -347,15 +357,8 @@ int pss_synch_get_frame_start_idx(pss_synch_t *q) { return q->frame_start_idx; } - - - - - /** High-level API */ - - int pss_synch_initialize(pss_synch_hl* h) { int fs = h->init.frame_size; if (!fs) { diff --git a/lib/sync/src/sfo.c b/lte/lib/sync/src/sfo.c similarity index 57% rename from lib/sync/src/sfo.c rename to lte/lib/sync/src/sfo.c index ab5553370..2d13d2d2e 100644 --- a/lib/sync/src/sfo.c +++ b/lte/lib/sync/src/sfo.c @@ -1,24 +1,34 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * \section COPYRIGHT * - * OSLD-lib is distributed in the hope that it will be useful, + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 #include -#include "sync/sfo.h" +#include "lte/sync/sfo.h" /* Estimate SFO based on the array of time estimates t0 * of length len. The parameter period is the time between t0 samples diff --git a/lib/sync/src/sss.c b/lte/lib/sync/src/sss.c similarity index 71% rename from lib/sync/src/sss.c rename to lte/lib/sync/src/sss.c index fff4a4828..25c915c6b 100644 --- a/lib/sync/src/sss.c +++ b/lte/lib/sync/src/sss.c @@ -1,29 +1,39 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * \section COPYRIGHT * - * OSLD-lib is distributed in the hope that it will be useful, + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 #include #include #include -#include "sync/sss.h" -#include "utils/dft.h" -#include "utils/convolution.h" +#include "lte/sync/sss.h" +#include "lte/utils/dft.h" +#include "lte/utils/convolution.h" void generate_sss_all_tables(struct sss_tables *tables, int N_id_2); void convert_tables(struct fc_tables *fc_tables, struct sss_tables *in); @@ -53,12 +63,25 @@ int sss_synch_set_N_id_2(sss_synch_t *q, int N_id_2) { } struct sss_tables sss_tables; - generate_sss_all_tables(&sss_tables,N_id_2); + generate_sss_all_tables(&sss_tables, N_id_2); convert_tables(&q->fc_tables, &sss_tables); return 0; } +/** 36.211 10.3 section 6.11.2.2 + */ +void sss_put_slot(float *sss, cf_t *slot, int nof_prb, lte_cp_t cp) { + int i, k; + + k = (CP_NSYMB(cp) - 2) * nof_prb * RE_X_RB + nof_prb * RE_X_RB / 2 - 31; + memset(&slot[k - 5], 0, 5 * sizeof(cf_t)); + for (i = 0; i < SSS_LEN; i++) { + __real__ slot[k + i] = sss[i]; + __imag__ slot[k + i] = 0; + } + memset(&slot[k + SSS_LEN], 0, 5 * sizeof(cf_t)); +} /* In this function, input points to the beginning of the subframe. Saves result in subframe_idx and N_id_1 * Return 1 if the sequence was found, 0 if the peak is not found, -1 if the subframe_sz or symbol_sz are @@ -66,19 +89,19 @@ int sss_synch_set_N_id_2(sss_synch_t *q, int N_id_2) { * Before calling this function, the correlation threshold and symbol size duration need to be set * using sss_synch_set_threshold() and sss_synch_set_symbol_sz(). */ -int sss_synch_frame(sss_synch_t *q, cf_t *input, int *subframe_idx, - int *N_id_1) { - int m0,m1; +int sss_synch_frame(sss_synch_t *q, cf_t *input, int *subframe_idx, int *N_id_1) { + int m0, m1; float m0_value, m1_value; if (q->subframe_sz <= 0 || q->symbol_sz <= 0) { return -1; } - sss_synch_m0m1(q, &input[SSS_SYMBOL_ST(q->subframe_sz, q->symbol_sz)], - &m0, &m0_value, &m1, &m1_value); + sss_synch_m0m1(q, &input[SSS_SYMBOL_ST(q->subframe_sz, q->symbol_sz)], &m0, + &m0_value, &m1, &m1_value); - if (m0_value > q->corr_peak_threshold && m1_value > q->corr_peak_threshold) { + if (m0_value > q->corr_peak_threshold + && m1_value > q->corr_peak_threshold) { if (subframe_idx) { *subframe_idx = sss_synch_subframe(m0, m1); } @@ -103,7 +126,6 @@ void sss_synch_set_subframe_sz(sss_synch_t *q, int subframe_sz) { q->subframe_sz = subframe_sz; } - /** Sets the SSS correlation peak detection threshold */ void sss_synch_set_threshold(sss_synch_t *q, float threshold) { q->corr_peak_threshold = threshold; @@ -120,13 +142,13 @@ int sss_synch_subframe(int m0, int m1) { /** Returns the N_id_1 value based on the m0 and m1 values */ int sss_synch_N_id_1(sss_synch_t *q, int m0, int m1) { - if (m0<0 || m0>29 || m1<0 || m1>29) { + if (m0 < 0 || m0 > 29 || m1 < 0 || m1 > 29) { return -1; } if (m1 > m0) { - return q->N_id_1_table[m0][m1-1]; + return q->N_id_1_table[m0][m1 - 1]; } else { - return q->N_id_1_table[m1][m0-1]; + return q->N_id_1_table[m1][m0 - 1]; } } @@ -153,7 +175,8 @@ int sss_synch_work(sss_synch_hl* hl) { if (hl->ctrl_in.symbol_sz) { sss_synch_set_symbol_sz(&hl->obj, hl->ctrl_in.symbol_sz); } - sss_synch_frame(&hl->obj, hl->input, &hl->ctrl_out.subframe_idx, &hl->ctrl_out.N_id_1); + sss_synch_frame(&hl->obj, hl->input, &hl->ctrl_out.subframe_idx, + &hl->ctrl_out.N_id_1); return 0; } diff --git a/lte/lib/sync/src/sync.c b/lte/lib/sync/src/sync.c new file mode 100644 index 000000000..6e2172b46 --- /dev/null +++ b/lte/lib/sync/src/sync.c @@ -0,0 +1,256 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 + +#include "lte/utils/debug.h" +#include "lte/common/base.h" +#include "lte/sync/sync.h" + +int sync_init(sync_t *q, int frame_size) { + int N_id_2; + + bzero(q, sizeof(sync_t)); + q->force_N_id_2 = -1; + q->threshold = 1.5; + q->pss_mode = PEAK_MEAN; + q->detect_cp = true; + q->sss_en = true; + + for (N_id_2=0;N_id_2<3;N_id_2++) { + if (pss_synch_init(&q->pss[N_id_2], frame_size)) { + fprintf(stderr, "Error initializing PSS object\n"); + return -1; + } + if (pss_synch_set_N_id_2(&q->pss[N_id_2], N_id_2)) { + fprintf(stderr, "Error initializing N_id_2\n"); + return -1; + } + if (sss_synch_init(&q->sss[N_id_2])) { + fprintf(stderr, "Error initializing SSS object\n"); + return -1; + } + if (sss_synch_set_N_id_2(&q->sss[N_id_2], N_id_2)) { + fprintf(stderr, "Error initializing N_id_2\n"); + return -1; + } + DEBUG("PSS and SSS initiated N_id_2=%d\n", N_id_2); + } + + return 0; +} + +void sync_free(sync_t *q) { + int N_id_2; + + for (N_id_2=0;N_id_2<3;N_id_2++) { + pss_synch_free(&q->pss[N_id_2]); + sss_synch_free(&q->sss[N_id_2]); + } +} + +void sync_pss_det_absolute(sync_t *q) { + q->pss_mode = ABSOLUTE; +} +void sync_pss_det_peak_to_avg(sync_t *q) { + q->pss_mode = PEAK_MEAN; +} + +void sync_set_threshold(sync_t *q, float threshold) { + q->threshold = threshold; +} + +void sync_force_N_id_2(sync_t *q, int force_N_id_2) { + q->force_N_id_2 = force_N_id_2; +} + +void sync_force_cp(sync_t *q, lte_cp_t cp) { + q->cp = cp; + q->detect_cp = false; +} + +void sync_sss_en(sync_t *q, bool enabled) { + q->sss_en = enabled; +} + +int sync_get_cell_id(sync_t *q) { + if (q->N_id_1 >=0 && q->N_id_2 >= 0) { + return q->N_id_1*3 + q->N_id_2; + } else { + return -1; + } +} + +int sync_get_N_id_1(sync_t *q) { + return q->N_id_1; +} + +int sync_get_N_id_2(sync_t *q) { + return q->N_id_2; +} + +int sync_get_slot_id(sync_t *q) { + return q->slot_id; +} + +float sync_get_cfo(sync_t *q) { + return q->cfo; +} + +float sync_get_peak_to_avg(sync_t *q) { + return q->peak_to_avg; +} + +lte_cp_t sync_get_cp(sync_t *q) { + return q->cp; +} + +int sync_run(sync_t *q, cf_t *input) { + int N_id_2, peak_pos[3], sss_idx_n, sss_idx_e; + int m0, m1; + float m0_value_e, m1_value_e,m0_value_n, m1_value_n; + int slot_id_e, N_id_1_e, slot_id_n, N_id_1_n; + float peak_value[3]; + float mean_value[3]; + float max=-999; + int i; + int peak_detected; + + if (q->force_N_id_2 == -1) { + for (N_id_2=0;N_id_2<3;N_id_2++) { + peak_pos[N_id_2] = pss_synch_find_pss(&q->pss[N_id_2], input, + &peak_value[N_id_2], &mean_value[N_id_2]); + } + for (i=0;i<3;i++) { + if (peak_value[i] > max) { + max = peak_value[i]; + N_id_2 = i; + } + } + } else { + N_id_2 = q->force_N_id_2; + peak_pos[N_id_2] = pss_synch_find_pss(&q->pss[N_id_2], input, + &peak_value[N_id_2], &mean_value[N_id_2]); + } + + q->peak_to_avg = peak_value[N_id_2] / mean_value[N_id_2]; + + DEBUG("PSS possible peak N_id_2=%d, pos=%d peak=%.2f par=%.2f threshold=%.2f\n", + N_id_2, peak_pos[N_id_2], peak_value[N_id_2], q->peak_to_avg, q->threshold); + + /* If peak detected */ + peak_detected = 0; + if (peak_pos[N_id_2] - 128 >= 0) { + if (q->pss_mode == ABSOLUTE) { + if (peak_value[N_id_2] > q->threshold) { + peak_detected = 1; + } + } else { + if (q->peak_to_avg > q->threshold) { + peak_detected = 1; + } + } + } + if (peak_detected) { + + q->cfo = pss_synch_cfo_compute(&q->pss[N_id_2], &input[peak_pos[N_id_2]-128]); + + INFO("PSS peak detected N_id_2=%d, pos=%d peak=%.2f par=%.2f th=%.2f cfo=%.4f\n", N_id_2, + peak_pos[N_id_2], peak_value[N_id_2], q->peak_to_avg, q->threshold, q->cfo); + + if (q->sss_en) { + + /* Make sure we have enough room to find SSS sequence */ + sss_idx_n = peak_pos[N_id_2]-2*(128+CP(128,CPNORM_LEN)); + sss_idx_e = peak_pos[N_id_2]-2*(128+CP(128,CPEXT_LEN)); + + if (q->detect_cp) { + if (sss_idx_n < 0 || sss_idx_e < 0) { + INFO("Not enough room to decode SSS (%d, %d)\n", sss_idx_n, sss_idx_e); + return -1; + } + } else { + if (CP_ISNORM(q->cp)) { + if (sss_idx_n < 0) { + INFO("Not enough room to decode SSS (%d)\n", sss_idx_n); + return -1; + } + } else { + if (sss_idx_e < 0) { + INFO("Not enough room to decode SSS (%d)\n", sss_idx_e); + return -1; + } + } + } + N_id_1_e = -1; + N_id_1_n = -1; + slot_id_e = -1; + slot_id_n = -1; + /* try Normal CP length */ + if (q->detect_cp || CP_ISNORM(q->cp)) { + sss_synch_m0m1(&q->sss[N_id_2], &input[sss_idx_n], + &m0, &m0_value_n, &m1, &m1_value_n); + + slot_id_n = 2 * sss_synch_subframe(m0, m1); + N_id_1_n = sss_synch_N_id_1(&q->sss[N_id_2], m0, m1); + } + + if (q->detect_cp || CP_ISEXT(q->cp)) { + /* Now try Extended CP length */ + sss_synch_m0m1(&q->sss[N_id_2], &input[sss_idx_e], + &m0, &m0_value_e, &m1, &m1_value_e); + + slot_id_e = 2 * sss_synch_subframe(m0, m1); + N_id_1_e = sss_synch_N_id_1(&q->sss[N_id_2], m0, m1); + } + + /* Correlation with extended CP hypoteshis is greater than with normal? */ + if ((q->detect_cp && m0_value_e * m1_value_e > m0_value_n * m1_value_n) + || CP_ISEXT(q->cp)) { + q->cp = CPEXT; + q->slot_id = slot_id_e; + q->N_id_1 = N_id_1_e; + /* then is normal CP */ + } else { + q->cp = CPNORM; + q->slot_id = slot_id_n; + q->N_id_1 = N_id_1_n; + } + q->N_id_2 = N_id_2; + + INFO("SSS detected N_id_1=%d, slot_idx=%d, %s CP\n", + q->N_id_1, q->slot_id, CP_ISNORM(q->cp)?"Normal":"Extended"); + } + + return peak_pos[N_id_2]; + + } else { + return -1; + } +} diff --git a/lte/lib/sync/test/CMakeLists.txt b/lte/lib/sync/test/CMakeLists.txt new file mode 100644 index 000000000..425edff73 --- /dev/null +++ b/lte/lib/sync/test/CMakeLists.txt @@ -0,0 +1,46 @@ +# +# Copyright 2012-2013 The libLTE Developers. See the +# COPYRIGHT file at the top-level directory of this distribution. +# +# This file is part of the libLTE library. +# +# libLTE is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# libLTE is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# A copy of the GNU Lesser 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/. +# + +######################################################################## +# SYNC TEST +######################################################################## + +ADD_EXECUTABLE(sync_test sync_test.c) +TARGET_LINK_LIBRARIES(sync_test lte) + +ADD_TEST(sync_test_100 sync_test -o 100) +ADD_TEST(sync_test_400 sync_test -o 400) +ADD_TEST(sync_test_100_e sync_test -o 100 -e) +ADD_TEST(sync_test_400_e sync_test -o 400 -e) + +######################################################################## +# CFO TEST +######################################################################## + +ADD_EXECUTABLE(cfo_test cfo_test.c) +TARGET_LINK_LIBRARIES(cfo_test lte) + +ADD_TEST(cfo_test_1 cfo_test -f 0.12345 -n 1000) +ADD_TEST(cfo_test_2 cfo_test -f 0.99849 -n 1000) + + + + diff --git a/lte/lib/sync/test/cfo_test.c b/lte/lib/sync/test/cfo_test.c new file mode 100644 index 000000000..13db50c75 --- /dev/null +++ b/lte/lib/sync/test/cfo_test.c @@ -0,0 +1,119 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 +#include +#include +#include +#include +#include +#include +#include + +#include "lte.h" + +#define MAX_MSE 0.1 + +float freq = 0; +int num_samples = 1000; + +void usage(char *prog) { + printf("Usage: %s -f freq -n num_samples\n", prog); +} + +void parse_args(int argc, char **argv) { + int opt; + while ((opt = getopt(argc, argv, "nf")) != -1) { + switch (opt) { + case 'n': + num_samples = atoi(argv[optind]); + break; + case 'f': + freq = atof(argv[optind]); + break; + default: + usage(argv[0]); + exit(-1); + } + } +} + +int main(int argc, char **argv) { + int i; + cf_t *input, *output; + cfo_t cfocorr; + float mse; + + if (argc < 5) { + usage(argv[0]); + exit(-1); + } + + parse_args(argc, argv); + + input = malloc(sizeof(cf_t) * num_samples); + if (!input) { + perror("malloc"); + exit(-1); + } + output = malloc(sizeof(cf_t) * num_samples); + if (!output) { + perror("malloc"); + exit(-1); + } + + for (i=0;i MAX_MSE) { + printf("MSE too large\n"); + exit(-1); + } else { + printf("Ok\n"); + exit(0); + } +} diff --git a/lte/lib/sync/test/sync_test.c b/lte/lib/sync/test/sync_test.c new file mode 100644 index 000000000..a74504b82 --- /dev/null +++ b/lte/lib/sync/test/sync_test.c @@ -0,0 +1,166 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 +#include +#include +#include +#include +#include +#include +#include + +#include "lte.h" + +int cell_id = -1, offset = 0; +lte_cp_t cp = CPNORM; + +#define FLEN 9600 + +void usage(char *prog) { + printf("Usage: %s [coev]\n", prog); + printf("\t-c cell_id [Default check for all]\n"); + printf("\t-o offset [Default %d]\n", offset); + printf("\t-e extended CP [Default normal]\n"); + printf("\t-v verbose\n"); +} + +void parse_args(int argc, char **argv) { + int opt; + while ((opt = getopt(argc, argv, "coev")) != -1) { + switch (opt) { + case 'c': + cell_id = atoi(argv[optind]); + break; + case 'o': + offset = atoi(argv[optind]); + break; + case 'e': + cp = CPEXT; + break; + case 'v': + verbose++; + break; + default: + usage(argv[0]); + exit(-1); + } + } +} + +int main(int argc, char **argv) { + int N_id_2, ns, find_ns; + cf_t *buffer, *fft_buffer; + cf_t pss_signal[PSS_LEN]; + float sss_signal0[SSS_LEN]; // for subframe 0 + float sss_signal5[SSS_LEN]; // for subframe 5 + int cid, max_cid, find_idx; + sync_t sync; + lte_fft_t ifft; + + parse_args(argc, argv); + + buffer = malloc(sizeof(cf_t) * FLEN); + if (!buffer) { + perror("malloc"); + exit(-1); + } + + fft_buffer = malloc(sizeof(cf_t) * 2 * FLEN); + if (!fft_buffer) { + perror("malloc"); + exit(-1); + } + + if (lte_ifft_init(&ifft, cp, 6)) { + fprintf(stderr, "Error creating iFFT object\n"); + exit(-1); + } + + if (sync_init(&sync, FLEN)) { + fprintf(stderr, "Error initiating PSS/SSS\n"); + return -1; + } + + sync_set_threshold(&sync, 20); + sync_force_N_id_2(&sync, -1); + + if (cell_id == -1) { + cid = 0; + max_cid = 149; + } else { + cid = cell_id; + max_cid = cell_id; +} + while(cid <= max_cid) { + N_id_2 = cid%3; + + /* Generate PSS/SSS signals */ + pss_generate(pss_signal, N_id_2); + sss_generate(sss_signal0, sss_signal5, cid); + + for (ns=0;ns<2;ns++) { + memset(buffer, 0, sizeof(cf_t) * FLEN); + pss_put_slot(pss_signal, buffer, 6, cp); + sss_put_slot(ns?sss_signal5:sss_signal0, buffer, 6, cp); + + /* Transform to OFDM symbols */ + memset(fft_buffer, 0, sizeof(cf_t) * 2 * FLEN); + lte_ifft_run(&ifft, buffer, &fft_buffer[offset]); + + find_idx = sync_run(&sync, fft_buffer); + find_ns = sync_get_slot_id(&sync); + printf("cell_id: %d find: %d, offset: %d, ns=%d find_ns=%d\n", cid, find_idx, offset, + ns, find_ns); + if (find_idx != offset + 960) { + printf("offset != find_offset: %d != %d\n", find_idx, offset + 960); + exit(-1); + } + if (ns*10 != find_ns) { + printf("ns != find_ns\n", 10 * ns, find_ns); + exit(-1); + } + if (sync_get_cp(&sync) != cp) { + printf("Detected CP should be %s\n", CP_ISNORM(cp)?"Normal":"Extended"); + exit(-1); + } + } + cid++; + } + + free(fft_buffer); + free(buffer); + + sync_free(&sync); + lte_ifft_free(&ifft); + + fftwf_cleanup(); + + printf("Ok\n"); + exit(0); +} + diff --git a/lib/utils/src/bit.c b/lte/lib/utils/src/bit.c similarity index 61% rename from lib/utils/src/bit.c rename to lte/lib/utils/src/bit.c index fda92913e..51e0c6d32 100644 --- a/lib/utils/src/bit.c +++ b/lte/lib/utils/src/bit.c @@ -1,21 +1,31 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * \section COPYRIGHT * - * OSLD-lib is distributed in the hope that it will be useful, + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 #include @@ -55,6 +65,7 @@ unsigned int bit_diff(char *x, char *y, int nbits) { unsigned int errors=0; for (int i=0;i +#include +#include +#include +#include + +#include "lte/utils/cexptab.h" + +int cexptab_init(cexptab_t *h, int size) { + int i; + + h->size = size; + h->tab = malloc(sizeof(cf_t) * size); + if (h->tab) { + for (i = 0; i < size; i++) { + h->tab[i] = cexpf(_Complex_I * 2 * M_PI * (float) i / size); + } + return 0; + } else { + return -1; + } +} + +void cexptab_free(cexptab_t *h) { + if (h->tab) { + free(h->tab); + } + bzero(h, sizeof(cexptab_t)); +} + +void cexptab_gen(cexptab_t *h, cf_t *x, float freq, int len) { + int i; + unsigned int idx; + float phase_inc = freq * h->size; + float phase=0; + + for (i = 0; i < len; i++) { + while (phase >= (float) h->size) { + phase -= (float) h->size; + } + while (phase < 0) { + phase += (float) h->size; + } + idx = (unsigned int) phase; + x[i] = h->tab[idx]; + phase += phase_inc; + + } +} + +void cexptab_gen_direct(cf_t *x, float freq, int len) { + int i; + for (i = 0; i < len; i++) { + x[i] = cexpf(_Complex_I * 2 * M_PI * freq * i); + } +} + diff --git a/lib/utils/src/convolution.c b/lte/lib/utils/src/convolution.c similarity index 71% rename from lib/utils/src/convolution.c rename to lte/lib/utils/src/convolution.c index b6ff45d08..f92ccd383 100644 --- a/lib/utils/src/convolution.c +++ b/lte/lib/utils/src/convolution.c @@ -1,27 +1,37 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * \section COPYRIGHT * - * OSLD-lib is distributed in the hope that it will be useful, + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 #include -#include "utils/dft.h" -#include "utils/vector.h" -#include "utils/convolution.h" +#include "lte/utils/dft.h" +#include "lte/utils/vector.h" +#include "lte/utils/convolution.h" int conv_fft_cc_init(conv_fft_cc_t *state, int input_len, int filter_len) { @@ -66,7 +76,7 @@ int conv_fft_cc_run(conv_fft_cc_t *state, _Complex float *input, _Complex float dft_run_c2c(&state->input_plan, input, state->input_fft); dft_run_c2c(&state->filter_plan, filter, state->filter_fft); - vec_dot_prod_ccc(state->input_fft,state->filter_fft,state->output_fft,state->output_len); + vec_prod_ccc(state->input_fft,state->filter_fft,state->output_fft,state->output_len); dft_run_c2c(&state->output_plan, state->output_fft, output); diff --git a/lte/lib/utils/src/debug.c b/lte/lib/utils/src/debug.c new file mode 100644 index 000000000..5f33ee0b0 --- /dev/null +++ b/lte/lib/utils/src/debug.c @@ -0,0 +1,40 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 "lte/utils/debug.h" + +int verbose = 0; + +void get_time_interval(struct timeval * tdata) { + + tdata[0].tv_sec = tdata[2].tv_sec - tdata[1].tv_sec; + tdata[0].tv_usec = tdata[2].tv_usec - tdata[1].tv_usec; + if (tdata[0].tv_usec < 0) { + tdata[0].tv_sec--; + tdata[0].tv_usec += 1000000; + } +} diff --git a/lib/utils/src/dft.c b/lte/lib/utils/src/dft.c similarity index 89% rename from lib/utils/src/dft.c rename to lte/lib/utils/src/dft.c index 682d6cd02..4434b8abc 100644 --- a/lib/utils/src/dft.c +++ b/lte/lib/utils/src/dft.c @@ -1,27 +1,37 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * \section COPYRIGHT * - * OSLD-lib is distributed in the hope that it will be useful, + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 #include #include #include -#include "utils/dft.h" +#include "lte/utils/dft.h" #define div(a,b) ((a-1)/b+1) @@ -177,6 +187,7 @@ void dft_run_c2c(dft_plan_t *plan, dft_c_t *in, dft_c_t *out) { fftwf_execute(plan->p); if (plan->options & DFT_NORMALIZE) { + /**FIXME: Use VOLK */ norm = sqrtf(plan->size); for (i=0;isize;i++) { f_out[i] /= norm; diff --git a/lib/utils/src/matrix.c b/lte/lib/utils/src/matrix.c similarity index 75% rename from lib/utils/src/matrix.c rename to lte/lib/utils/src/matrix.c index 4c33f6725..735edc9d0 100644 --- a/lib/utils/src/matrix.c +++ b/lte/lib/utils/src/matrix.c @@ -1,28 +1,38 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * \section COPYRIGHT * - * OSLD-lib is distributed in the hope that it will be useful, + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 #include #include #include -#include "utils/matrix.h" +#include "lte/utils/matrix.h" int matrix_init(void ***q, int sz_x, int sz_y, int elem_sz) { int i; diff --git a/lib/utils/src/mux.c b/lte/lib/utils/src/mux.c similarity index 71% rename from lib/utils/src/mux.c rename to lte/lib/utils/src/mux.c index af3595e11..1d6fc83dd 100644 --- a/lib/utils/src/mux.c +++ b/lte/lib/utils/src/mux.c @@ -1,23 +1,33 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This file is part of the libLTE library. * - * OSLD-lib is distributed in the hope that it will be useful, + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 /** diff --git a/lib/utils/src/pack.c b/lte/lib/utils/src/pack.c similarity index 50% rename from lib/utils/src/pack.c rename to lte/lib/utils/src/pack.c index c9456c5c1..dfa8a7e69 100644 --- a/lib/utils/src/pack.c +++ b/lte/lib/utils/src/pack.c @@ -1,22 +1,32 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * \section COPYRIGHT * - * OSLD-lib is distributed in the hope that it will be useful, + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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/. + * */ + void pack_bits(unsigned int value, char **bits, int nof_bits) { int i; diff --git a/lib/utils/src/vector.c b/lte/lib/utils/src/vector.c similarity index 63% rename from lib/utils/src/vector.c rename to lte/lib/utils/src/vector.c index a2c49c16f..1fb0c55fe 100644 --- a/lib/utils/src/vector.c +++ b/lte/lib/utils/src/vector.c @@ -1,28 +1,36 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib) +/** * - * OSLD-lib is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * \section COPYRIGHT * - * OSLD-lib is distributed in the hope that it will be useful, + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with OSLD-lib. If not, see . + * A copy of the GNU Lesser 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 "utils/vector.h" + +#include "lte/utils/vector.h" #include #include #include -//#define HAVE_VOLK - #ifdef HAVE_VOLK #include "volk/volk.h" #endif @@ -46,7 +54,7 @@ float vec_acc_ff(float *x, int len) { return z; #else float result; - volk_32f_accumulator_s32f_a(&result,x,(unsigned int) len); + volk_32f_accumulator_s32f_u(&result,x,(unsigned int) len); return result; #endif } @@ -84,7 +92,7 @@ void vec_sc_prod_cfc(cf_t *x, float h, cf_t *z, int len) { cf_t hh; __real__ hh = h; __imag__ hh = 0; - volk_32fc_s32fc_multiply_32fc_a(z,x,hh,(unsigned int) len); + volk_32fc_s32fc_multiply_32fc_u(z,x,hh,(unsigned int) len); #endif } @@ -95,7 +103,7 @@ void vec_sc_prod_ccc(cf_t *x, cf_t h, cf_t *z, int len) { z[i] = x[i]*h; } #else - volk_32fc_s32fc_multiply_32fc_a(z,x,h,(unsigned int) len); + volk_32fc_s32fc_multiply_32fc_u(z,x,h,(unsigned int) len); #endif } @@ -130,13 +138,20 @@ void vec_fprint_f(FILE *stream, float *x, int len) { fprintf(stream, "["); for (i=0;i clip) + tmp = clip; + out[i] = (unsigned char) tmp; + } + +} diff --git a/matlab/chest/get_ce.m b/matlab/chest/get_ce.m deleted file mode 100644 index 48221c75b..000000000 --- a/matlab/chest/get_ce.m +++ /dev/null @@ -1,230 +0,0 @@ -function [ symb, ce ] = get_ce( samps, N_sf, N_id_cell, N_ant ) - - N_sc_rb = 12; % Only dealing with normal cp at this time - N_rb_dl_max = 110; - v_shift = mod(N_id_cell, 6); - sf_start_idx = f_start_idx + N_sf*30720; - crs0 = lte_generate_crs(mod(N_sf*2+0, 20), 0, N_id_cell); - crs1 = lte_generate_crs(mod(N_sf*2+0, 20), 1, N_id_cell); - crs4 = lte_generate_crs(mod(N_sf*2+0, 20), 4, N_id_cell); - crs7 = lte_generate_crs(mod(N_sf*2+1, 20), 0, N_id_cell); - crs8 = lte_generate_crs(mod(N_sf*2+1, 20), 1, N_id_cell); - crs11 = lte_generate_crs(mod(N_sf*2+1, 20), 4, N_id_cell); - crs14 = lte_generate_crs(mod(N_sf*2+2, 20), 0, N_id_cell); - crs15 = lte_generate_crs(mod(N_sf*2+2, 20), 1, N_id_cell); - - N_rb_dl = 6; - FFT_pad_size = 988; % FFT_size = 2048 - - for(n=0:15) - if(n < 7) - idx = sf_start_idx; - elseif(n < 14) - idx = sf_start_idx + 15360; - else - idx = sf_start_idx + 2*15360; - end - symb(n+1,:) = samps_to_symbs(samps, idx, mod(n,7), FFT_pad_size, 0); - end - - for(p=0:N_ant-1) - % Define v, crs, sym, and N_sym - if(p == 0) - v = [0, 3, 0, 3, 0]; - crs = [crs0; crs4; crs7; crs11; crs14]; - sym = [symb(0+1,:); symb(4+1,:); symb(7+1,:); symb(11+1,:); symb(14+1,:)]; - N_sym = 5; - elseif(p == 1) - v = [3, 0, 3, 0, 3]; - crs = [crs0; crs4; crs7; crs11; crs14]; - sym = [symb(0+1,:); symb(4+1,:); symb(7+1,:); symb(11+1,:); symb(14+1,:)]; - N_sym = 5; - elseif(p == 2) - v = [0, 3, 0]; - crs = [crs1; crs8; crs15]; - sym = [symb(1+1,:); symb(8+1,:); symb(15+1,:)]; - N_sym = 3; - else % p == 3 - v = [3, 6, 3]; - crs = [crs1; crs8; crs15]; - sym = [symb(1+1,:); symb(8+1,:); symb(15+1,:)]; - N_sym = 3; - end - - for(n=1:N_sym) - for(m=0:2*N_rb_dl-1) - k = 6*m + mod((v(n) + v_shift), 6); - m_prime = m + N_rb_dl_max - N_rb_dl; - tmp = sym(n,k+1)/crs(n,m_prime+1); - mag(n,k+1) = abs(tmp); - ang(n,k+1) = angle(tmp); - - % Unwrap phase - if(m > 0) - while((ang(n,k+1) - ang(n,k-6+1)) > pi) - ang(n,k+1) = ang(n,k+1) - 2*pi; - end - while((ang(n,k+1) - ang(n,k-6+1)) < -pi) - ang(n,k+1) = ang(n,k+1) + 2*pi; - end - end - - % Interpolate between CRSs (simple linear interpolation) - if(m > 0) - frac_mag = (mag(n,k+1) - mag(n,k-6+1))/6; - frac_ang = (ang(n,k+1) - ang(n,k-6+1))/6; - for(o=1:5) - mag(n,k-o+1) = mag(n,k-(o-1)+1) - frac_mag; - ang(n,k-o+1) = ang(n,k-(o-1)+1) - frac_ang; - end - end - - % Interpolate before 1st CRS - if(m == 1) - for(o=1:mod(v(n) + v_shift, 6)) - mag(n,k-6-o+1) = mag(n,k-6-(o-1)+1) - frac_mag; - ang(n,k-6-o+1) = ang(n,k-6-(o-1)+1) - frac_ang; - end - end - end - - % Interpolate after last CRS - for(o=1:(5-mod(v(n) + v_shift, 6))) - mag(n,k+o+1) = mag(n,k+(o-1)+1) - frac_mag; - ang(n,k+o+1) = ang(n,k+(o-1)+1) - frac_ang; - end - end - - % Interpolate between symbols and construct channel estimates - if(N_sym == 3) - for(n=1:N_sc_rb*N_rb_dl) - % Construct symbol 1 and 8 channel estimates directly - ce(p+1,1+1,n) = mag(1,n)*(cos(ang(1,n)) + j*sin(ang(1,n))); - ce(p+1,8+1,n) = mag(2,n)*(cos(ang(2,n)) + j*sin(ang(2,n))); - - % Interpolate for symbol 2, 3, 4, 5, 6, and 7 channel estimates - frac_mag = (mag(2,n) - mag(1,n))/7; - frac_ang = ang(2,n) - ang(1,n); - if(frac_ang >= pi) % Wrap angle - frac_ang = frac_ang - 2*pi; - elseif(frac_ang <= -pi) - frac_ang = frac_ang + 2*pi; - end - frac_ang = frac_ang/7; - ce_mag = mag(2,n); - ce_ang = ang(2,n); - for(o=7:-1:2) - ce_mag = ce_mag - frac_mag; - ce_ang = ce_ang - frac_ang; - ce(p+1,o+1,n) = ce_mag*(cos(ce_ang) + j*sin(ce_ang)); - end - - % Interpolate for symbol 0 channel estimate - % FIXME: Use previous slot to do this correctly - ce_mag = mag(1,n) - frac_mag; - ce_ang = ang(1,n) - frac_ang; - ce(p+1,0+1,n) = ce_mag*(cos(ce_ang) + j*sin(ce_ang)); - - % Interpolate for symbol 9, 10, 11, 12, and 13 channel estimates - frac_mag = (mag(3,n) - mag(2,n))/7; - frac_ang = ang(3,n) - ang(2,n); - if(frac_ang >= pi) % Wrap angle - frac_ang = frac_ang - 2*pi; - elseif(frac_ang <= -pi) - frac_ang = frac_ang + 2*pi; - end - frac_ang = frac_ang/7; - ce_mag = mag(3,n) - frac_mag; - ce_ang = ang(3,n) - frac_ang; - for(o=13:-1:9) - ce_mag = ce_mag - frac_mag; - ce_ang = ce_ang - frac_ang; - ce(p+1,o+1,n) = ce_mag*(cos(ce_ang) + j*sin(ce_ang)); - end - end - else - for(n=1:N_sc_rb*N_rb_dl) - % Construct symbol 0, 4, 7, and 11 channel estimates directly - ce(p+1,0+1,n) = mag(1,n)*(cos(ang(1,n)) + j*sin(ang(1,n))); - ce(p+1,4+1,n) = mag(2,n)*(cos(ang(2,n)) + j*sin(ang(2,n))); - ce(p+1,7+1,n) = mag(3,n)*(cos(ang(3,n)) + j*sin(ang(3,n))); - ce(p+1,11+1,n) = mag(4,n)*(cos(ang(4,n)) + j*sin(ang(4,n))); - - % Interpolate for symbol 1, 2, and 3 channel estimates - frac_mag = (mag(2,n) - mag(1,n))/4; - frac_ang = ang(2,n) - ang(1,n); - if(frac_ang >= pi) % Wrap angle - frac_ang = frac_ang - 2*pi; - elseif(frac_ang <= -pi) - frac_ang = frac_ang + 2*pi; - end - frac_ang = frac_ang/4; - ce_mag = mag(2,n); - ce_ang = ang(2,n); - for(o=3:-1:1) - ce_mag = ce_mag - frac_mag; - ce_ang = ce_ang - frac_ang; - ce(p+1,o+1,n) = ce_mag*(cos(ce_ang) + j*sin(ce_ang)); - end - - % Interpolate for symbol 5 and 6 channel estimates - frac_mag = (mag(3,n) - mag(2,n))/3; - frac_ang = ang(3,n) - ang(2,n); - if(frac_ang >= pi) % Wrap angle - frac_ang = frac_ang - 2*pi; - elseif(frac_ang <= -pi) - frac_ang = frac_ang + 2*pi; - end - frac_ang = frac_ang/3; - ce_mag = mag(3,n); - ce_ang = ang(3,n); - for(o=6:-1:5) - ce_mag = ce_mag - frac_mag; - ce_ang = ce_ang - frac_ang; - ce(p+1,o+1,n) = ce_mag*(cos(ce_ang) + j*sin(ce_ang)); - end - - % Interpolate for symbol 8, 9, and 10 channel estimates - frac_mag = (mag(4,n) - mag(3,n))/4; - frac_ang = ang(4,n) - ang(3,n); - if(frac_ang >= pi) % Wrap angle - frac_ang = frac_ang - 2*pi; - elseif(frac_ang <= -pi) - frac_ang = frac_ang + 2*pi; - end - frac_ang = frac_ang/4; - ce_mag = mag(4,n); - ce_ang = ang(4,n); - for(o=10:-1:8) - ce_mag = ce_mag - frac_mag; - ce_ang = ce_ang - frac_ang; - ce(p+1,o+1,n) = ce_mag*(cos(ce_ang) + j*sin(ce_ang)); - end - - % Interpolate for symbol 12 and 13 channel estimates - frac_mag = (mag(5,n) - mag(4,n))/3; - frac_ang = ang(5,n) - ang(4,n); - if(frac_ang >= pi) % Wrap angle - frac_ang = frac_ang - 2*pi; - elseif(frac_ang <= -pi) - frac_ang = frac_ang + 2*pi; - end - - - frac_ang = frac_ang/3; - ce_mag = mag(5,n); - ce_ang = ang(5,n); - for(o=13:-1:12) - ce_mag = ce_mag - frac_mag; - ce_ang = ce_ang - frac_ang; - ce(p+1,o+1,n) = ce_mag*(cos(ce_ang) + j*sin(ce_ang)); - end - end - end - end - subplot(1,2,1) - pcolor(transpose(abs(reshape(ce(1,:,:),14,[])))) - subplot(1,2,2) - pcolor(transpose(real(symb(:,:)))) -end - diff --git a/matlab/chest/lte_generate_crs.m b/matlab/chest/lte_generate_crs.m deleted file mode 100644 index 371fa6c6d..000000000 --- a/matlab/chest/lte_generate_crs.m +++ /dev/null @@ -1,15 +0,0 @@ -function [r] = lte_generate_crs(ns, l, cell_id) - - % Calculate c_init and sequence length - N_cp = 1; - c_init = 1024 * (7 * (ns+1) + l + 1) * (2 * cell_id + 1) + 2*cell_id + N_cp; - - % Generate the psuedo random sequence c - c = lte_generate_prs_c(c_init, 220); - - % Construct r - r = zeros(1,len); - for(m=0:len-1) - r(m+1) = (1/sqrt(2))*(1 - 2*c(2*m+1)) + j*(1/sqrt(2))*(1 - 2*c(2*m+1+1)); - end -end diff --git a/matlab/chest/lte_generate_prs_c.m b/matlab/chest/lte_generate_prs_c.m deleted file mode 100644 index e1e192117..000000000 --- a/matlab/chest/lte_generate_prs_c.m +++ /dev/null @@ -1,23 +0,0 @@ - -function [c] = lte_generate_prs_c(c_init, seq_len) - % Initialize the m-sequences - x1 = zeros(1,1600+seq_len); - x2 = zeros(1,1600+seq_len); - tmp = c_init; - for(n=0:30) - x2(30-n+1) = floor(tmp/(2^(30-n))); - tmp = tmp - (floor(tmp/(2^(30-n)))*2^(30-n)); - end - x1(0+1) = 1; - - % Advance m-sequences - for(n=0:1600+seq_len) - x1(n+31+1) = mod(x1(n+3+1) + x1(n+1), 2); - x2(n+31+1) = mod(x2(n+3+1) + x2(n+2+1) + x2(n+1+1) + x2(n+1), 2); - end - - % Generate c - for(n=0:seq_len-1) - c(n+1) = mod(x1(n+1600+1) + x2(n+1600+1), 2); - end -end diff --git a/matlab/chest/samps_to_symbs.m b/matlab/chest/samps_to_symbs.m deleted file mode 100644 index f8f1320b1..000000000 --- a/matlab/chest/samps_to_symbs.m +++ /dev/null @@ -1,26 +0,0 @@ -function [symbs] = samps_to_symbs(samps, slot_start_idx, symb_offset, FFT_pad_size, scale) - % Calculate index and CP length - if(mod(symb_offset, 7) == 0) - CP_len = 160; - else - CP_len = 144; - end - index = slot_start_idx + (2048+144)*symb_offset; - if(symb_offset > 0) - index = index + 16; - end - - % Take FFT - tmp = fftshift(fft(samps(index+CP_len:index+CP_len+2047))); - - % Remove DC subcarrier - tmp_symbs = [tmp(FFT_pad_size+1:1024); tmp(1026:2048-(FFT_pad_size-1))]; - - if(scale == 0) - symbs = tmp_symbs; - else - for(n=1:length(tmp_symbs)) - symbs(n) = cos(angle(tmp_symbs(n))) + j*sin(angle(tmp_symbs(n))); - end - end -end \ No newline at end of file diff --git a/matlab/rate_algorithm.m b/matlab/rate_algorithm.m new file mode 100644 index 000000000..0edd42697 --- /dev/null +++ b/matlab/rate_algorithm.m @@ -0,0 +1,20 @@ +F=100000./(1:100); +PQ=(1:50); + +PRB=50; +Mmax=1024; +N=PRB*12; + +Fmin=N*15*1.1; +Fs=F(F>Fmin); + +for i=length(Fs):-1:1 + for p=PQ + for q=PQ + if (mod(p/q*Fs(i),15)==0 && p/q*Fs(i)/15 - -/* Low-level API */ -typedef struct { - unsigned int seed; - uint32_t *seq_buff; - int seq_buff_nwords; - int seq_cache_nbits; - int seq_cache_rp; -}binsource_t; - -void binsource_init(binsource_t* q); -void binsource_destroy(binsource_t* q); -void binsource_seed_set(binsource_t* q, unsigned int seed); -void binsource_seed_time(binsource_t *q); -int binsource_cache_gen(binsource_t* q, int nbits); -void binsource_cache_cpy(binsource_t* q, uint8_t *bits, int nbits); -int binsource_generate(binsource_t* q, uint8_t *bits, int nbits); - - -/* High-level API */ -typedef struct { - binsource_t obj; - struct binsource_init { - int cache_seq_nbits; /* default=2 */ - int seed; - } init; - struct binsource_ctrl_in { - int nbits; - } ctrl_in; - uint8_t* output[2]; /* size=2048*14 */ - int* out_len; -}binsource_hl; - -int binsource_initialize(binsource_hl* h); -int binsource_work( binsource_hl* hl); diff --git a/scripts/lib_binsource/CMakeLists.txt b/scripts/lib_binsource/CMakeLists.txt deleted file mode 100644 index 40fd36b4a..000000000 --- a/scripts/lib_binsource/CMakeLists.txt +++ /dev/null @@ -1,94 +0,0 @@ -# This configuration is for the aloe++ skeleton - -# set-up the program libraries here -set(LIBRARIES m rt osld) - -# set-up program includes here -include_directories(/usr/local/include/) - -############## DO NOT NEED TO MODIFY BEYOND HERE - -get_filename_component(module ${CMAKE_CURRENT_SOURCE_DIR} NAME) - -if( CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR ) - cmake_minimum_required (VERSION 2.6) - project (${module}) - - # The version number. - set (OECORE_VERSION_MAJOR 1) - set (OECORE_VERSION_MINOR 0) - set(MODULE_REPOS_NAME "default") - -else() - include_directories(${OESR_INCLUDE}) -endif() - - -file(GLOB_RECURSE SOURCES "src/*.c") -file(GLOB_RECURSE TEST_SOURCES "test/*.c") - -include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src) - -# aloe module -add_library(${module}-aloe SHARED ${SOURCES}) -set_target_properties(${module}-aloe PROPERTIES OUTPUT_NAME ${module}) -set_target_properties(${module}-aloe PROPERTIES COMPILE_FLAGS "-D_COMPILE_ALOE") -target_link_libraries(${module}-aloe oesrapi skeleton ${LIBRARIES}) -install(TARGETS ${module}-aloe DESTINATION lib/${MODULE_REPOS_NAME}/) - - -if (NOT ${TEST_SOURCES} STREQUAL "") - # standalone program for testing - add_executable(${module}-bin ${SOURCES} ${TEST_SOURCES}) - set_target_properties(${module}-bin PROPERTIES OUTPUT_NAME ${module}) - set_target_properties(${module}-bin PROPERTIES COMPILE_FLAGS "-D_COMPILE_STANDALONE") - target_link_libraries(${module}-bin standalone ${LIBRARIES}) - install(TARGETS ${module}-bin DESTINATION bin) -endif() - -# octave mex file -set(install_mex "") -if(NOT $ENV{OCTAVE_INCLUDE} STREQUAL "") - if(NOT $ENV{OCTAVE_LIBS} STREQUAL "") - - add_library(${module}-oct SHARED ${SOURCES}) - set_target_properties(${module}-oct PROPERTIES OUTPUT_NAME ${module}) - set_target_properties(${module}-oct PROPERTIES PREFIX "am_") - set_target_properties(${module}-oct PROPERTIES SUFFIX .mex) - - set_target_properties(${module}-oct PROPERTIES COMPILE_FLAGS "-I$ENV{OCTAVE_INCLUDE} -D_COMPILE_MEX -Wl,-Bsymbolic -L$ENV{OCTAVE_LIBS} -loctinterp -loctave -lcruft -Wl,-Bsymbolic-functions -Wl,-z,relro") - target_link_libraries(${module}-oct aloe_octave ${LIBRARIES}) - install(TARGETS ${module}-oct DESTINATION mex) - - endif() -endif() - -#matlab mex -if(NOT $ENV{MATLAB_ROOT} STREQUAL "") - add_library(${module}-mat SHARED ${SOURCES}) - set_target_properties(${module}-mat PROPERTIES OUTPUT_NAME ${module}) - set_target_properties(${module}-mat PROPERTIES PREFIX "am_") - - if(CMAKE_SIZEOF_VOID_P EQUAL 8) - set_target_properties(${module}-mat PROPERTIES SUFFIX .mexa64) - set_target_properties(${module}-mat PROPERTIES COMPILE_FLAGS "-I$ENV{MATLAB_ROOT} -O -pthread -shared -Wl,--version-script,$ENV{MATLAB_ROOT}/extern/lib/glnxa64/mexFunction.map -Wl,--no-undefined -Wl,-rpath-link,$ENV{MATLAB_ROOT}/bin/glnxa64 -L$ENV{MATLAB_ROOT}/bin/glnxa64 -lmx -lmex -lmat -lm -lstdc++") - else() - set_target_properties(${module}-mat PROPERTIES SUFFIX .mexglx) - set_target_properties(${module}-mat PROPERTIES COMPILE_FLAGS "-I$ENV{MATLAB_ROOT} -O -pthread -shared -m32 -Wl,--version-script,$ENV{MATLAB_ROOT}/extern/lib/glnx86/mexFunction.map -Wl,--no-undefined -Wl,-rpath-link,$ENV{MATLAB_ROOT}/bin/glnx86 -L$ENV{MATLAB_ROOT}/bin/glnx86 -lmx -lmex -lmat -lm -lstdc++") - endif() - - target_link_libraries(${module}-mat aloe_matlab ${LIBRARIES}) - install(TARGETS ${module}-mat DESTINATION mex) - -endif() - - - - - - - - - - - diff --git a/scripts/lib_binsource/src/binsource.c b/scripts/lib_binsource/src/binsource.c deleted file mode 100644 index 6fa811ba9..000000000 --- a/scripts/lib_binsource/src/binsource.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * This file has been automatically generated from binsource - */ - -#include -#include -#include -#include - -#include "binsource.h" - -binsource_hl binsource; - -pmid_t nbits_id; - -int out_len[NOF_OUTPUT_ITF]; - -int initialize() { - - /* Initialization Parameters */ - if (param_get_int_name("cache_seq_nbits", &binsource.init.cache_seq_nbits)) { - binsource.init.cache_seq_nbits = 2; - } - if (param_get_int_name("seed", &binsource.init.seed)) { - binsource.init.seed = 0; - } - - /* Input Control Parameters */ - nbits_id = param_id("nbits"); - - /* Initialization function */ - return binsource_initialize(&binsource); -} - - -int work(void **inp, void **out) { - int i,n; -#if NOF_INPUTS>1 - for (i=0;i1 - for (i=0;i - -typedef uint8_t output_t; - -#define INPUT_MAX_SAMPLES 0 -#define OUTPUT_MAX_SAMPLES 2048*14 - -#define NOF_INPUT_ITF 0 -#define NOF_OUTPUT_ITF 2 - -#endif -/**@} */ - -#define GENERATE_COMPLEX - -#ifndef INCLUDE_DEFS_ONLY - -/* Input and output buffer sizes (in number of samples) */ -const int input_max_samples = INPUT_MAX_SAMPLES; -const int output_max_samples = OUTPUT_MAX_SAMPLES; - -/* leave these two lines unmodified */ -const int input_sample_sz = sizeof(input_t); -int output_sample_sz = sizeof(output_t); - -/* Number of I/O interfaces. All have the same maximum size */ -const int nof_input_itf = NOF_INPUT_ITF; -const int nof_output_itf = NOF_OUTPUT_ITF; - -#endif diff --git a/scripts/lib_binsource/test/test_generate.c b/scripts/lib_binsource/test/test_generate.c deleted file mode 100644 index 8a2c6185c..000000000 --- a/scripts/lib_binsource/test/test_generate.c +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2012, Ismael Gomez-Miguelez . - * This file is part of ALOE++ (http://flexnets.upc.edu/) - * - * ALOE++ is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * ALOE++ is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with ALOE++. If not, see . - */ - -/* Functions that generate the test data fed into the DSP modules being developed */ -#include -#include -#include - -#include -#include - -#define INCLUDE_DEFS_ONLY -#include "binsource.h" - -int offset=0; - -/** - * Generates input signal. VERY IMPORTANT to fill length vector with the number of - * samples that have been generated. - * @param inp Input interface buffers. Data from other interfaces is stacked in the buffer. - * Use in(ptr,idx) to access the address. - * - * @param lengths Save on n-th position the number of samples generated for the n-th interface - */ -int generate_input_signal(void *in, int *lengths) -{ - int i; - input_t *input = in; - int block_length; - pmid_t blen_id; - - blen_id = param_id("block_length"); - if (!blen_id) { - moderror("Parameter block_length not found\n"); - return -1; - } - - if (!param_get_int(blen_id,&block_length)) { - moderror("Getting integer parameter block_length\n"); - return -1; - } - - modinfo_msg("Parameter block_length is %d\n",block_length); - - /** HERE INDICATE THE LENGTH OF THE SIGNAL */ - lengths[0] = block_length; - - for (i=0;i" % str(self._lib_) - - def _getFunction(self, funcName): - try: - func = getattr(self._lib_, funcName) - except: - raise Exception("Function name '%s' appears in headers but not in library!" % func) - - #print "create function %s," % (funcName), self._defs_['functions'][funcName] - return CFunction(self, func, self._defs_['functions'][funcName], funcName) - - def _ctype(self, typ, pointers=True): - """return a ctype object representing the named type. - If pointers is True, the class returned includes all pointer/array specs provided. - Otherwise, the class returned is just the base type with no pointers.""" - try: - typ = self._headers_.evalType(typ) - mods = typ[1:][:] - - ## Create the initial type - ## Some types like ['char', '*'] have a specific ctype (c_char_p) - ## (but only do this if pointers == True) - if pointers and len(typ) > 1 and typ[1] == '*' and typ[0] in CLibrary.cPtrTypes: - cls = CLibrary.cPtrTypes[typ[0]] - mods = typ[2:] - - ## If the base type is in the list of existing ctypes: - elif typ[0] in CLibrary.cTypes: - cls = CLibrary.cTypes[typ[0]] - - ## structs, unions, enums: - elif typ[0][:7] == 'struct ': - cls = self._cstruct('structs', self._defs_['types'][typ[0]][1]) - elif typ[0][:6] == 'union ': - cls = self._cstruct('unions', self._defs_['types'][typ[0]][1]) - elif typ[0][:5] == 'enum ': - cls = c_int - - ## void - elif typ[0] == 'void': - cls = None - else: - #print typ - raise Exception("Can't find base type for %s" % str(typ)) - - if not pointers: - return cls - - ## apply pointers and arrays - while len(mods) > 0: - m = mods.pop(0) - if isinstance(m, basestring): ## pointer or reference - if m[0] == '*' or m[0] == '&': - for i in m: - cls = POINTER(cls) - elif type(m) is list: ## array - for i in m: - if i == -1: ## -1 indicates an 'incomplete type' like "int variable[]" - cls = POINTER(cls) ## which we should interpret like "int *variable" - else: - cls = cls * i - elif type(m) is tuple: ## Probably a function pointer - ## Find pointer and calling convention - isPtr = False - conv = '__cdecl' - if len(mods) == 0: - raise Exception("Function signature with no pointer:", m, mods) - for i in [0,1]: - if len(mods) < 1: - break - if mods[0] == '*': - mods.pop(0) - isPtr = True - elif mods[0] in ['__stdcall', '__cdecl']: - conv = mods.pop(0) - else: - break - if not isPtr: - raise Exception("Not sure how to handle type (function without single pointer): %s" % str(typ)) - - if conv == '__stdcall': - mkfn = WINFUNCTYPE - else: - mkfn = CFUNCTYPE - #print "Create function pointer (%s)" % conv - - args = [self._ctype(arg[1]) for arg in m] - cls = mkfn(cls, *args) - - else: - raise Exception("Not sure what to do with this type modifier: '%s'" % str(p)) - return cls - except: - print "Error while processing type", typ - raise - - def _cstruct(self, strType, strName): - if strName not in self._structs_: - - ## Resolve struct name--typedef aliases allowed. - if strName not in self._defs_[strType]: - if strName not in self._defs_['types']: - raise Exception('No struct/union named "%s"' % strName) - typ = self._headers_.evalType([strName])[0] - if typ[:7] != 'struct ' and typ[:6] != 'union ': - raise Exception('No struct/union named "%s"' % strName) - strName = self._defs_['types'][typ][1] - - ## Pull struct definition - defn = self._defs_[strType][strName] - - - ## create ctypes class - defs = defn['members'][:] - if strType == 'structs': - class s(Structure): - def __repr__(self): - return "" % strName - elif strType == 'unions': - class s(Union): - def __repr__(self): - return "" % strName - - - ## must register struct here to allow recursive definitions. - self._structs_[strName] = s - - if defn['pack'] is not None: - s._pack_ = defn['pack'] - - ## assign names to anonymous members - members = [] - anon = [] - for i in range(len(defs)): - if defs[i][0] is None: - c = 0 - while True: - name = 'anon_member%d' % c - if name not in members: - defs[i][0] = name - anon.append(name) - break - members.append(defs[i][0]) - - s._anonymous_ = anon - s._fields_ = [(m[0], self._ctype(m[1])) for m in defs] - s._defaults_ = [m[2] for m in defs] - return self._structs_[strName] - - - -class CFunction: - def __init__(self, lib, func, sig, name): - self.lib = lib - self.func = func - #print sig - self.sig = list(sig) # looks like [return_type, [(argName, type, default), (argName, type, default), ...]] - self.sig[1] = [s for s in sig[1] if s[1] != ['void']] ## remove void args from list - for conv in ['__stdcall', '__cdecl']: - if conv in self.sig[0]: - self.sig[0].remove(conv) - self.name = name - self.restype = lib._ctype(self.sig[0]) - #func.restype = self.restype - self.argTypes = [lib._ctype(s[1]) for s in self.sig[1]] - func.argtypes = self.argTypes - self.reqArgs = [x[0] for x in self.sig[1] if x[2] is None] - self.argInds = dict([(self.sig[1][i][0], i) for i in range(len(self.sig[1]))]) ## mapping from argument names to indices - #print "created func", self, sig, self.argTypes - - def argCType(self, arg): - """Return the ctype required for the specified argument. - arg can be either an integer or the name of the argument. - """ - if isinstance(arg, basestring): - arg = self.argInds[arg] - return self.lib._ctype(self.sig[1][arg][1]) - - def __call__(self, *args, **kwargs): - """Invoke the SO or dll function referenced, converting all arguments to the correct type. - Keyword arguments are allowed as long as the header specifies the argument names. - Arguments which are passed byref may be omitted entirely, and will be automaticaly generated. - To pass a NULL pointer, give None as the argument. - Returns the return value of the function call as well as all of the arguments (so that objects passed by reference can be retrieved)""" - #print "CALL: %s(%s)" % (self.name, ", ".join(map(str, args) + ["%s=%s" % (k, str(kwargs[k])) for k in kwargs])) - #print " sig:", self.sig - argList = [None] * max(len(self.reqArgs), len(args)) ## We'll need at least this many arguments. - - ## First fill in args - for i in range(len(args)): - #argList[i] = self.argTypes[i](args[i]) - if args[i] is None: - argList[i] = self.lib.Null - else: - argList[i] = args[i] - - ## Next fill in kwargs - for k in kwargs: - #print " kw:", k - if k not in self.argInds: - print "Function signature:", self.prettySignature() - raise Exception("Function signature has no argument named '%s'" % k) - ind = self.argInds[k] - if ind >= len(argList): ## stretch argument list if needed - argList += [None] * (ind - len(argList) + 1) - #argList[ind] = self.coerce(kwargs[k], self.argTypes[ind]) - if kwargs[k] is None: - argList[ind] = self.lib.Null - else: - argList[ind] = kwargs[k] - - guessedArgs = [] - ## Finally, fill in remaining arguments if they are pointers to int/float/void*/struct values - ## (we assume these are to be modified by the function and their initial value is not important) - for i in range(len(argList)): - if argList[i] is None or argList[i] is self.lib.Null: - try: - sig = self.sig[1][i][1] - argType = self.lib._headers_.evalType(sig) - if argList[i] is self.lib.Null: ## request to build a null pointer - if len(argType) < 2: - raise Exception("Can not create NULL for non-pointer argument type: %s" % str(argType)) - argList[i] = self.lib._ctype(sig)() - #elif argType == ['char', '*']: ## pass null pointer if none was specified. This is a little dangerous, but some functions will expect it. - #argList[i] = c_char_p() ## On second thought: let's just require the user to explicitly ask for a NULL pointer. - else: - if argType == ['void', '**'] or argType == ['void', '*', '*']: - cls = c_void_p - else: - assert len(argType) == 2 and argType[1] == '*' ## Must be 2-part type, second part must be '*' - cls = self.lib._ctype(sig, pointers=False) - argList[i] = pointer(cls(0)) - guessedArgs.append(i) - except: - if sys.exc_info()[0] is not AssertionError: - raise - #sys.excepthook(*sys.exc_info()) - print "Function signature:", self.prettySignature() - raise Exception("Function call '%s' missing required argument %d '%s'. (See above for signature)" % (self.name, i, self.sig[1][i][0])) - #print " args:", argList - try: - res = self.func(*argList) - except: - print "Function call failed. Signature is:", self.prettySignature() - print "Arguments:", argList - print "Argtypes:", self.func.argtypes - raise - #print " result:", res - - cr = CallResult(res, argList, self.sig, guessed=guessedArgs) - return cr - - def prettySignature(self): - return "%s %s(%s)" % (''.join(self.sig[0]), self.name, ', '.join(["%s %s" % ("".join(map(str, s[1])), s[0]) for s in self.sig[1]])) - -class CallResult: - """Class for bundling results from C function calls. Allows access to the function - return value as well as all of the arguments, since the function call will often return - extra values via these arguments. - - Original ctype objects can be accessed via result.rval or result.args - - Python values carried by these objects can be accessed using () - To access values: - - The return value: () - - The nth argument passed: [n] - - The argument by name: ['name'] - - All values that were auto-generated: .auto() - - The class can also be used as an iterator, so that tuple unpacking is possible: - ret, arg1, arg2 = lib.runSomeFunction(...) - """ - def __init__(self, rval, args, sig, guessed): - self.rval = rval ## return value of function call - self.args = args ## list of arguments to function call - self.sig = sig ## function signature - self.guessed = guessed ## list of arguments that were generated automatically (usually byrefs) - - def __call__(self): - #print "Clibrary:", type(self.rval), self.mkVal(self.rval) - if self.sig[0] == ['void']: - return None - return self.mkVal(self.rval) - - def __getitem__(self, n): - if type(n) is int: - return self.mkVal(self.args[n]) - elif type(n) is str: - ind = self.findArg(n) - return self.mkVal(self.args[ind]) - else: - raise Exception("Index must be int or str.") - - def __setitem__(self, n, val): - if type(n) is int: - self.args[n] = val - elif type(n) is str: - ind = self.findArg(n) - self.args[ind] = val - else: - raise Exception("Index must be int or str.") - - - def mkVal(self, obj): - while not hasattr(obj, 'value'): - if not hasattr(obj, 'contents'): - return obj - try: - obj = obj.contents - except ValueError: - return None - - return obj.value - - - def findArg(self, arg): - for i in range(len(self.sig[1])): - if self.sig[1][i][0] == arg: - return i - raise Exception("Can't find argument '%s' in function signature. Arguments are: %s" % (arg, str([a[0] for a in self.sig[1]]))) - - def __iter__(self): - yield self() - for i in range(len(self.args)): - yield(self[i]) - - def auto(self): - return [self[n] for n in self.guessed] - - - - - diff --git a/scripts/pyclibrary/CParser.py b/scripts/pyclibrary/CParser.py deleted file mode 100644 index df2b4dea6..000000000 --- a/scripts/pyclibrary/CParser.py +++ /dev/null @@ -1,1274 +0,0 @@ -# -*- coding: utf-8 -*- -""" -CParser.py - C parsing library -Copyright 2010 Luke Campagnola -Distributed under MIT/X11 license. See license.txt for more infomation. - -Used for extracting data such as macro definitions, variables, typedefs, and function -signatures from C files (preferrably header files). -""" - -import sys, re, os - -__all__ = ['winDefs', 'CParser'] - - -def winDefs(verbose=False): - """Convenience function. Returns a parser which loads a selection of windows headers included with - CParser. These definitions can either be accessed directly or included before parsing - another file like this: - windefs = CParser.winDefs() - p = CParser.CParser("headerFile.h", copyFrom=windefs) - Definitions are pulled from a selection of header files included in Visual Studio - (possibly not legal to distribute? Who knows.), some of which have been abridged - because they take so long to parse. - """ - headerFiles = ['WinNt.h', 'WinDef.h', 'WinBase.h', 'BaseTsd.h', 'WTypes.h', 'WinUser.h'] - d = os.path.dirname(__file__) - p = CParser( - [os.path.join(d, 'headers', h) for h in headerFiles], - types={'__int64': ('long long')}, - macros={'_WIN32': '', '_MSC_VER': '800', 'CONST': 'const', 'NO_STRICT': None}, - processAll=False - ) - p.processAll(cache=os.path.join(d, 'headers', 'WinDefs.cache'), noCacheWarning=True, verbose=verbose) - return p - - -class CParser(): - """Class for parsing C code to extract variable, struct, enum, and function declarations as well as preprocessor macros. This is not a complete C parser; instead, it is meant to simplify the process - of extracting definitions from header files in the absence of a complete build system. Many files - will require some amount of manual intervention to parse properly (see 'replace' and extra arguments - to __init__) - - Usage: - ## create parser object, load two files - p = CParser(['header1.h', 'header2.h']) - - ## remove comments, preprocess, and search for declarations - p.processAll() - - ## just to see what was successfully parsed from the files - p.printAll() - - ## access parsed declarations - allValues = p.defs['values'] - functionSignatures = p.defs['functions'] - ... - - ## To see what was not successfully parsed: - unp = p.processAll(returnUnparsed=True) - for s in unp: - print s - """ - - cacheVersion = 22 ## increment every time cache structure or parsing changes to invalidate old cache files. - - def __init__(self, files=None, replace=None, copyFrom=None, processAll=True, cache=None, verbose=False, **args): - """Create a C parser object fiven a file or list of files. Files are read to memory and operated - on from there. - 'copyFrom' may be another CParser object from which definitions should be copied. - 'replace' may be specified to perform string replacements before parsing. - format is {'searchStr': 'replaceStr', ...} - Extra parameters may be used to specify the starting state of the parser. For example, - one could provide a set of missing type declarations by - types={'UINT': ('unsigned int'), 'STRING': ('char', 1)} - Similarly, preprocessor macros can be specified: - macros={'WINAPI': ''} - """ - - - self.defs = {} ## holds all definitions - self.fileDefs = {} ## holds definitions grouped by the file they came from - - self.initOpts = args.copy() - self.initOpts['files'] = [] - self.initOpts['replace'] = {} - - self.dataList = ['types', 'variables', 'fnmacros', 'macros', 'structs', 'unions', 'enums', 'functions', 'values'] - - self.verbose = False - - # placeholders for definitions that change during parsing - #if hasPyParsing: - #self.macroExpr = Forward() - #self.fnMacroExpr = Forward() - #self.definedType = Forward() - #self.definedStruct = Forward() - #self.definedEnum = Forward() - - self.fileOrder = [] - self.files = {} - self.packList = {} ## list describing struct packing rules as defined by #pragma pack - if files is not None: - if type(files) is str: - files = [files] - for f in files: - self.loadFile(f, replace) - - ## initialize empty definition lists - for k in self.dataList: - self.defs[k] = {} - #for f in files: - #self.fileDefs[f][k] = {} - - self.compiledTypes = {} ## holds translations from typedefs/structs/unions to fundamental types - - self.currentFile = None - - # Import extra arguments if specified - for t in args: - for k in args[t].keys(): - self.addDef(t, k, args[t][k]) - - # Import from other CParsers if specified - if copyFrom is not None: - if type(copyFrom) not in [list, tuple]: - copyFrom = [copyFrom] - for p in copyFrom: - self.importDict(p.fileDefs) - - if processAll: - self.processAll(cache=cache, verbose=verbose) - - def processAll(self, cache=None, returnUnparsed=False, printAfterPreprocess=False, noCacheWarning=True, verbose=False): - """Remove comments, preprocess, and parse declarations from all files. (operates in memory; does not alter the original files) - Returns a list of the results from parseDefs. - 'cache' may specify a file where cached results are be stored or retrieved. The cache - is automatically invalidated if any of the arguments to __init__ are changed, or if the - C files are newer than the cache. - 'returnUnparsed' is passed directly to parseDefs. - 'printAfterPreprocess' is for debugging; prints the result of preprocessing each file.""" - self.verbose = verbose - if cache is not None and self.loadCache(cache, checkValidity=True): - if verbose: - print "Loaded cached definitions; will skip parsing." - return ## cached values loaded successfully, nothing left to do here - #else: - #print "No cache.", cache - - - results = [] - if noCacheWarning or verbose: - print "Parsing C header files (no valid cache found). This could take several minutes..." - for f in self.fileOrder: - #fn = os.path.basename(f) - if self.files[f] is None: - ## This means the file could not be loaded and there was no cache. - raise Exception('Could not find header file "%s" or a suitable cache file.' % f) - if verbose: - print "Removing comments from file '%s'..." % f - self.removeComments(f) - if verbose: - print "Preprocessing file '%s'..." % f - self.preprocess(f) - if printAfterPreprocess: - print "===== PREPROCSSED %s =======" % f - print self.files[f] - if verbose: - print "Parsing definitions in file '%s'..." % f - results.append(self.parseDefs(f, returnUnparsed)) - - if cache is not None: - if verbose: - print "Writing cache file '%s'" % cache - self.writeCache(cache) - - return results - - - def loadCache(self, cacheFile, checkValidity=False): - """Load a cache file. Used internally if cache is specified in processAll(). - if checkValidity=True, then run several checks before loading the cache: - - cache file must not be older than any source files - - cache file must not be older than this library file - - options recorded in cache must match options used to initialize CParser""" - - ## make sure cache file exists - if type(cacheFile) is not str: - raise Exception("cache file option must be a string.") - if not os.path.isfile(cacheFile): - d = os.path.dirname(__file__) ## If file doesn't exist, search for it in this module's path - cacheFile = os.path.join(d, "headers", cacheFile) - if not os.path.isfile(cacheFile): - if self.verbose: - print "Can't find requested cache file." - return False - - ## make sure cache is newer than all input files - if checkValidity: - mtime = os.stat(cacheFile).st_mtime - for f in self.fileOrder: - ## if file does not exist, then it does not count against the validity of the cache. - if os.path.isfile(f) and os.stat(f).st_mtime > mtime: - if self.verbose: - print "Cache file is out of date." - return False - - try: - ## read cache file - import pickle - cache = pickle.load(open(cacheFile, 'rb')) - - ## make sure __init__ options match - if checkValidity: - if cache['opts'] != self.initOpts: - if self.verbose: - print "Cache file is not valid--created using different initialization options." - print cache['opts'] - print self.initOpts - return False - elif self.verbose: - print "Cache init opts are OK:" - print cache['opts'] - if cache['version'] < self.cacheVersion: - if self.verbose: - print "Cache file is not valid--cache format has changed." - return False - - ## import all parse results - self.importDict(cache['fileDefs']) - return True - except: - print "Warning--cache read failed:" - sys.excepthook(*sys.exc_info()) - return False - - def importDict(self, data): - """Import definitions from a dictionary. The dict format should be the - same as CParser.fileDefs. Used internally; does not need to be called - manually.""" - for f in data.keys(): - self.currentFile = f - for k in self.dataList: - for n in data[f][k]: - self.addDef(k, n, data[f][k][n]) - - def writeCache(self, cacheFile): - """Store all parsed declarations to cache. Used internally.""" - cache = {} - cache['opts'] = self.initOpts - cache['fileDefs'] = self.fileDefs - cache['version'] = self.cacheVersion - #for k in self.dataList: - #cache[k] = getattr(self, k) - import pickle - pickle.dump(cache, open(cacheFile, 'wb')) - - def loadFile(self, file, replace=None): - """Read a file, make replacements if requested. Called by __init__, should - not be called manually.""" - if not os.path.isfile(file): - ## Not a fatal error since we might be able to function properly if there is a cache file.. - #raise Exception("File %s not found" % file) - print "Warning: C header '%s' is missing; this may cause trouble." % file - self.files[file] = None - return False - - fd = open(file, 'rU') ## U causes all newline types to be converted to \n - self.files[file] = fd.read() - fd.close() - - if replace is not None: - for s in replace: - self.files[file] = re.sub(s, replace[s], self.files[file]) - self.fileOrder.append(file) - bn = os.path.basename(file) - self.initOpts['replace'][bn] = replace - self.initOpts['files'].append(bn) # only interested in the file names; the directory may change between systems. - return True - - - - - - #### Beginning of processing functions - - def assertPyparsing(self): - """Make sure pyparsing module is available.""" - global hasPyParsing - if not hasPyParsing: - raise Exception("CParser class requires 'pyparsing' library for actual parsing work. Without this library, CParser can only be used with previously cached parse results.") - - - def removeComments(self, file): - """Remove all comments from file. (operates in memory; does not alter the original files)""" - self.assertPyparsing() - text = self.files[file] - cplusplusLineComment = Literal("//") + restOfLine - # match quoted strings first to prevent matching comments inside quotes - self.files[file] = (quotedString | cStyleComment.suppress() | cplusplusLineComment.suppress()).transformString(text) - - - def preprocess(self, file): - """Scan named file for preprocessor directives, removing them while expanding macros. (operates in memory; does not alter the original files)""" - self.assertPyparsing() - self.buildParser() ## we need this so that evalExpr works properly - self.currentFile = file - packStack = [(None,None)] ## stack for #pragma pack push/pop - self.packList[file] = [(0,None)] - packing = None ## current packing value - - text = self.files[file] - - ## First join together lines split by \\n - text = Literal('\\\n').suppress().transformString(text) - - #self.ppDirective = Combine("#" + Word(alphas).leaveWhitespace()) + restOfLine - - # define the structure of a macro definition - name = Word(alphas+'_', alphanums+'_')('name') - self.ppDefine = name.setWhitespaceChars(' \t')("macro") + Optional(lparen + delimitedList(name) + rparen).setWhitespaceChars(' \t')('args') + SkipTo(LineEnd())('value') - self.ppDefine.setParseAction(self.processMacroDefn) - - #self.updateMacroDefns() - #self.updateFnMacroDefns() - - # define pattern for scanning through the input string - #self.macroExpander = (self.macroExpr | self.fnMacroExpr) - - ## Comb through lines, process all directives - lines = text.split('\n') - - result = [] - #macroExpander = (quotedString | self.macroExpander) - directive = re.compile(r'\s*#([a-zA-Z]+)(.*)$') - ifTrue = [True] - ifHit = [] - for i in range(len(lines)): - line = lines[i] - newLine = '' - m = directive.match(line) - if m is None: # regular code line - if ifTrue[-1]: # only include if we are inside the correct section of an IF block - #line = macroExpander.transformString(line) # expand all known macros - newLine = self.expandMacros(line) - else: # macro line - d = m.groups()[0] - rest = m.groups()[1] - - #print "PREPROCESS:", d, rest - if d == 'ifdef': - d = 'if' - rest = 'defined '+rest - elif d == 'ifndef': - d = 'if' - rest = '!defined '+rest - - ## Evaluate 'defined' operator before expanding macros - if d in ['if', 'elif']: - def pa(t): - return ['0', '1'][t['name'] in self.defs['macros'] or t['name'] in self.defs['fnmacros']] - rest = ( - Keyword('defined') + - (name | lparen + name + rparen) - ).setParseAction(pa).transformString(rest) - elif d in ['define', 'undef']: - macroName, rest = re.match(r'\s*([a-zA-Z_][a-zA-Z0-9_]*)(.*)$', rest).groups() - - ## Expand macros if needed - if rest is not None and (all(ifTrue) or d in ['if', 'elif']): - rest = self.expandMacros(rest) - - if d == 'elif': - if ifHit[-1] or not all(ifTrue[:-1]): - ev = False - else: - ev = self.evalPreprocessorExpr(rest) - if self.verbose: - print " "*(len(ifTrue)-2) + line, rest, ev - ifTrue[-1] = ev - ifHit[-1] = ifHit[-1] or ev - elif d == 'else': - if self.verbose: - print " "*(len(ifTrue)-2) + line, not ifHit[-1] - ifTrue[-1] = (not ifHit[-1]) and all(ifTrue[:-1]) - ifHit[-1] = True - elif d == 'endif': - ifTrue.pop() - ifHit.pop() - if self.verbose: - print " "*(len(ifTrue)-1) + line - elif d == 'if': - if all(ifTrue): - ev = self.evalPreprocessorExpr(rest) - else: - ev = False - if self.verbose: - print " "*(len(ifTrue)-1) + line, rest, ev - ifTrue.append(ev) - ifHit.append(ev) - elif d == 'define': - if not ifTrue[-1]: - continue - if self.verbose: - print " "*(len(ifTrue)) + "define:", macroName, rest - try: - self.ppDefine.parseString(macroName+ ' ' + rest) ## macro is registered here - except: - print "Error processing macro definition:", macroName, rest - print " ", sys.exc_info()[1] - elif d == 'undef': - if not ifTrue[-1]: - continue - try: - self.remDef('macros', macroName.strip()) - #self.macroListString = '|'.join(self.defs['macros'].keys() + self.defs['fnmacros'].keys()) - #self.updateMacroDefns() - except: - if sys.exc_info()[0] is not KeyError: - sys.excepthook(*sys.exc_info()) - print "Error removing macro definition '%s'" % macroName.strip() - elif d == 'pragma': ## Check for changes in structure packing - if not ifTrue[-1]: - continue - m = re.match(r'\s+pack\s*\(([^\)]+)\)', rest) - if m is None: - continue - opts = [s.strip() for s in m.groups()[0].split(',')] - - pushpop = id = val = None - for o in opts: - if o in ['push', 'pop']: - pushpop = o - elif o.isdigit(): - val = int(o) - else: - id = o - - if val is not None: - packing = val - - if pushpop == 'push': - packStack.append((packing, id)) - elif opts[0] == 'pop': - if id is None: - packStack.pop() - else: - ind = None - for i in range(len(packStack)): - if packStack[i][1] == id: - ind = i - break - if ind is not None: - packStack = packStack[:ind] - if val is None: - packing = packStack[-1][0] - else: - packing = int(opts[0]) - - if self.verbose: - print ">> Packing changed to %s at line %d" % (str(packing), i) - self.packList[file].append((i, packing)) - else: - pass ## Ignore any other directives - - result.append(newLine) - self.files[file] = '\n'.join(result) - - def evalPreprocessorExpr(self, expr): - ## make a few alterations so the expression can be eval'd - macroDiffs = ( - Literal('!').setParseAction(lambda: ' not ') | - Literal('&&').setParseAction(lambda: ' and ') | - Literal('||').setParseAction(lambda: ' or ') | - Word(alphas+'_',alphanums+'_').setParseAction(lambda: '0')) - expr2 = macroDiffs.transformString(expr) - - try: - ev = bool(eval(expr2)) - except: - if self.verbose: - print "Error evaluating preprocessor expression: %s [%s]" % (expr, expr2) - print " ", sys.exc_info()[1] - ev = False - return ev - - - - #def updateMacroDefns(self): - ##self.macroExpr << MatchFirst( [Keyword(m)('macro') for m in self.defs['macros']] ) - ##self.macroExpr.setParseAction(self.processMacroRef) - - ## regex is faster than pyparsing. - ## Matches quoted strings and macros - - ##names = self.defs['macros'].keys() + self.defs['fnmacros'].keys() - #if len(self.macroListString) == 0: - #self.macroRegex = None - #else: - #self.macroRegex = re.compile( - #r'("(\\"|[^"])*")|(\b(%s)\b)' % self.macroListString - #) - - #def updateFnMacroDefns(self): - #self.fnMacroExpr << MatchFirst( [(Keyword(m)('macro') + lparen + Group(delimitedList(expression))('args') + rparen) for m in self.defs['fnmacros']] ) - #self.fnMacroExpr.setParseAction(self.processFnMacroRef) - - - def processMacroDefn(self, t): - """Parse a #define macro and register the definition""" - if self.verbose: - print "MACRO:", t - #macroVal = self.macroExpander.transformString(t.value).strip() - #macroVal = Literal('\\\n').suppress().transformString(macroVal) ## remove escaped newlines - macroVal = t.value.strip() - if macroVal in self.defs['fnmacros']: - self.addDef('fnmacros', t.macro, self.defs['fnmacros'][macroVal]) - if self.verbose: - print " Copy fn macro %s => %s" % (macroVal, t.macro) - else: - if t.args == '': - val = self.evalExpr(macroVal) - self.addDef('macros', t.macro, macroVal) - self.addDef('values', t.macro, val) - if self.verbose: - print " Add macro:", t.macro, "("+str(val)+")", self.defs['macros'][t.macro] - else: - self.addDef('fnmacros', t.macro, self.compileFnMacro(macroVal, [x for x in t.args])) - if self.verbose: - print " Add fn macro:", t.macro, t.args, self.defs['fnmacros'][t.macro] - - #if self.macroListString == '': - #self.macroListString = t.macro - #else: - #self.macroListString += '|' + t.macro - #self.updateMacroDefns() - #self.macroExpr << MatchFirst( map(Keyword,self.defs['macros'].keys()) ) - return "#define " + t.macro + " " + macroVal - - - def compileFnMacro(self, text, args): - """Turn a function macro spec into a compiled description""" - ## find all instances of each arg in text - argRegex = re.compile(r'("(\\"|[^"])*")|(\b(%s)\b)' % ('|'.join(args))) - start = 0 - parts = [] - argOrder = [] - N = 3 - for m in argRegex.finditer(text): - arg = m.groups()[N] - #print m, arg - if arg is not None: - parts.append(text[start:m.start(N)] + '%s') - start = m.end(N) - argOrder.append(args.index(arg)) - parts.append(text[start:]) - return (''.join(parts), argOrder) - - - def expandMacros(self, line): - reg = re.compile(r'("(\\"|[^"])*")|(\b(\w+)\b)') - parts = [] - start = 0 - N = 3 ## the group number to check for macro names - macros = self.defs['macros'] - fnmacros = self.defs['fnmacros'] - for m in reg.finditer(line): - name = m.groups()[N] - if name in macros: - parts.append(line[start:m.start(N)]) - start = m.end(N) - parts.append(macros[name]) - elif name in fnmacros: - try: ## If function macro expansion fails, just ignore it. - exp, end = self.expandFnMacro(name, line[m.end(N):]) - parts.append(line[start:m.start(N)]) - start = end + m.end(N) - parts.append(exp) - except: - if sys.exc_info()[1][0] != 0: - print "Function macro expansion failed:", name, line[m.end(N):] - raise - parts.append(line[start:]) - return ''.join(parts) - - - - #def expandMacros(self, line): - #if self.macroRegex is None: - #return line - #parts = [] - #start = 0 - #N = 3 ## the group number to check for macro names - #for m in self.macroRegex.finditer(line): - #name = m.groups()[N] - #if name is not None: - #if name in self.defs['macros']: - #parts.append(line[start:m.start(N)]) - #start = m.end(N) - #parts.append(self.defs['macros'][name]) - #elif name in self.defs['fnmacros']: - #try: ## If function macro expansion fails, just ignore it. - #exp, end = self.expandFnMacro(name, line[m.end(N):]) - #parts.append(line[start:m.start(N)]) - #start = end + m.end(N) - #parts.append(exp) - #except: - #if sys.exc_info()[1][0] != 0: - #print "Function macro expansion failed:", name, line[m.end(N):] - #raise - - #else: - #raise Exception("Macro '%s' not found (internal error)" % name) - #parts.append(line[start:]) - #return ''.join(parts) - - def expandFnMacro(self, name, text): - #print "expandMacro:", name, text - defn = self.defs['fnmacros'][name] - ## defn looks like ('%s + %s / %s', (0, 0, 1)) - - argList = stringStart + lparen + Group(delimitedList(expression))('args') + rparen - res = [x for x in argList.scanString(text, 1)] - if len(res) == 0: - raise Exception(0, "Function macro '%s' not followed by (...)" % name) - args, start, end = res[0] - #print " ", res - #print " ", args - #print " ", defn - newStr = defn[0] % tuple([args[0][i] for i in defn[1]]) - #print " ", newStr - return (newStr, end) - - - # parse action to replace macro references with their respective definition - #def processMacroRef(self, t): - #return self.defs['macros'][t.macro] - - #def processFnMacroRef(self, t): - #m = self.defs['fnmacros'][t.macro] - ##print "=====>>" - ##print "Process FN MACRO:", t - ##print " macro defn:", t.macro, m - ##print " macro call:", t.args - ### m looks like ('a + b', ('a', 'b')) - #newStr = m[0][:] - ##print " starting str:", newStr - #try: - #for i in range(len(m[1])): - ##print " step", i - #arg = m[1][i] - ##print " arg:", arg, '=>', t.args[i] - - #newStr = Keyword(arg).copy().setParseAction(lambda: t.args[i]).transformString(newStr) - ##print " new str:", newStr - #except: - ##sys.excepthook(*sys.exc_info()) - #raise - ##print "<<=====" - #return newStr - - - - - - - - - def parseDefs(self, file, returnUnparsed=False): - """Scan through the named file for variable, struct, enum, and function declarations. - Returns the entire tree of successfully parsed tokens. - If returnUnparsed is True, return a string of all lines that failed to match (for debugging).""" - self.assertPyparsing() - self.currentFile = file - #self.definedType << kwl(self.defs['types'].keys()) - - parser = self.buildParser() - if returnUnparsed: - text = parser.suppress().transformString(self.files[file]) - return re.sub(r'\n\s*\n', '\n', text) - else: - return [x[0] for x in parser.scanString(self.files[file])] - - def buildParser(self): - """Builds the entire tree of parser elements for the C language (the bits we support, anyway). - """ - - if hasattr(self, 'parser'): - return self.parser - - - self.assertPyparsing() - - - self.structType = Forward() - self.enumType = Forward() - self.typeSpec = (typeQualifier + ( - fundType | - Optional(kwl(sizeModifiers + signModifiers)) + ident | - self.structType | - self.enumType - ) + typeQualifier + msModifier).setParseAction(recombine) - #self.argList = Forward() - - ### Abstract declarators for use in function pointer arguments - # Thus begins the extremely hairy business of parsing C declarators. - # Whomever decided this was a reasonable syntax should probably never breed. - # The following parsers combined with the processDeclarator function - # allow us to turn a nest of type modifiers into a correctly - # ordered list of modifiers. - - self.declarator = Forward() - self.abstractDeclarator = Forward() - - ## abstract declarators look like: - # - # * - # **[num] - # (*)(int, int) - # *( )(int, int)[10] - # ...etc... - self.abstractDeclarator << Group( - typeQualifier + Group(ZeroOrMore('*'))('ptrs') + typeQualifier + - ((Optional('&')('ref')) | (lparen + self.abstractDeclarator + rparen)('center')) + - Optional(lparen + Optional(delimitedList(Group( - self.typeSpec('type') + - self.abstractDeclarator('decl') + - Optional(Literal('=').suppress() + expression, default=None)('val') - )), default=None) + rparen)('args') + - Group(ZeroOrMore(lbrack + Optional(expression, default='-1') + rbrack))('arrays') - ) - - ## Argument list may consist of declarators or abstract declarators - #self.argList << delimitedList(Group( - #self.typeSpec('type') + - #(self.declarator('decl') | self.abstractDeclarator('decl')) + - #Optional(Keyword('=')) + expression - #)) - - ## declarators look like: - # varName - # *varName - # **varName[num] - # (*fnName)(int, int) - # * fnName(int arg1=0)[10] - # ...etc... - self.declarator << Group( - typeQualifier + callConv + Group(ZeroOrMore('*'))('ptrs') + typeQualifier + - ((Optional('&')('ref') + ident('name')) | (lparen + self.declarator + rparen)('center')) + - Optional(lparen + Optional(delimitedList(Group( - self.typeSpec('type') + - (self.declarator | self.abstractDeclarator)('decl') + - Optional(Literal('=').suppress() + expression, default=None)('val') - )), default=None) + rparen)('args') + - Group(ZeroOrMore(lbrack + Optional(expression, default='-1') + rbrack))('arrays') - ) - self.declaratorList = Group(delimitedList(self.declarator)) - - ## typedef - self.typeDecl = Keyword('typedef') + self.typeSpec('type') + self.declaratorList('declList') + semi - self.typeDecl.setParseAction(self.processTypedef) - - ## variable declaration - self.variableDecl = Group(self.typeSpec('type') + Optional(self.declaratorList('declList')) + Optional(Literal('=').suppress() + (expression('value') | (lbrace + Group(delimitedList(expression))('arrayValues') + rbrace)))) + semi - - self.variableDecl.setParseAction(self.processVariable) - - ## function definition - #self.paramDecl = Group(self.typeSpec + (self.declarator | self.abstractDeclarator)) + Optional(Literal('=').suppress() + expression('value')) - self.typelessFunctionDecl = self.declarator('decl') + nestedExpr('{', '}').suppress() - self.functionDecl = self.typeSpec('type') + self.declarator('decl') + nestedExpr('{', '}').suppress() - self.functionDecl.setParseAction(self.processFunction) - - - ## Struct definition - self.structDecl = Forward() - structKW = (Keyword('struct') | Keyword('union')) - #self.structType << structKW('structType') + ((Optional(ident)('name') + lbrace + Group(ZeroOrMore( Group(self.structDecl | self.variableDecl.copy().setParseAction(lambda: None)) ))('members') + rbrace) | ident('name')) - self.structMember = ( - Group(self.variableDecl.copy().setParseAction(lambda: None)) | - (self.typeSpec + self.declarator + nestedExpr('{', '}')).suppress() | - (self.declarator + nestedExpr('{', '}')).suppress() - ) - self.declList = lbrace + Group(OneOrMore(self.structMember))('members') + rbrace - self.structType << (Keyword('struct') | Keyword('union'))('structType') + ((Optional(ident)('name') + self.declList) | ident('name')) - - self.structType.setParseAction(self.processStruct) - #self.updateStructDefn() - - self.structDecl = self.structType + semi - - ## enum definition - enumVarDecl = Group(ident('name') + Optional(Literal('=').suppress() + (integer('value') | ident('valueName')))) - - self.enumType << Keyword('enum') + (Optional(ident)('name') + lbrace + Group(delimitedList(enumVarDecl))('members') + rbrace | ident('name')) - self.enumType.setParseAction(self.processEnum) - - self.enumDecl = self.enumType + semi - - - #self.parser = (self.typeDecl | self.variableDecl | self.structDecl | self.enumDecl | self.functionDecl) - self.parser = (self.typeDecl | self.variableDecl | self.functionDecl) - return self.parser - - def processDeclarator(self, decl): - """Process a declarator (without base type) and return a tuple (name, [modifiers]) - See processType(...) for more information.""" - toks = [] - name = None - #print "DECL:", decl - if 'callConv' in decl and len(decl['callConv']) > 0: - toks.append(decl['callConv']) - if 'ptrs' in decl and len(decl['ptrs']) > 0: - toks.append('*' * len(decl['ptrs'])) - if 'arrays' in decl and len(decl['arrays']) > 0: - #arrays = [] - #for x in decl['arrays']: - #n = self.evalExpr(x) - #if n == -1: ## If an array was given as '[]', interpret it as '*' instead. - #toks.append('*') - #else: - #arrays.append(n) - #if len(arrays) > 0: - #toks.append(arrays) - toks.append([self.evalExpr(x) for x in decl['arrays']]) - if 'args' in decl and len(decl['args']) > 0: - #print " process args" - if decl['args'][0] is None: - toks.append(()) - else: - toks.append(tuple([self.processType(a['type'], a['decl']) + (a['val'][0],) for a in decl['args']])) - if 'ref' in decl: - toks.append('&') - if 'center' in decl: - (n, t) = self.processDeclarator(decl['center'][0]) - if n is not None: - name = n - toks.extend(t) - if 'name' in decl: - name = decl['name'] - return (name, toks) - - def processType(self, typ, decl): - """Take a declarator + base type and return a serialized name/type description. - The description will be a list of elements (name, [basetype, modifier, modifier, ...]) - - name is the string name of the declarator or None for an abstract declarator - - basetype is the string representing the base type - - modifiers can be: - '*' - pointer (multiple pointers "***" allowed) - '&' - reference - '__X' - calling convention (windows only). X can be 'cdecl' or 'stdcall' - list - array. Value(s) indicate the length of each array, -1 for incomplete type. - tuple - function, items are the output of processType for each function argument. - - Examples: - int *x[10] => ('x', ['int', [10], '*']) - char fn(int x) => ('fn', ['char', [('x', ['int'])]]) - struct s (*)(int, int*) => (None, ["struct s", ((None, ['int']), (None, ['int', '*'])), '*']) - """ - #print "PROCESS TYPE/DECL:", typ, decl - (name, decl) = self.processDeclarator(decl) - return (name, [typ] + decl) - - - - def processEnum(self, s, l, t): - try: - if self.verbose: - print "ENUM:", t - if t.name == '': - n = 0 - while True: - name = 'anonEnum%d' % n - if name not in self.defs['enums']: - break - n += 1 - else: - name = t.name[0] - - if self.verbose: - print " name:", name - - if name not in self.defs['enums']: - i = 0 - enum = {} - for v in t.members: - if v.value != '': - i = eval(v.value) - if v.valueName != '': - i = enum[v.valueName] - enum[v.name] = i - self.addDef('values', v.name, i) - i += 1 - if self.verbose: - print " members:", enum - self.addDef('enums', name, enum) - self.addDef('types', 'enum '+name, ('enum', name)) - return ('enum ' + name) - except: - if self.verbose: - print "Error processing enum:", t - sys.excepthook(*sys.exc_info()) - - - def processFunction(self, s, l, t): - if self.verbose: - print "FUNCTION", t, t.keys() - - try: - (name, decl) = self.processType(t.type, t.decl[0]) - if len(decl) == 0 or type(decl[-1]) != tuple: - print t - raise Exception("Incorrect declarator type for function definition.") - if self.verbose: - print " name:", name - print " sig:", decl - self.addDef('functions', name, (decl[:-1], decl[-1])) - - except: - if self.verbose: - print "Error processing function:", t - sys.excepthook(*sys.exc_info()) - - - def packingAt(self, line): - """Return the structure packing value at the given line number""" - packing = None - for p in self.packList[self.currentFile]: - if p[0] <= line: - packing = p[1] - else: - break - return packing - - def processStruct(self, s, l, t): - try: - strTyp = t.structType # struct or union - - ## check for extra packing rules - packing = self.packingAt(lineno(l, s)) - - if self.verbose: - print strTyp.upper(), t.name, t - if t.name == '': - n = 0 - while True: - sname = 'anon_%s%d' % (strTyp, n) - if sname not in self.defs[strTyp+'s']: - break - n += 1 - else: - if type(t.name) is str: - sname = t.name - else: - sname = t.name[0] - if self.verbose: - print " NAME:", sname - if len(t.members) > 0 or sname not in self.defs[strTyp+'s'] or self.defs[strTyp+'s'][sname] == {}: - if self.verbose: - print " NEW " + strTyp.upper() - struct = [] - for m in t.members: - typ = m[0].type - val = self.evalExpr(m) - if self.verbose: - print " member:", m, m[0].keys(), m[0].declList - if len(m[0].declList) == 0: ## anonymous member - struct.append((None, [typ], None)) - for d in m[0].declList: - (name, decl) = self.processType(typ, d) - struct.append((name, decl, val)) - if self.verbose: - print " ", name, decl, val - self.addDef(strTyp+'s', sname, {'pack': packing, 'members': struct}) - self.addDef('types', strTyp+' '+sname, (strTyp, sname)) - #self.updateStructDefn() - return strTyp+' '+sname - except: - #print t - sys.excepthook(*sys.exc_info()) - - def processVariable(self, s, l, t): - if self.verbose: - print "VARIABLE:", t - try: - val = self.evalExpr(t[0]) - for d in t[0].declList: - (name, typ) = self.processType(t[0].type, d) - if type(typ[-1]) is tuple: ## this is a function prototype - if self.verbose: - print " Add function prototype:", name, typ, val - self.addDef('functions', name, (typ[:-1], typ[-1])) - else: - if self.verbose: - print " Add variable:", name, typ, val - self.addDef('variables', name, (val, typ)) - self.addDef('values', name, val) - except: - #print t, t[0].name, t.value - sys.excepthook(*sys.exc_info()) - - def processTypedef(self, s, l, t): - if self.verbose: - print "TYPE:", t - typ = t.type - #print t, t.type - for d in t.declList: - (name, decl) = self.processType(typ, d) - if self.verbose: - print " ", name, decl - self.addDef('types', name, decl) - #self.definedType << MatchFirst( map(Keyword,self.defs['types'].keys()) ) - - def evalExpr(self, toks): - ## Evaluates expressions. Currently only works for expressions that also - ## happen to be valid python expressions. - ## This function does not currently include previous variable - ## declarations, but that should not be too difficult to implement.. - #print "Eval:", toks - try: - if isinstance(toks, basestring): - #print " as string" - val = self.eval(toks, None, self.defs['values']) - elif toks.arrayValues != '': - #print " as list:", toks.arrayValues - val = [self.eval(x, None, self.defs['values']) for x in toks.arrayValues] - elif toks.value != '': - #print " as value" - val = self.eval(toks.value, None, self.defs['values']) - else: - #print " as None" - val = None - return val - except: - if self.verbose: - print " failed eval:", toks - print " ", sys.exc_info()[1] - return None - - def eval(self, expr, *args): - """Just eval with a little extra robustness.""" - expr = expr.strip() - cast = (lparen + self.typeSpec + self.abstractDeclarator + rparen).suppress() - expr = (quotedString | number | cast).transformString(expr) - if expr == '': - return None - return eval(expr, *args) - - def printAll(self, file=None): - """Print everything parsed from files. Useful for debugging.""" - from pprint import pprint - for k in self.dataList: - print "============== %s ==================" % k - if file is None: - pprint(self.defs[k]) - else: - pprint(self.fileDefs[file][k]) - - def addDef(self, typ, name, val): - """Add a definition of a specific type to both the definition set for the current file and the global definition set.""" - self.defs[typ][name] = val - if self.currentFile is None: - baseName = None - else: - baseName = os.path.basename(self.currentFile) - if baseName not in self.fileDefs: - self.fileDefs[baseName] = {} - for k in self.dataList: - self.fileDefs[baseName][k] = {} - self.fileDefs[baseName][typ][name] = val - - def remDef(self, typ, name): - if self.currentFile is None: - baseName = None - else: - baseName = os.path.basename(self.currentFile) - del self.defs[typ][name] - del self.fileDefs[baseName][typ][name] - - - def isFundType(self, typ): - """Return True if this type is a fundamental C type, struct, or union""" - if typ[0][:7] == 'struct ' or typ[0][:6] == 'union ' or typ[0][:5] == 'enum ': - return True - - names = baseTypes + sizeModifiers + signModifiers - for w in typ[0].split(): - if w not in names: - return False - return True - - def evalType(self, typ): - """evaluate a named type into its fundamental type""" - used = [] - while True: - if self.isFundType(typ): - ## remove 'signed' before returning evaluated type - typ[0] = re.sub(r'\bsigned\b', '', typ[0]).strip() - - - return typ - parent = typ[0] - if parent in used: - raise Exception('Recursive loop while evaluating types. (typedefs are %s)' % (' -> '.join(used+[parent]))) - used.append(parent) - if not parent in self.defs['types']: - raise Exception('Unknown type "%s" (typedefs are %s)' % (parent, ' -> '.join(used))) - pt = self.defs['types'][parent] - typ = pt + typ[1:] - - def find(self, name): - """Search all definitions for the given name""" - res = [] - for f in self.fileDefs: - fd = self.fileDefs[f] - for t in fd: - typ = fd[t] - for k in typ: - if isinstance(name, basestring): - if k == name: - res.append((f, t)) - else: - if re.match(name, k): - res.append((f, t, k)) - return res - - - - def findText(self, text): - """Search all file strings for text, return matching lines.""" - res = [] - for f in self.files: - l = self.files[f].split('\n') - for i in range(len(l)): - if text in l[i]: - res.append((f, i, l[i])) - return res - - -hasPyParsing = False -try: - from pyparsing import * - ParserElement.enablePackrat() - hasPyParsing = True -except: - pass ## no need to do anything yet as we might not be using any parsing functions.. - - -## Define some common language elements if pyparsing is available. -if hasPyParsing: - ## Some basic definitions - expression = Forward() - pexpr = '(' + expression + ')' - numTypes = ['int', 'float', 'double', '__int64'] - baseTypes = ['char', 'bool', 'void'] + numTypes - sizeModifiers = ['short', 'long'] - signModifiers = ['signed', 'unsigned'] - qualifiers = ['const', 'static', 'volatile', 'inline', 'restrict', 'near', 'far'] - msModifiers = ['__based', '__declspec', '__fastcall', '__restrict', '__sptr', '__uptr', '__w64', '__unaligned', '__nullterminated'] - keywords = ['struct', 'enum', 'union', '__stdcall', '__cdecl'] + qualifiers + baseTypes + sizeModifiers + signModifiers - - def kwl(strs): - """Generate a match-first list of keywords given a list of strings.""" - #return MatchFirst(map(Keyword,strs)) - return Regex(r'\b(%s)\b' % '|'.join(strs)) - - keyword = kwl(keywords) - wordchars = alphanums+'_$' - ident = (WordStart(wordchars) + ~keyword + Word(alphas+"_",alphanums+"_$") + WordEnd(wordchars)).setParseAction(lambda t: t[0]) - #integer = Combine(Optional("-") + (Word( nums ) | Combine("0x" + Word(hexnums)))) - semi = Literal(";").ignore(quotedString).suppress() - lbrace = Literal("{").ignore(quotedString).suppress() - rbrace = Literal("}").ignore(quotedString).suppress() - lbrack = Literal("[").ignore(quotedString).suppress() - rbrack = Literal("]").ignore(quotedString).suppress() - lparen = Literal("(").ignore(quotedString).suppress() - rparen = Literal(")").ignore(quotedString).suppress() - hexint = Regex('-?0x[%s]+[UL]*'%hexnums).setParseAction(lambda t: t[0].rstrip('UL')) - decint = Regex(r'-?\d+[UL]*').setParseAction(lambda t: t[0].rstrip('UL')) - integer = (hexint | decint) - floating = Regex(r'-?((\d+(\.\d*)?)|(\.\d+))([eE]-?\d+)?') - number = (hexint | floating | decint) - bitfieldspec = ":" + integer - biOperator = oneOf("+ - / * | & || && ! ~ ^ % == != > < >= <= -> . :: << >> = ? :") - uniRightOperator = oneOf("++ --") - uniLeftOperator = oneOf("++ -- - + * sizeof new") - name = (WordStart(wordchars) + Word(alphas+"_",alphanums+"_$") + WordEnd(wordchars)) - #number = Word(hexnums + ".-+xUL").setParseAction(lambda t: t[0].rstrip('UL')) - #stars = Optional(Word('*&'), default='')('ptrs') ## may need to separate & from * later? - callConv = Optional(Keyword('__cdecl')|Keyword('__stdcall'))('callConv') - - ## Removes '__name' from all type specs.. may cause trouble. - underscore2Ident = (WordStart(wordchars) + ~keyword + '__' + Word(alphanums,alphanums+"_$") + WordEnd(wordchars)).setParseAction(lambda t: t[0]) - typeQualifier = ZeroOrMore((underscore2Ident + Optional(nestedExpr())) | kwl(qualifiers)).suppress() - - msModifier = ZeroOrMore(kwl(msModifiers) + Optional(nestedExpr())).suppress() - pointerOperator = ( - '*' + typeQualifier | - '&' + typeQualifier | - '::' + ident + typeQualifier - ) - - - ## language elements - fundType = OneOrMore(kwl(signModifiers + sizeModifiers + baseTypes)).setParseAction(lambda t: ' '.join(t)) - - - - ## Is there a better way to process expressions with cast operators?? - castAtom = ( - ZeroOrMore(uniLeftOperator) + Optional('('+ident+')').suppress() + - (( - ident + '(' + Optional(delimitedList(expression)) + ')' | - ident + OneOrMore('[' + expression + ']') | - ident | number | quotedString - ) | - ('(' + expression + ')')) + - ZeroOrMore(uniRightOperator) - ) - uncastAtom = ( - ZeroOrMore(uniLeftOperator) + - (( - ident + '(' + Optional(delimitedList(expression)) + ')' | - ident + OneOrMore('[' + expression + ']') | - ident | number | quotedString - ) | - ('(' + expression + ')')) + - ZeroOrMore(uniRightOperator) - ) - atom = castAtom | uncastAtom - - expression << Group( - atom + ZeroOrMore(biOperator + atom) - ) - arrayOp = lbrack + expression + rbrack - - def recombine(tok): - """Flattens a tree of tokens and joins into one big string.""" - return " ".join(flatten(tok.asList())) - expression.setParseAction(recombine) - - def flatten(lst): - res = [] - for i in lst: - if type(i) in [list, tuple]: - res.extend(flatten(i)) - else: - res.append(str(i)) - return res - - def printParseResults(pr, depth=0, name=''): - """For debugging; pretty-prints parse result objects.""" - start = name + " "*(20-len(name)) + ':'+ '..'*depth - if isinstance(pr, ParseResults): - print start - for i in pr: - name = '' - for k in pr.keys(): - if pr[k] is i: - name = k - break - printParseResults(i, depth+1, name) - else: - print start + str(pr) - - - -## Just for fun.. -if __name__ == '__main__': - files = sys.argv[1:] - p = CParser(files) - p.processAll() - p.printAll() - \ No newline at end of file diff --git a/scripts/pyclibrary/README.md b/scripts/pyclibrary/README.md deleted file mode 100644 index f1af9afb7..000000000 --- a/scripts/pyclibrary/README.md +++ /dev/null @@ -1,8 +0,0 @@ -pyclibrary -========== - -C parser and ctypes automation for Python. - -Fork of . (`bzr branch lp:pyclibrary pyclibrary-bzr && mkdir pyclibrary && cd pyclibrary && bar fast-export --plain ../pyclibrary-bzr | git fast-import`) - -Pyclibrary includes 1) a pure-python C parser and 2) a ctypes automation library that uses C header file definitions to simplify the use of ctypes. The C parser currently processes all macros, typedefs, structs, unions, enums, function prototypes, and global variable declarations, and can evaluate typedefs down to their fundamental C types + pointers/arrays/function signatures. Pyclibrary can automatically build ctypes structs/unions and perform type conversions when calling functions via cdll/windll. diff --git a/scripts/pyclibrary/__init__.py b/scripts/pyclibrary/__init__.py deleted file mode 100644 index 618aaa1a8..000000000 --- a/scripts/pyclibrary/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# -*- coding: utf-8 -*- -from CParser import * -from CLibrary import * \ No newline at end of file diff --git a/scripts/pyclibrary/license.txt b/scripts/pyclibrary/license.txt deleted file mode 100644 index 3d04b87ea..000000000 --- a/scripts/pyclibrary/license.txt +++ /dev/null @@ -1,7 +0,0 @@ -Copyright (c) 2010 Luke Campagnola ('luke.campagnola@%s.com' % 'gmail') - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/scripts/pyclibrary/pyparsing.py b/scripts/pyclibrary/pyparsing.py deleted file mode 100644 index dec506ed0..000000000 --- a/scripts/pyclibrary/pyparsing.py +++ /dev/null @@ -1,3754 +0,0 @@ -# module pyparsing.py -# -# Copyright (c) 2003-2011 Paul T. McGuire -# -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -#from __future__ import generators - -__doc__ = \ -""" -pyparsing module - Classes and methods to define and execute parsing grammars - -The pyparsing module is an alternative approach to creating and executing simple grammars, -vs. the traditional lex/yacc approach, or the use of regular expressions. With pyparsing, you -don't need to learn a new syntax for defining grammars or matching expressions - the parsing module -provides a library of classes that you use to construct the grammar directly in Python. - -Here is a program to parse "Hello, World!" (or any greeting of the form C{", !"}):: - - from pyparsing import Word, alphas - - # define grammar of a greeting - greet = Word( alphas ) + "," + Word( alphas ) + "!" - - hello = "Hello, World!" - print hello, "->", greet.parseString( hello ) - -The program outputs the following:: - - Hello, World! -> ['Hello', ',', 'World', '!'] - -The Python representation of the grammar is quite readable, owing to the self-explanatory -class names, and the use of '+', '|' and '^' operators. - -The parsed results returned from C{parseString()} can be accessed as a nested list, a dictionary, or an -object with named attributes. - -The pyparsing module handles some of the problems that are typically vexing when writing text parsers: - - extra or missing whitespace (the above program will also handle "Hello,World!", "Hello , World !", etc.) - - quoted strings - - embedded comments -""" - -__version__ = "1.5.6" -__versionTime__ = "1 May 2011 23:41" -__author__ = "Paul McGuire " - -import string -from weakref import ref as wkref -import copy -import sys -import warnings -import re -import sre_constants -#~ sys.stderr.write( "testing pyparsing module, version %s, %s\n" % (__version__,__versionTime__ ) ) - -__all__ = [ -'And', 'CaselessKeyword', 'CaselessLiteral', 'CharsNotIn', 'Combine', 'Dict', 'Each', 'Empty', -'FollowedBy', 'Forward', 'GoToColumn', 'Group', 'Keyword', 'LineEnd', 'LineStart', 'Literal', -'MatchFirst', 'NoMatch', 'NotAny', 'OneOrMore', 'OnlyOnce', 'Optional', 'Or', -'ParseBaseException', 'ParseElementEnhance', 'ParseException', 'ParseExpression', 'ParseFatalException', -'ParseResults', 'ParseSyntaxException', 'ParserElement', 'QuotedString', 'RecursiveGrammarException', -'Regex', 'SkipTo', 'StringEnd', 'StringStart', 'Suppress', 'Token', 'TokenConverter', 'Upcase', -'White', 'Word', 'WordEnd', 'WordStart', 'ZeroOrMore', -'alphanums', 'alphas', 'alphas8bit', 'anyCloseTag', 'anyOpenTag', 'cStyleComment', 'col', -'commaSeparatedList', 'commonHTMLEntity', 'countedArray', 'cppStyleComment', 'dblQuotedString', -'dblSlashComment', 'delimitedList', 'dictOf', 'downcaseTokens', 'empty', 'getTokensEndLoc', 'hexnums', -'htmlComment', 'javaStyleComment', 'keepOriginalText', 'line', 'lineEnd', 'lineStart', 'lineno', -'makeHTMLTags', 'makeXMLTags', 'matchOnlyAtCol', 'matchPreviousExpr', 'matchPreviousLiteral', -'nestedExpr', 'nullDebugAction', 'nums', 'oneOf', 'opAssoc', 'operatorPrecedence', 'printables', -'punc8bit', 'pythonStyleComment', 'quotedString', 'removeQuotes', 'replaceHTMLEntity', -'replaceWith', 'restOfLine', 'sglQuotedString', 'srange', 'stringEnd', -'stringStart', 'traceParseAction', 'unicodeString', 'upcaseTokens', 'withAttribute', -'indentedBlock', 'originalTextFor', -] - -""" -Detect if we are running version 3.X and make appropriate changes -Robert A. Clark -""" -_PY3K = sys.version_info[0] > 2 -if _PY3K: - _MAX_INT = sys.maxsize - basestring = str - unichr = chr - _ustr = str - alphas = string.ascii_lowercase + string.ascii_uppercase -else: - _MAX_INT = sys.maxint - range = xrange - set = lambda s : dict( [(c,0) for c in s] ) - alphas = string.lowercase + string.uppercase - - def _ustr(obj): - """Drop-in replacement for str(obj) that tries to be Unicode friendly. It first tries - str(obj). If that fails with a UnicodeEncodeError, then it tries unicode(obj). It - then < returns the unicode object | encodes it with the default encoding | ... >. - """ - if isinstance(obj,unicode): - return obj - - try: - # If this works, then _ustr(obj) has the same behaviour as str(obj), so - # it won't break any existing code. - return str(obj) - - except UnicodeEncodeError: - # The Python docs (http://docs.python.org/ref/customization.html#l2h-182) - # state that "The return value must be a string object". However, does a - # unicode object (being a subclass of basestring) count as a "string - # object"? - # If so, then return a unicode object: - return unicode(obj) - # Else encode it... but how? There are many choices... :) - # Replace unprintables with escape codes? - #return unicode(obj).encode(sys.getdefaultencoding(), 'backslashreplace_errors') - # Replace unprintables with question marks? - #return unicode(obj).encode(sys.getdefaultencoding(), 'replace') - # ... - - alphas = string.lowercase + string.uppercase - -# build list of single arg builtins, tolerant of Python version, that can be used as parse actions -singleArgBuiltins = [] -import __builtin__ -for fname in "sum len enumerate sorted reversed list tuple set any all".split(): - try: - singleArgBuiltins.append(getattr(__builtin__,fname)) - except AttributeError: - continue - -def _xml_escape(data): - """Escape &, <, >, ", ', etc. in a string of data.""" - - # ampersand must be replaced first - from_symbols = '&><"\'' - to_symbols = ['&'+s+';' for s in "amp gt lt quot apos".split()] - for from_,to_ in zip(from_symbols, to_symbols): - data = data.replace(from_, to_) - return data - -class _Constants(object): - pass - -nums = string.digits -hexnums = nums + "ABCDEFabcdef" -alphanums = alphas + nums -_bslash = chr(92) -printables = "".join( [ c for c in string.printable if c not in string.whitespace ] ) - -class ParseBaseException(Exception): - """base exception class for all parsing runtime exceptions""" - # Performance tuning: we construct a *lot* of these, so keep this - # constructor as small and fast as possible - def __init__( self, pstr, loc=0, msg=None, elem=None ): - self.loc = loc - if msg is None: - self.msg = pstr - self.pstr = "" - else: - self.msg = msg - self.pstr = pstr - self.parserElement = elem - - def __getattr__( self, aname ): - """supported attributes by name are: - - lineno - returns the line number of the exception text - - col - returns the column number of the exception text - - line - returns the line containing the exception text - """ - if( aname == "lineno" ): - return lineno( self.loc, self.pstr ) - elif( aname in ("col", "column") ): - return col( self.loc, self.pstr ) - elif( aname == "line" ): - return line( self.loc, self.pstr ) - else: - raise AttributeError(aname) - - def __str__( self ): - return "%s (at char %d), (line:%d, col:%d)" % \ - ( self.msg, self.loc, self.lineno, self.column ) - def __repr__( self ): - return _ustr(self) - def markInputline( self, markerString = ">!<" ): - """Extracts the exception line from the input string, and marks - the location of the exception with a special symbol. - """ - line_str = self.line - line_column = self.column - 1 - if markerString: - line_str = "".join( [line_str[:line_column], - markerString, line_str[line_column:]]) - return line_str.strip() - def __dir__(self): - return "loc msg pstr parserElement lineno col line " \ - "markInputLine __str__ __repr__".split() - -class ParseException(ParseBaseException): - """exception thrown when parse expressions don't match class; - supported attributes by name are: - - lineno - returns the line number of the exception text - - col - returns the column number of the exception text - - line - returns the line containing the exception text - """ - pass - -class ParseFatalException(ParseBaseException): - """user-throwable exception thrown when inconsistent parse content - is found; stops all parsing immediately""" - pass - -class ParseSyntaxException(ParseFatalException): - """just like C{ParseFatalException}, but thrown internally when an - C{ErrorStop} ('-' operator) indicates that parsing is to stop immediately because - an unbacktrackable syntax error has been found""" - def __init__(self, pe): - super(ParseSyntaxException, self).__init__( - pe.pstr, pe.loc, pe.msg, pe.parserElement) - -#~ class ReparseException(ParseBaseException): - #~ """Experimental class - parse actions can raise this exception to cause - #~ pyparsing to reparse the input string: - #~ - with a modified input string, and/or - #~ - with a modified start location - #~ Set the values of the ReparseException in the constructor, and raise the - #~ exception in a parse action to cause pyparsing to use the new string/location. - #~ Setting the values as None causes no change to be made. - #~ """ - #~ def __init_( self, newstring, restartLoc ): - #~ self.newParseText = newstring - #~ self.reparseLoc = restartLoc - -class RecursiveGrammarException(Exception): - """exception thrown by C{validate()} if the grammar could be improperly recursive""" - def __init__( self, parseElementList ): - self.parseElementTrace = parseElementList - - def __str__( self ): - return "RecursiveGrammarException: %s" % self.parseElementTrace - -class _ParseResultsWithOffset(object): - def __init__(self,p1,p2): - self.tup = (p1,p2) - def __getitem__(self,i): - return self.tup[i] - def __repr__(self): - return repr(self.tup) - def setOffset(self,i): - self.tup = (self.tup[0],i) - -class ParseResults(object): - """Structured parse results, to provide multiple means of access to the parsed data: - - as a list (C{len(results)}) - - by list index (C{results[0], results[1]}, etc.) - - by attribute (C{results.}) - """ - #~ __slots__ = ( "__toklist", "__tokdict", "__doinit", "__name", "__parent", "__accumNames", "__weakref__" ) - def __new__(cls, toklist, name=None, asList=True, modal=True ): - if isinstance(toklist, cls): - return toklist - retobj = object.__new__(cls) - retobj.__doinit = True - return retobj - - # Performance tuning: we construct a *lot* of these, so keep this - # constructor as small and fast as possible - def __init__( self, toklist, name=None, asList=True, modal=True, isinstance=isinstance ): - if self.__doinit: - self.__doinit = False - self.__name = None - self.__parent = None - self.__accumNames = {} - if isinstance(toklist, list): - self.__toklist = toklist[:] - else: - self.__toklist = [toklist] - self.__tokdict = dict() - - if name is not None and name: - if not modal: - self.__accumNames[name] = 0 - if isinstance(name,int): - name = _ustr(name) # will always return a str, but use _ustr for consistency - self.__name = name - if not toklist in (None,'',[]): - if isinstance(toklist,basestring): - toklist = [ toklist ] - if asList: - if isinstance(toklist,ParseResults): - self[name] = _ParseResultsWithOffset(toklist.copy(),0) - else: - self[name] = _ParseResultsWithOffset(ParseResults(toklist[0]),0) - self[name].__name = name - else: - try: - self[name] = toklist[0] - except (KeyError,TypeError,IndexError): - self[name] = toklist - - def __getitem__( self, i ): - if isinstance( i, (int,slice) ): - return self.__toklist[i] - else: - if i not in self.__accumNames: - return self.__tokdict[i][-1][0] - else: - return ParseResults([ v[0] for v in self.__tokdict[i] ]) - - def __setitem__( self, k, v, isinstance=isinstance ): - if isinstance(v,_ParseResultsWithOffset): - self.__tokdict[k] = self.__tokdict.get(k,list()) + [v] - sub = v[0] - elif isinstance(k,int): - self.__toklist[k] = v - sub = v - else: - self.__tokdict[k] = self.__tokdict.get(k,list()) + [_ParseResultsWithOffset(v,0)] - sub = v - if isinstance(sub,ParseResults): - sub.__parent = wkref(self) - - def __delitem__( self, i ): - if isinstance(i,(int,slice)): - mylen = len( self.__toklist ) - del self.__toklist[i] - - # convert int to slice - if isinstance(i, int): - if i < 0: - i += mylen - i = slice(i, i+1) - # get removed indices - removed = list(range(*i.indices(mylen))) - removed.reverse() - # fixup indices in token dictionary - for name in self.__tokdict: - occurrences = self.__tokdict[name] - for j in removed: - for k, (value, position) in enumerate(occurrences): - occurrences[k] = _ParseResultsWithOffset(value, position - (position > j)) - else: - del self.__tokdict[i] - - def __contains__( self, k ): - return k in self.__tokdict - - def __len__( self ): return len( self.__toklist ) - def __bool__(self): return len( self.__toklist ) > 0 - __nonzero__ = __bool__ - def __iter__( self ): return iter( self.__toklist ) - def __reversed__( self ): return iter( self.__toklist[::-1] ) - def keys( self ): - """Returns all named result keys.""" - return self.__tokdict.keys() - - def pop( self, index=-1 ): - """Removes and returns item at specified index (default=last). - Will work with either numeric indices or dict-key indicies.""" - ret = self[index] - del self[index] - return ret - - def get(self, key, defaultValue=None): - """Returns named result matching the given key, or if there is no - such name, then returns the given C{defaultValue} or C{None} if no - C{defaultValue} is specified.""" - if key in self: - return self[key] - else: - return defaultValue - - def insert( self, index, insStr ): - """Inserts new element at location index in the list of parsed tokens.""" - self.__toklist.insert(index, insStr) - # fixup indices in token dictionary - for name in self.__tokdict: - occurrences = self.__tokdict[name] - for k, (value, position) in enumerate(occurrences): - occurrences[k] = _ParseResultsWithOffset(value, position + (position > index)) - - def items( self ): - """Returns all named result keys and values as a list of tuples.""" - return [(k,self[k]) for k in self.__tokdict] - - def values( self ): - """Returns all named result values.""" - return [ v[-1][0] for v in self.__tokdict.values() ] - - def __getattr__( self, name ): - if True: #name not in self.__slots__: - if name in self.__tokdict: - if name not in self.__accumNames: - return self.__tokdict[name][-1][0] - else: - return ParseResults([ v[0] for v in self.__tokdict[name] ]) - else: - return "" - return None - - def __add__( self, other ): - ret = self.copy() - ret += other - return ret - - def __iadd__( self, other ): - if other.__tokdict: - offset = len(self.__toklist) - addoffset = ( lambda a: (a<0 and offset) or (a+offset) ) - otheritems = other.__tokdict.items() - otherdictitems = [(k, _ParseResultsWithOffset(v[0],addoffset(v[1])) ) - for (k,vlist) in otheritems for v in vlist] - for k,v in otherdictitems: - self[k] = v - if isinstance(v[0],ParseResults): - v[0].__parent = wkref(self) - - self.__toklist += other.__toklist - self.__accumNames.update( other.__accumNames ) - return self - - def __radd__(self, other): - if isinstance(other,int) and other == 0: - return self.copy() - - def __repr__( self ): - return "(%s, %s)" % ( repr( self.__toklist ), repr( self.__tokdict ) ) - - def __str__( self ): - out = "[" - sep = "" - for i in self.__toklist: - if isinstance(i, ParseResults): - out += sep + _ustr(i) - else: - out += sep + repr(i) - sep = ", " - out += "]" - return out - - def _asStringList( self, sep='' ): - out = [] - for item in self.__toklist: - if out and sep: - out.append(sep) - if isinstance( item, ParseResults ): - out += item._asStringList() - else: - out.append( _ustr(item) ) - return out - - def asList( self ): - """Returns the parse results as a nested list of matching tokens, all converted to strings.""" - out = [] - for res in self.__toklist: - if isinstance(res,ParseResults): - out.append( res.asList() ) - else: - out.append( res ) - return out - - def asDict( self ): - """Returns the named parse results as dictionary.""" - return dict( self.items() ) - - def copy( self ): - """Returns a new copy of a C{ParseResults} object.""" - ret = ParseResults( self.__toklist ) - ret.__tokdict = self.__tokdict.copy() - ret.__parent = self.__parent - ret.__accumNames.update( self.__accumNames ) - ret.__name = self.__name - return ret - - def asXML( self, doctag=None, namedItemsOnly=False, indent="", formatted=True ): - """Returns the parse results as XML. Tags are created for tokens and lists that have defined results names.""" - nl = "\n" - out = [] - namedItems = dict( [ (v[1],k) for (k,vlist) in self.__tokdict.items() - for v in vlist ] ) - nextLevelIndent = indent + " " - - # collapse out indents if formatting is not desired - if not formatted: - indent = "" - nextLevelIndent = "" - nl = "" - - selfTag = None - if doctag is not None: - selfTag = doctag - else: - if self.__name: - selfTag = self.__name - - if not selfTag: - if namedItemsOnly: - return "" - else: - selfTag = "ITEM" - - out += [ nl, indent, "<", selfTag, ">" ] - - worklist = self.__toklist - for i,res in enumerate(worklist): - if isinstance(res,ParseResults): - if i in namedItems: - out += [ res.asXML(namedItems[i], - namedItemsOnly and doctag is None, - nextLevelIndent, - formatted)] - else: - out += [ res.asXML(None, - namedItemsOnly and doctag is None, - nextLevelIndent, - formatted)] - else: - # individual token, see if there is a name for it - resTag = None - if i in namedItems: - resTag = namedItems[i] - if not resTag: - if namedItemsOnly: - continue - else: - resTag = "ITEM" - xmlBodyText = _xml_escape(_ustr(res)) - out += [ nl, nextLevelIndent, "<", resTag, ">", - xmlBodyText, - "" ] - - out += [ nl, indent, "" ] - return "".join(out) - - def __lookup(self,sub): - for k,vlist in self.__tokdict.items(): - for v,loc in vlist: - if sub is v: - return k - return None - - def getName(self): - """Returns the results name for this token expression.""" - if self.__name: - return self.__name - elif self.__parent: - par = self.__parent() - if par: - return par.__lookup(self) - else: - return None - elif (len(self) == 1 and - len(self.__tokdict) == 1 and - self.__tokdict.values()[0][0][1] in (0,-1)): - return self.__tokdict.keys()[0] - else: - return None - - def dump(self,indent='',depth=0): - """Diagnostic method for listing out the contents of a C{ParseResults}. - Accepts an optional C{indent} argument so that this string can be embedded - in a nested display of other data.""" - out = [] - out.append( indent+_ustr(self.asList()) ) - keys = self.items() - keys.sort() - for k,v in keys: - if out: - out.append('\n') - out.append( "%s%s- %s: " % (indent,(' '*depth), k) ) - if isinstance(v,ParseResults): - if v.keys(): - out.append( v.dump(indent,depth+1) ) - else: - out.append(_ustr(v)) - else: - out.append(_ustr(v)) - return "".join(out) - - # add support for pickle protocol - def __getstate__(self): - return ( self.__toklist, - ( self.__tokdict.copy(), - self.__parent is not None and self.__parent() or None, - self.__accumNames, - self.__name ) ) - - def __setstate__(self,state): - self.__toklist = state[0] - self.__tokdict, \ - par, \ - inAccumNames, \ - self.__name = state[1] - self.__accumNames = {} - self.__accumNames.update(inAccumNames) - if par is not None: - self.__parent = wkref(par) - else: - self.__parent = None - - def __dir__(self): - return dir(super(ParseResults,self)) + self.keys() - -def col (loc,strg): - """Returns current column within a string, counting newlines as line separators. - The first column is number 1. - - Note: the default parsing behavior is to expand tabs in the input string - before starting the parsing process. See L{I{ParserElement.parseString}} for more information - on parsing strings containing s, and suggested methods to maintain a - consistent view of the parsed string, the parse location, and line and column - positions within the parsed string. - """ - return (loc} for more information - on parsing strings containing s, and suggested methods to maintain a - consistent view of the parsed string, the parse location, and line and column - positions within the parsed string. - """ - return strg.count("\n",0,loc) + 1 - -def line( loc, strg ): - """Returns the line of text containing loc within a string, counting newlines as line separators. - """ - lastCR = strg.rfind("\n", 0, loc) - nextCR = strg.find("\n", loc) - if nextCR >= 0: - return strg[lastCR+1:nextCR] - else: - return strg[lastCR+1:] - -def _defaultStartDebugAction( instring, loc, expr ): - print ("Match " + _ustr(expr) + " at loc " + _ustr(loc) + "(%d,%d)" % ( lineno(loc,instring), col(loc,instring) )) - -def _defaultSuccessDebugAction( instring, startloc, endloc, expr, toks ): - print ("Matched " + _ustr(expr) + " -> " + str(toks.asList())) - -def _defaultExceptionDebugAction( instring, loc, expr, exc ): - print ("Exception raised:" + _ustr(exc)) - -def nullDebugAction(*args): - """'Do-nothing' debug action, to suppress debugging output during parsing.""" - pass - -'decorator to trim function calls to match the arity of the target' -if not _PY3K: - def _trim_arity(func, maxargs=2): - limit = [0] - def wrapper(*args): - while 1: - try: - return func(*args[limit[0]:]) - except TypeError: - if limit[0] <= maxargs: - limit[0] += 1 - continue - raise - return wrapper -else: - def _trim_arity(func, maxargs=2): - limit = maxargs - def wrapper(*args): - #~ nonlocal limit - while 1: - try: - return func(*args[limit:]) - except TypeError: - if limit: - limit -= 1 - continue - raise - return wrapper - -class ParserElement(object): - """Abstract base level parser element class.""" - DEFAULT_WHITE_CHARS = " \n\t\r" - verbose_stacktrace = False - - def setDefaultWhitespaceChars( chars ): - """Overrides the default whitespace chars - """ - ParserElement.DEFAULT_WHITE_CHARS = chars - setDefaultWhitespaceChars = staticmethod(setDefaultWhitespaceChars) - - def __init__( self, savelist=False ): - self.parseAction = list() - self.failAction = None - #~ self.name = "" # don't define self.name, let subclasses try/except upcall - self.strRepr = None - self.resultsName = None - self.saveAsList = savelist - self.skipWhitespace = True - self.whiteChars = ParserElement.DEFAULT_WHITE_CHARS - self.copyDefaultWhiteChars = True - self.mayReturnEmpty = False # used when checking for left-recursion - self.keepTabs = False - self.ignoreExprs = list() - self.debug = False - self.streamlined = False - self.mayIndexError = True # used to optimize exception handling for subclasses that don't advance parse index - self.errmsg = "" - self.modalResults = True # used to mark results names as modal (report only last) or cumulative (list all) - self.debugActions = ( None, None, None ) #custom debug actions - self.re = None - self.callPreparse = True # used to avoid redundant calls to preParse - self.callDuringTry = False - - def copy( self ): - """Make a copy of this C{ParserElement}. Useful for defining different parse actions - for the same parsing pattern, using copies of the original parse element.""" - cpy = copy.copy( self ) - cpy.parseAction = self.parseAction[:] - cpy.ignoreExprs = self.ignoreExprs[:] - if self.copyDefaultWhiteChars: - cpy.whiteChars = ParserElement.DEFAULT_WHITE_CHARS - return cpy - - def setName( self, name ): - """Define name for this expression, for use in debugging.""" - self.name = name - self.errmsg = "Expected " + self.name - if hasattr(self,"exception"): - self.exception.msg = self.errmsg - return self - - def setResultsName( self, name, listAllMatches=False ): - """Define name for referencing matching tokens as a nested attribute - of the returned parse results. - NOTE: this returns a *copy* of the original C{ParserElement} object; - this is so that the client can define a basic element, such as an - integer, and reference it in multiple places with different names. - - You can also set results names using the abbreviated syntax, - C{expr("name")} in place of C{expr.setResultsName("name")} - - see L{I{__call__}<__call__>}. - """ - newself = self.copy() - newself.resultsName = name - newself.modalResults = not listAllMatches - return newself - - def setBreak(self,breakFlag = True): - """Method to invoke the Python pdb debugger when this element is - about to be parsed. Set C{breakFlag} to True to enable, False to - disable. - """ - if breakFlag: - _parseMethod = self._parse - def breaker(instring, loc, doActions=True, callPreParse=True): - import pdb - pdb.set_trace() - return _parseMethod( instring, loc, doActions, callPreParse ) - breaker._originalParseMethod = _parseMethod - self._parse = breaker - else: - if hasattr(self._parse,"_originalParseMethod"): - self._parse = self._parse._originalParseMethod - return self - - def setParseAction( self, *fns, **kwargs ): - """Define action to perform when successfully matching parse element definition. - Parse action fn is a callable method with 0-3 arguments, called as C{fn(s,loc,toks)}, - C{fn(loc,toks)}, C{fn(toks)}, or just C{fn()}, where: - - s = the original string being parsed (see note below) - - loc = the location of the matching substring - - toks = a list of the matched tokens, packaged as a ParseResults object - If the functions in fns modify the tokens, they can return them as the return - value from fn, and the modified list of tokens will replace the original. - Otherwise, fn does not need to return any value. - - Note: the default parsing behavior is to expand tabs in the input string - before starting the parsing process. See L{I{parseString}} for more information - on parsing strings containing s, and suggested methods to maintain a - consistent view of the parsed string, the parse location, and line and column - positions within the parsed string. - """ - self.parseAction = list(map(_trim_arity, list(fns))) - self.callDuringTry = ("callDuringTry" in kwargs and kwargs["callDuringTry"]) - return self - - def addParseAction( self, *fns, **kwargs ): - """Add parse action to expression's list of parse actions. See L{I{setParseAction}}.""" - self.parseAction += list(map(_trim_arity, list(fns))) - self.callDuringTry = self.callDuringTry or ("callDuringTry" in kwargs and kwargs["callDuringTry"]) - return self - - def setFailAction( self, fn ): - """Define action to perform if parsing fails at this expression. - Fail acton fn is a callable function that takes the arguments - C{fn(s,loc,expr,err)} where: - - s = string being parsed - - loc = location where expression match was attempted and failed - - expr = the parse expression that failed - - err = the exception thrown - The function returns no value. It may throw C{ParseFatalException} - if it is desired to stop parsing immediately.""" - self.failAction = fn - return self - - def _skipIgnorables( self, instring, loc ): - exprsFound = True - while exprsFound: - exprsFound = False - for e in self.ignoreExprs: - try: - while 1: - loc,dummy = e._parse( instring, loc ) - exprsFound = True - except ParseException: - pass - return loc - - def preParse( self, instring, loc ): - if self.ignoreExprs: - loc = self._skipIgnorables( instring, loc ) - - if self.skipWhitespace: - wt = self.whiteChars - instrlen = len(instring) - while loc < instrlen and instring[loc] in wt: - loc += 1 - - return loc - - def parseImpl( self, instring, loc, doActions=True ): - return loc, [] - - def postParse( self, instring, loc, tokenlist ): - return tokenlist - - #~ @profile - def _parseNoCache( self, instring, loc, doActions=True, callPreParse=True ): - debugging = ( self.debug ) #and doActions ) - - if debugging or self.failAction: - #~ print ("Match",self,"at loc",loc,"(%d,%d)" % ( lineno(loc,instring), col(loc,instring) )) - if (self.debugActions[0] ): - self.debugActions[0]( instring, loc, self ) - if callPreParse and self.callPreparse: - preloc = self.preParse( instring, loc ) - else: - preloc = loc - tokensStart = preloc - try: - try: - loc,tokens = self.parseImpl( instring, preloc, doActions ) - except IndexError: - raise ParseException( instring, len(instring), self.errmsg, self ) - except ParseBaseException: - #~ print ("Exception raised:", err) - err = None - if self.debugActions[2]: - err = sys.exc_info()[1] - self.debugActions[2]( instring, tokensStart, self, err ) - if self.failAction: - if err is None: - err = sys.exc_info()[1] - self.failAction( instring, tokensStart, self, err ) - raise - else: - if callPreParse and self.callPreparse: - preloc = self.preParse( instring, loc ) - else: - preloc = loc - tokensStart = preloc - if self.mayIndexError or loc >= len(instring): - try: - loc,tokens = self.parseImpl( instring, preloc, doActions ) - except IndexError: - raise ParseException( instring, len(instring), self.errmsg, self ) - else: - loc,tokens = self.parseImpl( instring, preloc, doActions ) - - tokens = self.postParse( instring, loc, tokens ) - - retTokens = ParseResults( tokens, self.resultsName, asList=self.saveAsList, modal=self.modalResults ) - if self.parseAction and (doActions or self.callDuringTry): - if debugging: - try: - for fn in self.parseAction: - tokens = fn( instring, tokensStart, retTokens ) - if tokens is not None: - retTokens = ParseResults( tokens, - self.resultsName, - asList=self.saveAsList and isinstance(tokens,(ParseResults,list)), - modal=self.modalResults ) - except ParseBaseException: - #~ print "Exception raised in user parse action:", err - if (self.debugActions[2] ): - err = sys.exc_info()[1] - self.debugActions[2]( instring, tokensStart, self, err ) - raise - else: - for fn in self.parseAction: - tokens = fn( instring, tokensStart, retTokens ) - if tokens is not None: - retTokens = ParseResults( tokens, - self.resultsName, - asList=self.saveAsList and isinstance(tokens,(ParseResults,list)), - modal=self.modalResults ) - - if debugging: - #~ print ("Matched",self,"->",retTokens.asList()) - if (self.debugActions[1] ): - self.debugActions[1]( instring, tokensStart, loc, self, retTokens ) - - return loc, retTokens - - def tryParse( self, instring, loc ): - try: - return self._parse( instring, loc, doActions=False )[0] - except ParseFatalException: - raise ParseException( instring, loc, self.errmsg, self) - - # this method gets repeatedly called during backtracking with the same arguments - - # we can cache these arguments and save ourselves the trouble of re-parsing the contained expression - def _parseCache( self, instring, loc, doActions=True, callPreParse=True ): - lookup = (self,instring,loc,callPreParse,doActions) - if lookup in ParserElement._exprArgCache: - value = ParserElement._exprArgCache[ lookup ] - if isinstance(value, Exception): - raise value - return (value[0],value[1].copy()) - else: - try: - value = self._parseNoCache( instring, loc, doActions, callPreParse ) - ParserElement._exprArgCache[ lookup ] = (value[0],value[1].copy()) - return value - except ParseBaseException: - pe = sys.exc_info()[1] - ParserElement._exprArgCache[ lookup ] = pe - raise - - _parse = _parseNoCache - - # argument cache for optimizing repeated calls when backtracking through recursive expressions - _exprArgCache = {} - def resetCache(): - ParserElement._exprArgCache.clear() - resetCache = staticmethod(resetCache) - - _packratEnabled = False - def enablePackrat(): - """Enables "packrat" parsing, which adds memoizing to the parsing logic. - Repeated parse attempts at the same string location (which happens - often in many complex grammars) can immediately return a cached value, - instead of re-executing parsing/validating code. Memoizing is done of - both valid results and parsing exceptions. - - This speedup may break existing programs that use parse actions that - have side-effects. For this reason, packrat parsing is disabled when - you first import pyparsing. To activate the packrat feature, your - program must call the class method C{ParserElement.enablePackrat()}. If - your program uses C{psyco} to "compile as you go", you must call - C{enablePackrat} before calling C{psyco.full()}. If you do not do this, - Python will crash. For best results, call C{enablePackrat()} immediately - after importing pyparsing. - """ - if not ParserElement._packratEnabled: - ParserElement._packratEnabled = True - ParserElement._parse = ParserElement._parseCache - enablePackrat = staticmethod(enablePackrat) - - def parseString( self, instring, parseAll=False ): - """Execute the parse expression with the given string. - This is the main interface to the client code, once the complete - expression has been built. - - If you want the grammar to require that the entire input string be - successfully parsed, then set C{parseAll} to True (equivalent to ending - the grammar with C{StringEnd()}). - - Note: C{parseString} implicitly calls C{expandtabs()} on the input string, - in order to report proper column numbers in parse actions. - If the input string contains tabs and - the grammar uses parse actions that use the C{loc} argument to index into the - string being parsed, you can ensure you have a consistent view of the input - string by: - - calling C{parseWithTabs} on your grammar before calling C{parseString} - (see L{I{parseWithTabs}}) - - define your parse action using the full C{(s,loc,toks)} signature, and - reference the input string using the parse action's C{s} argument - - explictly expand the tabs in your input string before calling - C{parseString} - """ - ParserElement.resetCache() - if not self.streamlined: - self.streamline() - #~ self.saveAsList = True - for e in self.ignoreExprs: - e.streamline() - if not self.keepTabs: - instring = instring.expandtabs() - try: - loc, tokens = self._parse( instring, 0 ) - if parseAll: - loc = self.preParse( instring, loc ) - se = Empty() + StringEnd() - se._parse( instring, loc ) - except ParseBaseException: - if ParserElement.verbose_stacktrace: - raise - else: - # catch and re-raise exception from here, clears out pyparsing internal stack trace - exc = sys.exc_info()[1] - raise exc - else: - return tokens - - def scanString( self, instring, maxMatches=_MAX_INT, overlap=False ): - """Scan the input string for expression matches. Each match will return the - matching tokens, start location, and end location. May be called with optional - C{maxMatches} argument, to clip scanning after 'n' matches are found. If - C{overlap} is specified, then overlapping matches will be reported. - - Note that the start and end locations are reported relative to the string - being parsed. See L{I{parseString}} for more information on parsing - strings with embedded tabs.""" - if not self.streamlined: - self.streamline() - for e in self.ignoreExprs: - e.streamline() - - if not self.keepTabs: - instring = _ustr(instring).expandtabs() - instrlen = len(instring) - loc = 0 - preparseFn = self.preParse - parseFn = self._parse - ParserElement.resetCache() - matches = 0 - try: - while loc <= instrlen and matches < maxMatches: - try: - preloc = preparseFn( instring, loc ) - nextLoc,tokens = parseFn( instring, preloc, callPreParse=False ) - except ParseException: - loc = preloc+1 - else: - if nextLoc > loc: - matches += 1 - yield tokens, preloc, nextLoc - if overlap: - nextloc = preparseFn( instring, loc ) - if nextloc > loc: - loc = nextLoc - else: - loc += 1 - else: - loc = nextLoc - else: - loc = preloc+1 - except ParseBaseException: - if ParserElement.verbose_stacktrace: - raise - else: - # catch and re-raise exception from here, clears out pyparsing internal stack trace - exc = sys.exc_info()[1] - raise exc - - def transformString( self, instring ): - """Extension to C{scanString}, to modify matching text with modified tokens that may - be returned from a parse action. To use C{transformString}, define a grammar and - attach a parse action to it that modifies the returned token list. - Invoking C{transformString()} on a target string will then scan for matches, - and replace the matched text patterns according to the logic in the parse - action. C{transformString()} returns the resulting transformed string.""" - out = [] - lastE = 0 - # force preservation of s, to minimize unwanted transformation of string, and to - # keep string locs straight between transformString and scanString - self.keepTabs = True - try: - for t,s,e in self.scanString( instring ): - out.append( instring[lastE:s] ) - if t: - if isinstance(t,ParseResults): - out += t.asList() - elif isinstance(t,list): - out += t - else: - out.append(t) - lastE = e - out.append(instring[lastE:]) - out = [o for o in out if o] - return "".join(map(_ustr,_flatten(out))) - except ParseBaseException: - if ParserElement.verbose_stacktrace: - raise - else: - # catch and re-raise exception from here, clears out pyparsing internal stack trace - exc = sys.exc_info()[1] - raise exc - - def searchString( self, instring, maxMatches=_MAX_INT ): - """Another extension to C{scanString}, simplifying the access to the tokens found - to match the given parse expression. May be called with optional - C{maxMatches} argument, to clip searching after 'n' matches are found. - """ - try: - return ParseResults([ t for t,s,e in self.scanString( instring, maxMatches ) ]) - except ParseBaseException: - if ParserElement.verbose_stacktrace: - raise - else: - # catch and re-raise exception from here, clears out pyparsing internal stack trace - exc = sys.exc_info()[1] - raise exc - - def __add__(self, other ): - """Implementation of + operator - returns And""" - if isinstance( other, basestring ): - other = Literal( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return And( [ self, other ] ) - - def __radd__(self, other ): - """Implementation of + operator when left operand is not a C{ParserElement}""" - if isinstance( other, basestring ): - other = Literal( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return other + self - - def __sub__(self, other): - """Implementation of - operator, returns C{And} with error stop""" - if isinstance( other, basestring ): - other = Literal( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return And( [ self, And._ErrorStop(), other ] ) - - def __rsub__(self, other ): - """Implementation of - operator when left operand is not a C{ParserElement}""" - if isinstance( other, basestring ): - other = Literal( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return other - self - - def __mul__(self,other): - """Implementation of * operator, allows use of C{expr * 3} in place of - C{expr + expr + expr}. Expressions may also me multiplied by a 2-integer - tuple, similar to C{{min,max}} multipliers in regular expressions. Tuples - may also include C{None} as in: - - C{expr*(n,None)} or C{expr*(n,)} is equivalent - to C{expr*n + ZeroOrMore(expr)} - (read as "at least n instances of C{expr}") - - C{expr*(None,n)} is equivalent to C{expr*(0,n)} - (read as "0 to n instances of C{expr}") - - C{expr*(None,None)} is equivalent to C{ZeroOrMore(expr)} - - C{expr*(1,None)} is equivalent to C{OneOrMore(expr)} - - Note that C{expr*(None,n)} does not raise an exception if - more than n exprs exist in the input stream; that is, - C{expr*(None,n)} does not enforce a maximum number of expr - occurrences. If this behavior is desired, then write - C{expr*(None,n) + ~expr} - - """ - if isinstance(other,int): - minElements, optElements = other,0 - elif isinstance(other,tuple): - other = (other + (None, None))[:2] - if other[0] is None: - other = (0, other[1]) - if isinstance(other[0],int) and other[1] is None: - if other[0] == 0: - return ZeroOrMore(self) - if other[0] == 1: - return OneOrMore(self) - else: - return self*other[0] + ZeroOrMore(self) - elif isinstance(other[0],int) and isinstance(other[1],int): - minElements, optElements = other - optElements -= minElements - else: - raise TypeError("cannot multiply 'ParserElement' and ('%s','%s') objects", type(other[0]),type(other[1])) - else: - raise TypeError("cannot multiply 'ParserElement' and '%s' objects", type(other)) - - if minElements < 0: - raise ValueError("cannot multiply ParserElement by negative value") - if optElements < 0: - raise ValueError("second tuple value must be greater or equal to first tuple value") - if minElements == optElements == 0: - raise ValueError("cannot multiply ParserElement by 0 or (0,0)") - - if (optElements): - def makeOptionalList(n): - if n>1: - return Optional(self + makeOptionalList(n-1)) - else: - return Optional(self) - if minElements: - if minElements == 1: - ret = self + makeOptionalList(optElements) - else: - ret = And([self]*minElements) + makeOptionalList(optElements) - else: - ret = makeOptionalList(optElements) - else: - if minElements == 1: - ret = self - else: - ret = And([self]*minElements) - return ret - - def __rmul__(self, other): - return self.__mul__(other) - - def __or__(self, other ): - """Implementation of | operator - returns C{MatchFirst}""" - if isinstance( other, basestring ): - other = Literal( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return MatchFirst( [ self, other ] ) - - def __ror__(self, other ): - """Implementation of | operator when left operand is not a C{ParserElement}""" - if isinstance( other, basestring ): - other = Literal( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return other | self - - def __xor__(self, other ): - """Implementation of ^ operator - returns C{Or}""" - if isinstance( other, basestring ): - other = Literal( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return Or( [ self, other ] ) - - def __rxor__(self, other ): - """Implementation of ^ operator when left operand is not a C{ParserElement}""" - if isinstance( other, basestring ): - other = Literal( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return other ^ self - - def __and__(self, other ): - """Implementation of & operator - returns C{Each}""" - if isinstance( other, basestring ): - other = Literal( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return Each( [ self, other ] ) - - def __rand__(self, other ): - """Implementation of & operator when left operand is not a C{ParserElement}""" - if isinstance( other, basestring ): - other = Literal( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return other & self - - def __invert__( self ): - """Implementation of ~ operator - returns C{NotAny}""" - return NotAny( self ) - - def __call__(self, name): - """Shortcut for C{setResultsName}, with C{listAllMatches=default}:: - userdata = Word(alphas).setResultsName("name") + Word(nums+"-").setResultsName("socsecno") - could be written as:: - userdata = Word(alphas)("name") + Word(nums+"-")("socsecno") - - If C{name} is given with a trailing C{'*'} character, then C{listAllMatches} will be - passed as C{True}. - """ - if not name.endswith("*"): - return self.setResultsName(name) - else: - return self.setResultsName(name[:-1], listAllMatches=True) - - def suppress( self ): - """Suppresses the output of this C{ParserElement}; useful to keep punctuation from - cluttering up returned output. - """ - return Suppress( self ) - - def leaveWhitespace( self ): - """Disables the skipping of whitespace before matching the characters in the - C{ParserElement}'s defined pattern. This is normally only used internally by - the pyparsing module, but may be needed in some whitespace-sensitive grammars. - """ - self.skipWhitespace = False - return self - - def setWhitespaceChars( self, chars ): - """Overrides the default whitespace chars - """ - self.skipWhitespace = True - self.whiteChars = chars - self.copyDefaultWhiteChars = False - return self - - def parseWithTabs( self ): - """Overrides default behavior to expand C{}s to spaces before parsing the input string. - Must be called before C{parseString} when the input grammar contains elements that - match C{} characters.""" - self.keepTabs = True - return self - - def ignore( self, other ): - """Define expression to be ignored (e.g., comments) while doing pattern - matching; may be called repeatedly, to define multiple comment or other - ignorable patterns. - """ - if isinstance( other, Suppress ): - if other not in self.ignoreExprs: - self.ignoreExprs.append( other.copy() ) - else: - self.ignoreExprs.append( Suppress( other.copy() ) ) - return self - - def setDebugActions( self, startAction, successAction, exceptionAction ): - """Enable display of debugging messages while doing pattern matching.""" - self.debugActions = (startAction or _defaultStartDebugAction, - successAction or _defaultSuccessDebugAction, - exceptionAction or _defaultExceptionDebugAction) - self.debug = True - return self - - def setDebug( self, flag=True ): - """Enable display of debugging messages while doing pattern matching. - Set C{flag} to True to enable, False to disable.""" - if flag: - self.setDebugActions( _defaultStartDebugAction, _defaultSuccessDebugAction, _defaultExceptionDebugAction ) - else: - self.debug = False - return self - - def __str__( self ): - return self.name - - def __repr__( self ): - return _ustr(self) - - def streamline( self ): - self.streamlined = True - self.strRepr = None - return self - - def checkRecursion( self, parseElementList ): - pass - - def validate( self, validateTrace=[] ): - """Check defined expressions for valid structure, check for infinite recursive definitions.""" - self.checkRecursion( [] ) - - def parseFile( self, file_or_filename, parseAll=False ): - """Execute the parse expression on the given file or filename. - If a filename is specified (instead of a file object), - the entire file is opened, read, and closed before parsing. - """ - try: - file_contents = file_or_filename.read() - except AttributeError: - f = open(file_or_filename, "rb") - file_contents = f.read() - f.close() - try: - return self.parseString(file_contents, parseAll) - except ParseBaseException: - # catch and re-raise exception from here, clears out pyparsing internal stack trace - exc = sys.exc_info()[1] - raise exc - - def getException(self): - return ParseException("",0,self.errmsg,self) - - def __getattr__(self,aname): - if aname == "myException": - self.myException = ret = self.getException(); - return ret; - else: - raise AttributeError("no such attribute " + aname) - - def __eq__(self,other): - if isinstance(other, ParserElement): - return self is other or self.__dict__ == other.__dict__ - elif isinstance(other, basestring): - try: - self.parseString(_ustr(other), parseAll=True) - return True - except ParseBaseException: - return False - else: - return super(ParserElement,self)==other - - def __ne__(self,other): - return not (self == other) - - def __hash__(self): - return hash(id(self)) - - def __req__(self,other): - return self == other - - def __rne__(self,other): - return not (self == other) - - -class Token(ParserElement): - """Abstract C{ParserElement} subclass, for defining atomic matching patterns.""" - def __init__( self ): - super(Token,self).__init__( savelist=False ) - #self.myException = ParseException("",0,"",self) - - def setName(self, name): - s = super(Token,self).setName(name) - self.errmsg = "Expected " + self.name - #s.myException.msg = self.errmsg - return s - - -class Empty(Token): - """An empty token, will always match.""" - def __init__( self ): - super(Empty,self).__init__() - self.name = "Empty" - self.mayReturnEmpty = True - self.mayIndexError = False - - -class NoMatch(Token): - """A token that will never match.""" - def __init__( self ): - super(NoMatch,self).__init__() - self.name = "NoMatch" - self.mayReturnEmpty = True - self.mayIndexError = False - self.errmsg = "Unmatchable token" - #self.myException.msg = self.errmsg - - def parseImpl( self, instring, loc, doActions=True ): - exc = self.myException - exc.loc = loc - exc.pstr = instring - raise exc - - -class Literal(Token): - """Token to exactly match a specified string.""" - def __init__( self, matchString ): - super(Literal,self).__init__() - self.match = matchString - self.matchLen = len(matchString) - try: - self.firstMatchChar = matchString[0] - except IndexError: - warnings.warn("null string passed to Literal; use Empty() instead", - SyntaxWarning, stacklevel=2) - self.__class__ = Empty - self.name = '"%s"' % _ustr(self.match) - self.errmsg = "Expected " + self.name - self.mayReturnEmpty = False - #self.myException.msg = self.errmsg - self.mayIndexError = False - - # Performance tuning: this routine gets called a *lot* - # if this is a single character match string and the first character matches, - # short-circuit as quickly as possible, and avoid calling startswith - #~ @profile - def parseImpl( self, instring, loc, doActions=True ): - if (instring[loc] == self.firstMatchChar and - (self.matchLen==1 or instring.startswith(self.match,loc)) ): - return loc+self.matchLen, self.match - #~ raise ParseException( instring, loc, self.errmsg ) - exc = self.myException - exc.loc = loc - exc.pstr = instring - raise exc -_L = Literal - -class Keyword(Token): - """Token to exactly match a specified string as a keyword, that is, it must be - immediately followed by a non-keyword character. Compare with C{Literal}:: - Literal("if") will match the leading C{'if'} in C{'ifAndOnlyIf'}. - Keyword("if") will not; it will only match the leading C{'if'} in C{'if x=1'}, or C{'if(y==2)'} - Accepts two optional constructor arguments in addition to the keyword string: - C{identChars} is a string of characters that would be valid identifier characters, - defaulting to all alphanumerics + "_" and "$"; C{caseless} allows case-insensitive - matching, default is C{False}. - """ - DEFAULT_KEYWORD_CHARS = alphanums+"_$" - - def __init__( self, matchString, identChars=DEFAULT_KEYWORD_CHARS, caseless=False ): - super(Keyword,self).__init__() - self.match = matchString - self.matchLen = len(matchString) - try: - self.firstMatchChar = matchString[0] - except IndexError: - warnings.warn("null string passed to Keyword; use Empty() instead", - SyntaxWarning, stacklevel=2) - self.name = '"%s"' % self.match - self.errmsg = "Expected " + self.name - self.mayReturnEmpty = False - #self.myException.msg = self.errmsg - self.mayIndexError = False - self.caseless = caseless - if caseless: - self.caselessmatch = matchString.upper() - identChars = identChars.upper() - self.identChars = set(identChars) - - def parseImpl( self, instring, loc, doActions=True ): - if self.caseless: - if ( (instring[ loc:loc+self.matchLen ].upper() == self.caselessmatch) and - (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen].upper() not in self.identChars) and - (loc == 0 or instring[loc-1].upper() not in self.identChars) ): - return loc+self.matchLen, self.match - else: - if (instring[loc] == self.firstMatchChar and - (self.matchLen==1 or instring.startswith(self.match,loc)) and - (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen] not in self.identChars) and - (loc == 0 or instring[loc-1] not in self.identChars) ): - return loc+self.matchLen, self.match - #~ raise ParseException( instring, loc, self.errmsg ) - exc = self.myException - exc.loc = loc - exc.pstr = instring - raise exc - - def copy(self): - c = super(Keyword,self).copy() - c.identChars = Keyword.DEFAULT_KEYWORD_CHARS - return c - - def setDefaultKeywordChars( chars ): - """Overrides the default Keyword chars - """ - Keyword.DEFAULT_KEYWORD_CHARS = chars - setDefaultKeywordChars = staticmethod(setDefaultKeywordChars) - -class CaselessLiteral(Literal): - """Token to match a specified string, ignoring case of letters. - Note: the matched results will always be in the case of the given - match string, NOT the case of the input text. - """ - def __init__( self, matchString ): - super(CaselessLiteral,self).__init__( matchString.upper() ) - # Preserve the defining literal. - self.returnString = matchString - self.name = "'%s'" % self.returnString - self.errmsg = "Expected " + self.name - #self.myException.msg = self.errmsg - - def parseImpl( self, instring, loc, doActions=True ): - if instring[ loc:loc+self.matchLen ].upper() == self.match: - return loc+self.matchLen, self.returnString - #~ raise ParseException( instring, loc, self.errmsg ) - exc = self.myException - exc.loc = loc - exc.pstr = instring - raise exc - -class CaselessKeyword(Keyword): - def __init__( self, matchString, identChars=Keyword.DEFAULT_KEYWORD_CHARS ): - super(CaselessKeyword,self).__init__( matchString, identChars, caseless=True ) - - def parseImpl( self, instring, loc, doActions=True ): - if ( (instring[ loc:loc+self.matchLen ].upper() == self.caselessmatch) and - (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen].upper() not in self.identChars) ): - return loc+self.matchLen, self.match - #~ raise ParseException( instring, loc, self.errmsg ) - exc = self.myException - exc.loc = loc - exc.pstr = instring - raise exc - -class Word(Token): - """Token for matching words composed of allowed character sets. - Defined with string containing all allowed initial characters, - an optional string containing allowed body characters (if omitted, - defaults to the initial character set), and an optional minimum, - maximum, and/or exact length. The default value for C{min} is 1 (a - minimum value < 1 is not valid); the default values for C{max} and C{exact} - are 0, meaning no maximum or exact length restriction. - """ - def __init__( self, initChars, bodyChars=None, min=1, max=0, exact=0, asKeyword=False ): - super(Word,self).__init__() - self.initCharsOrig = initChars - self.initChars = set(initChars) - if bodyChars : - self.bodyCharsOrig = bodyChars - self.bodyChars = set(bodyChars) - else: - self.bodyCharsOrig = initChars - self.bodyChars = set(initChars) - - self.maxSpecified = max > 0 - - if min < 1: - raise ValueError("cannot specify a minimum length < 1; use Optional(Word()) if zero-length word is permitted") - - self.minLen = min - - if max > 0: - self.maxLen = max - else: - self.maxLen = _MAX_INT - - if exact > 0: - self.maxLen = exact - self.minLen = exact - - self.name = _ustr(self) - self.errmsg = "Expected " + self.name - #self.myException.msg = self.errmsg - self.mayIndexError = False - self.asKeyword = asKeyword - - if ' ' not in self.initCharsOrig+self.bodyCharsOrig and (min==1 and max==0 and exact==0): - if self.bodyCharsOrig == self.initCharsOrig: - self.reString = "[%s]+" % _escapeRegexRangeChars(self.initCharsOrig) - elif len(self.bodyCharsOrig) == 1: - self.reString = "%s[%s]*" % \ - (re.escape(self.initCharsOrig), - _escapeRegexRangeChars(self.bodyCharsOrig),) - else: - self.reString = "[%s][%s]*" % \ - (_escapeRegexRangeChars(self.initCharsOrig), - _escapeRegexRangeChars(self.bodyCharsOrig),) - if self.asKeyword: - self.reString = r"\b"+self.reString+r"\b" - try: - self.re = re.compile( self.reString ) - except: - self.re = None - - def parseImpl( self, instring, loc, doActions=True ): - if self.re: - result = self.re.match(instring,loc) - if not result: - exc = self.myException - exc.loc = loc - exc.pstr = instring - raise exc - - loc = result.end() - return loc, result.group() - - if not(instring[ loc ] in self.initChars): - #~ raise ParseException( instring, loc, self.errmsg ) - exc = self.myException - exc.loc = loc - exc.pstr = instring - raise exc - start = loc - loc += 1 - instrlen = len(instring) - bodychars = self.bodyChars - maxloc = start + self.maxLen - maxloc = min( maxloc, instrlen ) - while loc < maxloc and instring[loc] in bodychars: - loc += 1 - - throwException = False - if loc - start < self.minLen: - throwException = True - if self.maxSpecified and loc < instrlen and instring[loc] in bodychars: - throwException = True - if self.asKeyword: - if (start>0 and instring[start-1] in bodychars) or (loc4: - return s[:4]+"..." - else: - return s - - if ( self.initCharsOrig != self.bodyCharsOrig ): - self.strRepr = "W:(%s,%s)" % ( charsAsStr(self.initCharsOrig), charsAsStr(self.bodyCharsOrig) ) - else: - self.strRepr = "W:(%s)" % charsAsStr(self.initCharsOrig) - - return self.strRepr - - -class Regex(Token): - """Token for matching strings that match a given regular expression. - Defined with string specifying the regular expression in a form recognized by the inbuilt Python re module. - """ - compiledREtype = type(re.compile("[A-Z]")) - def __init__( self, pattern, flags=0): - """The parameters C{pattern} and C{flags} are passed to the C{re.compile()} function as-is. See the Python C{re} module for an explanation of the acceptable patterns and flags.""" - super(Regex,self).__init__() - - if isinstance(pattern, basestring): - if len(pattern) == 0: - warnings.warn("null string passed to Regex; use Empty() instead", - SyntaxWarning, stacklevel=2) - - self.pattern = pattern - self.flags = flags - - try: - self.re = re.compile(self.pattern, self.flags) - self.reString = self.pattern - except sre_constants.error: - warnings.warn("invalid pattern (%s) passed to Regex" % pattern, - SyntaxWarning, stacklevel=2) - raise - - elif isinstance(pattern, Regex.compiledREtype): - self.re = pattern - self.pattern = \ - self.reString = str(pattern) - self.flags = flags - - else: - raise ValueError("Regex may only be constructed with a string or a compiled RE object") - - self.name = _ustr(self) - self.errmsg = "Expected " + self.name - #self.myException.msg = self.errmsg - self.mayIndexError = False - self.mayReturnEmpty = True - - def parseImpl( self, instring, loc, doActions=True ): - result = self.re.match(instring,loc) - if not result: - exc = self.myException - exc.loc = loc - exc.pstr = instring - raise exc - - loc = result.end() - d = result.groupdict() - ret = ParseResults(result.group()) - if d: - for k in d: - ret[k] = d[k] - return loc,ret - - def __str__( self ): - try: - return super(Regex,self).__str__() - except: - pass - - if self.strRepr is None: - self.strRepr = "Re:(%s)" % repr(self.pattern) - - return self.strRepr - - -class QuotedString(Token): - """Token for matching strings that are delimited by quoting characters. - """ - def __init__( self, quoteChar, escChar=None, escQuote=None, multiline=False, unquoteResults=True, endQuoteChar=None): - """ - Defined with the following parameters: - - quoteChar - string of one or more characters defining the quote delimiting string - - escChar - character to escape quotes, typically backslash (default=None) - - escQuote - special quote sequence to escape an embedded quote string (such as SQL's "" to escape an embedded ") (default=None) - - multiline - boolean indicating whether quotes can span multiple lines (default=False) - - unquoteResults - boolean indicating whether the matched text should be unquoted (default=True) - - endQuoteChar - string of one or more characters defining the end of the quote delimited string (default=None => same as quoteChar) - """ - super(QuotedString,self).__init__() - - # remove white space from quote chars - wont work anyway - quoteChar = quoteChar.strip() - if len(quoteChar) == 0: - warnings.warn("quoteChar cannot be the empty string",SyntaxWarning,stacklevel=2) - raise SyntaxError() - - if endQuoteChar is None: - endQuoteChar = quoteChar - else: - endQuoteChar = endQuoteChar.strip() - if len(endQuoteChar) == 0: - warnings.warn("endQuoteChar cannot be the empty string",SyntaxWarning,stacklevel=2) - raise SyntaxError() - - self.quoteChar = quoteChar - self.quoteCharLen = len(quoteChar) - self.firstQuoteChar = quoteChar[0] - self.endQuoteChar = endQuoteChar - self.endQuoteCharLen = len(endQuoteChar) - self.escChar = escChar - self.escQuote = escQuote - self.unquoteResults = unquoteResults - - if multiline: - self.flags = re.MULTILINE | re.DOTALL - self.pattern = r'%s(?:[^%s%s]' % \ - ( re.escape(self.quoteChar), - _escapeRegexRangeChars(self.endQuoteChar[0]), - (escChar is not None and _escapeRegexRangeChars(escChar) or '') ) - else: - self.flags = 0 - self.pattern = r'%s(?:[^%s\n\r%s]' % \ - ( re.escape(self.quoteChar), - _escapeRegexRangeChars(self.endQuoteChar[0]), - (escChar is not None and _escapeRegexRangeChars(escChar) or '') ) - if len(self.endQuoteChar) > 1: - self.pattern += ( - '|(?:' + ')|(?:'.join(["%s[^%s]" % (re.escape(self.endQuoteChar[:i]), - _escapeRegexRangeChars(self.endQuoteChar[i])) - for i in range(len(self.endQuoteChar)-1,0,-1)]) + ')' - ) - if escQuote: - self.pattern += (r'|(?:%s)' % re.escape(escQuote)) - if escChar: - self.pattern += (r'|(?:%s.)' % re.escape(escChar)) - charset = ''.join(set(self.quoteChar[0]+self.endQuoteChar[0])).replace('^',r'\^').replace('-',r'\-') - self.escCharReplacePattern = re.escape(self.escChar)+("([%s])" % charset) - self.pattern += (r')*%s' % re.escape(self.endQuoteChar)) - - try: - self.re = re.compile(self.pattern, self.flags) - self.reString = self.pattern - except sre_constants.error: - warnings.warn("invalid pattern (%s) passed to Regex" % self.pattern, - SyntaxWarning, stacklevel=2) - raise - - self.name = _ustr(self) - self.errmsg = "Expected " + self.name - #self.myException.msg = self.errmsg - self.mayIndexError = False - self.mayReturnEmpty = True - - def parseImpl( self, instring, loc, doActions=True ): - result = instring[loc] == self.firstQuoteChar and self.re.match(instring,loc) or None - if not result: - exc = self.myException - exc.loc = loc - exc.pstr = instring - raise exc - - loc = result.end() - ret = result.group() - - if self.unquoteResults: - - # strip off quotes - ret = ret[self.quoteCharLen:-self.endQuoteCharLen] - - if isinstance(ret,basestring): - # replace escaped characters - if self.escChar: - ret = re.sub(self.escCharReplacePattern,"\g<1>",ret) - - # replace escaped quotes - if self.escQuote: - ret = ret.replace(self.escQuote, self.endQuoteChar) - - return loc, ret - - def __str__( self ): - try: - return super(QuotedString,self).__str__() - except: - pass - - if self.strRepr is None: - self.strRepr = "quoted string, starting with %s ending with %s" % (self.quoteChar, self.endQuoteChar) - - return self.strRepr - - -class CharsNotIn(Token): - """Token for matching words composed of characters *not* in a given set. - Defined with string containing all disallowed characters, and an optional - minimum, maximum, and/or exact length. The default value for C{min} is 1 (a - minimum value < 1 is not valid); the default values for C{max} and C{exact} - are 0, meaning no maximum or exact length restriction. - """ - def __init__( self, notChars, min=1, max=0, exact=0 ): - super(CharsNotIn,self).__init__() - self.skipWhitespace = False - self.notChars = notChars - - if min < 1: - raise ValueError("cannot specify a minimum length < 1; use Optional(CharsNotIn()) if zero-length char group is permitted") - - self.minLen = min - - if max > 0: - self.maxLen = max - else: - self.maxLen = _MAX_INT - - if exact > 0: - self.maxLen = exact - self.minLen = exact - - self.name = _ustr(self) - self.errmsg = "Expected " + self.name - self.mayReturnEmpty = ( self.minLen == 0 ) - #self.myException.msg = self.errmsg - self.mayIndexError = False - - def parseImpl( self, instring, loc, doActions=True ): - if instring[loc] in self.notChars: - #~ raise ParseException( instring, loc, self.errmsg ) - exc = self.myException - exc.loc = loc - exc.pstr = instring - raise exc - - start = loc - loc += 1 - notchars = self.notChars - maxlen = min( start+self.maxLen, len(instring) ) - while loc < maxlen and \ - (instring[loc] not in notchars): - loc += 1 - - if loc - start < self.minLen: - #~ raise ParseException( instring, loc, self.errmsg ) - exc = self.myException - exc.loc = loc - exc.pstr = instring - raise exc - - return loc, instring[start:loc] - - def __str__( self ): - try: - return super(CharsNotIn, self).__str__() - except: - pass - - if self.strRepr is None: - if len(self.notChars) > 4: - self.strRepr = "!W:(%s...)" % self.notChars[:4] - else: - self.strRepr = "!W:(%s)" % self.notChars - - return self.strRepr - -class White(Token): - """Special matching class for matching whitespace. Normally, whitespace is ignored - by pyparsing grammars. This class is included when some whitespace structures - are significant. Define with a string containing the whitespace characters to be - matched; default is C{" \\t\\r\\n"}. Also takes optional C{min}, C{max}, and C{exact} arguments, - as defined for the C{Word} class.""" - whiteStrs = { - " " : "", - "\t": "", - "\n": "", - "\r": "", - "\f": "", - } - def __init__(self, ws=" \t\r\n", min=1, max=0, exact=0): - super(White,self).__init__() - self.matchWhite = ws - self.setWhitespaceChars( "".join([c for c in self.whiteChars if c not in self.matchWhite]) ) - #~ self.leaveWhitespace() - self.name = ("".join([White.whiteStrs[c] for c in self.matchWhite])) - self.mayReturnEmpty = True - self.errmsg = "Expected " + self.name - #self.myException.msg = self.errmsg - - self.minLen = min - - if max > 0: - self.maxLen = max - else: - self.maxLen = _MAX_INT - - if exact > 0: - self.maxLen = exact - self.minLen = exact - - def parseImpl( self, instring, loc, doActions=True ): - if not(instring[ loc ] in self.matchWhite): - #~ raise ParseException( instring, loc, self.errmsg ) - exc = self.myException - exc.loc = loc - exc.pstr = instring - raise exc - start = loc - loc += 1 - maxloc = start + self.maxLen - maxloc = min( maxloc, len(instring) ) - while loc < maxloc and instring[loc] in self.matchWhite: - loc += 1 - - if loc - start < self.minLen: - #~ raise ParseException( instring, loc, self.errmsg ) - exc = self.myException - exc.loc = loc - exc.pstr = instring - raise exc - - return loc, instring[start:loc] - - -class _PositionToken(Token): - def __init__( self ): - super(_PositionToken,self).__init__() - self.name=self.__class__.__name__ - self.mayReturnEmpty = True - self.mayIndexError = False - -class GoToColumn(_PositionToken): - """Token to advance to a specific column of input text; useful for tabular report scraping.""" - def __init__( self, colno ): - super(GoToColumn,self).__init__() - self.col = colno - - def preParse( self, instring, loc ): - if col(loc,instring) != self.col: - instrlen = len(instring) - if self.ignoreExprs: - loc = self._skipIgnorables( instring, loc ) - while loc < instrlen and instring[loc].isspace() and col( loc, instring ) != self.col : - loc += 1 - return loc - - def parseImpl( self, instring, loc, doActions=True ): - thiscol = col( loc, instring ) - if thiscol > self.col: - raise ParseException( instring, loc, "Text not in expected column", self ) - newloc = loc + self.col - thiscol - ret = instring[ loc: newloc ] - return newloc, ret - -class LineStart(_PositionToken): - """Matches if current position is at the beginning of a line within the parse string""" - def __init__( self ): - super(LineStart,self).__init__() - self.setWhitespaceChars( ParserElement.DEFAULT_WHITE_CHARS.replace("\n","") ) - self.errmsg = "Expected start of line" - #self.myException.msg = self.errmsg - - def preParse( self, instring, loc ): - preloc = super(LineStart,self).preParse(instring,loc) - if instring[preloc] == "\n": - loc += 1 - return loc - - def parseImpl( self, instring, loc, doActions=True ): - if not( loc==0 or - (loc == self.preParse( instring, 0 )) or - (instring[loc-1] == "\n") ): #col(loc, instring) != 1: - #~ raise ParseException( instring, loc, "Expected start of line" ) - exc = self.myException - exc.loc = loc - exc.pstr = instring - raise exc - return loc, [] - -class LineEnd(_PositionToken): - """Matches if current position is at the end of a line within the parse string""" - def __init__( self ): - super(LineEnd,self).__init__() - self.setWhitespaceChars( ParserElement.DEFAULT_WHITE_CHARS.replace("\n","") ) - self.errmsg = "Expected end of line" - #self.myException.msg = self.errmsg - - def parseImpl( self, instring, loc, doActions=True ): - if loc len(instring): - return loc, [] - else: - exc = self.myException - exc.loc = loc - exc.pstr = instring - raise exc - -class WordStart(_PositionToken): - """Matches if the current position is at the beginning of a Word, and - is not preceded by any character in a given set of C{wordChars} - (default=C{printables}). To emulate the C{\b} behavior of regular expressions, - use C{WordStart(alphanums)}. C{WordStart} will also match at the beginning of - the string being parsed, or at the beginning of a line. - """ - def __init__(self, wordChars = printables): - super(WordStart,self).__init__() - self.wordChars = set(wordChars) - self.errmsg = "Not at the start of a word" - - def parseImpl(self, instring, loc, doActions=True ): - if loc != 0: - if (instring[loc-1] in self.wordChars or - instring[loc] not in self.wordChars): - exc = self.myException - exc.loc = loc - exc.pstr = instring - raise exc - return loc, [] - -class WordEnd(_PositionToken): - """Matches if the current position is at the end of a Word, and - is not followed by any character in a given set of C{wordChars} - (default=C{printables}). To emulate the C{\b} behavior of regular expressions, - use C{WordEnd(alphanums)}. C{WordEnd} will also match at the end of - the string being parsed, or at the end of a line. - """ - def __init__(self, wordChars = printables): - super(WordEnd,self).__init__() - self.wordChars = set(wordChars) - self.skipWhitespace = False - self.errmsg = "Not at the end of a word" - - def parseImpl(self, instring, loc, doActions=True ): - instrlen = len(instring) - if instrlen>0 and loc maxExcLoc: - maxException = err - maxExcLoc = err.loc - except IndexError: - if len(instring) > maxExcLoc: - maxException = ParseException(instring,len(instring),e.errmsg,self) - maxExcLoc = len(instring) - else: - if loc2 > maxMatchLoc: - maxMatchLoc = loc2 - maxMatchExp = e - - if maxMatchLoc < 0: - if maxException is not None: - raise maxException - else: - raise ParseException(instring, loc, "no defined alternatives to match", self) - - return maxMatchExp._parse( instring, loc, doActions ) - - def __ixor__(self, other ): - if isinstance( other, basestring ): - other = Literal( other ) - return self.append( other ) #Or( [ self, other ] ) - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - if self.strRepr is None: - self.strRepr = "{" + " ^ ".join( [ _ustr(e) for e in self.exprs ] ) + "}" - - return self.strRepr - - def checkRecursion( self, parseElementList ): - subRecCheckList = parseElementList[:] + [ self ] - for e in self.exprs: - e.checkRecursion( subRecCheckList ) - - -class MatchFirst(ParseExpression): - """Requires that at least one C{ParseExpression} is found. - If two expressions match, the first one listed is the one that will match. - May be constructed using the C{'|'} operator. - """ - def __init__( self, exprs, savelist = False ): - super(MatchFirst,self).__init__(exprs, savelist) - if exprs: - self.mayReturnEmpty = False - for e in self.exprs: - if e.mayReturnEmpty: - self.mayReturnEmpty = True - break - else: - self.mayReturnEmpty = True - - def parseImpl( self, instring, loc, doActions=True ): - maxExcLoc = -1 - maxException = None - for e in self.exprs: - try: - ret = e._parse( instring, loc, doActions ) - return ret - except ParseException, err: - if err.loc > maxExcLoc: - maxException = err - maxExcLoc = err.loc - except IndexError: - if len(instring) > maxExcLoc: - maxException = ParseException(instring,len(instring),e.errmsg,self) - maxExcLoc = len(instring) - - # only got here if no expression matched, raise exception for match that made it the furthest - else: - if maxException is not None: - raise maxException - else: - raise ParseException(instring, loc, "no defined alternatives to match", self) - - def __ior__(self, other ): - if isinstance( other, basestring ): - other = Literal( other ) - return self.append( other ) #MatchFirst( [ self, other ] ) - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - if self.strRepr is None: - self.strRepr = "{" + " | ".join( [ _ustr(e) for e in self.exprs ] ) + "}" - - return self.strRepr - - def checkRecursion( self, parseElementList ): - subRecCheckList = parseElementList[:] + [ self ] - for e in self.exprs: - e.checkRecursion( subRecCheckList ) - - -class Each(ParseExpression): - """Requires all given C{ParseExpression}s to be found, but in any order. - Expressions may be separated by whitespace. - May be constructed using the C{'&'} operator. - """ - def __init__( self, exprs, savelist = True ): - super(Each,self).__init__(exprs, savelist) - self.mayReturnEmpty = True - for e in self.exprs: - if not e.mayReturnEmpty: - self.mayReturnEmpty = False - break - self.skipWhitespace = True - self.initExprGroups = True - - def parseImpl( self, instring, loc, doActions=True ): - if self.initExprGroups: - opt1 = [ e.expr for e in self.exprs if isinstance(e,Optional) ] - opt2 = [ e for e in self.exprs if e.mayReturnEmpty and e not in opt1 ] - self.optionals = opt1 + opt2 - self.multioptionals = [ e.expr for e in self.exprs if isinstance(e,ZeroOrMore) ] - self.multirequired = [ e.expr for e in self.exprs if isinstance(e,OneOrMore) ] - self.required = [ e for e in self.exprs if not isinstance(e,(Optional,ZeroOrMore,OneOrMore)) ] - self.required += self.multirequired - self.initExprGroups = False - tmpLoc = loc - tmpReqd = self.required[:] - tmpOpt = self.optionals[:] - matchOrder = [] - - keepMatching = True - while keepMatching: - tmpExprs = tmpReqd + tmpOpt + self.multioptionals + self.multirequired - failed = [] - for e in tmpExprs: - try: - tmpLoc = e.tryParse( instring, tmpLoc ) - except ParseException: - failed.append(e) - else: - matchOrder.append(e) - if e in tmpReqd: - tmpReqd.remove(e) - elif e in tmpOpt: - tmpOpt.remove(e) - if len(failed) == len(tmpExprs): - keepMatching = False - - if tmpReqd: - missing = ", ".join( [ _ustr(e) for e in tmpReqd ] ) - raise ParseException(instring,loc,"Missing one or more required elements (%s)" % missing ) - - # add any unmatched Optionals, in case they have default values defined - matchOrder += [e for e in self.exprs if isinstance(e,Optional) and e.expr in tmpOpt] - - resultlist = [] - for e in matchOrder: - loc,results = e._parse(instring,loc,doActions) - resultlist.append(results) - - finalResults = ParseResults([]) - for r in resultlist: - dups = {} - for k in r.keys(): - if k in finalResults.keys(): - tmp = ParseResults(finalResults[k]) - tmp += ParseResults(r[k]) - dups[k] = tmp - finalResults += ParseResults(r) - for k,v in dups.items(): - finalResults[k] = v - return loc, finalResults - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - if self.strRepr is None: - self.strRepr = "{" + " & ".join( [ _ustr(e) for e in self.exprs ] ) + "}" - - return self.strRepr - - def checkRecursion( self, parseElementList ): - subRecCheckList = parseElementList[:] + [ self ] - for e in self.exprs: - e.checkRecursion( subRecCheckList ) - - -class ParseElementEnhance(ParserElement): - """Abstract subclass of C{ParserElement}, for combining and post-processing parsed tokens.""" - def __init__( self, expr, savelist=False ): - super(ParseElementEnhance,self).__init__(savelist) - if isinstance( expr, basestring ): - expr = Literal(expr) - self.expr = expr - self.strRepr = None - if expr is not None: - self.mayIndexError = expr.mayIndexError - self.mayReturnEmpty = expr.mayReturnEmpty - self.setWhitespaceChars( expr.whiteChars ) - self.skipWhitespace = expr.skipWhitespace - self.saveAsList = expr.saveAsList - self.callPreparse = expr.callPreparse - self.ignoreExprs.extend(expr.ignoreExprs) - - def parseImpl( self, instring, loc, doActions=True ): - if self.expr is not None: - return self.expr._parse( instring, loc, doActions, callPreParse=False ) - else: - raise ParseException("",loc,self.errmsg,self) - - def leaveWhitespace( self ): - self.skipWhitespace = False - self.expr = self.expr.copy() - if self.expr is not None: - self.expr.leaveWhitespace() - return self - - def ignore( self, other ): - if isinstance( other, Suppress ): - if other not in self.ignoreExprs: - super( ParseElementEnhance, self).ignore( other ) - if self.expr is not None: - self.expr.ignore( self.ignoreExprs[-1] ) - else: - super( ParseElementEnhance, self).ignore( other ) - if self.expr is not None: - self.expr.ignore( self.ignoreExprs[-1] ) - return self - - def streamline( self ): - super(ParseElementEnhance,self).streamline() - if self.expr is not None: - self.expr.streamline() - return self - - def checkRecursion( self, parseElementList ): - if self in parseElementList: - raise RecursiveGrammarException( parseElementList+[self] ) - subRecCheckList = parseElementList[:] + [ self ] - if self.expr is not None: - self.expr.checkRecursion( subRecCheckList ) - - def validate( self, validateTrace=[] ): - tmp = validateTrace[:]+[self] - if self.expr is not None: - self.expr.validate(tmp) - self.checkRecursion( [] ) - - def __str__( self ): - try: - return super(ParseElementEnhance,self).__str__() - except: - pass - - if self.strRepr is None and self.expr is not None: - self.strRepr = "%s:(%s)" % ( self.__class__.__name__, _ustr(self.expr) ) - return self.strRepr - - -class FollowedBy(ParseElementEnhance): - """Lookahead matching of the given parse expression. C{FollowedBy} - does *not* advance the parsing position within the input string, it only - verifies that the specified parse expression matches at the current - position. C{FollowedBy} always returns a null token list.""" - def __init__( self, expr ): - super(FollowedBy,self).__init__(expr) - self.mayReturnEmpty = True - - def parseImpl( self, instring, loc, doActions=True ): - self.expr.tryParse( instring, loc ) - return loc, [] - - -class NotAny(ParseElementEnhance): - """Lookahead to disallow matching with the given parse expression. C{NotAny} - does *not* advance the parsing position within the input string, it only - verifies that the specified parse expression does *not* match at the current - position. Also, C{NotAny} does *not* skip over leading whitespace. C{NotAny} - always returns a null token list. May be constructed using the '~' operator.""" - def __init__( self, expr ): - super(NotAny,self).__init__(expr) - #~ self.leaveWhitespace() - self.skipWhitespace = False # do NOT use self.leaveWhitespace(), don't want to propagate to exprs - self.mayReturnEmpty = True - self.errmsg = "Found unwanted token, "+_ustr(self.expr) - #self.myException = ParseException("",0,self.errmsg,self) - - def parseImpl( self, instring, loc, doActions=True ): - try: - self.expr.tryParse( instring, loc ) - except (ParseException,IndexError): - pass - else: - #~ raise ParseException(instring, loc, self.errmsg ) - exc = self.myException - exc.loc = loc - exc.pstr = instring - raise exc - return loc, [] - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - if self.strRepr is None: - self.strRepr = "~{" + _ustr(self.expr) + "}" - - return self.strRepr - - -class ZeroOrMore(ParseElementEnhance): - """Optional repetition of zero or more of the given expression.""" - def __init__( self, expr ): - super(ZeroOrMore,self).__init__(expr) - self.mayReturnEmpty = True - - def parseImpl( self, instring, loc, doActions=True ): - tokens = [] - try: - loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False ) - hasIgnoreExprs = ( len(self.ignoreExprs) > 0 ) - while 1: - if hasIgnoreExprs: - preloc = self._skipIgnorables( instring, loc ) - else: - preloc = loc - loc, tmptokens = self.expr._parse( instring, preloc, doActions ) - if tmptokens or tmptokens.keys(): - tokens += tmptokens - except (ParseException,IndexError): - pass - - return loc, tokens - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - if self.strRepr is None: - self.strRepr = "[" + _ustr(self.expr) + "]..." - - return self.strRepr - - def setResultsName( self, name, listAllMatches=False ): - ret = super(ZeroOrMore,self).setResultsName(name,listAllMatches) - ret.saveAsList = True - return ret - - -class OneOrMore(ParseElementEnhance): - """Repetition of one or more of the given expression.""" - def parseImpl( self, instring, loc, doActions=True ): - # must be at least one - loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False ) - try: - hasIgnoreExprs = ( len(self.ignoreExprs) > 0 ) - while 1: - if hasIgnoreExprs: - preloc = self._skipIgnorables( instring, loc ) - else: - preloc = loc - loc, tmptokens = self.expr._parse( instring, preloc, doActions ) - if tmptokens or tmptokens.keys(): - tokens += tmptokens - except (ParseException,IndexError): - pass - - return loc, tokens - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - if self.strRepr is None: - self.strRepr = "{" + _ustr(self.expr) + "}..." - - return self.strRepr - - def setResultsName( self, name, listAllMatches=False ): - ret = super(OneOrMore,self).setResultsName(name,listAllMatches) - ret.saveAsList = True - return ret - -class _NullToken(object): - def __bool__(self): - return False - __nonzero__ = __bool__ - def __str__(self): - return "" - -_optionalNotMatched = _NullToken() -class Optional(ParseElementEnhance): - """Optional matching of the given expression. - A default return string can also be specified, if the optional expression - is not found. - """ - def __init__( self, exprs, default=_optionalNotMatched ): - super(Optional,self).__init__( exprs, savelist=False ) - self.defaultValue = default - self.mayReturnEmpty = True - - def parseImpl( self, instring, loc, doActions=True ): - try: - loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False ) - except (ParseException,IndexError): - if self.defaultValue is not _optionalNotMatched: - if self.expr.resultsName: - tokens = ParseResults([ self.defaultValue ]) - tokens[self.expr.resultsName] = self.defaultValue - else: - tokens = [ self.defaultValue ] - else: - tokens = [] - return loc, tokens - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - if self.strRepr is None: - self.strRepr = "[" + _ustr(self.expr) + "]" - - return self.strRepr - - -class SkipTo(ParseElementEnhance): - """Token for skipping over all undefined text until the matched expression is found. - If C{include} is set to true, the matched expression is also parsed (the skipped text - and matched expression are returned as a 2-element list). The C{ignore} - argument is used to define grammars (typically quoted strings and comments) that - might contain false matches. - """ - def __init__( self, other, include=False, ignore=None, failOn=None ): - super( SkipTo, self ).__init__( other ) - self.ignoreExpr = ignore - self.mayReturnEmpty = True - self.mayIndexError = False - self.includeMatch = include - self.asList = False - if failOn is not None and isinstance(failOn, basestring): - self.failOn = Literal(failOn) - else: - self.failOn = failOn - self.errmsg = "No match found for "+_ustr(self.expr) - #self.myException = ParseException("",0,self.errmsg,self) - - def parseImpl( self, instring, loc, doActions=True ): - startLoc = loc - instrlen = len(instring) - expr = self.expr - failParse = False - while loc <= instrlen: - try: - if self.failOn: - try: - self.failOn.tryParse(instring, loc) - except ParseBaseException: - pass - else: - failParse = True - raise ParseException(instring, loc, "Found expression " + str(self.failOn)) - failParse = False - if self.ignoreExpr is not None: - while 1: - try: - loc = self.ignoreExpr.tryParse(instring,loc) - # print "found ignoreExpr, advance to", loc - except ParseBaseException: - break - expr._parse( instring, loc, doActions=False, callPreParse=False ) - skipText = instring[startLoc:loc] - if self.includeMatch: - loc,mat = expr._parse(instring,loc,doActions,callPreParse=False) - if mat: - skipRes = ParseResults( skipText ) - skipRes += mat - return loc, [ skipRes ] - else: - return loc, [ skipText ] - else: - return loc, [ skipText ] - except (ParseException,IndexError): - if failParse: - raise - else: - loc += 1 - exc = self.myException - exc.loc = loc - exc.pstr = instring - raise exc - -class Forward(ParseElementEnhance): - """Forward declaration of an expression to be defined later - - used for recursive grammars, such as algebraic infix notation. - When the expression is known, it is assigned to the C{Forward} variable using the '<<' operator. - - Note: take care when assigning to C{Forward} not to overlook precedence of operators. - Specifically, '|' has a lower precedence than '<<', so that:: - fwdExpr << a | b | c - will actually be evaluated as:: - (fwdExpr << a) | b | c - thereby leaving b and c out as parseable alternatives. It is recommended that you - explicitly group the values inserted into the C{Forward}:: - fwdExpr << (a | b | c) - """ - def __init__( self, other=None ): - super(Forward,self).__init__( other, savelist=False ) - - def __lshift__( self, other ): - if isinstance( other, basestring ): - other = Literal(other) - self.expr = other - self.mayReturnEmpty = other.mayReturnEmpty - self.strRepr = None - self.mayIndexError = self.expr.mayIndexError - self.mayReturnEmpty = self.expr.mayReturnEmpty - self.setWhitespaceChars( self.expr.whiteChars ) - self.skipWhitespace = self.expr.skipWhitespace - self.saveAsList = self.expr.saveAsList - self.ignoreExprs.extend(self.expr.ignoreExprs) - return None - - def leaveWhitespace( self ): - self.skipWhitespace = False - return self - - def streamline( self ): - if not self.streamlined: - self.streamlined = True - if self.expr is not None: - self.expr.streamline() - return self - - def validate( self, validateTrace=[] ): - if self not in validateTrace: - tmp = validateTrace[:]+[self] - if self.expr is not None: - self.expr.validate(tmp) - self.checkRecursion([]) - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - self._revertClass = self.__class__ - self.__class__ = _ForwardNoRecurse - try: - if self.expr is not None: - retString = _ustr(self.expr) - else: - retString = "None" - finally: - self.__class__ = self._revertClass - return self.__class__.__name__ + ": " + retString - - def copy(self): - if self.expr is not None: - return super(Forward,self).copy() - else: - ret = Forward() - ret << self - return ret - -class _ForwardNoRecurse(Forward): - def __str__( self ): - return "..." - -class TokenConverter(ParseElementEnhance): - """Abstract subclass of C{ParseExpression}, for converting parsed results.""" - def __init__( self, expr, savelist=False ): - super(TokenConverter,self).__init__( expr )#, savelist ) - self.saveAsList = False - -class Upcase(TokenConverter): - """Converter to upper case all matching tokens.""" - def __init__(self, *args): - super(Upcase,self).__init__(*args) - warnings.warn("Upcase class is deprecated, use upcaseTokens parse action instead", - DeprecationWarning,stacklevel=2) - - def postParse( self, instring, loc, tokenlist ): - return list(map( string.upper, tokenlist )) - - -class Combine(TokenConverter): - """Converter to concatenate all matching tokens to a single string. - By default, the matching patterns must also be contiguous in the input string; - this can be disabled by specifying C{'adjacent=False'} in the constructor. - """ - def __init__( self, expr, joinString="", adjacent=True ): - super(Combine,self).__init__( expr ) - # suppress whitespace-stripping in contained parse expressions, but re-enable it on the Combine itself - if adjacent: - self.leaveWhitespace() - self.adjacent = adjacent - self.skipWhitespace = True - self.joinString = joinString - self.callPreparse = True - - def ignore( self, other ): - if self.adjacent: - ParserElement.ignore(self, other) - else: - super( Combine, self).ignore( other ) - return self - - def postParse( self, instring, loc, tokenlist ): - retToks = tokenlist.copy() - del retToks[:] - retToks += ParseResults([ "".join(tokenlist._asStringList(self.joinString)) ], modal=self.modalResults) - - if self.resultsName and len(retToks.keys())>0: - return [ retToks ] - else: - return retToks - -class Group(TokenConverter): - """Converter to return the matched tokens as a list - useful for returning tokens of C{ZeroOrMore} and C{OneOrMore} expressions.""" - def __init__( self, expr ): - super(Group,self).__init__( expr ) - self.saveAsList = True - - def postParse( self, instring, loc, tokenlist ): - return [ tokenlist ] - -class Dict(TokenConverter): - """Converter to return a repetitive expression as a list, but also as a dictionary. - Each element can also be referenced using the first token in the expression as its key. - Useful for tabular report scraping when the first column can be used as a item key. - """ - def __init__( self, exprs ): - super(Dict,self).__init__( exprs ) - self.saveAsList = True - - def postParse( self, instring, loc, tokenlist ): - for i,tok in enumerate(tokenlist): - if len(tok) == 0: - continue - ikey = tok[0] - if isinstance(ikey,int): - ikey = _ustr(tok[0]).strip() - if len(tok)==1: - tokenlist[ikey] = _ParseResultsWithOffset("",i) - elif len(tok)==2 and not isinstance(tok[1],ParseResults): - tokenlist[ikey] = _ParseResultsWithOffset(tok[1],i) - else: - dictvalue = tok.copy() #ParseResults(i) - del dictvalue[0] - if len(dictvalue)!= 1 or (isinstance(dictvalue,ParseResults) and dictvalue.keys()): - tokenlist[ikey] = _ParseResultsWithOffset(dictvalue,i) - else: - tokenlist[ikey] = _ParseResultsWithOffset(dictvalue[0],i) - - if self.resultsName: - return [ tokenlist ] - else: - return tokenlist - - -class Suppress(TokenConverter): - """Converter for ignoring the results of a parsed expression.""" - def postParse( self, instring, loc, tokenlist ): - return [] - - def suppress( self ): - return self - - -class OnlyOnce(object): - """Wrapper for parse actions, to ensure they are only called once.""" - def __init__(self, methodCall): - self.callable = _trim_arity(methodCall) - self.called = False - def __call__(self,s,l,t): - if not self.called: - results = self.callable(s,l,t) - self.called = True - return results - raise ParseException(s,l,"") - def reset(self): - self.called = False - -def traceParseAction(f): - """Decorator for debugging parse actions.""" - f = _trim_arity(f) - def z(*paArgs): - thisFunc = f.func_name - s,l,t = paArgs[-3:] - if len(paArgs)>3: - thisFunc = paArgs[0].__class__.__name__ + '.' + thisFunc - sys.stderr.write( ">>entering %s(line: '%s', %d, %s)\n" % (thisFunc,line(l,s),l,t) ) - try: - ret = f(*paArgs) - except Exception: - exc = sys.exc_info()[1] - sys.stderr.write( "<", "|".join( [ _escapeRegexChars(sym) for sym in symbols] )) - try: - if len(symbols)==len("".join(symbols)): - return Regex( "[%s]" % "".join( [ _escapeRegexRangeChars(sym) for sym in symbols] ) ) - else: - return Regex( "|".join( [ re.escape(sym) for sym in symbols] ) ) - except: - warnings.warn("Exception creating Regex for oneOf, building MatchFirst", - SyntaxWarning, stacklevel=2) - - - # last resort, just use MatchFirst - return MatchFirst( [ parseElementClass(sym) for sym in symbols ] ) - -def dictOf( key, value ): - """Helper to easily and clearly define a dictionary by specifying the respective patterns - for the key and value. Takes care of defining the C{Dict}, C{ZeroOrMore}, and C{Group} tokens - in the proper order. The key pattern can include delimiting markers or punctuation, - as long as they are suppressed, thereby leaving the significant key text. The value - pattern can include named results, so that the C{Dict} results can include named token - fields. - """ - return Dict( ZeroOrMore( Group ( key + value ) ) ) - -def originalTextFor(expr, asString=True): - """Helper to return the original, untokenized text for a given expression. Useful to - restore the parsed fields of an HTML start tag into the raw tag text itself, or to - revert separate tokens with intervening whitespace back to the original matching - input text. Simpler to use than the parse action C{L{keepOriginalText}}, and does not - require the inspect module to chase up the call stack. By default, returns a - string containing the original parsed text. - - If the optional C{asString} argument is passed as C{False}, then the return value is a - C{ParseResults} containing any results names that were originally matched, and a - single token containing the original matched text from the input string. So if - the expression passed to C{L{originalTextFor}} contains expressions with defined - results names, you must set C{asString} to C{False} if you want to preserve those - results name values.""" - locMarker = Empty().setParseAction(lambda s,loc,t: loc) - endlocMarker = locMarker.copy() - endlocMarker.callPreparse = False - matchExpr = locMarker("_original_start") + expr + endlocMarker("_original_end") - if asString: - extractText = lambda s,l,t: s[t._original_start:t._original_end] - else: - def extractText(s,l,t): - del t[:] - t.insert(0, s[t._original_start:t._original_end]) - del t["_original_start"] - del t["_original_end"] - matchExpr.setParseAction(extractText) - return matchExpr - -# convenience constants for positional expressions -empty = Empty().setName("empty") -lineStart = LineStart().setName("lineStart") -lineEnd = LineEnd().setName("lineEnd") -stringStart = StringStart().setName("stringStart") -stringEnd = StringEnd().setName("stringEnd") - -_escapedPunc = Word( _bslash, r"\[]-*.$+^?()~ ", exact=2 ).setParseAction(lambda s,l,t:t[0][1]) -_printables_less_backslash = "".join([ c for c in printables if c not in r"\]" ]) -_escapedHexChar = Regex(r"\\0?[xX][0-9a-fA-F]+").setParseAction(lambda s,l,t:unichr(int(t[0][1:],16))) -_escapedOctChar = Regex(r"\\0[0-7]+").setParseAction(lambda s,l,t:unichr(int(t[0][1:],8))) -_singleChar = _escapedPunc | _escapedHexChar | _escapedOctChar | Word(_printables_less_backslash,exact=1) -_charRange = Group(_singleChar + Suppress("-") + _singleChar) -_reBracketExpr = Literal("[") + Optional("^").setResultsName("negate") + Group( OneOrMore( _charRange | _singleChar ) ).setResultsName("body") + "]" - -_expanded = lambda p: (isinstance(p,ParseResults) and ''.join([ unichr(c) for c in range(ord(p[0]),ord(p[1])+1) ]) or p) - -def srange(s): - r"""Helper to easily define string ranges for use in Word construction. Borrows - syntax from regexp '[]' string range definitions:: - srange("[0-9]") -> "0123456789" - srange("[a-z]") -> "abcdefghijklmnopqrstuvwxyz" - srange("[a-z$_]") -> "abcdefghijklmnopqrstuvwxyz$_" - The input string must be enclosed in []'s, and the returned string is the expanded - character set joined into a single string. - The values enclosed in the []'s may be:: - a single character - an escaped character with a leading backslash (such as \- or \]) - an escaped hex character with a leading '\x' (\x21, which is a '!' character) - (\0x## is also supported for backwards compatibility) - an escaped octal character with a leading '\0' (\041, which is a '!' character) - a range of any of the above, separated by a dash ('a-z', etc.) - any combination of the above ('aeiouy', 'a-zA-Z0-9_$', etc.) - """ - try: - return "".join([_expanded(part) for part in _reBracketExpr.parseString(s).body]) - except: - return "" - -def matchOnlyAtCol(n): - """Helper method for defining parse actions that require matching at a specific - column in the input text. - """ - def verifyCol(strg,locn,toks): - if col(locn,strg) != n: - raise ParseException(strg,locn,"matched token not at column %d" % n) - return verifyCol - -def replaceWith(replStr): - """Helper method for common parse actions that simply return a literal value. Especially - useful when used with C{transformString()}. - """ - def _replFunc(*args): - return [replStr] - return _replFunc - -def removeQuotes(s,l,t): - """Helper parse action for removing quotation marks from parsed quoted strings. - To use, add this parse action to quoted string using:: - quotedString.setParseAction( removeQuotes ) - """ - return t[0][1:-1] - -def upcaseTokens(s,l,t): - """Helper parse action to convert tokens to upper case.""" - return [ tt.upper() for tt in map(_ustr,t) ] - -def downcaseTokens(s,l,t): - """Helper parse action to convert tokens to lower case.""" - return [ tt.lower() for tt in map(_ustr,t) ] - -def keepOriginalText(s,startLoc,t): - """DEPRECATED - use new helper method C{originalTextFor}. - Helper parse action to preserve original parsed text, - overriding any nested parse actions.""" - try: - endloc = getTokensEndLoc() - except ParseException: - raise ParseFatalException("incorrect usage of keepOriginalText - may only be called as a parse action") - del t[:] - t += ParseResults(s[startLoc:endloc]) - return t - -def getTokensEndLoc(): - """Method to be called from within a parse action to determine the end - location of the parsed tokens.""" - import inspect - fstack = inspect.stack() - try: - # search up the stack (through intervening argument normalizers) for correct calling routine - for f in fstack[2:]: - if f[3] == "_parseNoCache": - endloc = f[0].f_locals["loc"] - return endloc - else: - raise ParseFatalException("incorrect usage of getTokensEndLoc - may only be called from within a parse action") - finally: - del fstack - -def _makeTags(tagStr, xml): - """Internal helper to construct opening and closing tag expressions, given a tag name""" - if isinstance(tagStr,basestring): - resname = tagStr - tagStr = Keyword(tagStr, caseless=not xml) - else: - resname = tagStr.name - - tagAttrName = Word(alphas,alphanums+"_-:") - if (xml): - tagAttrValue = dblQuotedString.copy().setParseAction( removeQuotes ) - openTag = Suppress("<") + tagStr("tag") + \ - Dict(ZeroOrMore(Group( tagAttrName + Suppress("=") + tagAttrValue ))) + \ - Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">") - else: - printablesLessRAbrack = "".join( [ c for c in printables if c not in ">" ] ) - tagAttrValue = quotedString.copy().setParseAction( removeQuotes ) | Word(printablesLessRAbrack) - openTag = Suppress("<") + tagStr("tag") + \ - Dict(ZeroOrMore(Group( tagAttrName.setParseAction(downcaseTokens) + \ - Optional( Suppress("=") + tagAttrValue ) ))) + \ - Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">") - closeTag = Combine(_L("") - - openTag = openTag.setResultsName("start"+"".join(resname.replace(":"," ").title().split())).setName("<%s>" % tagStr) - closeTag = closeTag.setResultsName("end"+"".join(resname.replace(":"," ").title().split())).setName("" % tagStr) - openTag.tag = resname - closeTag.tag = resname - return openTag, closeTag - -def makeHTMLTags(tagStr): - """Helper to construct opening and closing tag expressions for HTML, given a tag name""" - return _makeTags( tagStr, False ) - -def makeXMLTags(tagStr): - """Helper to construct opening and closing tag expressions for XML, given a tag name""" - return _makeTags( tagStr, True ) - -def withAttribute(*args,**attrDict): - """Helper to create a validating parse action to be used with start tags created - with C{makeXMLTags} or C{makeHTMLTags}. Use C{withAttribute} to qualify a starting tag - with a required attribute value, to avoid false matches on common tags such as - C{} or C{
}. - - Call C{withAttribute} with a series of attribute names and values. Specify the list - of filter attributes names and values as: - - keyword arguments, as in C{(align="right")}, or - - as an explicit dict with C{**} operator, when an attribute name is also a Python - reserved word, as in C{**{"class":"Customer", "align":"right"}} - - a list of name-value tuples, as in ( ("ns1:class", "Customer"), ("ns2:align","right") ) - For attribute names with a namespace prefix, you must use the second form. Attribute - names are matched insensitive to upper/lower case. - - To verify that the attribute exists, but without specifying a value, pass - C{withAttribute.ANY_VALUE} as the value. - """ - if args: - attrs = args[:] - else: - attrs = attrDict.items() - attrs = [(k,v) for k,v in attrs] - def pa(s,l,tokens): - for attrName,attrValue in attrs: - if attrName not in tokens: - raise ParseException(s,l,"no matching attribute " + attrName) - if attrValue != withAttribute.ANY_VALUE and tokens[attrName] != attrValue: - raise ParseException(s,l,"attribute '%s' has value '%s', must be '%s'" % - (attrName, tokens[attrName], attrValue)) - return pa -withAttribute.ANY_VALUE = object() - -opAssoc = _Constants() -opAssoc.LEFT = object() -opAssoc.RIGHT = object() - -def operatorPrecedence( baseExpr, opList ): - """Helper method for constructing grammars of expressions made up of - operators working in a precedence hierarchy. Operators may be unary or - binary, left- or right-associative. Parse actions can also be attached - to operator expressions. - - Parameters: - - baseExpr - expression representing the most basic element for the nested - - opList - list of tuples, one for each operator precedence level in the - expression grammar; each tuple is of the form - (opExpr, numTerms, rightLeftAssoc, parseAction), where: - - opExpr is the pyparsing expression for the operator; - may also be a string, which will be converted to a Literal; - if numTerms is 3, opExpr is a tuple of two expressions, for the - two operators separating the 3 terms - - numTerms is the number of terms for this operator (must - be 1, 2, or 3) - - rightLeftAssoc is the indicator whether the operator is - right or left associative, using the pyparsing-defined - constants opAssoc.RIGHT and opAssoc.LEFT. - - parseAction is the parse action to be associated with - expressions matching this operator expression (the - parse action tuple member may be omitted) - """ - ret = Forward() - lastExpr = baseExpr | ( Suppress('(') + ret + Suppress(')') ) - for i,operDef in enumerate(opList): - opExpr,arity,rightLeftAssoc,pa = (operDef + (None,))[:4] - if arity == 3: - if opExpr is None or len(opExpr) != 2: - raise ValueError("if numterms=3, opExpr must be a tuple or list of two expressions") - opExpr1, opExpr2 = opExpr - thisExpr = Forward()#.setName("expr%d" % i) - if rightLeftAssoc == opAssoc.LEFT: - if arity == 1: - matchExpr = FollowedBy(lastExpr + opExpr) + Group( lastExpr + OneOrMore( opExpr ) ) - elif arity == 2: - if opExpr is not None: - matchExpr = FollowedBy(lastExpr + opExpr + lastExpr) + Group( lastExpr + OneOrMore( opExpr + lastExpr ) ) - else: - matchExpr = FollowedBy(lastExpr+lastExpr) + Group( lastExpr + OneOrMore(lastExpr) ) - elif arity == 3: - matchExpr = FollowedBy(lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr) + \ - Group( lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr ) - else: - raise ValueError("operator must be unary (1), binary (2), or ternary (3)") - elif rightLeftAssoc == opAssoc.RIGHT: - if arity == 1: - # try to avoid LR with this extra test - if not isinstance(opExpr, Optional): - opExpr = Optional(opExpr) - matchExpr = FollowedBy(opExpr.expr + thisExpr) + Group( opExpr + thisExpr ) - elif arity == 2: - if opExpr is not None: - matchExpr = FollowedBy(lastExpr + opExpr + thisExpr) + Group( lastExpr + OneOrMore( opExpr + thisExpr ) ) - else: - matchExpr = FollowedBy(lastExpr + thisExpr) + Group( lastExpr + OneOrMore( thisExpr ) ) - elif arity == 3: - matchExpr = FollowedBy(lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr) + \ - Group( lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr ) - else: - raise ValueError("operator must be unary (1), binary (2), or ternary (3)") - else: - raise ValueError("operator must indicate right or left associativity") - if pa: - matchExpr.setParseAction( pa ) - thisExpr << ( matchExpr | lastExpr ) - lastExpr = thisExpr - ret << lastExpr - return ret - -dblQuotedString = Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\x[0-9a-fA-F]+)|(?:\\.))*"').setName("string enclosed in double quotes") -sglQuotedString = Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\x[0-9a-fA-F]+)|(?:\\.))*'").setName("string enclosed in single quotes") -quotedString = Regex(r'''(?:"(?:[^"\n\r\\]|(?:"")|(?:\\x[0-9a-fA-F]+)|(?:\\.))*")|(?:'(?:[^'\n\r\\]|(?:'')|(?:\\x[0-9a-fA-F]+)|(?:\\.))*')''').setName("quotedString using single or double quotes") -unicodeString = Combine(_L('u') + quotedString.copy()) - -def nestedExpr(opener="(", closer=")", content=None, ignoreExpr=quotedString.copy()): - """Helper method for defining nested lists enclosed in opening and closing - delimiters ("(" and ")" are the default). - - Parameters: - - opener - opening character for a nested list (default="("); can also be a pyparsing expression - - closer - closing character for a nested list (default=")"); can also be a pyparsing expression - - content - expression for items within the nested lists (default=None) - - ignoreExpr - expression for ignoring opening and closing delimiters (default=quotedString) - - If an expression is not provided for the content argument, the nested - expression will capture all whitespace-delimited content between delimiters - as a list of separate values. - - Use the C{ignoreExpr} argument to define expressions that may contain - opening or closing characters that should not be treated as opening - or closing characters for nesting, such as quotedString or a comment - expression. Specify multiple expressions using an C{L{Or}} or C{L{MatchFirst}}. - The default is L{quotedString}, but if no expressions are to be ignored, - then pass C{None} for this argument. - """ - if opener == closer: - raise ValueError("opening and closing strings cannot be the same") - if content is None: - if isinstance(opener,basestring) and isinstance(closer,basestring): - if len(opener) == 1 and len(closer)==1: - if ignoreExpr is not None: - content = (Combine(OneOrMore(~ignoreExpr + - CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS,exact=1)) - ).setParseAction(lambda t:t[0].strip())) - else: - content = (empty.copy()+CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS - ).setParseAction(lambda t:t[0].strip())) - else: - if ignoreExpr is not None: - content = (Combine(OneOrMore(~ignoreExpr + - ~Literal(opener) + ~Literal(closer) + - CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1)) - ).setParseAction(lambda t:t[0].strip())) - else: - content = (Combine(OneOrMore(~Literal(opener) + ~Literal(closer) + - CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1)) - ).setParseAction(lambda t:t[0].strip())) - else: - raise ValueError("opening and closing arguments must be strings if no content expression is given") - ret = Forward() - if ignoreExpr is not None: - ret << Group( Suppress(opener) + ZeroOrMore( ignoreExpr | ret | content ) + Suppress(closer) ) - else: - ret << Group( Suppress(opener) + ZeroOrMore( ret | content ) + Suppress(closer) ) - return ret - -def indentedBlock(blockStatementExpr, indentStack, indent=True): - """Helper method for defining space-delimited indentation blocks, such as - those used to define block statements in Python source code. - - Parameters: - - blockStatementExpr - expression defining syntax of statement that - is repeated within the indented block - - indentStack - list created by caller to manage indentation stack - (multiple statementWithIndentedBlock expressions within a single grammar - should share a common indentStack) - - indent - boolean indicating whether block must be indented beyond the - the current level; set to False for block of left-most statements - (default=True) - - A valid block must contain at least one C{blockStatement}. - """ - def checkPeerIndent(s,l,t): - if l >= len(s): return - curCol = col(l,s) - if curCol != indentStack[-1]: - if curCol > indentStack[-1]: - raise ParseFatalException(s,l,"illegal nesting") - raise ParseException(s,l,"not a peer entry") - - def checkSubIndent(s,l,t): - curCol = col(l,s) - if curCol > indentStack[-1]: - indentStack.append( curCol ) - else: - raise ParseException(s,l,"not a subentry") - - def checkUnindent(s,l,t): - if l >= len(s): return - curCol = col(l,s) - if not(indentStack and curCol < indentStack[-1] and curCol <= indentStack[-2]): - raise ParseException(s,l,"not an unindent") - indentStack.pop() - - NL = OneOrMore(LineEnd().setWhitespaceChars("\t ").suppress()) - INDENT = Empty() + Empty().setParseAction(checkSubIndent) - PEER = Empty().setParseAction(checkPeerIndent) - UNDENT = Empty().setParseAction(checkUnindent) - if indent: - smExpr = Group( Optional(NL) + - #~ FollowedBy(blockStatementExpr) + - INDENT + (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) + UNDENT) - else: - smExpr = Group( Optional(NL) + - (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) ) - blockStatementExpr.ignore(_bslash + LineEnd()) - return smExpr - -alphas8bit = srange(r"[\0xc0-\0xd6\0xd8-\0xf6\0xf8-\0xff]") -punc8bit = srange(r"[\0xa1-\0xbf\0xd7\0xf7]") - -anyOpenTag,anyCloseTag = makeHTMLTags(Word(alphas,alphanums+"_:")) -commonHTMLEntity = Combine(_L("&") + oneOf("gt lt amp nbsp quot").setResultsName("entity") +";").streamline() -_htmlEntityMap = dict(zip("gt lt amp nbsp quot".split(),'><& "')) -replaceHTMLEntity = lambda t : t.entity in _htmlEntityMap and _htmlEntityMap[t.entity] or None - -# it's easy to get these comment structures wrong - they're very common, so may as well make them available -cStyleComment = Regex(r"/\*(?:[^*]*\*+)+?/").setName("C style comment") - -htmlComment = Regex(r"") -restOfLine = Regex(r".*").leaveWhitespace() -dblSlashComment = Regex(r"\/\/(\\\n|.)*").setName("// comment") -cppStyleComment = Regex(r"/(?:\*(?:[^*]*\*+)+?/|/[^\n]*(?:\n[^\n]*)*?(?:(?" + str(tokenlist)) - print ("tokens = " + str(tokens)) - print ("tokens.columns = " + str(tokens.columns)) - print ("tokens.tables = " + str(tokens.tables)) - print (tokens.asXML("SQL",True)) - except ParseBaseException: - err = sys.exc_info()[1] - print (teststring + "->") - print (err.line) - print (" "*(err.column-1) + "^") - print (err) - print() - - selectToken = CaselessLiteral( "select" ) - fromToken = CaselessLiteral( "from" ) - - ident = Word( alphas, alphanums + "_$" ) - columnName = delimitedList( ident, ".", combine=True ).setParseAction( upcaseTokens ) - columnNameList = Group( delimitedList( columnName ) )#.setName("columns") - tableName = delimitedList( ident, ".", combine=True ).setParseAction( upcaseTokens ) - tableNameList = Group( delimitedList( tableName ) )#.setName("tables") - simpleSQL = ( selectToken + \ - ( '*' | columnNameList ).setResultsName( "columns" ) + \ - fromToken + \ - tableNameList.setResultsName( "tables" ) ) - - test( "SELECT * from XYZZY, ABC" ) - test( "select * from SYS.XYZZY" ) - test( "Select A from Sys.dual" ) - test( "Select AA,BB,CC from Sys.dual" ) - test( "Select A, B, C from Sys.dual" ) - test( "Select A, B, C from Sys.dual" ) - test( "Xelect A, B, C from Sys.dual" ) - test( "Select A, B, C frox Sys.dual" ) - test( "Select" ) - test( "Select ^^^ frox Sys.dual" ) - test( "Select A, B, C from Sys.dual, Table2 " ) diff --git a/scripts/xml2aloe/__init__.py b/scripts/xml2aloe/__init__.py index 78baf7aaf..1a26a8b67 100644 --- a/scripts/xml2aloe/__init__.py +++ b/scripts/xml2aloe/__init__.py @@ -1,3 +1,26 @@ +# +# Copyright 2012-2013 The libLTE Developers. See the +# COPYRIGHT file at the top-level directory of this distribution. +# +# This file is part of the libLTE library. +# +# libLTE is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# libLTE is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# A copy of the GNU Lesser 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/. +# + + + import shutil import os diff --git a/scripts/xml2aloe/template/src/template.c b/scripts/xml2aloe/template/src/template.c index a96676b01..cdf1cdf14 100644 --- a/scripts/xml2aloe/template/src/template.c +++ b/scripts/xml2aloe/template/src/template.c @@ -1,3 +1,30 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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/. + * + */ + /* * This file has been automatically generated from -name- */ diff --git a/scripts/xml2aloe/template/src/template.h b/scripts/xml2aloe/template/src/template.h index c09551d7e..c9283193a 100644 --- a/scripts/xml2aloe/template/src/template.h +++ b/scripts/xml2aloe/template/src/template.h @@ -1,3 +1,30 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 DEFINE_H #define DEFINE_H diff --git a/scripts/xml2aloe/template/test/test_generate.c b/scripts/xml2aloe/template/test/test_generate.c index c21002790..1f31903c0 100644 --- a/scripts/xml2aloe/template/test/test_generate.c +++ b/scripts/xml2aloe/template/test/test_generate.c @@ -1,21 +1,31 @@ -/* - * Copyright (c) 2013, Ismael Gomez-Miguelez . - * This file is part of ALOE++ (http://flexnets.upc.edu/) - * - * ALOE++ is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * ALOE++ is distributed in the hope that it will be useful, +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with ALOE++. If not, see . + * + * A copy of the GNU Lesser 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/. + * */ + /* Functions that generate the test data fed into the DSP modules being developed */ #include #include diff --git a/uhd/uhd.h b/uhd/uhd.h deleted file mode 100644 index bcc41b11b..000000000 --- a/uhd/uhd.h +++ /dev/null @@ -1,25 +0,0 @@ - - -#ifdef __cplusplus -extern "C" { -#endif -#include - -int uhd_open(char *args, void **handler); -int uhd_close(void *h); -int uhd_start_rx_stream(void *h); -int uhd_start_rx_stream_nsamples(void *h, int nsamples); -int uhd_stop_rx_stream(void *h); - -bool uhd_rx_wait_lo_locked(void *h); -double uhd_set_rx_srate(void *h, double freq); -double uhd_set_rx_gain(void *h, double gain); - -double uhd_set_rx_freq(void *h, double freq); - -int uhd_recv(void *h, void *data, int nsamples, int blocking); - - -#ifdef __cplusplus -} -#endif diff --git a/uhd/uhd_handler.hpp b/uhd/uhd_handler.hpp deleted file mode 100644 index 633ef00d0..000000000 --- a/uhd/uhd_handler.hpp +++ /dev/null @@ -1,9 +0,0 @@ -#include - -class uhd_handler { -public: - uhd::usrp::multi_usrp::sptr usrp; - uhd::rx_streamer::sptr rx_stream; - bool rx_stream_enable; - -}; diff --git a/uhd/uhd_imp.cpp b/uhd/uhd_imp.cpp deleted file mode 100644 index 91a04d983..000000000 --- a/uhd/uhd_imp.cpp +++ /dev/null @@ -1,138 +0,0 @@ -#include -#include -#include -#include -#include - -void my_handler(uhd::msg::type_t type, const std::string &msg){ - //handle the message... -} - -#include "uhd_handler.hpp" -#include "uhd.h" - -typedef _Complex float complex_t; - -#define SAMPLE_SZ sizeof(complex_t) - -bool isLocked(void *h) -{ - uhd_handler* handler = static_cast(h); - return handler->usrp->get_rx_sensor("lo_locked", 0).to_bool(); -} - -bool uhd_rx_wait_lo_locked(void *h) -{ - - double report = 0.0; - while(isLocked(h) && report < 3.0) - { - report += 0.1; - usleep(1000); - } - return isLocked(h); -} - -int uhd_start_rx_stream(void *h) { - uhd_handler* handler = static_cast(h); - uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS); - cmd.time_spec = handler->usrp->get_time_now(); - cmd.stream_now = true; - handler->usrp->issue_stream_cmd(cmd); - return 0; -} - -int uhd_stop_rx_stream(void *h) { - uhd_handler* handler = static_cast(h); - uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS); - cmd.time_spec = handler->usrp->get_time_now(); - cmd.stream_now = true; - handler->usrp->issue_stream_cmd(cmd); - return 0; -} - -int uhd_start_rx_stream_nsamples(void *h, int nsamples) { - uhd_handler* handler = static_cast(h); - uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE); - cmd.time_spec = handler->usrp->get_time_now(); - cmd.stream_now = true; - cmd.num_samps = nsamples; - handler->usrp->issue_stream_cmd(cmd); - return 0; -} - - - -int uhd_open(char *args, void **h) { - uhd_handler* handler = new uhd_handler(); - std::string _args=std::string(args); - handler->usrp = uhd::usrp::multi_usrp::make(_args); - - //uhd::msg::register_handler(&my_handler); - - std::string otw, cpu; - otw="sc16"; - cpu="fc32"; - - handler->usrp->set_clock_source("internal"); - - uhd::stream_args_t stream_args(cpu, otw); -// stream_args.channels.push_back(0); -// stream_args.args["noclear"] = "1"; - - handler->rx_stream = handler->usrp->get_rx_stream(stream_args); - *h = handler; - - int size = 10000*handler->rx_stream->get_max_num_samps(); - - return 0; -} - -int uhd_close(void *h) { - uhd_handler* handler = static_cast(h); - return 0; -} - - -double uhd_set_rx_srate(void *h, double freq) { - uhd_handler* handler = static_cast(h); - handler->usrp->set_rx_rate(freq); - double ret = handler->usrp->get_rx_rate(); - return ret; -} - -double uhd_set_rx_gain(void *h, double gain) { - uhd_handler* handler = static_cast(h); - handler->usrp->set_rx_gain(gain); - return handler->usrp->get_rx_gain(); -} - -float uhd_get_rx_srate(void *h) { - uhd_handler* handler = static_cast(h); - return handler->usrp->get_tx_rate(); -} - -double uhd_set_rx_freq(void *h, double freq) { - uhd_handler* handler = static_cast(h); - handler->usrp->set_rx_freq(freq); - return handler->usrp->get_rx_freq(); -} - -int uhd_recv(void *h, void *data, int nsamples, int blocking) { - uhd_handler* handler = static_cast(h); - uhd::rx_metadata_t md; - if (blocking) { - int n=0,p; - complex_t *data_c = (complex_t*) data; - do { - p=handler->rx_stream->recv(&data_c[n], nsamples-n, md); - if (p == -1) { - return -1; - } - n+=p; - } while(nrx_stream->recv(data, nsamples, md, 0.0); - } -} diff --git a/uhd/uhd_utils.c b/uhd/uhd_utils.c deleted file mode 100644 index 89548991e..000000000 --- a/uhd/uhd_utils.c +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include -#include -#include - -#include "uhd.h" -#include "utils/vector.h" -#include "utils/debug.h" - -int uhd_rssi_scan(void *uhd, float *freqs, float *rssi, int nof_bands, double fs, int nsamp) { - int i, j; - int ret = -1; - _Complex float *buffer; - double f; - - buffer = calloc(nsamp, sizeof(_Complex float)); - if (!buffer) { - goto free_and_exit; - } - - uhd_set_rx_gain(uhd, 0.0); - uhd_set_rx_srate(uhd, fs); - - for (i=0;i